1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "xetable.hxx"
23 #include <com/sun/star/i18n/ScriptType.hpp>
24 #include "scitems.hxx"
25 #include <svl/intitem.hxx>
26 #include "document.hxx"
27 #include "dociter.hxx"
28 #include "olinetab.hxx"
29 #include "formulacell.hxx"
30 #include "patattr.hxx"
32 #include "xehelper.hxx"
33 #include "xecontent.hxx"
34 #include "xeescher.hxx"
35 #include "xeextlst.hxx"
36 #include "tokenarray.hxx"
38 using namespace ::oox
;
41 namespace ApiScriptType
= ::com::sun::star::i18n::ScriptType
;
43 // ============================================================================
44 // Helper records for cell records
45 // ============================================================================
47 XclExpStringRec::XclExpStringRec( const XclExpRoot
& rRoot
, const String
& rResult
) :
48 XclExpRecord( EXC_ID3_STRING
),
49 mxResult( XclExpStringHelper::CreateString( rRoot
, rResult
) )
51 OSL_ENSURE( (rRoot
.GetBiff() <= EXC_BIFF5
) || (mxResult
->Len() > 0),
52 "XclExpStringRec::XclExpStringRec - empty result not allowed in BIFF8+" );
53 SetRecSize( mxResult
->GetSize() );
56 void XclExpStringRec::WriteBody( XclExpStream
& rStrm
)
61 // Additional records for special formula ranges ==============================
63 XclExpRangeFmlaBase::XclExpRangeFmlaBase(
64 sal_uInt16 nRecId
, sal_uInt32 nRecSize
, const ScAddress
& rScPos
) :
65 XclExpRecord( nRecId
, nRecSize
),
66 maXclRange( ScAddress::UNINITIALIZED
),
67 maBaseXclPos( ScAddress::UNINITIALIZED
)
69 maBaseXclPos
.Set( static_cast< sal_uInt16
>( rScPos
.Col() ), static_cast< sal_uInt16
>( rScPos
.Row() ) );
70 maXclRange
.maFirst
= maXclRange
.maLast
= maBaseXclPos
;
73 XclExpRangeFmlaBase::XclExpRangeFmlaBase(
74 sal_uInt16 nRecId
, sal_uInt32 nRecSize
, const ScRange
& rScRange
) :
75 XclExpRecord( nRecId
, nRecSize
),
76 maXclRange( ScAddress::UNINITIALIZED
),
77 maBaseXclPos( ScAddress::UNINITIALIZED
)
80 static_cast< sal_uInt16
>( rScRange
.aStart
.Col() ),
81 static_cast< sal_uInt16
>( rScRange
.aStart
.Row() ),
82 static_cast< sal_uInt16
>( rScRange
.aEnd
.Col() ),
83 static_cast< sal_uInt16
>( rScRange
.aEnd
.Row() ) );
84 maBaseXclPos
= maXclRange
.maFirst
;
87 bool XclExpRangeFmlaBase::IsBasePos( sal_uInt16 nXclCol
, sal_uInt32 nXclRow
) const
89 return (maBaseXclPos
.mnCol
== nXclCol
) && (maBaseXclPos
.mnRow
== nXclRow
);
92 void XclExpRangeFmlaBase::Extend( const ScAddress
& rScPos
)
94 sal_uInt16 nXclCol
= static_cast< sal_uInt16
>( rScPos
.Col() );
95 sal_uInt32 nXclRow
= static_cast< sal_uInt32
>( rScPos
.Row() );
96 maXclRange
.maFirst
.mnCol
= ::std::min( maXclRange
.maFirst
.mnCol
, nXclCol
);
97 maXclRange
.maFirst
.mnRow
= ::std::min( maXclRange
.maFirst
.mnRow
, nXclRow
);
98 maXclRange
.maLast
.mnCol
= ::std::max( maXclRange
.maLast
.mnCol
, nXclCol
);
99 maXclRange
.maLast
.mnRow
= ::std::max( maXclRange
.maLast
.mnRow
, nXclRow
);
102 void XclExpRangeFmlaBase::WriteRangeAddress( XclExpStream
& rStrm
) const
104 maXclRange
.Write( rStrm
, false );
107 // Array formulas =============================================================
109 XclExpArray::XclExpArray( XclTokenArrayRef xTokArr
, const ScRange
& rScRange
) :
110 XclExpRangeFmlaBase( EXC_ID3_ARRAY
, 14 + xTokArr
->GetSize(), rScRange
),
115 XclTokenArrayRef
XclExpArray::CreateCellTokenArray( const XclExpRoot
& rRoot
) const
117 return rRoot
.GetFormulaCompiler().CreateSpecialRefFormula( EXC_TOKID_EXP
, maBaseXclPos
);
120 bool XclExpArray::IsVolatile() const
122 return mxTokArr
->IsVolatile();
125 void XclExpArray::WriteBody( XclExpStream
& rStrm
)
127 WriteRangeAddress( rStrm
);
128 sal_uInt16 nFlags
= EXC_ARRAY_DEFAULTFLAGS
;
129 ::set_flag( nFlags
, EXC_ARRAY_RECALC_ALWAYS
, IsVolatile() );
130 rStrm
<< nFlags
<< sal_uInt32( 0 ) << *mxTokArr
;
133 // ----------------------------------------------------------------------------
135 XclExpArrayBuffer::XclExpArrayBuffer( const XclExpRoot
& rRoot
) :
140 XclExpArrayRef
XclExpArrayBuffer::CreateArray( const ScTokenArray
& rScTokArr
, const ScRange
& rScRange
)
142 const ScAddress
& rScPos
= rScRange
.aStart
;
143 XclTokenArrayRef xTokArr
= GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_MATRIX
, rScTokArr
, &rScPos
);
145 OSL_ENSURE( maRecMap
.find( rScPos
) == maRecMap
.end(), "XclExpArrayBuffer::CreateArray - array exists already" );
146 XclExpArrayRef
& rxRec
= maRecMap
[ rScPos
];
147 rxRec
.reset( new XclExpArray( xTokArr
, rScRange
) );
151 XclExpArrayRef
XclExpArrayBuffer::FindArray( const ScTokenArray
& rScTokArr
) const
154 // try to extract a matrix reference token
155 if( rScTokArr
.GetLen() == 1 )
157 const formula::FormulaToken
* pToken
= rScTokArr
.GetArray()[ 0 ];
158 if( pToken
&& (pToken
->GetOpCode() == ocMatRef
) )
160 const ScSingleRefData
& rRef
= static_cast<const ScToken
*>(pToken
)->GetSingleRef();
161 ScAddress
aBasePos( rRef
.nCol
, rRef
.nRow
, GetCurrScTab() );
162 XclExpArrayMap::const_iterator aIt
= maRecMap
.find( aBasePos
);
163 if( aIt
!= maRecMap
.end() )
170 // Shared formulas ============================================================
172 XclExpShrfmla::XclExpShrfmla( XclTokenArrayRef xTokArr
, const ScAddress
& rScPos
) :
173 XclExpRangeFmlaBase( EXC_ID_SHRFMLA
, 10 + xTokArr
->GetSize(), rScPos
),
179 void XclExpShrfmla::ExtendRange( const ScAddress
& rScPos
)
185 XclTokenArrayRef
XclExpShrfmla::CreateCellTokenArray( const XclExpRoot
& rRoot
) const
187 return rRoot
.GetFormulaCompiler().CreateSpecialRefFormula( EXC_TOKID_EXP
, maBaseXclPos
);
190 bool XclExpShrfmla::IsVolatile() const
192 return mxTokArr
->IsVolatile();
195 void XclExpShrfmla::WriteBody( XclExpStream
& rStrm
)
197 WriteRangeAddress( rStrm
);
198 rStrm
<< sal_uInt8( 0 ) << mnUsedCount
<< *mxTokArr
;
201 // ----------------------------------------------------------------------------
203 XclExpShrfmlaBuffer::XclExpShrfmlaBuffer( const XclExpRoot
& rRoot
) :
208 XclExpShrfmlaRef
XclExpShrfmlaBuffer::CreateOrExtendShrfmla(
209 const ScTokenArray
& rScTokArr
, const ScAddress
& rScPos
)
211 XclExpShrfmlaRef xRec
;
212 if( const ScTokenArray
* pShrdScTokArr
= XclTokenArrayHelper::GetSharedFormula( GetRoot(), rScTokArr
) )
214 XclExpShrfmlaMap::iterator aIt
= maRecMap
.find( pShrdScTokArr
);
215 if( aIt
== maRecMap
.end() )
217 // create a new record
218 XclTokenArrayRef xTokArr
= GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_SHARED
, *pShrdScTokArr
, &rScPos
);
219 xRec
.reset( new XclExpShrfmla( xTokArr
, rScPos
) );
220 maRecMap
[ pShrdScTokArr
] = xRec
;
224 // extend existing record
225 OSL_ENSURE( aIt
->second
, "XclExpShrfmlaBuffer::CreateOrExtendShrfmla - missing record" );
227 xRec
->ExtendRange( rScPos
);
233 // Multiple operations ========================================================
235 XclExpTableop::XclExpTableop( const ScAddress
& rScPos
,
236 const XclMultipleOpRefs
& rRefs
, sal_uInt8 nScMode
) :
237 XclExpRangeFmlaBase( EXC_ID3_TABLEOP
, 16, rScPos
),
238 mnLastAppXclCol( static_cast< sal_uInt16
>( rScPos
.Col() ) ),
239 mnColInpXclCol( static_cast< sal_uInt16
>( rRefs
.maColFirstScPos
.Col() ) ),
240 mnColInpXclRow( static_cast< sal_uInt16
>( rRefs
.maColFirstScPos
.Row() ) ),
241 mnRowInpXclCol( static_cast< sal_uInt16
>( rRefs
.maRowFirstScPos
.Col() ) ),
242 mnRowInpXclRow( static_cast< sal_uInt16
>( rRefs
.maRowFirstScPos
.Row() ) ),
248 bool XclExpTableop::TryExtend( const ScAddress
& rScPos
, const XclMultipleOpRefs
& rRefs
)
250 sal_uInt16 nXclCol
= static_cast< sal_uInt16
>( rScPos
.Col() );
251 sal_uInt16 nXclRow
= static_cast< sal_uInt16
>( rScPos
.Row() );
253 bool bOk
= IsAppendable( nXclCol
, nXclRow
);
256 SCCOL nFirstScCol
= static_cast< SCCOL
>( maXclRange
.maFirst
.mnCol
);
257 SCROW nFirstScRow
= static_cast< SCROW
>( maXclRange
.maFirst
.mnRow
);
258 SCCOL nColInpScCol
= static_cast< SCCOL
>( mnColInpXclCol
);
259 SCROW nColInpScRow
= static_cast< SCROW
>( mnColInpXclRow
);
260 SCCOL nRowInpScCol
= static_cast< SCCOL
>( mnRowInpXclCol
);
261 SCROW nRowInpScRow
= static_cast< SCROW
>( mnRowInpXclRow
);
263 bOk
= ((mnScMode
== 2) == rRefs
.mbDblRefMode
) &&
264 (rScPos
.Tab() == rRefs
.maFmlaScPos
.Tab()) &&
265 (nColInpScCol
== rRefs
.maColFirstScPos
.Col()) &&
266 (nColInpScRow
== rRefs
.maColFirstScPos
.Row()) &&
267 (rScPos
.Tab() == rRefs
.maColFirstScPos
.Tab()) &&
268 (rScPos
.Tab() == rRefs
.maColRelScPos
.Tab());
270 if( bOk
) switch( mnScMode
)
273 bOk
= (rScPos
.Col() == rRefs
.maFmlaScPos
.Col()) &&
274 (nFirstScRow
== rRefs
.maFmlaScPos
.Row() + 1) &&
275 (nFirstScCol
== rRefs
.maColRelScPos
.Col() + 1) &&
276 (rScPos
.Row() == rRefs
.maColRelScPos
.Row());
279 bOk
= (nFirstScCol
== rRefs
.maFmlaScPos
.Col() + 1) &&
280 (rScPos
.Row() == rRefs
.maFmlaScPos
.Row()) &&
281 (rScPos
.Col() == rRefs
.maColRelScPos
.Col()) &&
282 (nFirstScRow
== rRefs
.maColRelScPos
.Row() + 1);
285 bOk
= (nFirstScCol
== rRefs
.maFmlaScPos
.Col() + 1) &&
286 (nFirstScRow
== rRefs
.maFmlaScPos
.Row() + 1) &&
287 (nFirstScCol
== rRefs
.maColRelScPos
.Col() + 1) &&
288 (rScPos
.Row() == rRefs
.maColRelScPos
.Row()) &&
289 (nRowInpScCol
== rRefs
.maRowFirstScPos
.Col()) &&
290 (nRowInpScRow
== rRefs
.maRowFirstScPos
.Row()) &&
291 (rScPos
.Tab() == rRefs
.maRowFirstScPos
.Tab()) &&
292 (rScPos
.Col() == rRefs
.maRowRelScPos
.Col()) &&
293 (nFirstScRow
== rRefs
.maRowRelScPos
.Row() + 1) &&
294 (rScPos
.Tab() == rRefs
.maRowRelScPos
.Tab());
302 // extend the cell range
303 OSL_ENSURE( IsAppendable( nXclCol
, nXclRow
), "XclExpTableop::TryExtend - wrong cell address" );
305 mnLastAppXclCol
= nXclCol
;
312 void XclExpTableop::Finalize()
314 // is the range complete? (last appended cell is in last column)
315 mbValid
= maXclRange
.maLast
.mnCol
== mnLastAppXclCol
;
316 // if last row is incomplete, try to shorten the used range
317 if( !mbValid
&& (maXclRange
.maFirst
.mnRow
< maXclRange
.maLast
.mnRow
) )
319 --maXclRange
.maLast
.mnRow
;
323 // check if referred cells are outside of own range
324 if( mbValid
) switch( mnScMode
)
327 mbValid
= (mnColInpXclCol
+ 1 < maXclRange
.maFirst
.mnCol
) || (mnColInpXclCol
> maXclRange
.maLast
.mnCol
) ||
328 (mnColInpXclRow
< maXclRange
.maFirst
.mnRow
) || (mnColInpXclRow
> maXclRange
.maLast
.mnRow
);
331 mbValid
= (mnColInpXclCol
< maXclRange
.maFirst
.mnCol
) || (mnColInpXclCol
> maXclRange
.maLast
.mnCol
) ||
332 (mnColInpXclRow
+ 1 < maXclRange
.maFirst
.mnRow
) || (mnColInpXclRow
> maXclRange
.maLast
.mnRow
);
335 mbValid
= ((mnColInpXclCol
+ 1 < maXclRange
.maFirst
.mnCol
) || (mnColInpXclCol
> maXclRange
.maLast
.mnCol
) ||
336 (mnColInpXclRow
+ 1 < maXclRange
.maFirst
.mnRow
) || (mnColInpXclRow
> maXclRange
.maLast
.mnRow
)) &&
337 ((mnRowInpXclCol
+ 1 < maXclRange
.maFirst
.mnCol
) || (mnRowInpXclCol
> maXclRange
.maLast
.mnCol
) ||
338 (mnRowInpXclRow
+ 1 < maXclRange
.maFirst
.mnRow
) || (mnRowInpXclRow
> maXclRange
.maLast
.mnRow
));
343 XclTokenArrayRef
XclExpTableop::CreateCellTokenArray( const XclExpRoot
& rRoot
) const
345 XclExpFormulaCompiler
& rFmlaComp
= rRoot
.GetFormulaCompiler();
347 rFmlaComp
.CreateSpecialRefFormula( EXC_TOKID_TBL
, maBaseXclPos
) :
348 rFmlaComp
.CreateErrorFormula( EXC_ERR_NA
);
351 bool XclExpTableop::IsVolatile() const
356 void XclExpTableop::Save( XclExpStream
& rStrm
)
359 XclExpRangeFmlaBase::Save( rStrm
);
362 bool XclExpTableop::IsAppendable( sal_uInt16 nXclCol
, sal_uInt16 nXclRow
) const
364 return ((nXclCol
== mnLastAppXclCol
+ 1) && (nXclRow
== maXclRange
.maFirst
.mnRow
)) ||
365 ((nXclCol
== mnLastAppXclCol
+ 1) && (nXclCol
<= maXclRange
.maLast
.mnCol
) && (nXclRow
== maXclRange
.maLast
.mnRow
)) ||
366 ((mnLastAppXclCol
== maXclRange
.maLast
.mnCol
) && (nXclCol
== maXclRange
.maFirst
.mnCol
) && (nXclRow
== maXclRange
.maLast
.mnRow
+ 1));
369 void XclExpTableop::WriteBody( XclExpStream
& rStrm
)
371 sal_uInt16 nFlags
= EXC_TABLEOP_DEFAULTFLAGS
;
372 ::set_flag( nFlags
, EXC_TABLEOP_RECALC_ALWAYS
, IsVolatile() );
375 case 1: ::set_flag( nFlags
, EXC_TABLEOP_ROW
); break;
376 case 2: ::set_flag( nFlags
, EXC_TABLEOP_BOTH
); break;
379 WriteRangeAddress( rStrm
);
382 rStrm
<< mnRowInpXclRow
<< mnRowInpXclCol
<< mnColInpXclRow
<< mnColInpXclCol
;
384 rStrm
<< mnColInpXclRow
<< mnColInpXclCol
<< sal_uInt32( 0 );
387 // ----------------------------------------------------------------------------
389 XclExpTableopBuffer::XclExpTableopBuffer( const XclExpRoot
& rRoot
) :
394 XclExpTableopRef
XclExpTableopBuffer::CreateOrExtendTableop(
395 const ScTokenArray
& rScTokArr
, const ScAddress
& rScPos
)
397 XclExpTableopRef xRec
;
399 // try to extract cell references of a multiple operations formula
400 XclMultipleOpRefs aRefs
;
401 if( XclTokenArrayHelper::GetMultipleOpRefs( aRefs
, rScTokArr
) )
403 // try to find an existing TABLEOP record for this cell position
404 for( size_t nPos
= 0, nSize
= maTableopList
.GetSize(); !xRec
&& (nPos
< nSize
); ++nPos
)
406 XclExpTableopRef xTempRec
= maTableopList
.GetRecord( nPos
);
407 if( xTempRec
->TryExtend( rScPos
, aRefs
) )
411 // no record found, or found record not extensible
413 xRec
= TryCreate( rScPos
, aRefs
);
419 void XclExpTableopBuffer::Finalize()
421 for( size_t nPos
= 0, nSize
= maTableopList
.GetSize(); nPos
< nSize
; ++nPos
)
422 maTableopList
.GetRecord( nPos
)->Finalize();
425 XclExpTableopRef
XclExpTableopBuffer::TryCreate( const ScAddress
& rScPos
, const XclMultipleOpRefs
& rRefs
)
427 sal_uInt8 nScMode
= 0;
428 bool bOk
= (rScPos
.Tab() == rRefs
.maFmlaScPos
.Tab()) &&
429 (rScPos
.Tab() == rRefs
.maColFirstScPos
.Tab()) &&
430 (rScPos
.Tab() == rRefs
.maColRelScPos
.Tab());
434 if( rRefs
.mbDblRefMode
)
437 bOk
= (rScPos
.Col() == rRefs
.maFmlaScPos
.Col() + 1) &&
438 (rScPos
.Row() == rRefs
.maFmlaScPos
.Row() + 1) &&
439 (rScPos
.Col() == rRefs
.maColRelScPos
.Col() + 1) &&
440 (rScPos
.Row() == rRefs
.maColRelScPos
.Row()) &&
441 (rScPos
.Tab() == rRefs
.maRowFirstScPos
.Tab()) &&
442 (rScPos
.Col() == rRefs
.maRowRelScPos
.Col()) &&
443 (rScPos
.Row() == rRefs
.maRowRelScPos
.Row() + 1) &&
444 (rScPos
.Tab() == rRefs
.maRowRelScPos
.Tab());
446 else if( (rScPos
.Col() == rRefs
.maFmlaScPos
.Col()) &&
447 (rScPos
.Row() == rRefs
.maFmlaScPos
.Row() + 1) &&
448 (rScPos
.Col() == rRefs
.maColRelScPos
.Col() + 1) &&
449 (rScPos
.Row() == rRefs
.maColRelScPos
.Row()) )
453 else if( (rScPos
.Col() == rRefs
.maFmlaScPos
.Col() + 1) &&
454 (rScPos
.Row() == rRefs
.maFmlaScPos
.Row()) &&
455 (rScPos
.Col() == rRefs
.maColRelScPos
.Col()) &&
456 (rScPos
.Row() == rRefs
.maColRelScPos
.Row() + 1) )
466 XclExpTableopRef xRec
;
469 xRec
.reset( new XclExpTableop( rScPos
, rRefs
, nScMode
) );
470 maTableopList
.AppendRecord( xRec
);
476 // ============================================================================
478 // ============================================================================
480 XclExpCellBase::XclExpCellBase(
481 sal_uInt16 nRecId
, sal_Size nContSize
, const XclAddress
& rXclPos
) :
482 XclExpRecord( nRecId
, nContSize
+ 4 ),
487 bool XclExpCellBase::IsMultiLineText() const
492 bool XclExpCellBase::TryMerge( const XclExpCellBase
& /*rCell*/ )
497 void XclExpCellBase::GetBlankXFIndexes( ScfUInt16Vec
& /*rXFIndexes*/ ) const
499 // default: do nothing
502 void XclExpCellBase::RemoveUnusedBlankCells( const ScfUInt16Vec
& /*rXFIndexes*/ )
504 // default: do nothing
507 // Single cell records ========================================================
509 XclExpSingleCellBase::XclExpSingleCellBase(
510 sal_uInt16 nRecId
, sal_Size nContSize
, const XclAddress
& rXclPos
, sal_uInt32 nXFId
) :
511 XclExpCellBase( nRecId
, 2, rXclPos
),
513 mnContSize( nContSize
)
517 XclExpSingleCellBase::XclExpSingleCellBase( const XclExpRoot
& rRoot
,
518 sal_uInt16 nRecId
, sal_Size nContSize
, const XclAddress
& rXclPos
,
519 const ScPatternAttr
* pPattern
, sal_Int16 nScript
, sal_uInt32 nForcedXFId
) :
520 XclExpCellBase( nRecId
, 2, rXclPos
),
521 maXFId( nForcedXFId
),
522 mnContSize( nContSize
)
524 if( GetXFId() == EXC_XFID_NOTFOUND
)
525 SetXFId( rRoot
.GetXFBuffer().Insert( pPattern
, nScript
) );
528 sal_uInt16
XclExpSingleCellBase::GetLastXclCol() const
533 sal_uInt32
XclExpSingleCellBase::GetFirstXFId() const
538 bool XclExpSingleCellBase::IsEmpty() const
543 void XclExpSingleCellBase::ConvertXFIndexes( const XclExpRoot
& rRoot
)
545 maXFId
.ConvertXFIndex( rRoot
);
548 void XclExpSingleCellBase::Save( XclExpStream
& rStrm
)
550 OSL_ENSURE_BIFF( rStrm
.GetRoot().GetBiff() >= EXC_BIFF3
);
551 AddRecSize( mnContSize
);
552 XclExpCellBase::Save( rStrm
);
555 void XclExpSingleCellBase::WriteBody( XclExpStream
& rStrm
)
557 rStrm
<< static_cast<sal_uInt16
> (GetXclRow()) << GetXclCol() << maXFId
.mnXFIndex
;
558 WriteContents( rStrm
);
561 // ----------------------------------------------------------------------------
563 IMPL_FIXEDMEMPOOL_NEWDEL( XclExpNumberCell
)
565 XclExpNumberCell::XclExpNumberCell(
566 const XclExpRoot
& rRoot
, const XclAddress
& rXclPos
,
567 const ScPatternAttr
* pPattern
, sal_uInt32 nForcedXFId
, double fValue
) :
568 // #i41210# always use latin script for number cells - may look wrong for special number formats...
569 XclExpSingleCellBase( rRoot
, EXC_ID3_NUMBER
, 8, rXclPos
, pPattern
, ApiScriptType::LATIN
, nForcedXFId
),
574 static OString
lcl_GetStyleId( XclExpXmlStream
& rStrm
, sal_uInt32 nXFIndex
)
576 return OString::valueOf( rStrm
.GetRoot().GetXFBuffer()
577 .GetXmlCellIndex( nXFIndex
) );
580 static OString
lcl_GetStyleId( XclExpXmlStream
& rStrm
, const XclExpCellBase
& rCell
)
582 sal_uInt32 nXFId
= rCell
.GetFirstXFId();
583 sal_uInt16 nXFIndex
= rStrm
.GetRoot().GetXFBuffer().GetXFIndex( nXFId
);
584 return lcl_GetStyleId( rStrm
, nXFIndex
);
587 void XclExpNumberCell::SaveXml( XclExpXmlStream
& rStrm
)
589 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
590 rWorksheet
->startElement( XML_c
,
591 XML_r
, XclXmlUtils::ToOString( GetXclPos() ).getStr(),
592 XML_s
, lcl_GetStyleId( rStrm
, *this ).getStr(),
594 // OOXTODO: XML_cm, XML_vm, XML_ph
596 rWorksheet
->startElement( XML_v
, FSEND
);
597 rWorksheet
->write( mfValue
);
598 rWorksheet
->endElement( XML_v
);
599 rWorksheet
->endElement( XML_c
);
602 void XclExpNumberCell::WriteContents( XclExpStream
& rStrm
)
607 // ----------------------------------------------------------------------------
609 IMPL_FIXEDMEMPOOL_NEWDEL( XclExpBooleanCell
)
611 XclExpBooleanCell::XclExpBooleanCell(
612 const XclExpRoot rRoot
, const XclAddress
& rXclPos
,
613 const ScPatternAttr
* pPattern
, sal_uInt32 nForcedXFId
, bool bValue
) :
614 // #i41210# always use latin script for boolean cells
615 XclExpSingleCellBase( rRoot
, EXC_ID3_BOOLERR
, 2, rXclPos
, pPattern
, ApiScriptType::LATIN
, nForcedXFId
),
620 void XclExpBooleanCell::SaveXml( XclExpXmlStream
& rStrm
)
622 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
623 rWorksheet
->startElement( XML_c
,
624 XML_r
, XclXmlUtils::ToOString( GetXclPos() ).getStr(),
625 XML_s
, lcl_GetStyleId( rStrm
, *this ).getStr(),
627 // OOXTODO: XML_cm, XML_vm, XML_ph
629 rWorksheet
->startElement( XML_v
, FSEND
);
630 rWorksheet
->write( mbValue
? "1" : "0" );
631 rWorksheet
->endElement( XML_v
);
632 rWorksheet
->endElement( XML_c
);
635 void XclExpBooleanCell::WriteContents( XclExpStream
& rStrm
)
637 rStrm
<< sal_uInt16( mbValue
? 1 : 0 ) << EXC_BOOLERR_BOOL
;
640 IMPL_FIXEDMEMPOOL_NEWDEL( XclExpLabelCell
)
642 XclExpLabelCell::XclExpLabelCell(
643 const XclExpRoot
& rRoot
, const XclAddress
& rXclPos
,
644 const ScPatternAttr
* pPattern
, sal_uInt32 nForcedXFId
, const OUString
& rStr
) :
645 XclExpSingleCellBase( EXC_ID3_LABEL
, 0, rXclPos
, nForcedXFId
)
647 sal_uInt16 nMaxLen
= (rRoot
.GetBiff() == EXC_BIFF8
) ? EXC_STR_MAXLEN
: EXC_LABEL_MAXLEN
;
648 XclExpStringRef xText
= XclExpStringHelper::CreateCellString(
649 rRoot
, rStr
, pPattern
, EXC_STR_DEFAULT
, nMaxLen
);
650 Init( rRoot
, pPattern
, xText
);
653 XclExpLabelCell::XclExpLabelCell(
654 const XclExpRoot
& rRoot
, const XclAddress
& rXclPos
,
655 const ScPatternAttr
* pPattern
, sal_uInt32 nForcedXFId
,
656 const EditTextObject
* pEditText
, XclExpHyperlinkHelper
& rLinkHelper
) :
657 XclExpSingleCellBase( EXC_ID3_LABEL
, 0, rXclPos
, nForcedXFId
)
659 sal_uInt16 nMaxLen
= (rRoot
.GetBiff() == EXC_BIFF8
) ? EXC_STR_MAXLEN
: EXC_LABEL_MAXLEN
;
661 XclExpStringRef xText
;
663 xText
= XclExpStringHelper::CreateCellString(
664 rRoot
, *pEditText
, pPattern
, rLinkHelper
, EXC_STR_DEFAULT
, nMaxLen
);
666 xText
= XclExpStringHelper::CreateCellString(
667 rRoot
, EMPTY_OUSTRING
, pPattern
, EXC_STR_DEFAULT
, nMaxLen
);
669 Init( rRoot
, pPattern
, xText
);
672 bool XclExpLabelCell::IsMultiLineText() const
674 return mbLineBreak
|| mxText
->IsWrapped();
677 void XclExpLabelCell::Init( const XclExpRoot
& rRoot
,
678 const ScPatternAttr
* pPattern
, XclExpStringRef xText
)
680 OSL_ENSURE( xText
&& xText
->Len(), "XclExpLabelCell::XclExpLabelCell - empty string passed" );
684 // create the cell format
685 sal_uInt16 nXclFont
= mxText
->RemoveLeadingFont();
686 if( GetXFId() == EXC_XFID_NOTFOUND
)
688 OSL_ENSURE( nXclFont
!= EXC_FONT_NOTFOUND
, "XclExpLabelCell::Init - leading font not found" );
689 bool bForceLineBreak
= mxText
->IsWrapped();
690 SetXFId( rRoot
.GetXFBuffer().InsertWithFont( pPattern
, ApiScriptType::WEAK
, nXclFont
, bForceLineBreak
) );
693 // get auto-wrap attribute from cell format
694 const XclExpXF
* pXF
= rRoot
.GetXFBuffer().GetXFById( GetXFId() );
695 mbLineBreak
= pXF
&& pXF
->GetAlignmentData().mbLineBreak
;
697 // initialize the record contents
698 switch( rRoot
.GetBiff() )
701 // BIFF5-BIFF7: create a LABEL or RSTRING record
702 OSL_ENSURE( mxText
->Len() <= EXC_LABEL_MAXLEN
, "XclExpLabelCell::XclExpLabelCell - string too long" );
703 SetContSize( mxText
->GetSize() );
704 // formatted string is exported in an RSTRING record
705 if( mxText
->IsRich() )
707 OSL_ENSURE( mxText
->GetFormatsCount() <= EXC_LABEL_MAXLEN
, "XclExpLabelCell::WriteContents - too many formats" );
708 mxText
->LimitFormatCount( EXC_LABEL_MAXLEN
);
709 SetRecId( EXC_ID_RSTRING
);
710 SetContSize( GetContSize() + 1 + 2 * mxText
->GetFormatsCount() );
714 // BIFF8+: create a LABELSST record
715 mnSstIndex
= rRoot
.GetSst().Insert( xText
);
716 SetRecId( EXC_ID_LABELSST
);
719 default: DBG_ERROR_BIFF();
723 void XclExpLabelCell::SaveXml( XclExpXmlStream
& rStrm
)
725 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
726 rWorksheet
->startElement( XML_c
,
727 XML_r
, XclXmlUtils::ToOString( GetXclPos() ).getStr(),
728 XML_s
, lcl_GetStyleId( rStrm
, *this ).getStr(),
730 // OOXTODO: XML_cm, XML_vm, XML_ph
732 rWorksheet
->startElement( XML_v
, FSEND
);
733 rWorksheet
->write( (sal_Int32
) mnSstIndex
);
734 rWorksheet
->endElement( XML_v
);
735 rWorksheet
->endElement( XML_c
);
738 void XclExpLabelCell::WriteContents( XclExpStream
& rStrm
)
740 switch( rStrm
.GetRoot().GetBiff() )
744 if( mxText
->IsRich() )
746 rStrm
<< static_cast< sal_uInt8
>( mxText
->GetFormatsCount() );
747 mxText
->WriteFormats( rStrm
);
753 default: DBG_ERROR_BIFF();
757 // ----------------------------------------------------------------------------
759 IMPL_FIXEDMEMPOOL_NEWDEL( XclExpFormulaCell
)
761 XclExpFormulaCell::XclExpFormulaCell(
762 const XclExpRoot
& rRoot
, const XclAddress
& rXclPos
,
763 const ScPatternAttr
* pPattern
, sal_uInt32 nForcedXFId
,
764 const ScFormulaCell
& rScFmlaCell
,
765 XclExpArrayBuffer
& rArrayBfr
,
766 XclExpShrfmlaBuffer
& rShrfmlaBfr
,
767 XclExpTableopBuffer
& rTableopBfr
) :
768 XclExpSingleCellBase( EXC_ID2_FORMULA
, 0, rXclPos
, nForcedXFId
),
769 mrScFmlaCell( const_cast< ScFormulaCell
& >( rScFmlaCell
) )
771 // *** Find result number format overwriting cell number format *** -------
773 if( GetXFId() == EXC_XFID_NOTFOUND
)
775 SvNumberFormatter
& rFormatter
= rRoot
.GetFormatter();
776 XclExpNumFmtBuffer
& rNumFmtBfr
= rRoot
.GetNumFmtBuffer();
778 // current cell number format
779 sal_uLong nScNumFmt
= pPattern
?
780 GETITEMVALUE( pPattern
->GetItemSet(), SfxUInt32Item
, ATTR_VALUE_FORMAT
, sal_uLong
) :
781 rNumFmtBfr
.GetStandardFormat();
783 // alternative number format passed to XF buffer
784 sal_uLong nAltScNumFmt
= NUMBERFORMAT_ENTRY_NOT_FOUND
;
785 /* Xcl doesn't know Boolean number formats, we write
786 "TRUE";"FALSE" (language dependent). Don't do it for automatic
787 formula formats, because Excel gets them right. */
788 /* #i8640# Don't set text format, if we have string results. */
789 short nFormatType
= mrScFmlaCell
.GetFormatType();
790 if( ((nScNumFmt
% SV_COUNTRY_LANGUAGE_OFFSET
) == 0) &&
791 (nFormatType
!= NUMBERFORMAT_LOGICAL
) &&
792 (nFormatType
!= NUMBERFORMAT_TEXT
) )
793 nAltScNumFmt
= nScNumFmt
;
794 /* If cell number format is Boolean and automatic formula
795 format is Boolean don't write that ugly special format. */
796 else if( (nFormatType
== NUMBERFORMAT_LOGICAL
) &&
797 (rFormatter
.GetType( nScNumFmt
) == NUMBERFORMAT_LOGICAL
) )
798 nAltScNumFmt
= rNumFmtBfr
.GetStandardFormat();
800 // #i41420# find script type according to result type (always latin for numeric results)
801 sal_Int16 nScript
= ApiScriptType::LATIN
;
802 bool bForceLineBreak
= false;
803 if( nFormatType
== NUMBERFORMAT_TEXT
)
805 String aResult
= mrScFmlaCell
.GetString();
806 bForceLineBreak
= mrScFmlaCell
.IsMultilineResult();
807 nScript
= XclExpStringHelper::GetLeadingScriptType( rRoot
, aResult
);
809 SetXFId( rRoot
.GetXFBuffer().InsertWithNumFmt( pPattern
, nScript
, nAltScNumFmt
, bForceLineBreak
) );
812 // *** Convert the formula token array *** --------------------------------
814 ScAddress
aScPos( static_cast< SCCOL
>( rXclPos
.mnCol
), static_cast< SCROW
>( rXclPos
.mnRow
), rRoot
.GetCurrScTab() );
815 const ScTokenArray
& rScTokArr
= *mrScFmlaCell
.GetCode();
817 // first try to create multiple operations
818 mxAddRec
= rTableopBfr
.CreateOrExtendTableop( rScTokArr
, aScPos
);
820 // no multiple operation found - try to create matrix formula
821 if( !mxAddRec
) switch( static_cast< ScMatrixMode
>( mrScFmlaCell
.GetMatrixFlag() ) )
825 // origin of the matrix - find the used matrix range
828 mrScFmlaCell
.GetMatColsRows( nMatWidth
, nMatHeight
);
829 OSL_ENSURE( nMatWidth
&& nMatHeight
, "XclExpFormulaCell::XclExpFormulaCell - empty matrix" );
830 ScRange
aMatScRange( aScPos
);
831 ScAddress
& rMatEnd
= aMatScRange
.aEnd
;
832 rMatEnd
.IncCol( static_cast< SCsCOL
>( nMatWidth
- 1 ) );
833 rMatEnd
.IncRow( static_cast< SCsROW
>( nMatHeight
- 1 ) );
834 // reduce to valid range (range keeps valid, because start position IS valid)
835 rRoot
.GetAddressConverter().ValidateRange( aMatScRange
, true );
836 // create the ARRAY record
837 mxAddRec
= rArrayBfr
.CreateArray( rScTokArr
, aMatScRange
);
842 // other formula cell covered by a matrix - find the ARRAY record
843 mxAddRec
= rArrayBfr
.FindArray( rScTokArr
);
844 // should always be found, if Calc document is not broken
845 OSL_ENSURE( mxAddRec
, "XclExpFormulaCell::XclExpFormulaCell - no matrix found" );
851 // no matrix found - try to create shared formula
853 mxAddRec
= rShrfmlaBfr
.CreateOrExtendShrfmla( rScTokArr
, aScPos
);
855 // no shared formula found - create a simple cell formula
857 mxTokArr
= rRoot
.GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CELL
, rScTokArr
, &aScPos
);
860 void XclExpFormulaCell::Save( XclExpStream
& rStrm
)
862 // create token array for FORMULA cells with additional record
864 mxTokArr
= mxAddRec
->CreateCellTokenArray( rStrm
.GetRoot() );
866 // FORMULA record itself
867 OSL_ENSURE( mxTokArr
, "XclExpFormulaCell::Save - missing token array" );
869 mxTokArr
= rStrm
.GetRoot().GetFormulaCompiler().CreateErrorFormula( EXC_ERR_NA
);
870 SetContSize( 16 + mxTokArr
->GetSize() );
871 XclExpSingleCellBase::Save( rStrm
);
873 // additional record (ARRAY, SHRFMLA, or TABLEOP), only for first FORMULA record
874 if( mxAddRec
&& mxAddRec
->IsBasePos( GetXclCol(), GetXclRow() ) )
875 mxAddRec
->Save( rStrm
);
877 // STRING record for string result
879 mxStringRec
->Save( rStrm
);
882 void XclExpFormulaCell::SaveXml( XclExpXmlStream
& rStrm
)
884 const char* sType
= NULL
;
887 XclXmlUtils::GetFormulaTypeAndValue( mrScFmlaCell
, sType
, sValue
);
888 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
889 rWorksheet
->startElement( XML_c
,
890 XML_r
, XclXmlUtils::ToOString( GetXclPos() ).getStr(),
891 XML_s
, lcl_GetStyleId( rStrm
, *this ).getStr(),
893 // OOXTODO: XML_cm, XML_vm, XML_ph
896 rWorksheet
->startElement( XML_f
,
897 // OOXTODO: XML_t, ST_CellFormulaType
898 XML_aca
, XclXmlUtils::ToPsz( (mxTokArr
&& mxTokArr
->IsVolatile()) || (mxAddRec
&& mxAddRec
->IsVolatile()) ),
899 // OOXTODO: XML_ref, ST_Ref
900 // OOXTODO: XML_dt2D, bool
901 // OOXTODO: XML_dtr, bool
902 // OOXTODO: XML_del1, bool
903 // OOXTODO: XML_del2, bool
904 // OOXTODO: XML_r1, ST_CellRef
905 // OOXTODO: XML_r2, ST_CellRef
906 // OOXTODO: XML_ca, bool
907 // OOXTODO: XML_si, uint
908 // OOXTODO: XML_bx bool
910 rWorksheet
->writeEscaped( XclXmlUtils::ToOUString( *mrScFmlaCell
.GetDocument(), mrScFmlaCell
.aPos
,
911 mrScFmlaCell
.GetCode(), rStrm
.GetRoot().GetOpCodeMap() ) );
912 rWorksheet
->endElement( XML_f
);
913 if( strcmp( sType
, "inlineStr" ) == 0 )
915 rWorksheet
->startElement( XML_is
, FSEND
);
916 rWorksheet
->startElement( XML_t
, FSEND
);
917 rWorksheet
->writeEscaped( sValue
);
918 rWorksheet
->endElement( XML_t
);
919 rWorksheet
->endElement( XML_is
);
923 rWorksheet
->startElement( XML_v
, FSEND
);
924 rWorksheet
->writeEscaped( sValue
);
925 rWorksheet
->endElement( XML_v
);
927 rWorksheet
->endElement( XML_c
);
930 void XclExpFormulaCell::WriteContents( XclExpStream
& rStrm
)
932 sal_uInt16 nScErrCode
= mrScFmlaCell
.GetErrCode();
935 rStrm
<< EXC_FORMULA_RES_ERROR
<< sal_uInt8( 0 )
936 << XclTools::GetXclErrorCode( nScErrCode
)
937 << sal_uInt8( 0 ) << sal_uInt16( 0 )
938 << sal_uInt16( 0xFFFF );
942 // result of the formula
943 switch( mrScFmlaCell
.GetFormatType() )
945 case NUMBERFORMAT_NUMBER
:
947 // either value or error code
948 rStrm
<< mrScFmlaCell
.GetValue();
952 case NUMBERFORMAT_TEXT
:
954 OUString aResult
= mrScFmlaCell
.GetString();
955 if( !aResult
.isEmpty() || (rStrm
.GetRoot().GetBiff() <= EXC_BIFF5
) )
957 rStrm
<< EXC_FORMULA_RES_STRING
;
958 mxStringRec
.reset( new XclExpStringRec( rStrm
.GetRoot(), aResult
) );
961 rStrm
<< EXC_FORMULA_RES_EMPTY
; // BIFF8 only
962 rStrm
<< sal_uInt8( 0 ) << sal_uInt32( 0 ) << sal_uInt16( 0xFFFF );
966 case NUMBERFORMAT_LOGICAL
:
968 sal_uInt8 nXclValue
= (mrScFmlaCell
.GetValue() == 0.0) ? 0 : 1;
969 rStrm
<< EXC_FORMULA_RES_BOOL
<< sal_uInt8( 0 )
970 << nXclValue
<< sal_uInt8( 0 ) << sal_uInt16( 0 )
971 << sal_uInt16( 0xFFFF );
976 rStrm
<< mrScFmlaCell
.GetValue();
980 // flags and formula token array
981 sal_uInt16 nFlags
= EXC_FORMULA_DEFAULTFLAGS
;
982 ::set_flag( nFlags
, EXC_FORMULA_RECALC_ALWAYS
, mxTokArr
->IsVolatile() || (mxAddRec
&& mxAddRec
->IsVolatile()) );
983 ::set_flag( nFlags
, EXC_FORMULA_SHARED
, mxAddRec
&& (mxAddRec
->GetRecId() == EXC_ID_SHRFMLA
) );
984 rStrm
<< nFlags
<< sal_uInt32( 0 ) << *mxTokArr
;
987 // Multiple cell records ======================================================
989 XclExpMultiCellBase::XclExpMultiCellBase(
990 sal_uInt16 nRecId
, sal_uInt16 nMulRecId
, sal_Size nContSize
, const XclAddress
& rXclPos
) :
991 XclExpCellBase( nRecId
, 0, rXclPos
),
992 mnMulRecId( nMulRecId
),
993 mnContSize( nContSize
)
997 sal_uInt16
XclExpMultiCellBase::GetLastXclCol() const
999 return GetXclCol() + GetCellCount() - 1;
1002 sal_uInt32
XclExpMultiCellBase::GetFirstXFId() const
1004 return maXFIds
.empty() ? XclExpXFBuffer::GetDefCellXFId() : maXFIds
.front().mnXFId
;
1007 bool XclExpMultiCellBase::IsEmpty() const
1009 return maXFIds
.empty();
1012 void XclExpMultiCellBase::ConvertXFIndexes( const XclExpRoot
& rRoot
)
1014 for( XclExpMultiXFIdDeq::iterator aIt
= maXFIds
.begin(), aEnd
= maXFIds
.end(); aIt
!= aEnd
; ++aIt
)
1015 aIt
->ConvertXFIndex( rRoot
);
1018 void XclExpMultiCellBase::Save( XclExpStream
& rStrm
)
1020 OSL_ENSURE_BIFF( rStrm
.GetRoot().GetBiff() >= EXC_BIFF3
);
1022 XclExpMultiXFIdDeq::const_iterator aEnd
= maXFIds
.end();
1023 XclExpMultiXFIdDeq::const_iterator aRangeBeg
= maXFIds
.begin();
1024 XclExpMultiXFIdDeq::const_iterator aRangeEnd
= aRangeBeg
;
1025 sal_uInt16 nBegXclCol
= GetXclCol();
1026 sal_uInt16 nEndXclCol
= nBegXclCol
;
1028 while( aRangeEnd
!= aEnd
)
1030 // find begin of next used XF range
1031 aRangeBeg
= aRangeEnd
;
1032 nBegXclCol
= nEndXclCol
;
1033 while( (aRangeBeg
!= aEnd
) && (aRangeBeg
->mnXFIndex
== EXC_XF_NOTFOUND
) )
1035 nBegXclCol
= nBegXclCol
+ aRangeBeg
->mnCount
;
1038 // find end of next used XF range
1039 aRangeEnd
= aRangeBeg
;
1040 nEndXclCol
= nBegXclCol
;
1041 while( (aRangeEnd
!= aEnd
) && (aRangeEnd
->mnXFIndex
!= EXC_XF_NOTFOUND
) )
1043 nEndXclCol
= nEndXclCol
+ aRangeEnd
->mnCount
;
1047 // export this range as a record
1048 if( aRangeBeg
!= aRangeEnd
)
1050 sal_uInt16 nCount
= nEndXclCol
- nBegXclCol
;
1051 bool bIsMulti
= nCount
> 1;
1052 sal_Size nTotalSize
= GetRecSize() + (2 + mnContSize
) * nCount
;
1053 if( bIsMulti
) nTotalSize
+= 2;
1055 rStrm
.StartRecord( bIsMulti
? mnMulRecId
: GetRecId(), nTotalSize
);
1056 rStrm
<< static_cast<sal_uInt16
> (GetXclRow()) << nBegXclCol
;
1058 sal_uInt16 nRelCol
= nBegXclCol
- GetXclCol();
1059 for( XclExpMultiXFIdDeq::const_iterator aIt
= aRangeBeg
; aIt
!= aRangeEnd
; ++aIt
)
1061 for( sal_uInt16 nIdx
= 0; nIdx
< aIt
->mnCount
; ++nIdx
)
1063 rStrm
<< aIt
->mnXFIndex
;
1064 WriteContents( rStrm
, nRelCol
);
1069 rStrm
<< static_cast< sal_uInt16
>( nEndXclCol
- 1 );
1075 void XclExpMultiCellBase::SaveXml( XclExpXmlStream
& rStrm
)
1077 XclExpMultiXFIdDeq::const_iterator aEnd
= maXFIds
.end();
1078 XclExpMultiXFIdDeq::const_iterator aRangeBeg
= maXFIds
.begin();
1079 XclExpMultiXFIdDeq::const_iterator aRangeEnd
= aRangeBeg
;
1080 sal_uInt16 nBegXclCol
= GetXclCol();
1081 sal_uInt16 nEndXclCol
= nBegXclCol
;
1083 while( aRangeEnd
!= aEnd
)
1085 // find begin of next used XF range
1086 aRangeBeg
= aRangeEnd
;
1087 nBegXclCol
= nEndXclCol
;
1088 while( (aRangeBeg
!= aEnd
) && (aRangeBeg
->mnXFIndex
== EXC_XF_NOTFOUND
) )
1090 nBegXclCol
= nBegXclCol
+ aRangeBeg
->mnCount
;
1093 // find end of next used XF range
1094 aRangeEnd
= aRangeBeg
;
1095 nEndXclCol
= nBegXclCol
;
1096 while( (aRangeEnd
!= aEnd
) && (aRangeEnd
->mnXFIndex
!= EXC_XF_NOTFOUND
) )
1098 nEndXclCol
= nEndXclCol
+ aRangeEnd
->mnCount
;
1102 // export this range as a record
1103 if( aRangeBeg
!= aRangeEnd
)
1105 sal_uInt16 nRelColIdx
= nBegXclCol
- GetXclCol();
1106 sal_Int32 nRelCol
= 0;
1107 for( XclExpMultiXFIdDeq::const_iterator aIt
= aRangeBeg
; aIt
!= aRangeEnd
; ++aIt
)
1109 for( sal_uInt16 nIdx
= 0; nIdx
< aIt
->mnCount
; ++nIdx
)
1113 XclAddress( static_cast<sal_uInt16
>(nBegXclCol
+ nRelCol
), GetXclRow() ),
1124 sal_uInt16
XclExpMultiCellBase::GetCellCount() const
1126 sal_uInt16 nCount
= 0;
1127 for( XclExpMultiXFIdDeq::const_iterator aIt
= maXFIds
.begin(), aEnd
= maXFIds
.end(); aIt
!= aEnd
; ++aIt
)
1128 nCount
= nCount
+ aIt
->mnCount
;
1132 void XclExpMultiCellBase::AppendXFId( const XclExpMultiXFId
& rXFId
)
1134 if( maXFIds
.empty() || (maXFIds
.back().mnXFId
!= rXFId
.mnXFId
) )
1135 maXFIds
.push_back( rXFId
);
1137 maXFIds
.back().mnCount
= maXFIds
.back().mnCount
+ rXFId
.mnCount
;
1140 void XclExpMultiCellBase::AppendXFId( const XclExpRoot
& rRoot
,
1141 const ScPatternAttr
* pPattern
, sal_uInt16 nScript
, sal_uInt32 nForcedXFId
, sal_uInt16 nCount
)
1143 sal_uInt32 nXFId
= (nForcedXFId
== EXC_XFID_NOTFOUND
) ?
1144 rRoot
.GetXFBuffer().Insert( pPattern
, nScript
) : nForcedXFId
;
1145 AppendXFId( XclExpMultiXFId( nXFId
, nCount
) );
1148 bool XclExpMultiCellBase::TryMergeXFIds( const XclExpMultiCellBase
& rCell
)
1150 if( GetLastXclCol() + 1 == rCell
.GetXclCol() )
1152 maXFIds
.insert( maXFIds
.end(), rCell
.maXFIds
.begin(), rCell
.maXFIds
.end() );
1158 void XclExpMultiCellBase::GetXFIndexes( ScfUInt16Vec
& rXFIndexes
) const
1160 OSL_ENSURE( GetLastXclCol() < rXFIndexes
.size(), "XclExpMultiCellBase::GetXFIndexes - vector too small" );
1161 ScfUInt16Vec::iterator aDestIt
= rXFIndexes
.begin() + GetXclCol();
1162 for( XclExpMultiXFIdDeq::const_iterator aIt
= maXFIds
.begin(), aEnd
= maXFIds
.end(); aIt
!= aEnd
; ++aIt
)
1164 ::std::fill( aDestIt
, aDestIt
+ aIt
->mnCount
, aIt
->mnXFIndex
);
1165 aDestIt
+= aIt
->mnCount
;
1169 void XclExpMultiCellBase::RemoveUnusedXFIndexes( const ScfUInt16Vec
& rXFIndexes
)
1171 // save last column before calling maXFIds.clear()
1172 sal_uInt16 nLastXclCol
= GetLastXclCol();
1173 OSL_ENSURE( nLastXclCol
< rXFIndexes
.size(), "XclExpMultiCellBase::RemoveUnusedXFIndexes - XF index vector too small" );
1175 // build new XF index vector, containing passed XF indexes
1177 XclExpMultiXFId
aXFId( 0 );
1178 for( ScfUInt16Vec::const_iterator aIt
= rXFIndexes
.begin() + GetXclCol(), aEnd
= rXFIndexes
.begin() + nLastXclCol
+ 1; aIt
!= aEnd
; ++aIt
)
1180 // AppendXFId() tests XclExpXFIndex::mnXFId, set it too
1181 aXFId
.mnXFId
= aXFId
.mnXFIndex
= *aIt
;
1182 AppendXFId( aXFId
);
1185 // remove leading and trailing unused XF indexes
1186 if( !maXFIds
.empty() && (maXFIds
.front().mnXFIndex
== EXC_XF_NOTFOUND
) )
1188 SetXclCol( GetXclCol() + maXFIds
.front().mnCount
);
1189 maXFIds
.pop_front();
1191 if( !maXFIds
.empty() && (maXFIds
.back().mnXFIndex
== EXC_XF_NOTFOUND
) )
1194 // The Save() function will skip all XF indexes equal to EXC_XF_NOTFOUND.
1197 // ----------------------------------------------------------------------------
1199 IMPL_FIXEDMEMPOOL_NEWDEL( XclExpBlankCell
)
1201 XclExpBlankCell::XclExpBlankCell( const XclAddress
& rXclPos
, const XclExpMultiXFId
& rXFId
) :
1202 XclExpMultiCellBase( EXC_ID3_BLANK
, EXC_ID_MULBLANK
, 0, rXclPos
)
1204 OSL_ENSURE( rXFId
.mnCount
> 0, "XclExpBlankCell::XclExpBlankCell - invalid count" );
1205 AppendXFId( rXFId
);
1208 XclExpBlankCell::XclExpBlankCell(
1209 const XclExpRoot
& rRoot
, const XclAddress
& rXclPos
, sal_uInt16 nLastXclCol
,
1210 const ScPatternAttr
* pPattern
, sal_uInt32 nForcedXFId
) :
1211 XclExpMultiCellBase( EXC_ID3_BLANK
, EXC_ID_MULBLANK
, 0, rXclPos
)
1213 OSL_ENSURE( rXclPos
.mnCol
<= nLastXclCol
, "XclExpBlankCell::XclExpBlankCell - invalid column range" );
1214 // #i46627# use default script type instead of ApiScriptType::WEAK
1215 AppendXFId( rRoot
, pPattern
, rRoot
.GetDefApiScript(), nForcedXFId
, nLastXclCol
- rXclPos
.mnCol
+ 1 );
1218 bool XclExpBlankCell::TryMerge( const XclExpCellBase
& rCell
)
1220 const XclExpBlankCell
* pBlankCell
= dynamic_cast< const XclExpBlankCell
* >( &rCell
);
1221 return pBlankCell
&& TryMergeXFIds( *pBlankCell
);
1224 void XclExpBlankCell::GetBlankXFIndexes( ScfUInt16Vec
& rXFIndexes
) const
1226 GetXFIndexes( rXFIndexes
);
1229 void XclExpBlankCell::RemoveUnusedBlankCells( const ScfUInt16Vec
& rXFIndexes
)
1231 RemoveUnusedXFIndexes( rXFIndexes
);
1234 void XclExpBlankCell::WriteContents( XclExpStream
& /*rStrm*/, sal_uInt16
/*nRelCol*/ )
1238 void XclExpBlankCell::WriteXmlContents( XclExpXmlStream
& rStrm
, const XclAddress
& rAddress
, sal_uInt32 nXFId
, sal_uInt16
/* nRelCol */ )
1240 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
1241 rWorksheet
->singleElement( XML_c
,
1242 XML_r
, XclXmlUtils::ToOString( rAddress
).getStr(),
1243 XML_s
, lcl_GetStyleId( rStrm
, nXFId
).getStr(),
1247 // ----------------------------------------------------------------------------
1249 IMPL_FIXEDMEMPOOL_NEWDEL( XclExpRkCell
)
1251 XclExpRkCell::XclExpRkCell(
1252 const XclExpRoot
& rRoot
, const XclAddress
& rXclPos
,
1253 const ScPatternAttr
* pPattern
, sal_uInt32 nForcedXFId
, sal_Int32 nRkValue
) :
1254 XclExpMultiCellBase( EXC_ID_RK
, EXC_ID_MULRK
, 4, rXclPos
)
1256 // #i41210# always use latin script for number cells - may look wrong for special number formats...
1257 AppendXFId( rRoot
, pPattern
, ApiScriptType::LATIN
, nForcedXFId
);
1258 maRkValues
.push_back( nRkValue
);
1261 bool XclExpRkCell::TryMerge( const XclExpCellBase
& rCell
)
1263 const XclExpRkCell
* pRkCell
= dynamic_cast< const XclExpRkCell
* >( &rCell
);
1264 if( pRkCell
&& TryMergeXFIds( *pRkCell
) )
1266 maRkValues
.insert( maRkValues
.end(), pRkCell
->maRkValues
.begin(), pRkCell
->maRkValues
.end() );
1272 void XclExpRkCell::WriteXmlContents( XclExpXmlStream
& rStrm
, const XclAddress
& rAddress
, sal_uInt32 nXFId
, sal_uInt16 nRelCol
)
1274 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
1275 rWorksheet
->startElement( XML_c
,
1276 XML_r
, XclXmlUtils::ToOString( rAddress
).getStr(),
1277 XML_s
, lcl_GetStyleId( rStrm
, nXFId
).getStr(),
1279 // OOXTODO: XML_cm, XML_vm, XML_ph
1281 rWorksheet
->startElement( XML_v
, FSEND
);
1282 rWorksheet
->write( XclTools::GetDoubleFromRK( maRkValues
[ nRelCol
] ) );
1283 rWorksheet
->endElement( XML_v
);
1284 rWorksheet
->endElement( XML_c
);
1287 void XclExpRkCell::WriteContents( XclExpStream
& rStrm
, sal_uInt16 nRelCol
)
1289 OSL_ENSURE( nRelCol
< maRkValues
.size(), "XclExpRkCell::WriteContents - overflow error" );
1290 rStrm
<< maRkValues
[ nRelCol
];
1293 // ============================================================================
1295 // ============================================================================
1297 XclExpOutlineBuffer::XclExpOutlineBuffer( const XclExpRoot
& rRoot
, bool bRows
) :
1299 maLevelInfos( SC_OL_MAXDEPTH
),
1301 mbCurrCollapse( false )
1303 if( const ScOutlineTable
* pOutlineTable
= rRoot
.GetDoc().GetOutlineTable( rRoot
.GetCurrScTab() ) )
1304 mpScOLArray
= bRows
? pOutlineTable
->GetRowArray() : pOutlineTable
->GetColArray();
1307 for( size_t nLevel
= 0; nLevel
< SC_OL_MAXDEPTH
; ++nLevel
)
1308 if( const ScOutlineEntry
* pEntry
= mpScOLArray
->GetEntryByPos( nLevel
, 0 ) )
1309 maLevelInfos
[ nLevel
].mnScEndPos
= pEntry
->GetEnd();
1312 void XclExpOutlineBuffer::UpdateColRow( SCCOLROW nScPos
)
1316 // find open level index for passed position
1317 size_t nNewOpenScLevel
= 0; // new open level (0-based Calc index)
1318 sal_uInt8 nNewLevel
= 0; // new open level (1-based Excel index)
1320 if( mpScOLArray
->FindTouchedLevel( nScPos
, nScPos
, nNewOpenScLevel
) )
1321 nNewLevel
= static_cast< sal_uInt8
>( nNewOpenScLevel
+ 1 );
1322 // else nNewLevel keeps 0 to show that there are no groups
1324 mbCurrCollapse
= false;
1325 if( nNewLevel
>= mnCurrLevel
)
1327 // new level(s) opened, or no level closed - update all level infos
1328 for( sal_uInt16 nScLevel
= 0; nScLevel
<= nNewOpenScLevel
; ++nScLevel
)
1330 /* In each level: check if a new group is started (there may be
1331 neighbored groups without gap - therefore check ALL levels). */
1332 if( maLevelInfos
[ nScLevel
].mnScEndPos
< nScPos
)
1334 if( const ScOutlineEntry
* pEntry
= mpScOLArray
->GetEntryByPos( nScLevel
, nScPos
) )
1336 maLevelInfos
[ nScLevel
].mnScEndPos
= pEntry
->GetEnd();
1337 maLevelInfos
[ nScLevel
].mbHidden
= pEntry
->IsHidden();
1344 // level(s) closed - check if any of the closed levels are collapsed
1345 // Calc uses 0-based level indexes
1346 sal_uInt16 nOldOpenScLevel
= mnCurrLevel
- 1;
1347 for( sal_uInt16 nScLevel
= nNewOpenScLevel
+ 1; !mbCurrCollapse
&& (nScLevel
<= nOldOpenScLevel
); ++nScLevel
)
1348 mbCurrCollapse
= maLevelInfos
[ nScLevel
].mbHidden
;
1351 // cache new opened level
1352 mnCurrLevel
= nNewLevel
;
1356 // ----------------------------------------------------------------------------
1358 XclExpGuts::XclExpGuts( const XclExpRoot
& rRoot
) :
1359 XclExpRecord( EXC_ID_GUTS
, 8 ),
1365 if( const ScOutlineTable
* pOutlineTable
= rRoot
.GetDoc().GetOutlineTable( rRoot
.GetCurrScTab() ) )
1367 // column outline groups
1368 if( const ScOutlineArray
* pColArray
= pOutlineTable
->GetColArray() )
1369 mnColLevels
= ulimit_cast
< sal_uInt16
>( pColArray
->GetDepth(), EXC_OUTLINE_MAX
);
1373 mnColWidth
= 12 * mnColLevels
+ 5;
1376 // row outline groups
1377 if( const ScOutlineArray
* pRowArray
= pOutlineTable
->GetRowArray() )
1378 mnRowLevels
= ulimit_cast
< sal_uInt16
>( pRowArray
->GetDepth(), EXC_OUTLINE_MAX
);
1382 mnRowWidth
= 12 * mnRowLevels
+ 5;
1387 void XclExpGuts::WriteBody( XclExpStream
& rStrm
)
1389 rStrm
<< mnRowWidth
<< mnColWidth
<< mnRowLevels
<< mnColLevels
;
1392 // ----------------------------------------------------------------------------
1394 XclExpDimensions::XclExpDimensions( const XclExpRoot
& rRoot
) :
1395 mnFirstUsedXclRow( 0 ),
1396 mnFirstFreeXclRow( 0 ),
1397 mnFirstUsedXclCol( 0 ),
1398 mnFirstFreeXclCol( 0 )
1400 switch( rRoot
.GetBiff() )
1402 case EXC_BIFF2
: SetRecHeader( EXC_ID2_DIMENSIONS
, 8 ); break;
1405 case EXC_BIFF5
: SetRecHeader( EXC_ID3_DIMENSIONS
, 10 ); break;
1406 case EXC_BIFF8
: SetRecHeader( EXC_ID3_DIMENSIONS
, 14 ); break;
1407 default: DBG_ERROR_BIFF();
1411 void XclExpDimensions::SetDimensions(
1412 sal_uInt16 nFirstUsedXclCol
, sal_uInt32 nFirstUsedXclRow
,
1413 sal_uInt16 nFirstFreeXclCol
, sal_uInt32 nFirstFreeXclRow
)
1415 mnFirstUsedXclRow
= nFirstUsedXclRow
;
1416 mnFirstFreeXclRow
= nFirstFreeXclRow
;
1417 mnFirstUsedXclCol
= nFirstUsedXclCol
;
1418 mnFirstFreeXclCol
= nFirstFreeXclCol
;
1421 void XclExpDimensions::SaveXml( XclExpXmlStream
& rStrm
)
1424 aRange
.aStart
.SetRow( (SCROW
) mnFirstUsedXclRow
);
1425 aRange
.aStart
.SetCol( (SCCOL
) mnFirstUsedXclCol
);
1427 if( mnFirstFreeXclRow
!= mnFirstUsedXclRow
&& mnFirstFreeXclCol
!= mnFirstUsedXclCol
)
1429 aRange
.aEnd
.SetRow( (SCROW
) (mnFirstFreeXclRow
-1) );
1430 aRange
.aEnd
.SetCol( (SCCOL
) (mnFirstFreeXclCol
-1) );
1433 rStrm
.GetCurrentStream()->singleElement( XML_dimension
,
1434 XML_ref
, XclXmlUtils::ToOString( aRange
).getStr(),
1438 void XclExpDimensions::WriteBody( XclExpStream
& rStrm
)
1440 XclBiff eBiff
= rStrm
.GetRoot().GetBiff();
1441 if( eBiff
== EXC_BIFF8
)
1442 rStrm
<< mnFirstUsedXclRow
<< mnFirstFreeXclRow
;
1444 rStrm
<< static_cast< sal_uInt16
>( mnFirstUsedXclRow
) << static_cast< sal_uInt16
>( mnFirstFreeXclRow
);
1445 rStrm
<< mnFirstUsedXclCol
<< mnFirstFreeXclCol
;
1446 if( eBiff
>= EXC_BIFF3
)
1447 rStrm
<< sal_uInt16( 0 );
1450 // ============================================================================
1454 double lclGetCorrectedColWidth( const XclExpRoot
& rRoot
, sal_uInt16 nXclColWidth
)
1456 long nFontHt
= rRoot
.GetFontBuffer().GetAppFontData().mnHeight
;
1457 return nXclColWidth
- XclTools::GetXclDefColWidthCorrection( nFontHt
);
1462 // ----------------------------------------------------------------------------
1464 XclExpDefcolwidth::XclExpDefcolwidth( const XclExpRoot
& rRoot
) :
1465 XclExpUInt16Record( EXC_ID_DEFCOLWIDTH
, EXC_DEFCOLWIDTH_DEF
),
1470 bool XclExpDefcolwidth::IsDefWidth( sal_uInt16 nXclColWidth
) const
1472 double fNewColWidth
= lclGetCorrectedColWidth( GetRoot(), nXclColWidth
);
1473 // exactly matched, if difference is less than 1/16 of a character to the left or to the right
1474 return std::abs( static_cast< long >( GetValue() * 256.0 - fNewColWidth
+ 0.5 ) ) < 16;
1477 void XclExpDefcolwidth::SetDefWidth( sal_uInt16 nXclColWidth
)
1479 double fNewColWidth
= lclGetCorrectedColWidth( GetRoot(), nXclColWidth
);
1480 SetValue( limit_cast
< sal_uInt16
>( fNewColWidth
/ 256.0 + 0.5 ) );
1483 // ----------------------------------------------------------------------------
1485 XclExpColinfo::XclExpColinfo( const XclExpRoot
& rRoot
,
1486 SCCOL nScCol
, SCROW nLastScRow
, XclExpColOutlineBuffer
& rOutlineBfr
) :
1487 XclExpRecord( EXC_ID_COLINFO
, 12 ),
1488 XclExpRoot( rRoot
),
1492 mnFirstXclCol( static_cast< sal_uInt16
>( nScCol
) ),
1493 mnLastXclCol( static_cast< sal_uInt16
>( nScCol
) )
1495 ScDocument
& rDoc
= GetDoc();
1496 SCTAB nScTab
= GetCurrScTab();
1498 // column default format
1499 maXFId
.mnXFId
= GetXFBuffer().Insert(
1500 rDoc
.GetMostUsedPattern( nScCol
, 0, nLastScRow
, nScTab
), GetDefApiScript() );
1503 sal_uInt16 nScWidth
= rDoc
.GetColWidth( nScCol
, nScTab
);
1504 mnWidth
= XclTools::GetXclColumnWidth( nScWidth
, GetCharWidth() );
1505 mnScWidth
= sc::TwipsToHMM( nScWidth
);
1507 ::set_flag( mnFlags
, EXC_COLINFO_HIDDEN
, rDoc
.ColHidden(nScCol
, nScTab
) );
1510 rOutlineBfr
.Update( nScCol
);
1511 ::set_flag( mnFlags
, EXC_COLINFO_COLLAPSED
, rOutlineBfr
.IsCollapsed() );
1512 ::insert_value( mnFlags
, rOutlineBfr
.GetLevel(), 8, 3 );
1515 sal_uInt16
XclExpColinfo::ConvertXFIndexes()
1517 maXFId
.ConvertXFIndex( GetRoot() );
1518 return maXFId
.mnXFIndex
;
1521 bool XclExpColinfo::IsDefault( const XclExpDefcolwidth
& rDefColWidth
) const
1523 return (maXFId
.mnXFIndex
== EXC_XF_DEFAULTCELL
) && (mnFlags
== 0) && rDefColWidth
.IsDefWidth( mnWidth
);
1526 bool XclExpColinfo::TryMerge( const XclExpColinfo
& rColInfo
)
1528 if( (maXFId
.mnXFIndex
== rColInfo
.maXFId
.mnXFIndex
) &&
1529 (mnWidth
== rColInfo
.mnWidth
) &&
1530 (mnFlags
== rColInfo
.mnFlags
) &&
1531 (mnLastXclCol
+ 1 == rColInfo
.mnFirstXclCol
) )
1533 mnLastXclCol
= rColInfo
.mnLastXclCol
;
1539 void XclExpColinfo::WriteBody( XclExpStream
& rStrm
)
1541 // if last column is equal to last possible column, Excel adds one more
1542 sal_uInt16 nLastXclCol
= mnLastXclCol
;
1543 if( nLastXclCol
== static_cast< sal_uInt16
>( rStrm
.GetRoot().GetMaxPos().Col() ) )
1546 rStrm
<< mnFirstXclCol
1554 void XclExpColinfo::SaveXml( XclExpXmlStream
& rStrm
)
1556 // if last column is equal to last possible column, Excel adds one more
1557 sal_uInt16 nLastXclCol
= mnLastXclCol
;
1558 if( nLastXclCol
== static_cast< sal_uInt16
>( rStrm
.GetRoot().GetMaxPos().Col() ) )
1561 rStrm
.GetCurrentStream()->singleElement( XML_col
,
1562 // OOXTODO: XML_bestFit,
1563 XML_collapsed
, XclXmlUtils::ToPsz( ::get_flag( mnFlags
, EXC_COLINFO_COLLAPSED
) ),
1564 // OOXTODO: XML_customWidth,
1565 XML_hidden
, XclXmlUtils::ToPsz( ::get_flag( mnFlags
, EXC_COLINFO_HIDDEN
) ),
1566 XML_max
, OString::valueOf( (sal_Int32
) (nLastXclCol
+1) ).getStr(),
1567 XML_min
, OString::valueOf( (sal_Int32
) (mnFirstXclCol
+1) ).getStr(),
1568 // OOXTODO: XML_outlineLevel,
1569 // OOXTODO: XML_phonetic,
1570 XML_style
, lcl_GetStyleId( rStrm
, maXFId
.mnXFIndex
).getStr(),
1571 XML_width
, OString::valueOf( (double) (mnScWidth
/ (double)sc::TwipsToHMM( GetCharWidth() )) ).getStr(),
1575 // ----------------------------------------------------------------------------
1577 XclExpColinfoBuffer::XclExpColinfoBuffer( const XclExpRoot
& rRoot
) :
1578 XclExpRoot( rRoot
),
1579 maDefcolwidth( rRoot
),
1580 maOutlineBfr( rRoot
)
1584 void XclExpColinfoBuffer::Initialize( SCROW nLastScRow
)
1587 for( sal_uInt16 nScCol
= 0, nLastScCol
= GetMaxPos().Col(); nScCol
<= nLastScCol
; ++nScCol
)
1588 maColInfos
.AppendNewRecord( new XclExpColinfo( GetRoot(), nScCol
, nLastScRow
, maOutlineBfr
) );
1591 void XclExpColinfoBuffer::Finalize( ScfUInt16Vec
& rXFIndexes
)
1594 rXFIndexes
.reserve( maColInfos
.GetSize() );
1598 // do not cache the record list size, it may change in the loop
1599 for( nPos
= 0; nPos
< maColInfos
.GetSize(); ++nPos
)
1601 XclExpColinfoRef xRec
= maColInfos
.GetRecord( nPos
);
1602 xRec
->ConvertXFIndexes();
1604 // try to merge with previous record
1607 XclExpColinfoRef xPrevRec
= maColInfos
.GetRecord( nPos
- 1 );
1608 if( xPrevRec
->TryMerge( *xRec
) )
1609 // adjust nPos to get the next COLINFO record at the same position
1610 maColInfos
.RemoveRecord( nPos
-- );
1614 // put XF indexes into passed vector, collect use count of all different widths
1615 typedef ::std::map
< sal_uInt16
, sal_uInt16
> XclExpWidthMap
;
1616 XclExpWidthMap aWidthMap
;
1617 sal_uInt16 nMaxColCount
= 0;
1618 sal_uInt16 nMaxUsedWidth
= 0;
1619 for( nPos
= 0, nSize
= maColInfos
.GetSize(); nPos
< nSize
; ++nPos
)
1621 XclExpColinfoRef xRec
= maColInfos
.GetRecord( nPos
);
1622 sal_uInt16 nColCount
= xRec
->GetColCount();
1624 // add XF index to passed vector
1625 rXFIndexes
.resize( rXFIndexes
.size() + nColCount
, xRec
->GetXFIndex() );
1627 // collect use count of column width
1628 sal_uInt16 nWidth
= xRec
->GetColWidth();
1629 sal_uInt16
& rnMapCount
= aWidthMap
[ nWidth
];
1630 rnMapCount
= rnMapCount
+ nColCount
;
1631 if( rnMapCount
> nMaxColCount
)
1633 nMaxColCount
= rnMapCount
;
1634 nMaxUsedWidth
= nWidth
;
1637 maDefcolwidth
.SetDefWidth( nMaxUsedWidth
);
1639 // remove all default COLINFO records
1641 while( nPos
< maColInfos
.GetSize() )
1643 XclExpColinfoRef xRec
= maColInfos
.GetRecord( nPos
);
1644 if( xRec
->IsDefault( maDefcolwidth
) )
1645 maColInfos
.RemoveRecord( nPos
);
1651 void XclExpColinfoBuffer::Save( XclExpStream
& rStrm
)
1654 maDefcolwidth
.Save( rStrm
);
1656 maColInfos
.Save( rStrm
);
1659 void XclExpColinfoBuffer::SaveXml( XclExpXmlStream
& rStrm
)
1661 if( maColInfos
.IsEmpty() )
1664 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
1665 rWorksheet
->startElement( XML_cols
,
1667 maColInfos
.SaveXml( rStrm
);
1668 rWorksheet
->endElement( XML_cols
);
1671 // ============================================================================
1673 XclExpDefaultRowData::XclExpDefaultRowData() :
1674 mnFlags( EXC_DEFROW_DEFAULTFLAGS
),
1675 mnHeight( EXC_DEFROW_DEFAULTHEIGHT
)
1679 XclExpDefaultRowData::XclExpDefaultRowData( const XclExpRow
& rRow
) :
1680 mnFlags( EXC_DEFROW_DEFAULTFLAGS
),
1681 mnHeight( rRow
.GetHeight() )
1683 ::set_flag( mnFlags
, EXC_DEFROW_HIDDEN
, rRow
.IsHidden() );
1684 ::set_flag( mnFlags
, EXC_DEFROW_UNSYNCED
, rRow
.IsUnsynced() );
1687 bool operator<( const XclExpDefaultRowData
& rLeft
, const XclExpDefaultRowData
& rRight
)
1689 return (rLeft
.mnHeight
< rRight
.mnHeight
) ||
1690 ((rLeft
.mnHeight
== rRight
.mnHeight
) && (rLeft
.mnFlags
< rRight
.mnFlags
));
1693 // ----------------------------------------------------------------------------
1695 XclExpDefrowheight::XclExpDefrowheight() :
1696 XclExpRecord( EXC_ID3_DEFROWHEIGHT
, 4 )
1700 void XclExpDefrowheight::SetDefaultData( const XclExpDefaultRowData
& rDefData
)
1702 maDefData
= rDefData
;
1705 void XclExpDefrowheight::WriteBody( XclExpStream
& rStrm
)
1707 OSL_ENSURE_BIFF( rStrm
.GetRoot().GetBiff() >= EXC_BIFF3
);
1708 rStrm
<< maDefData
.mnFlags
<< maDefData
.mnHeight
;
1711 // ----------------------------------------------------------------------------
1713 XclExpRow::XclExpRow( const XclExpRoot
& rRoot
, sal_uInt32 nXclRow
,
1714 XclExpRowOutlineBuffer
& rOutlineBfr
, bool bAlwaysEmpty
) :
1715 XclExpRecord( EXC_ID3_ROW
, 16 ),
1716 XclExpRoot( rRoot
),
1717 mnXclRow( nXclRow
),
1719 mnFlags( EXC_ROW_DEFAULTFLAGS
),
1720 mnXFIndex( EXC_XF_DEFAULTCELL
),
1721 mnOutlineLevel( 0 ),
1723 mnCurrentRow( nXclRow
),
1724 mbAlwaysEmpty( bAlwaysEmpty
),
1727 SCTAB nScTab
= GetCurrScTab();
1728 SCROW nScRow
= static_cast< SCROW
>( mnXclRow
);
1730 // *** Row flags *** ------------------------------------------------------
1732 sal_uInt8 nRowFlags
= GetDoc().GetRowFlags( nScRow
, nScTab
);
1733 bool bUserHeight
= ::get_flag
< sal_uInt8
>( nRowFlags
, CR_MANUALSIZE
);
1734 bool bHidden
= GetDoc().RowHidden(nScRow
, nScTab
);
1735 ::set_flag( mnFlags
, EXC_ROW_UNSYNCED
, bUserHeight
);
1736 ::set_flag( mnFlags
, EXC_ROW_HIDDEN
, bHidden
);
1738 // *** Row height *** -----------------------------------------------------
1740 // Always get the actual row height even if the manual size flag is not set,
1741 // to correctly export the heights of rows with wrapped texts.
1743 mnHeight
= GetDoc().GetRowHeight(nScRow
, nScTab
, false);
1745 // *** Outline data *** ---------------------------------------------------
1747 rOutlineBfr
.Update( nScRow
);
1748 ::set_flag( mnFlags
, EXC_ROW_COLLAPSED
, rOutlineBfr
.IsCollapsed() );
1749 ::insert_value( mnFlags
, rOutlineBfr
.GetLevel(), 0, 3 );
1750 mnOutlineLevel
= rOutlineBfr
.GetLevel();
1752 // *** Progress bar *** ---------------------------------------------------
1754 XclExpProgressBar
& rProgress
= GetProgressBar();
1755 rProgress
.IncRowRecordCount();
1756 rProgress
.Progress();
1759 void XclExpRow::AppendCell( XclExpCellRef xCell
, bool bIsMergedBase
)
1761 OSL_ENSURE( !mbAlwaysEmpty
, "XclExpRow::AppendCell - row is marked to be always empty" );
1762 // try to merge with last existing cell
1763 InsertCell( xCell
, maCellList
.GetSize(), bIsMergedBase
);
1766 void XclExpRow::Finalize( const ScfUInt16Vec
& rColXFIndexes
)
1770 // *** Convert XF identifiers *** -----------------------------------------
1772 // additionally collect the blank XF indexes
1773 size_t nColCount
= GetMaxPos().Col() + 1;
1774 OSL_ENSURE( rColXFIndexes
.size() == nColCount
, "XclExpRow::Finalize - wrong column XF index count" );
1776 ScfUInt16Vec
aXFIndexes( nColCount
, EXC_XF_NOTFOUND
);
1777 for( nPos
= 0, nSize
= maCellList
.GetSize(); nPos
< nSize
; ++nPos
)
1779 XclExpCellRef xCell
= maCellList
.GetRecord( nPos
);
1780 xCell
->ConvertXFIndexes( GetRoot() );
1781 xCell
->GetBlankXFIndexes( aXFIndexes
);
1784 // *** Fill gaps with BLANK/MULBLANK cell records *** ---------------------
1786 /* This is needed because nonexistant cells in Calc are not formatted at all,
1787 but in Excel they would have the column default format. Blank cells that
1788 are equal to the respective column default are removed later in this function. */
1789 if( !mbAlwaysEmpty
)
1791 // XF identifier representing default cell XF
1792 XclExpMultiXFId
aXFId( XclExpXFBuffer::GetDefCellXFId() );
1793 aXFId
.ConvertXFIndex( GetRoot() );
1796 while( nPos
<= maCellList
.GetSize() ) // don't cache list size, may change in the loop
1798 // get column index that follows previous cell
1799 sal_uInt16 nFirstFreeXclCol
= (nPos
> 0) ? (maCellList
.GetRecord( nPos
- 1 )->GetLastXclCol() + 1) : 0;
1800 // get own column index
1801 sal_uInt16 nNextUsedXclCol
= (nPos
< maCellList
.GetSize()) ? maCellList
.GetRecord( nPos
)->GetXclCol() : (GetMaxPos().Col() + 1);
1804 if( nFirstFreeXclCol
< nNextUsedXclCol
)
1806 aXFId
.mnCount
= nNextUsedXclCol
- nFirstFreeXclCol
;
1807 XclExpCellRef
xNewCell( new XclExpBlankCell( XclAddress( nFirstFreeXclCol
, mnXclRow
), aXFId
) );
1808 // insert the cell, InsertCell() may merge it with existing BLANK records
1809 InsertCell( xNewCell
, nPos
, false );
1810 // insert default XF indexes into aXFIndexes
1811 ::std::fill( aXFIndexes
.begin() + nFirstFreeXclCol
,
1812 aXFIndexes
.begin() + nNextUsedXclCol
, aXFId
.mnXFIndex
);
1813 // don't step forward with nPos, InsertCell() may remove records
1820 // *** Find default row format *** ----------------------------------------
1822 ScfUInt16Vec::iterator aCellBeg
= aXFIndexes
.begin(), aCellEnd
= aXFIndexes
.end(), aCellIt
;
1823 ScfUInt16Vec::const_iterator aColBeg
= rColXFIndexes
.begin(), aColIt
;
1825 // find most used XF index in the row
1826 typedef ::std::map
< sal_uInt16
, size_t > XclExpXFIndexMap
;
1827 XclExpXFIndexMap aIndexMap
;
1828 sal_uInt16 nRowXFIndex
= EXC_XF_DEFAULTCELL
;
1829 size_t nMaxXFCount
= 0;
1830 for( aCellIt
= aCellBeg
; aCellIt
!= aCellEnd
; ++aCellIt
)
1832 if( *aCellIt
!= EXC_XF_NOTFOUND
)
1834 size_t& rnCount
= aIndexMap
[ *aCellIt
];
1836 if( rnCount
> nMaxXFCount
)
1838 nRowXFIndex
= *aCellIt
;
1839 nMaxXFCount
= rnCount
;
1844 // decide whether to use the row default XF index or column default XF indexes
1845 bool bUseColDefXFs
= nRowXFIndex
== EXC_XF_DEFAULTCELL
;
1846 if( !bUseColDefXFs
)
1848 // count needed XF indexes for blank cells with and without row default XF index
1849 size_t nXFCountWithRowDefXF
= 0;
1850 size_t nXFCountWithoutRowDefXF
= 0;
1851 for( aCellIt
= aCellBeg
, aColIt
= aColBeg
; aCellIt
!= aCellEnd
; ++aCellIt
, ++aColIt
)
1853 sal_uInt16 nXFIndex
= *aCellIt
;
1854 if( nXFIndex
!= EXC_XF_NOTFOUND
)
1856 if( nXFIndex
!= nRowXFIndex
)
1857 ++nXFCountWithRowDefXF
; // with row default XF index
1858 if( nXFIndex
!= *aColIt
)
1859 ++nXFCountWithoutRowDefXF
; // without row default XF index
1863 // use column XF indexes if this would cause less or equal number of BLANK records
1864 bUseColDefXFs
= nXFCountWithoutRowDefXF
<= nXFCountWithRowDefXF
;
1867 // *** Remove unused BLANK cell records *** -------------------------------
1871 // use column default XF indexes
1872 // #i194#: remove cell XF indexes equal to column default XF indexes
1873 for( aCellIt
= aCellBeg
, aColIt
= aColBeg
; aCellIt
!= aCellEnd
; ++aCellIt
, ++aColIt
)
1874 if( *aCellIt
== *aColIt
)
1875 *aCellIt
= EXC_XF_NOTFOUND
;
1879 // use row default XF index
1880 mnXFIndex
= nRowXFIndex
;
1881 ::set_flag( mnFlags
, EXC_ROW_USEDEFXF
);
1882 // #98133#, #i194#, #i27407#: remove cell XF indexes equal to row default XF index
1883 for( aCellIt
= aCellBeg
; aCellIt
!= aCellEnd
; ++aCellIt
)
1884 if( *aCellIt
== nRowXFIndex
)
1885 *aCellIt
= EXC_XF_NOTFOUND
;
1888 // remove unused parts of BLANK/MULBLANK cell records
1890 while( nPos
< maCellList
.GetSize() ) // do not cache list size, may change in the loop
1892 XclExpCellRef xCell
= maCellList
.GetRecord( nPos
);
1893 xCell
->RemoveUnusedBlankCells( aXFIndexes
);
1894 if( xCell
->IsEmpty() )
1895 maCellList
.RemoveRecord( nPos
);
1900 // progress bar includes disabled rows
1901 GetProgressBar().Progress();
1904 sal_uInt16
XclExpRow::GetFirstUsedXclCol() const
1906 return maCellList
.IsEmpty() ? 0 : maCellList
.GetFirstRecord()->GetXclCol();
1909 sal_uInt16
XclExpRow::GetFirstFreeXclCol() const
1911 return maCellList
.IsEmpty() ? 0 : (maCellList
.GetLastRecord()->GetLastXclCol() + 1);
1914 bool XclExpRow::IsDefaultable() const
1916 const sal_uInt16 nAllowedFlags
= EXC_ROW_DEFAULTFLAGS
| EXC_ROW_HIDDEN
| EXC_ROW_UNSYNCED
;
1917 return !::get_flag( mnFlags
, static_cast< sal_uInt16
>( ~nAllowedFlags
) ) && IsEmpty();
1920 void XclExpRow::DisableIfDefault( const XclExpDefaultRowData
& rDefRowData
)
1922 mbEnabled
= !IsDefaultable() ||
1923 (mnHeight
!= rDefRowData
.mnHeight
) ||
1924 (IsHidden() != rDefRowData
.IsHidden()) ||
1925 (IsUnsynced() != rDefRowData
.IsUnsynced());
1928 void XclExpRow::WriteCellList( XclExpStream
& rStrm
)
1930 OSL_ENSURE( mbEnabled
|| maCellList
.IsEmpty(), "XclExpRow::WriteCellList - cells in disabled row" );
1931 maCellList
.Save( rStrm
);
1934 void XclExpRow::Save( XclExpStream
& rStrm
)
1938 mnCurrentRow
= mnXclRow
;
1939 for ( sal_uInt32 i
= 0; i
< mnXclRowRpt
; ++i
, ++mnCurrentRow
)
1940 XclExpRecord::Save( rStrm
);
1944 void XclExpRow::InsertCell( XclExpCellRef xCell
, size_t nPos
, bool bIsMergedBase
)
1946 OSL_ENSURE( xCell
, "XclExpRow::InsertCell - missing cell" );
1948 /* If we have a multi-line text in a merged cell, and the resulting
1949 row height has not been confirmed, we need to force the EXC_ROW_UNSYNCED
1950 flag to be true to ensure Excel works correctly. */
1951 if( bIsMergedBase
&& xCell
->IsMultiLineText() )
1952 ::set_flag( mnFlags
, EXC_ROW_UNSYNCED
);
1954 // try to merge with previous cell, insert the new cell if not successful
1955 XclExpCellRef xPrevCell
= maCellList
.GetRecord( nPos
- 1 );
1956 if( xPrevCell
&& xPrevCell
->TryMerge( *xCell
) )
1959 maCellList
.InsertRecord( xCell
, nPos
++ );
1960 // nPos points now to following cell
1962 // try to merge with following cell, remove it if successful
1963 XclExpCellRef xNextCell
= maCellList
.GetRecord( nPos
);
1964 if( xNextCell
&& xCell
->TryMerge( *xNextCell
) )
1965 maCellList
.RemoveRecord( nPos
);
1968 void XclExpRow::WriteBody( XclExpStream
& rStrm
)
1970 rStrm
<< static_cast< sal_uInt16
>(mnCurrentRow
)
1971 << GetFirstUsedXclCol()
1972 << GetFirstFreeXclCol()
1979 void XclExpRow::SaveXml( XclExpXmlStream
& rStrm
)
1983 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
1984 bool haveFormat
= ::get_flag( mnFlags
, EXC_ROW_USEDEFXF
);
1985 mnCurrentRow
= mnXclRow
+ 1;
1986 for ( sal_uInt32 i
=0; i
<mnXclRowRpt
; ++i
)
1988 rWorksheet
->startElement( XML_row
,
1989 XML_r
, OString::valueOf( (sal_Int32
) (mnCurrentRow
++) ).getStr(),
1990 // OOXTODO: XML_spans, optional
1991 XML_s
, haveFormat
? lcl_GetStyleId( rStrm
, mnXFIndex
).getStr() : NULL
,
1992 XML_customFormat
, XclXmlUtils::ToPsz( haveFormat
),
1993 XML_ht
, OString::valueOf( (double) mnHeight
/ 20.0 ).getStr(),
1994 XML_hidden
, XclXmlUtils::ToPsz( ::get_flag( mnFlags
, EXC_ROW_HIDDEN
) ),
1995 XML_customHeight
, XclXmlUtils::ToPsz( ::get_flag( mnFlags
, EXC_ROW_UNSYNCED
) ),
1996 XML_outlineLevel
, OString::valueOf( (sal_Int32
) mnOutlineLevel
).getStr(),
1997 XML_collapsed
, XclXmlUtils::ToPsz( ::get_flag( mnFlags
, EXC_ROW_COLLAPSED
) ),
1998 // OOXTODO: XML_thickTop, bool
1999 // OOXTODO: XML_thickBot, bool
2000 // OOXTODO: XML_ph, bool
2002 // OOXTODO: XML_extLst
2003 maCellList
.SaveXml( rStrm
);
2004 rWorksheet
->endElement( XML_row
);
2008 // ----------------------------------------------------------------------------
2010 XclExpRowBuffer::XclExpRowBuffer( const XclExpRoot
& rRoot
) :
2011 XclExpRoot( rRoot
),
2012 maOutlineBfr( rRoot
),
2013 maDimensions( rRoot
)
2017 void XclExpRowBuffer::AppendCell( XclExpCellRef xCell
, bool bIsMergedBase
)
2019 OSL_ENSURE( xCell
, "XclExpRowBuffer::AppendCell - missing cell" );
2020 GetOrCreateRow( xCell
->GetXclRow(), false ).AppendCell( xCell
, bIsMergedBase
);
2023 void XclExpRowBuffer::CreateRows( SCROW nFirstFreeScRow
)
2025 if( nFirstFreeScRow
> 0 )
2026 GetOrCreateRow( ::std::max ( nFirstFreeScRow
- 1, GetMaxPos().Row() ), true );
2029 void XclExpRowBuffer::Finalize( XclExpDefaultRowData
& rDefRowData
, const ScfUInt16Vec
& rColXFIndexes
)
2031 // *** Finalize all rows *** ----------------------------------------------
2033 GetProgressBar().ActivateFinalRowsSegment();
2035 RowMap::iterator itr
, itrBeg
= maRowMap
.begin(), itrEnd
= maRowMap
.end();
2036 for (itr
= itrBeg
; itr
!= itrEnd
; ++itr
)
2037 itr
->second
->Finalize(rColXFIndexes
);
2039 // *** Default row format *** ---------------------------------------------
2041 typedef ::std::map
< XclExpDefaultRowData
, size_t > XclExpDefRowDataMap
;
2042 XclExpDefRowDataMap aDefRowMap
;
2044 XclExpDefaultRowData aMaxDefData
;
2045 size_t nMaxDefCount
= 0;
2046 // only look for default format in existing rows, if there are more than unused
2047 XclExpRow
* pPrev
= NULL
;
2048 typedef std::vector
< XclExpRow
* > XclRepeatedRows
;
2049 XclRepeatedRows aRepeated
;
2050 for (itr
= itrBeg
; itr
!= itrEnd
; ++itr
)
2052 const RowRef
& rRow
= itr
->second
;
2053 if (rRow
->IsDefaultable())
2055 XclExpDefaultRowData
aDefData( *rRow
);
2056 size_t& rnDefCount
= aDefRowMap
[ aDefData
];
2058 if( rnDefCount
> nMaxDefCount
)
2060 nMaxDefCount
= rnDefCount
;
2061 aMaxDefData
= aDefData
;
2066 if ( pPrev
->IsDefaultable())
2068 // if the previous row we processed is not
2069 // defaultable then afaict the rows inbetween are
2070 // not used ( and not repeatable )
2071 sal_uInt32 nRpt
= rRow
->GetXclRow() - pPrev
->GetXclRow();
2073 aRepeated
.push_back( pPrev
);
2074 pPrev
->SetXclRowRpt( nRpt
);
2075 XclExpDefaultRowData
aDefData( *pPrev
);
2076 size_t& rnDefCount
= aDefRowMap
[ aDefData
];
2077 rnDefCount
+= ( pPrev
->GetXclRowRpt() - 1 );
2078 if( rnDefCount
> nMaxDefCount
)
2080 nMaxDefCount
= rnDefCount
;
2081 aMaxDefData
= aDefData
;
2087 // return the default row format to caller
2088 rDefRowData
= aMaxDefData
;
2090 // now disable repeating extra (empty) rows that are equal to
2091 // default row height
2092 for ( XclRepeatedRows::iterator it
= aRepeated
.begin(), it_end
= aRepeated
.end(); it
!= it_end
; ++it
)
2094 if ( (*it
)->GetXclRowRpt() > 1 && (*it
)->GetHeight() == rDefRowData
.mnHeight
)
2095 (*it
)->SetXclRowRpt( 1 );
2098 // *** Disable unused ROW records, find used area *** ---------------------
2100 sal_uInt16 nFirstUsedXclCol
= SAL_MAX_UINT16
;
2101 sal_uInt16 nFirstFreeXclCol
= 0;
2102 sal_uInt32 nFirstUsedXclRow
= SAL_MAX_UINT32
;
2103 sal_uInt32 nFirstFreeXclRow
= 0;
2105 for (itr
= itrBeg
; itr
!= itrEnd
; ++itr
)
2107 const RowRef
& rRow
= itr
->second
;
2108 // disable unused rows
2109 rRow
->DisableIfDefault( aMaxDefData
);
2111 // find used column range
2112 if( !rRow
->IsEmpty() ) // empty rows return (0...0) as used range
2114 nFirstUsedXclCol
= ::std::min( nFirstUsedXclCol
, rRow
->GetFirstUsedXclCol() );
2115 nFirstFreeXclCol
= ::std::max( nFirstFreeXclCol
, rRow
->GetFirstFreeXclCol() );
2118 // find used row range
2119 if( rRow
->IsEnabled() )
2121 sal_uInt16 nXclRow
= rRow
->GetXclRow();
2122 nFirstUsedXclRow
= ::std::min
< sal_uInt32
>( nFirstUsedXclRow
, nXclRow
);
2123 nFirstFreeXclRow
= ::std::max
< sal_uInt32
>( nFirstFreeXclRow
, nXclRow
+ 1 );
2127 // adjust start position, if there are no or only empty/disabled ROW records
2128 nFirstUsedXclCol
= ::std::min( nFirstUsedXclCol
, nFirstFreeXclCol
);
2129 nFirstUsedXclRow
= ::std::min( nFirstUsedXclRow
, nFirstFreeXclRow
);
2131 // initialize the DIMENSIONS record
2132 maDimensions
.SetDimensions(
2133 nFirstUsedXclCol
, nFirstUsedXclRow
, nFirstFreeXclCol
, nFirstFreeXclRow
);
2136 void XclExpRowBuffer::Save( XclExpStream
& rStrm
)
2138 // DIMENSIONS record
2139 maDimensions
.Save( rStrm
);
2141 // save in blocks of 32 rows, each block contains first all ROWs, then all cells
2142 size_t nSize
= maRowMap
.size();
2143 RowMap::iterator itr
, itrBeg
= maRowMap
.begin(), itrEnd
= maRowMap
.end();
2144 RowMap::iterator itrBlkStart
= maRowMap
.begin(), itrBlkEnd
= maRowMap
.begin();
2145 sal_uInt16 nStartXclRow
= (nSize
== 0) ? 0 : itrBeg
->second
->GetXclRow();
2148 for (itr
= itrBeg
; itr
!= itrEnd
; ++itr
)
2150 // find end of row block
2151 while( (itrBlkEnd
!= itrEnd
) && (itrBlkEnd
->second
->GetXclRow() - nStartXclRow
< EXC_ROW_ROWBLOCKSIZE
) )
2154 // write the ROW records
2155 RowMap::iterator itRow
;
2156 for( itRow
= itrBlkStart
; itRow
!= itrBlkEnd
; ++itRow
)
2157 itRow
->second
->Save( rStrm
);
2159 // write the cell records
2160 for( itRow
= itrBlkStart
; itRow
!= itrBlkEnd
; ++itRow
)
2161 itRow
->second
->WriteCellList( rStrm
);
2163 itrBlkStart
= (itrBlkEnd
== itrEnd
) ? itrBlkEnd
: itrBlkEnd
++;
2164 nStartXclRow
+= EXC_ROW_ROWBLOCKSIZE
;
2168 void XclExpRowBuffer::SaveXml( XclExpXmlStream
& rStrm
)
2170 sal_Int32 nNonEmpty
= 0;
2171 RowMap::iterator itr
= maRowMap
.begin(), itrEnd
= maRowMap
.end();
2172 for (; itr
!= itrEnd
; ++itr
)
2173 if (itr
->second
->IsEnabled())
2178 rStrm
.GetCurrentStream()->singleElement( XML_sheetData
, FSEND
);
2182 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
2183 rWorksheet
->startElement( XML_sheetData
, FSEND
);
2184 for (itr
= maRowMap
.begin(); itr
!= itrEnd
; ++itr
)
2185 itr
->second
->SaveXml(rStrm
);
2186 rWorksheet
->endElement( XML_sheetData
);
2189 XclExpDimensions
* XclExpRowBuffer::GetDimensions()
2191 return &maDimensions
;
2194 XclExpRow
& XclExpRowBuffer::GetOrCreateRow( sal_uInt32 nXclRow
, bool bRowAlwaysEmpty
)
2196 RowMap::iterator itr
= maRowMap
.begin();
2197 ScDocument
& rDoc
= GetRoot().GetDoc();
2198 SCTAB nScTab
= GetRoot().GetCurrScTab();
2199 for ( size_t nFrom
= maRowMap
.size(); nFrom
<= nXclRow
; ++nFrom
)
2201 itr
= maRowMap
.find(nFrom
);
2202 if ( itr
== maRowMap
.end() )
2204 // only create RowMap entries for rows that differ from previous,
2205 // or if it is the desired row
2206 if ( !nFrom
|| ( nFrom
== nXclRow
) || ( nFrom
&& ( rDoc
.GetRowHeight(nFrom
, nScTab
, false) != rDoc
.GetRowHeight(nFrom
-1, nScTab
, false) ) ) )
2208 RowRef
p(new XclExpRow(GetRoot(), nFrom
, maOutlineBfr
, bRowAlwaysEmpty
));
2209 maRowMap
.insert(RowMap::value_type(nFrom
, p
));
2213 itr
= maRowMap
.find(nXclRow
);
2214 return *itr
->second
;
2218 // ============================================================================
2220 // ============================================================================
2222 XclExpCellTable::XclExpCellTable( const XclExpRoot
& rRoot
) :
2223 XclExpRoot( rRoot
),
2224 maColInfoBfr( rRoot
),
2226 maArrayBfr( rRoot
),
2227 maShrfmlaBfr( rRoot
),
2228 maTableopBfr( rRoot
),
2229 mxDefrowheight( new XclExpDefrowheight
),
2230 mxGuts( new XclExpGuts( rRoot
) ),
2231 mxNoteList( new XclExpNoteList
),
2232 mxMergedcells( new XclExpMergedcells( rRoot
) ),
2233 mxHyperlinkList( new XclExpHyperlinkList
),
2234 mxDval( new XclExpDval( rRoot
) ),
2235 mxExtLst( new XclExtLst( rRoot
) )
2237 ScDocument
& rDoc
= GetDoc();
2238 SCTAB nScTab
= GetCurrScTab();
2239 SvNumberFormatter
& rFormatter
= GetFormatter();
2241 // maximum sheet limits
2242 SCCOL nMaxScCol
= GetMaxPos().Col();
2243 SCROW nMaxScRow
= GetMaxPos().Row();
2245 // find used area (non-empty cells)
2246 SCCOL nLastUsedScCol
;
2247 SCROW nLastUsedScRow
;
2248 rDoc
.GetTableArea( nScTab
, nLastUsedScCol
, nLastUsedScRow
);
2250 if(nLastUsedScCol
> nMaxScCol
)
2251 nLastUsedScCol
= nMaxScCol
;
2253 if(nLastUsedScRow
> nMaxScRow
)
2254 nLastUsedScRow
= nMaxScRow
;
2256 ScRange
aUsedRange( 0, 0, nScTab
, nLastUsedScCol
, nLastUsedScRow
, nScTab
);
2257 GetAddressConverter().ValidateRange( aUsedRange
, true );
2258 nLastUsedScCol
= aUsedRange
.aEnd
.Col();
2259 nLastUsedScRow
= aUsedRange
.aEnd
.Row();
2261 // first row without any set attributes (height/hidden/...)
2262 SCROW nFirstUnflaggedScRow
= rDoc
.GetLastFlaggedRow( nScTab
) + 1;
2264 // find range of outlines
2265 SCROW nFirstUngroupedScRow
= 0;
2266 if( const ScOutlineTable
* pOutlineTable
= rDoc
.GetOutlineTable( nScTab
) )
2268 SCCOLROW nScStartPos
, nScEndPos
;
2269 if( const ScOutlineArray
* pRowArray
= pOutlineTable
->GetRowArray() )
2271 pRowArray
->GetRange( nScStartPos
, nScEndPos
);
2272 // +1 because open/close button is in next row in Excel, +1 for "end->first unused"
2273 nFirstUngroupedScRow
= static_cast< SCROW
>( nScEndPos
+ 2 );
2278 /* #i30411# Files saved with SO7/OOo1.x with nonstandard default column
2279 formatting cause big Excel files, because all rows from row 1 to row
2280 32000 are exported. Now, if the used area goes exactly to row 32000,
2281 use this row as default and ignore all rows >32000.
2282 #i59220# Tolerance of +-128 rows for inserted/removed rows. */
2283 if( (31871 <= nLastUsedScRow
) && (nLastUsedScRow
<= 32127) && (nFirstUnflaggedScRow
< nLastUsedScRow
) && (nFirstUngroupedScRow
<= nLastUsedScRow
) )
2284 nMaxScRow
= nLastUsedScRow
;
2285 maColInfoBfr
.Initialize( nMaxScRow
);
2287 // range for cell iterator
2288 SCCOL nLastIterScCol
= nMaxScCol
;
2289 SCROW nLastIterScRow
= ulimit_cast
< SCROW
>( nLastUsedScRow
, nMaxScRow
);
2290 ScUsedAreaIterator
aIt( &rDoc
, nScTab
, 0, 0, nLastIterScCol
, nLastIterScRow
);
2292 // activate the correct segment and sub segment at the progress bar
2293 GetProgressBar().ActivateCreateRowsSegment();
2295 for( bool bIt
= aIt
.GetNext(); bIt
; bIt
= aIt
.GetNext() )
2297 SCCOL nScCol
= aIt
.GetStartCol();
2298 SCROW nScRow
= aIt
.GetRow();
2299 SCCOL nLastScCol
= aIt
.GetEndCol();
2300 ScAddress
aScPos( nScCol
, nScRow
, nScTab
);
2302 XclAddress
aXclPos( static_cast< sal_uInt16
>( nScCol
), static_cast< sal_uInt32
>( nScRow
) );
2303 sal_uInt16 nLastXclCol
= static_cast< sal_uInt16
>( nLastScCol
);
2305 const ScRefCellValue
& rScCell
= aIt
.GetCell();
2306 XclExpCellRef xCell
;
2308 const ScPatternAttr
* pPattern
= aIt
.GetPattern();
2310 // handle overlapped merged cells before creating the cell record
2311 sal_uInt32 nMergeBaseXFId
= EXC_XFID_NOTFOUND
;
2312 bool bIsMergedBase
= false;
2315 const SfxItemSet
& rItemSet
= pPattern
->GetItemSet();
2316 // base cell in a merged range
2317 const ScMergeAttr
& rMergeItem
= GETITEM( rItemSet
, ScMergeAttr
, ATTR_MERGE
);
2318 bIsMergedBase
= rMergeItem
.IsMerged();
2319 /* overlapped cell in a merged range; in Excel all merged cells
2320 must contain same XF index, for correct border */
2321 const ScMergeFlagAttr
& rMergeFlagItem
= GETITEM( rItemSet
, ScMergeFlagAttr
, ATTR_MERGE_FLAG
);
2322 if( rMergeFlagItem
.IsOverlapped() )
2323 nMergeBaseXFId
= mxMergedcells
->GetBaseXFId( aScPos
);
2326 String aAddNoteText
; // additional text to be appended to a note
2328 switch (rScCell
.meType
)
2330 case CELLTYPE_VALUE
:
2332 double fValue
= rScCell
.mfValue
;
2334 // try to create a Boolean cell
2335 if( pPattern
&& ((fValue
== 0.0) || (fValue
== 1.0)) )
2337 sal_uLong nScNumFmt
= GETITEMVALUE( pPattern
->GetItemSet(), SfxUInt32Item
, ATTR_VALUE_FORMAT
, sal_uLong
);
2338 if( rFormatter
.GetType( nScNumFmt
) == NUMBERFORMAT_LOGICAL
)
2339 xCell
.reset( new XclExpBooleanCell(
2340 GetRoot(), aXclPos
, pPattern
, nMergeBaseXFId
, fValue
!= 0.0 ) );
2343 // try to create an RK value (compressed floating-point number)
2345 if( !xCell
&& XclTools::GetRKFromDouble( nRkValue
, fValue
) )
2346 xCell
.reset( new XclExpRkCell(
2347 GetRoot(), aXclPos
, pPattern
, nMergeBaseXFId
, nRkValue
) );
2349 // else: simple floating-point number cell
2351 xCell
.reset( new XclExpNumberCell(
2352 GetRoot(), aXclPos
, pPattern
, nMergeBaseXFId
, fValue
) );
2356 case CELLTYPE_STRING
:
2358 xCell
.reset(new XclExpLabelCell(
2359 GetRoot(), aXclPos
, pPattern
, nMergeBaseXFId
, *rScCell
.mpString
));
2365 XclExpHyperlinkHelper
aLinkHelper( GetRoot(), aScPos
);
2366 xCell
.reset(new XclExpLabelCell(
2367 GetRoot(), aXclPos
, pPattern
, nMergeBaseXFId
, rScCell
.mpEditText
, aLinkHelper
));
2369 // add a single created HLINK record to the record list
2370 if( aLinkHelper
.HasLinkRecord() )
2371 mxHyperlinkList
->AppendRecord( aLinkHelper
.GetLinkRecord() );
2372 // add list of multiple URLs to the additional cell note text
2373 if( aLinkHelper
.HasMultipleUrls() )
2374 aAddNoteText
= ScGlobal::addToken( aAddNoteText
, aLinkHelper
.GetUrlList(), '\n', 2 );
2378 case CELLTYPE_FORMULA
:
2380 xCell
.reset(new XclExpFormulaCell(
2381 GetRoot(), aXclPos
, pPattern
, nMergeBaseXFId
,
2382 *rScCell
.mpFormula
, maArrayBfr
, maShrfmlaBfr
, maTableopBfr
));
2387 OSL_FAIL( "XclExpCellTable::XclExpCellTable - unknown cell type" );
2391 xCell
.reset( new XclExpBlankCell(
2392 GetRoot(), aXclPos
, nLastXclCol
, pPattern
, nMergeBaseXFId
) );
2397 // insert the cell into the current row
2399 maRowBfr
.AppendCell( xCell
, bIsMergedBase
);
2401 if ( aAddNoteText
.Len() )
2402 mxNoteList
->AppendNewRecord( new XclExpNote( GetRoot(), aScPos
, NULL
, aAddNoteText
) );
2404 // other sheet contents
2407 const SfxItemSet
& rItemSet
= pPattern
->GetItemSet();
2409 // base cell in a merged range
2412 const ScMergeAttr
& rMergeItem
= GETITEM( rItemSet
, ScMergeAttr
, ATTR_MERGE
);
2413 ScRange
aScRange( aScPos
);
2414 aScRange
.aEnd
.IncCol( rMergeItem
.GetColMerge() - 1 );
2415 aScRange
.aEnd
.IncRow( rMergeItem
.GetRowMerge() - 1 );
2416 sal_uInt32 nXFId
= xCell
? xCell
->GetFirstXFId() : EXC_XFID_NOTFOUND
;
2417 // blank cells merged vertically may occur repeatedly
2418 OSL_ENSURE( (aScRange
.aStart
.Col() == aScRange
.aEnd
.Col()) || (nScCol
== nLastScCol
),
2419 "XclExpCellTable::XclExpCellTable - invalid repeated blank merged cell" );
2420 for( SCCOL nIndex
= nScCol
; nIndex
<= nLastScCol
; ++nIndex
)
2422 mxMergedcells
->AppendRange( aScRange
, nXFId
);
2423 aScRange
.aStart
.IncCol();
2424 aScRange
.aEnd
.IncCol();
2429 if( ScfTools::CheckItem( rItemSet
, ATTR_VALIDDATA
, false ) )
2431 sal_uLong nScHandle
= GETITEMVALUE( rItemSet
, SfxUInt32Item
, ATTR_VALIDDATA
, sal_uLong
);
2432 ScRange
aScRange( aScPos
);
2433 aScRange
.aEnd
.SetCol( nLastScCol
);
2434 mxDval
->InsertCellRange( aScRange
, nScHandle
);
2439 // create missing row settings for rows anyhow flagged or with outlines
2440 maRowBfr
.CreateRows( ::std::max( nFirstUnflaggedScRow
, nFirstUngroupedScRow
) );
2443 void XclExpCellTable::Finalize()
2445 // Finalize multiple operations.
2446 maTableopBfr
.Finalize();
2448 /* Finalize column buffer. This calculates column default XF indexes from
2449 the XF identifiers and fills a vector with these XF indexes. */
2450 ScfUInt16Vec aColXFIndexes
;
2451 maColInfoBfr
.Finalize( aColXFIndexes
);
2453 /* Finalize row buffer. This calculates all cell XF indexes from the XF
2454 identifiers. Then the XF index vector aColXFIndexes (filled above) is
2455 used to calculate the row default formats. With this, all unneeded blank
2456 cell records (equal to row default or column default) will be removed.
2457 The function returns the (most used) default row format in aDefRowData. */
2458 XclExpDefaultRowData aDefRowData
;
2459 maRowBfr
.Finalize( aDefRowData
, aColXFIndexes
);
2461 // Initialize the DEFROWHEIGHT record.
2462 mxDefrowheight
->SetDefaultData( aDefRowData
);
2465 XclExpRecordRef
XclExpCellTable::CreateRecord( sal_uInt16 nRecId
) const
2467 XclExpRecordRef xRec
;
2470 case EXC_ID3_DIMENSIONS
: xRec
.reset( new XclExpDelegatingRecord( const_cast<XclExpRowBuffer
*>(&maRowBfr
)->GetDimensions() ) ); break;
2471 case EXC_ID2_DEFROWHEIGHT
: xRec
= mxDefrowheight
; break;
2472 case EXC_ID_GUTS
: xRec
= mxGuts
; break;
2473 case EXC_ID_NOTE
: xRec
= mxNoteList
; break;
2474 case EXC_ID_MERGEDCELLS
: xRec
= mxMergedcells
; break;
2475 case EXC_ID_HLINK
: xRec
= mxHyperlinkList
; break;
2476 case EXC_ID_DVAL
: xRec
= mxDval
; break;
2477 case EXC_ID_EXTLST
: xRec
= mxExtLst
; break;
2478 default: OSL_FAIL( "XclExpCellTable::CreateRecord - unknown record id" );
2483 void XclExpCellTable::Save( XclExpStream
& rStrm
)
2485 // DEFCOLWIDTH and COLINFOs
2486 maColInfoBfr
.Save( rStrm
);
2487 // ROWs and cell records
2488 maRowBfr
.Save( rStrm
);
2491 void XclExpCellTable::SaveXml( XclExpXmlStream
& rStrm
)
2493 // DEFAULT row height
2494 XclExpDefaultRowData
& rDefData
= mxDefrowheight
->GetDefaultData();
2495 sax_fastparser::FSHelperPtr
& rWorksheet
= rStrm
.GetCurrentStream();
2496 rWorksheet
->startElement( XML_sheetFormatPr
,
2497 XML_defaultRowHeight
, OString::valueOf( (double) rDefData
.mnHeight
/ 20.0 ).getStr(), FSEND
);
2498 rWorksheet
->endElement( XML_sheetFormatPr
);
2500 maColInfoBfr
.SaveXml( rStrm
);
2501 maRowBfr
.SaveXml( rStrm
);
2502 mxExtLst
->SaveXml( rStrm
);
2505 // ============================================================================
2507 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */