Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include "xetable.hxx"
21 :
22 : #include <map>
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"
31 : #include "attrib.hxx"
32 : #include "xehelper.hxx"
33 : #include "xecontent.hxx"
34 : #include "xeescher.hxx"
35 : #include "xeextlst.hxx"
36 : #include "tokenarray.hxx"
37 :
38 : using namespace ::oox;
39 :
40 : namespace ApiScriptType = ::com::sun::star::i18n::ScriptType;
41 :
42 : // Helper records for cell records
43 :
44 0 : XclExpStringRec::XclExpStringRec( const XclExpRoot& rRoot, const OUString& rResult ) :
45 : XclExpRecord( EXC_ID3_STRING ),
46 0 : mxResult( XclExpStringHelper::CreateString( rRoot, rResult ) )
47 : {
48 : OSL_ENSURE( (rRoot.GetBiff() <= EXC_BIFF5) || (mxResult->Len() > 0),
49 : "XclExpStringRec::XclExpStringRec - empty result not allowed in BIFF8+" );
50 0 : SetRecSize( mxResult->GetSize() );
51 0 : }
52 :
53 0 : void XclExpStringRec::WriteBody( XclExpStream& rStrm )
54 : {
55 0 : rStrm << *mxResult;
56 0 : }
57 :
58 : // Additional records for special formula ranges ==============================
59 :
60 252 : XclExpRangeFmlaBase::XclExpRangeFmlaBase(
61 : sal_uInt16 nRecId, sal_uInt32 nRecSize, const ScAddress& rScPos ) :
62 : XclExpRecord( nRecId, nRecSize ),
63 : maXclRange( ScAddress::UNINITIALIZED ),
64 252 : maBaseXclPos( ScAddress::UNINITIALIZED )
65 : {
66 252 : maBaseXclPos.Set( static_cast< sal_uInt16 >( rScPos.Col() ), static_cast< sal_uInt16 >( rScPos.Row() ) );
67 252 : maXclRange.maFirst = maXclRange.maLast = maBaseXclPos;
68 252 : }
69 :
70 6 : XclExpRangeFmlaBase::XclExpRangeFmlaBase(
71 : sal_uInt16 nRecId, sal_uInt32 nRecSize, const ScRange& rScRange ) :
72 : XclExpRecord( nRecId, nRecSize ),
73 : maXclRange( ScAddress::UNINITIALIZED ),
74 6 : maBaseXclPos( ScAddress::UNINITIALIZED )
75 : {
76 : maXclRange.Set(
77 6 : static_cast< sal_uInt16 >( rScRange.aStart.Col() ),
78 6 : static_cast< sal_uInt16 >( rScRange.aStart.Row() ),
79 6 : static_cast< sal_uInt16 >( rScRange.aEnd.Col() ),
80 24 : static_cast< sal_uInt16 >( rScRange.aEnd.Row() ) );
81 6 : maBaseXclPos = maXclRange.maFirst;
82 6 : }
83 :
84 772 : bool XclExpRangeFmlaBase::IsBasePos( sal_uInt16 nXclCol, sal_uInt32 nXclRow ) const
85 : {
86 772 : return (maBaseXclPos.mnCol == nXclCol) && (maBaseXclPos.mnRow == nXclRow);
87 : }
88 :
89 1252 : void XclExpRangeFmlaBase::Extend( const ScAddress& rScPos )
90 : {
91 1252 : sal_uInt16 nXclCol = static_cast< sal_uInt16 >( rScPos.Col() );
92 1252 : sal_uInt32 nXclRow = static_cast< sal_uInt32 >( rScPos.Row() );
93 1252 : maXclRange.maFirst.mnCol = ::std::min( maXclRange.maFirst.mnCol, nXclCol );
94 1252 : maXclRange.maFirst.mnRow = ::std::min( maXclRange.maFirst.mnRow, nXclRow );
95 1252 : maXclRange.maLast.mnCol = ::std::max( maXclRange.maLast.mnCol, nXclCol );
96 1252 : maXclRange.maLast.mnRow = ::std::max( maXclRange.maLast.mnRow, nXclRow );
97 1252 : }
98 :
99 130 : void XclExpRangeFmlaBase::WriteRangeAddress( XclExpStream& rStrm ) const
100 : {
101 130 : maXclRange.Write( rStrm, false );
102 130 : }
103 :
104 : // Array formulas =============================================================
105 :
106 6 : XclExpArray::XclExpArray( XclTokenArrayRef xTokArr, const ScRange& rScRange ) :
107 6 : XclExpRangeFmlaBase( EXC_ID3_ARRAY, 14 + xTokArr->GetSize(), rScRange ),
108 6 : mxTokArr( xTokArr )
109 : {
110 6 : }
111 :
112 32 : XclTokenArrayRef XclExpArray::CreateCellTokenArray( const XclExpRoot& rRoot ) const
113 : {
114 32 : return rRoot.GetFormulaCompiler().CreateSpecialRefFormula( EXC_TOKID_EXP, maBaseXclPos );
115 : }
116 :
117 38 : bool XclExpArray::IsVolatile() const
118 : {
119 38 : return mxTokArr->IsVolatile();
120 : }
121 :
122 6 : void XclExpArray::WriteBody( XclExpStream& rStrm )
123 : {
124 6 : WriteRangeAddress( rStrm );
125 6 : sal_uInt16 nFlags = EXC_ARRAY_DEFAULTFLAGS;
126 6 : ::set_flag( nFlags, EXC_ARRAY_RECALC_ALWAYS, IsVolatile() );
127 6 : rStrm << nFlags << sal_uInt32( 0 ) << *mxTokArr;
128 6 : }
129 :
130 124 : XclExpArrayBuffer::XclExpArrayBuffer( const XclExpRoot& rRoot ) :
131 124 : XclExpRoot( rRoot )
132 : {
133 124 : }
134 :
135 6 : XclExpArrayRef XclExpArrayBuffer::CreateArray( const ScTokenArray& rScTokArr, const ScRange& rScRange )
136 : {
137 6 : const ScAddress& rScPos = rScRange.aStart;
138 6 : XclTokenArrayRef xTokArr = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_MATRIX, rScTokArr, &rScPos );
139 :
140 : OSL_ENSURE( maRecMap.find( rScPos ) == maRecMap.end(), "XclExpArrayBuffer::CreateArray - array exists already" );
141 6 : XclExpArrayRef& rxRec = maRecMap[ rScPos ];
142 6 : rxRec.reset( new XclExpArray( xTokArr, rScRange ) );
143 6 : return rxRec;
144 : }
145 :
146 26 : XclExpArrayRef XclExpArrayBuffer::FindArray( const ScTokenArray& rScTokArr, const ScAddress& rBasePos ) const
147 : {
148 26 : XclExpArrayRef xRec;
149 : // try to extract a matrix reference token
150 26 : if (rScTokArr.GetLen() != 1)
151 : // Must consist of a single reference token.
152 0 : return xRec;
153 :
154 26 : const formula::FormulaToken* pToken = rScTokArr.GetArray()[0];
155 26 : if (!pToken || pToken->GetOpCode() != ocMatRef)
156 : // not a matrix reference token.
157 0 : return xRec;
158 :
159 26 : const ScSingleRefData& rRef = *pToken->GetSingleRef();
160 26 : ScAddress aAbsPos = rRef.toAbs(rBasePos);
161 26 : XclExpArrayMap::const_iterator it = maRecMap.find(aAbsPos);
162 :
163 26 : return (it == maRecMap.end()) ? xRec : xRec = it->second;
164 : }
165 :
166 : // Shared formulas ============================================================
167 :
168 252 : XclExpShrfmla::XclExpShrfmla( XclTokenArrayRef xTokArr, const ScAddress& rScPos ) :
169 252 : XclExpRangeFmlaBase( EXC_ID_SHRFMLA, 10 + xTokArr->GetSize(), rScPos ),
170 : mxTokArr( xTokArr ),
171 252 : mnUsedCount( 1 )
172 : {
173 252 : }
174 :
175 1252 : void XclExpShrfmla::ExtendRange( const ScAddress& rScPos )
176 : {
177 1252 : Extend( rScPos );
178 1252 : ++mnUsedCount;
179 1252 : }
180 :
181 740 : XclTokenArrayRef XclExpShrfmla::CreateCellTokenArray( const XclExpRoot& rRoot ) const
182 : {
183 740 : return rRoot.GetFormulaCompiler().CreateSpecialRefFormula( EXC_TOKID_EXP, maBaseXclPos );
184 : }
185 :
186 1504 : bool XclExpShrfmla::IsVolatile() const
187 : {
188 1504 : return mxTokArr->IsVolatile();
189 : }
190 :
191 124 : void XclExpShrfmla::WriteBody( XclExpStream& rStrm )
192 : {
193 124 : WriteRangeAddress( rStrm );
194 124 : rStrm << sal_uInt8( 0 ) << mnUsedCount << *mxTokArr;
195 124 : }
196 :
197 124 : XclExpShrfmlaBuffer::XclExpShrfmlaBuffer( const XclExpRoot& rRoot ) :
198 124 : XclExpRoot( rRoot )
199 : {
200 124 : }
201 :
202 1512 : bool XclExpShrfmlaBuffer::IsValidTokenArray( const ScTokenArray& rArray ) const
203 : {
204 : using namespace formula;
205 :
206 1512 : FormulaToken** pTokens = rArray.GetArray();
207 1512 : sal_uInt16 nLen = rArray.GetLen();
208 19152 : for (sal_uInt16 i = 0; i < nLen; ++i)
209 : {
210 17648 : const FormulaToken* p = pTokens[i];
211 17648 : switch (p->GetType())
212 : {
213 : case svSingleRef:
214 : {
215 2992 : const ScSingleRefData& rRefData = *p->GetSingleRef();
216 2992 : if (!GetFormulaCompiler().IsRef2D(rRefData))
217 : // Excel's shared formula cannot include 3D reference.
218 8 : return false;
219 : }
220 2984 : break;
221 : case svDoubleRef:
222 : {
223 476 : const ScComplexRefData& rRefData = *p->GetDoubleRef();
224 476 : if (!GetFormulaCompiler().IsRef2D(rRefData))
225 : // Excel's shared formula cannot include 3D reference.
226 0 : return false;
227 : }
228 476 : break;
229 : case svExternalSingleRef:
230 : case svExternalDoubleRef:
231 : case svExternalName:
232 : // External references aren't allowed.
233 0 : return false;
234 : default:
235 : ;
236 : }
237 : }
238 1504 : return true;
239 : }
240 :
241 2174 : XclExpShrfmlaRef XclExpShrfmlaBuffer::CreateOrExtendShrfmla(
242 : const ScFormulaCell& rScCell, const ScAddress& rScPos )
243 : {
244 2174 : XclExpShrfmlaRef xRec;
245 2174 : const ScTokenArray* pShrdScTokArr = rScCell.GetSharedCode();
246 2174 : if (!pShrdScTokArr)
247 : // This formula cell is not shared formula cell.
248 614 : return xRec;
249 :
250 : // Check to see if this shared formula contains any tokens that Excel's shared formula cannot handle.
251 1560 : if (maBadTokens.count(pShrdScTokArr) > 0)
252 : // Already on the black list. Skip it.
253 48 : return xRec;
254 :
255 1512 : if (!IsValidTokenArray(*pShrdScTokArr))
256 : {
257 : // We can't export this as shared formula.
258 8 : maBadTokens.insert(pShrdScTokArr);
259 8 : return xRec;
260 : }
261 :
262 1504 : TokensType::iterator aIt = maRecMap.find(pShrdScTokArr);
263 1504 : if( aIt == maRecMap.end() )
264 : {
265 : // create a new record
266 252 : XclTokenArrayRef xTokArr = GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_SHARED, *pShrdScTokArr, &rScPos );
267 252 : xRec.reset( new XclExpShrfmla( xTokArr, rScPos ) );
268 252 : maRecMap[ pShrdScTokArr ] = xRec;
269 : }
270 : else
271 : {
272 : // extend existing record
273 : OSL_ENSURE( aIt->second, "XclExpShrfmlaBuffer::CreateOrExtendShrfmla - missing record" );
274 1252 : xRec = aIt->second;
275 1252 : xRec->ExtendRange( rScPos );
276 : }
277 :
278 1504 : return xRec;
279 : }
280 :
281 : // Multiple operations ========================================================
282 :
283 0 : XclExpTableop::XclExpTableop( const ScAddress& rScPos,
284 : const XclMultipleOpRefs& rRefs, sal_uInt8 nScMode ) :
285 : XclExpRangeFmlaBase( EXC_ID3_TABLEOP, 16, rScPos ),
286 0 : mnLastAppXclCol( static_cast< sal_uInt16 >( rScPos.Col() ) ),
287 0 : mnColInpXclCol( static_cast< sal_uInt16 >( rRefs.maColFirstScPos.Col() ) ),
288 0 : mnColInpXclRow( static_cast< sal_uInt16 >( rRefs.maColFirstScPos.Row() ) ),
289 0 : mnRowInpXclCol( static_cast< sal_uInt16 >( rRefs.maRowFirstScPos.Col() ) ),
290 0 : mnRowInpXclRow( static_cast< sal_uInt16 >( rRefs.maRowFirstScPos.Row() ) ),
291 : mnScMode( nScMode ),
292 0 : mbValid( false )
293 : {
294 0 : }
295 :
296 0 : bool XclExpTableop::TryExtend( const ScAddress& rScPos, const XclMultipleOpRefs& rRefs )
297 : {
298 0 : sal_uInt16 nXclCol = static_cast< sal_uInt16 >( rScPos.Col() );
299 0 : sal_uInt16 nXclRow = static_cast< sal_uInt16 >( rScPos.Row() );
300 :
301 0 : bool bOk = IsAppendable( nXclCol, nXclRow );
302 0 : if( bOk )
303 : {
304 0 : SCCOL nFirstScCol = static_cast< SCCOL >( maXclRange.maFirst.mnCol );
305 0 : SCROW nFirstScRow = static_cast< SCROW >( maXclRange.maFirst.mnRow );
306 0 : SCCOL nColInpScCol = static_cast< SCCOL >( mnColInpXclCol );
307 0 : SCROW nColInpScRow = static_cast< SCROW >( mnColInpXclRow );
308 0 : SCCOL nRowInpScCol = static_cast< SCCOL >( mnRowInpXclCol );
309 0 : SCROW nRowInpScRow = static_cast< SCROW >( mnRowInpXclRow );
310 :
311 0 : bOk = ((mnScMode == 2) == rRefs.mbDblRefMode) &&
312 0 : (rScPos.Tab() == rRefs.maFmlaScPos.Tab()) &&
313 0 : (nColInpScCol == rRefs.maColFirstScPos.Col()) &&
314 0 : (nColInpScRow == rRefs.maColFirstScPos.Row()) &&
315 0 : (rScPos.Tab() == rRefs.maColFirstScPos.Tab()) &&
316 0 : (rScPos.Tab() == rRefs.maColRelScPos.Tab());
317 :
318 0 : if( bOk ) switch( mnScMode )
319 : {
320 : case 0:
321 0 : bOk = (rScPos.Col() == rRefs.maFmlaScPos.Col()) &&
322 0 : (nFirstScRow == rRefs.maFmlaScPos.Row() + 1) &&
323 0 : (nFirstScCol == rRefs.maColRelScPos.Col() + 1) &&
324 0 : (rScPos.Row() == rRefs.maColRelScPos.Row());
325 0 : break;
326 : case 1:
327 0 : bOk = (nFirstScCol == rRefs.maFmlaScPos.Col() + 1) &&
328 0 : (rScPos.Row() == rRefs.maFmlaScPos.Row()) &&
329 0 : (rScPos.Col() == rRefs.maColRelScPos.Col()) &&
330 0 : (nFirstScRow == rRefs.maColRelScPos.Row() + 1);
331 0 : break;
332 : case 2:
333 0 : bOk = (nFirstScCol == rRefs.maFmlaScPos.Col() + 1) &&
334 0 : (nFirstScRow == rRefs.maFmlaScPos.Row() + 1) &&
335 0 : (nFirstScCol == rRefs.maColRelScPos.Col() + 1) &&
336 0 : (rScPos.Row() == rRefs.maColRelScPos.Row()) &&
337 0 : (nRowInpScCol == rRefs.maRowFirstScPos.Col()) &&
338 0 : (nRowInpScRow == rRefs.maRowFirstScPos.Row()) &&
339 0 : (rScPos.Tab() == rRefs.maRowFirstScPos.Tab()) &&
340 0 : (rScPos.Col() == rRefs.maRowRelScPos.Col()) &&
341 0 : (nFirstScRow == rRefs.maRowRelScPos.Row() + 1) &&
342 0 : (rScPos.Tab() == rRefs.maRowRelScPos.Tab());
343 0 : break;
344 : default:
345 0 : bOk = false;
346 : }
347 :
348 0 : if( bOk )
349 : {
350 : // extend the cell range
351 : OSL_ENSURE( IsAppendable( nXclCol, nXclRow ), "XclExpTableop::TryExtend - wrong cell address" );
352 0 : Extend( rScPos );
353 0 : mnLastAppXclCol = nXclCol;
354 : }
355 : }
356 :
357 0 : return bOk;
358 : }
359 :
360 0 : void XclExpTableop::Finalize()
361 : {
362 : // is the range complete? (last appended cell is in last column)
363 0 : mbValid = maXclRange.maLast.mnCol == mnLastAppXclCol;
364 : // if last row is incomplete, try to shorten the used range
365 0 : if( !mbValid && (maXclRange.maFirst.mnRow < maXclRange.maLast.mnRow) )
366 : {
367 0 : --maXclRange.maLast.mnRow;
368 0 : mbValid = true;
369 : }
370 :
371 : // check if referred cells are outside of own range
372 0 : if( mbValid ) switch( mnScMode )
373 : {
374 : case 0:
375 0 : mbValid = (mnColInpXclCol + 1 < maXclRange.maFirst.mnCol) || (mnColInpXclCol > maXclRange.maLast.mnCol) ||
376 0 : (mnColInpXclRow < maXclRange.maFirst.mnRow) || (mnColInpXclRow > maXclRange.maLast.mnRow);
377 0 : break;
378 : case 1:
379 0 : mbValid = (mnColInpXclCol < maXclRange.maFirst.mnCol) || (mnColInpXclCol > maXclRange.maLast.mnCol) ||
380 0 : (mnColInpXclRow + 1 < maXclRange.maFirst.mnRow) || (mnColInpXclRow > maXclRange.maLast.mnRow);
381 0 : break;
382 : case 2:
383 0 : mbValid = ((mnColInpXclCol + 1 < maXclRange.maFirst.mnCol) || (mnColInpXclCol > maXclRange.maLast.mnCol) ||
384 0 : (mnColInpXclRow + 1 < maXclRange.maFirst.mnRow) || (mnColInpXclRow > maXclRange.maLast.mnRow)) &&
385 0 : ((mnRowInpXclCol + 1 < maXclRange.maFirst.mnCol) || (mnRowInpXclCol > maXclRange.maLast.mnCol) ||
386 0 : (mnRowInpXclRow + 1 < maXclRange.maFirst.mnRow) || (mnRowInpXclRow > maXclRange.maLast.mnRow));
387 0 : break;
388 : }
389 0 : }
390 :
391 0 : XclTokenArrayRef XclExpTableop::CreateCellTokenArray( const XclExpRoot& rRoot ) const
392 : {
393 0 : XclExpFormulaCompiler& rFmlaComp = rRoot.GetFormulaCompiler();
394 : return mbValid ?
395 : rFmlaComp.CreateSpecialRefFormula( EXC_TOKID_TBL, maBaseXclPos ) :
396 0 : rFmlaComp.CreateErrorFormula( EXC_ERR_NA );
397 : }
398 :
399 0 : bool XclExpTableop::IsVolatile() const
400 : {
401 0 : return true;
402 : }
403 :
404 0 : void XclExpTableop::Save( XclExpStream& rStrm )
405 : {
406 0 : if( mbValid )
407 0 : XclExpRangeFmlaBase::Save( rStrm );
408 0 : }
409 :
410 0 : bool XclExpTableop::IsAppendable( sal_uInt16 nXclCol, sal_uInt16 nXclRow ) const
411 : {
412 0 : return ((nXclCol == mnLastAppXclCol + 1) && (nXclRow == maXclRange.maFirst.mnRow)) ||
413 0 : ((nXclCol == mnLastAppXclCol + 1) && (nXclCol <= maXclRange.maLast.mnCol) && (nXclRow == maXclRange.maLast.mnRow)) ||
414 0 : ((mnLastAppXclCol == maXclRange.maLast.mnCol) && (nXclCol == maXclRange.maFirst.mnCol) && (nXclRow == maXclRange.maLast.mnRow + 1));
415 : }
416 :
417 0 : void XclExpTableop::WriteBody( XclExpStream& rStrm )
418 : {
419 0 : sal_uInt16 nFlags = EXC_TABLEOP_DEFAULTFLAGS;
420 0 : ::set_flag( nFlags, EXC_TABLEOP_RECALC_ALWAYS, IsVolatile() );
421 0 : switch( mnScMode )
422 : {
423 0 : case 1: ::set_flag( nFlags, EXC_TABLEOP_ROW ); break;
424 0 : case 2: ::set_flag( nFlags, EXC_TABLEOP_BOTH ); break;
425 : }
426 :
427 0 : WriteRangeAddress( rStrm );
428 0 : rStrm << nFlags;
429 0 : if( mnScMode == 2 )
430 0 : rStrm << mnRowInpXclRow << mnRowInpXclCol << mnColInpXclRow << mnColInpXclCol;
431 : else
432 0 : rStrm << mnColInpXclRow << mnColInpXclCol << sal_uInt32( 0 );
433 0 : }
434 :
435 124 : XclExpTableopBuffer::XclExpTableopBuffer( const XclExpRoot& rRoot ) :
436 124 : XclExpRoot( rRoot )
437 : {
438 124 : }
439 :
440 2206 : XclExpTableopRef XclExpTableopBuffer::CreateOrExtendTableop(
441 : const ScTokenArray& rScTokArr, const ScAddress& rScPos )
442 : {
443 2206 : XclExpTableopRef xRec;
444 :
445 : // try to extract cell references of a multiple operations formula
446 2206 : XclMultipleOpRefs aRefs;
447 2206 : if (XclTokenArrayHelper::GetMultipleOpRefs(aRefs, rScTokArr, rScPos))
448 : {
449 : // try to find an existing TABLEOP record for this cell position
450 0 : for( size_t nPos = 0, nSize = maTableopList.GetSize(); !xRec && (nPos < nSize); ++nPos )
451 : {
452 0 : XclExpTableopRef xTempRec = maTableopList.GetRecord( nPos );
453 0 : if( xTempRec->TryExtend( rScPos, aRefs ) )
454 0 : xRec = xTempRec;
455 0 : }
456 :
457 : // no record found, or found record not extensible
458 0 : if( !xRec )
459 0 : xRec = TryCreate( rScPos, aRefs );
460 : }
461 :
462 2206 : return xRec;
463 : }
464 :
465 124 : void XclExpTableopBuffer::Finalize()
466 : {
467 124 : for( size_t nPos = 0, nSize = maTableopList.GetSize(); nPos < nSize; ++nPos )
468 0 : maTableopList.GetRecord( nPos )->Finalize();
469 124 : }
470 :
471 0 : XclExpTableopRef XclExpTableopBuffer::TryCreate( const ScAddress& rScPos, const XclMultipleOpRefs& rRefs )
472 : {
473 0 : sal_uInt8 nScMode = 0;
474 0 : bool bOk = (rScPos.Tab() == rRefs.maFmlaScPos.Tab()) &&
475 0 : (rScPos.Tab() == rRefs.maColFirstScPos.Tab()) &&
476 0 : (rScPos.Tab() == rRefs.maColRelScPos.Tab());
477 :
478 0 : if( bOk )
479 : {
480 0 : if( rRefs.mbDblRefMode )
481 : {
482 0 : nScMode = 2;
483 0 : bOk = (rScPos.Col() == rRefs.maFmlaScPos.Col() + 1) &&
484 0 : (rScPos.Row() == rRefs.maFmlaScPos.Row() + 1) &&
485 0 : (rScPos.Col() == rRefs.maColRelScPos.Col() + 1) &&
486 0 : (rScPos.Row() == rRefs.maColRelScPos.Row()) &&
487 0 : (rScPos.Tab() == rRefs.maRowFirstScPos.Tab()) &&
488 0 : (rScPos.Col() == rRefs.maRowRelScPos.Col()) &&
489 0 : (rScPos.Row() == rRefs.maRowRelScPos.Row() + 1) &&
490 0 : (rScPos.Tab() == rRefs.maRowRelScPos.Tab());
491 : }
492 0 : else if( (rScPos.Col() == rRefs.maFmlaScPos.Col()) &&
493 0 : (rScPos.Row() == rRefs.maFmlaScPos.Row() + 1) &&
494 0 : (rScPos.Col() == rRefs.maColRelScPos.Col() + 1) &&
495 0 : (rScPos.Row() == rRefs.maColRelScPos.Row()) )
496 : {
497 0 : nScMode = 0;
498 : }
499 0 : else if( (rScPos.Col() == rRefs.maFmlaScPos.Col() + 1) &&
500 0 : (rScPos.Row() == rRefs.maFmlaScPos.Row()) &&
501 0 : (rScPos.Col() == rRefs.maColRelScPos.Col()) &&
502 0 : (rScPos.Row() == rRefs.maColRelScPos.Row() + 1) )
503 : {
504 0 : nScMode = 1;
505 : }
506 : else
507 : {
508 0 : bOk = false;
509 : }
510 : }
511 :
512 0 : XclExpTableopRef xRec;
513 0 : if( bOk )
514 : {
515 0 : xRec.reset( new XclExpTableop( rScPos, rRefs, nScMode ) );
516 0 : maTableopList.AppendRecord( xRec );
517 : }
518 :
519 0 : return xRec;
520 : }
521 :
522 : // Cell records
523 :
524 8108 : XclExpCellBase::XclExpCellBase(
525 : sal_uInt16 nRecId, sal_Size nContSize, const XclAddress& rXclPos ) :
526 : XclExpRecord( nRecId, nContSize + 4 ),
527 8108 : maXclPos( rXclPos )
528 : {
529 8108 : }
530 :
531 0 : bool XclExpCellBase::IsMultiLineText() const
532 : {
533 0 : return false;
534 : }
535 :
536 3538 : bool XclExpCellBase::TryMerge( const XclExpCellBase& /*rCell*/ )
537 : {
538 3538 : return false;
539 : }
540 :
541 4542 : void XclExpCellBase::GetBlankXFIndexes( ScfUInt16Vec& /*rXFIndexes*/ ) const
542 : {
543 : // default: do nothing
544 4542 : }
545 :
546 4542 : void XclExpCellBase::RemoveUnusedBlankCells( const ScfUInt16Vec& /*rXFIndexes*/ )
547 : {
548 : // default: do nothing
549 4542 : }
550 :
551 : // Single cell records ========================================================
552 :
553 3026 : XclExpSingleCellBase::XclExpSingleCellBase(
554 : sal_uInt16 nRecId, sal_Size nContSize, const XclAddress& rXclPos, sal_uInt32 nXFId ) :
555 : XclExpCellBase( nRecId, 2, rXclPos ),
556 : maXFId( nXFId ),
557 3026 : mnContSize( nContSize )
558 : {
559 3026 : }
560 :
561 466 : XclExpSingleCellBase::XclExpSingleCellBase( const XclExpRoot& rRoot,
562 : sal_uInt16 nRecId, sal_Size nContSize, const XclAddress& rXclPos,
563 : const ScPatternAttr* pPattern, sal_Int16 nScript, sal_uInt32 nForcedXFId ) :
564 : XclExpCellBase( nRecId, 2, rXclPos ),
565 : maXFId( nForcedXFId ),
566 466 : mnContSize( nContSize )
567 : {
568 466 : if( GetXFId() == EXC_XFID_NOTFOUND )
569 466 : SetXFId( rRoot.GetXFBuffer().Insert( pPattern, nScript ) );
570 466 : }
571 :
572 4310 : sal_uInt16 XclExpSingleCellBase::GetLastXclCol() const
573 : {
574 4310 : return GetXclCol();
575 : }
576 :
577 1830 : sal_uInt32 XclExpSingleCellBase::GetFirstXFId() const
578 : {
579 1830 : return GetXFId();
580 : }
581 :
582 3492 : bool XclExpSingleCellBase::IsEmpty() const
583 : {
584 3492 : return false;
585 : }
586 :
587 3492 : void XclExpSingleCellBase::ConvertXFIndexes( const XclExpRoot& rRoot )
588 : {
589 3492 : maXFId.ConvertXFIndex( rRoot );
590 3492 : }
591 :
592 1674 : void XclExpSingleCellBase::Save( XclExpStream& rStrm )
593 : {
594 : OSL_ENSURE_BIFF( rStrm.GetRoot().GetBiff() >= EXC_BIFF3 );
595 1674 : AddRecSize( mnContSize );
596 1674 : XclExpCellBase::Save( rStrm );
597 1674 : }
598 :
599 1674 : void XclExpSingleCellBase::WriteBody( XclExpStream& rStrm )
600 : {
601 1674 : rStrm << static_cast<sal_uInt16> (GetXclRow()) << GetXclCol() << maXFId.mnXFIndex;
602 1674 : WriteContents( rStrm );
603 1674 : }
604 :
605 16 : IMPL_FIXEDMEMPOOL_NEWDEL( XclExpNumberCell )
606 :
607 466 : XclExpNumberCell::XclExpNumberCell(
608 : const XclExpRoot& rRoot, const XclAddress& rXclPos,
609 : const ScPatternAttr* pPattern, sal_uInt32 nForcedXFId, double fValue ) :
610 : // #i41210# always use latin script for number cells - may look wrong for special number formats...
611 : XclExpSingleCellBase( rRoot, EXC_ID3_NUMBER, 8, rXclPos, pPattern, ApiScriptType::LATIN, nForcedXFId ),
612 466 : mfValue( fValue )
613 : {
614 466 : }
615 :
616 3622 : static OString lcl_GetStyleId( XclExpXmlStream& rStrm, sal_uInt32 nXFIndex )
617 : {
618 3622 : return OString::number( rStrm.GetRoot().GetXFBuffer()
619 3622 : .GetXmlCellIndex( nXFIndex ) );
620 : }
621 :
622 1818 : static OString lcl_GetStyleId( XclExpXmlStream& rStrm, const XclExpCellBase& rCell )
623 : {
624 1818 : sal_uInt32 nXFId = rCell.GetFirstXFId();
625 1818 : sal_uInt16 nXFIndex = rStrm.GetRoot().GetXFBuffer().GetXFIndex( nXFId );
626 1818 : return lcl_GetStyleId( rStrm, nXFIndex );
627 : }
628 :
629 248 : void XclExpNumberCell::SaveXml( XclExpXmlStream& rStrm )
630 : {
631 248 : sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
632 : rWorksheet->startElement( XML_c,
633 248 : XML_r, XclXmlUtils::ToOString( GetXclPos() ).getStr(),
634 : XML_s, lcl_GetStyleId( rStrm, *this ).getStr(),
635 : XML_t, "n",
636 : // OOXTODO: XML_cm, XML_vm, XML_ph
637 496 : FSEND );
638 248 : rWorksheet->startElement( XML_v, FSEND );
639 248 : rWorksheet->write( mfValue );
640 248 : rWorksheet->endElement( XML_v );
641 248 : rWorksheet->endElement( XML_c );
642 248 : }
643 :
644 218 : void XclExpNumberCell::WriteContents( XclExpStream& rStrm )
645 : {
646 218 : rStrm << mfValue;
647 218 : }
648 :
649 16 : IMPL_FIXEDMEMPOOL_NEWDEL( XclExpBooleanCell )
650 :
651 0 : XclExpBooleanCell::XclExpBooleanCell(
652 : const XclExpRoot rRoot, const XclAddress& rXclPos,
653 : const ScPatternAttr* pPattern, sal_uInt32 nForcedXFId, bool bValue ) :
654 : // #i41210# always use latin script for boolean cells
655 : XclExpSingleCellBase( rRoot, EXC_ID3_BOOLERR, 2, rXclPos, pPattern, ApiScriptType::LATIN, nForcedXFId ),
656 0 : mbValue( bValue )
657 : {
658 0 : }
659 :
660 0 : void XclExpBooleanCell::SaveXml( XclExpXmlStream& rStrm )
661 : {
662 0 : sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
663 : rWorksheet->startElement( XML_c,
664 0 : XML_r, XclXmlUtils::ToOString( GetXclPos() ).getStr(),
665 : XML_s, lcl_GetStyleId( rStrm, *this ).getStr(),
666 : XML_t, "b",
667 : // OOXTODO: XML_cm, XML_vm, XML_ph
668 0 : FSEND );
669 0 : rWorksheet->startElement( XML_v, FSEND );
670 0 : rWorksheet->write( mbValue ? "1" : "0" );
671 0 : rWorksheet->endElement( XML_v );
672 0 : rWorksheet->endElement( XML_c );
673 0 : }
674 :
675 0 : void XclExpBooleanCell::WriteContents( XclExpStream& rStrm )
676 : {
677 0 : rStrm << sal_uInt16( mbValue ? 1 : 0 ) << EXC_BOOLERR_BOOL;
678 0 : }
679 :
680 16 : IMPL_FIXEDMEMPOOL_NEWDEL( XclExpLabelCell )
681 :
682 820 : XclExpLabelCell::XclExpLabelCell(
683 : const XclExpRoot& rRoot, const XclAddress& rXclPos,
684 : const ScPatternAttr* pPattern, sal_uInt32 nForcedXFId, const OUString& rStr ) :
685 820 : XclExpSingleCellBase( EXC_ID3_LABEL, 0, rXclPos, nForcedXFId )
686 : {
687 820 : sal_uInt16 nMaxLen = (rRoot.GetBiff() == EXC_BIFF8) ? EXC_STR_MAXLEN : EXC_LABEL_MAXLEN;
688 : XclExpStringRef xText = XclExpStringHelper::CreateCellString(
689 820 : rRoot, rStr, pPattern, EXC_STR_DEFAULT, nMaxLen);
690 820 : Init( rRoot, pPattern, xText );
691 820 : }
692 :
693 0 : XclExpLabelCell::XclExpLabelCell(
694 : const XclExpRoot& rRoot, const XclAddress& rXclPos,
695 : const ScPatternAttr* pPattern, sal_uInt32 nForcedXFId,
696 : const EditTextObject* pEditText, XclExpHyperlinkHelper& rLinkHelper ) :
697 0 : XclExpSingleCellBase( EXC_ID3_LABEL, 0, rXclPos, nForcedXFId )
698 : {
699 0 : sal_uInt16 nMaxLen = (rRoot.GetBiff() == EXC_BIFF8) ? EXC_STR_MAXLEN : EXC_LABEL_MAXLEN;
700 :
701 0 : XclExpStringRef xText;
702 0 : if (pEditText)
703 0 : xText = XclExpStringHelper::CreateCellString(
704 0 : rRoot, *pEditText, pPattern, rLinkHelper, EXC_STR_DEFAULT, nMaxLen);
705 : else
706 0 : xText = XclExpStringHelper::CreateCellString(
707 0 : rRoot, EMPTY_OUSTRING, pPattern, EXC_STR_DEFAULT, nMaxLen);
708 :
709 0 : Init( rRoot, pPattern, xText );
710 0 : }
711 :
712 12 : bool XclExpLabelCell::IsMultiLineText() const
713 : {
714 12 : return mbLineBreak || mxText->IsWrapped();
715 : }
716 :
717 820 : void XclExpLabelCell::Init( const XclExpRoot& rRoot,
718 : const ScPatternAttr* pPattern, XclExpStringRef xText )
719 : {
720 : OSL_ENSURE( xText && xText->Len(), "XclExpLabelCell::XclExpLabelCell - empty string passed" );
721 820 : mxText = xText;
722 820 : mnSstIndex = 0;
723 :
724 : // create the cell format
725 820 : sal_uInt16 nXclFont = mxText->RemoveLeadingFont();
726 820 : if( GetXFId() == EXC_XFID_NOTFOUND )
727 : {
728 : OSL_ENSURE( nXclFont != EXC_FONT_NOTFOUND, "XclExpLabelCell::Init - leading font not found" );
729 820 : bool bForceLineBreak = mxText->IsWrapped();
730 820 : SetXFId( rRoot.GetXFBuffer().InsertWithFont( pPattern, ApiScriptType::WEAK, nXclFont, bForceLineBreak ) );
731 : }
732 :
733 : // get auto-wrap attribute from cell format
734 820 : const XclExpXF* pXF = rRoot.GetXFBuffer().GetXFById( GetXFId() );
735 820 : mbLineBreak = pXF && pXF->GetAlignmentData().mbLineBreak;
736 :
737 : // initialize the record contents
738 820 : switch( rRoot.GetBiff() )
739 : {
740 : case EXC_BIFF5:
741 : // BIFF5-BIFF7: create a LABEL or RSTRING record
742 : OSL_ENSURE( mxText->Len() <= EXC_LABEL_MAXLEN, "XclExpLabelCell::XclExpLabelCell - string too long" );
743 0 : SetContSize( mxText->GetSize() );
744 : // formatted string is exported in an RSTRING record
745 0 : if( mxText->IsRich() )
746 : {
747 : OSL_ENSURE( mxText->GetFormatsCount() <= EXC_LABEL_MAXLEN, "XclExpLabelCell::WriteContents - too many formats" );
748 0 : mxText->LimitFormatCount( EXC_LABEL_MAXLEN );
749 0 : SetRecId( EXC_ID_RSTRING );
750 0 : SetContSize( GetContSize() + 1 + 2 * mxText->GetFormatsCount() );
751 : }
752 0 : break;
753 : case EXC_BIFF8:
754 : // BIFF8+: create a LABELSST record
755 820 : mnSstIndex = rRoot.GetSst().Insert( xText );
756 820 : SetRecId( EXC_ID_LABELSST );
757 820 : SetContSize( 4 );
758 820 : break;
759 : default: DBG_ERROR_BIFF();
760 : }
761 820 : }
762 :
763 472 : void XclExpLabelCell::SaveXml( XclExpXmlStream& rStrm )
764 : {
765 472 : sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
766 : rWorksheet->startElement( XML_c,
767 472 : XML_r, XclXmlUtils::ToOString( GetXclPos() ).getStr(),
768 : XML_s, lcl_GetStyleId( rStrm, *this ).getStr(),
769 : XML_t, "s",
770 : // OOXTODO: XML_cm, XML_vm, XML_ph
771 944 : FSEND );
772 472 : rWorksheet->startElement( XML_v, FSEND );
773 472 : rWorksheet->write( (sal_Int32) mnSstIndex );
774 472 : rWorksheet->endElement( XML_v );
775 472 : rWorksheet->endElement( XML_c );
776 472 : }
777 :
778 348 : void XclExpLabelCell::WriteContents( XclExpStream& rStrm )
779 : {
780 348 : switch( rStrm.GetRoot().GetBiff() )
781 : {
782 : case EXC_BIFF5:
783 0 : rStrm << *mxText;
784 0 : if( mxText->IsRich() )
785 : {
786 0 : rStrm << static_cast< sal_uInt8 >( mxText->GetFormatsCount() );
787 0 : mxText->WriteFormats( rStrm );
788 : }
789 0 : break;
790 : case EXC_BIFF8:
791 348 : rStrm << mnSstIndex;
792 348 : break;
793 : default: DBG_ERROR_BIFF();
794 : }
795 348 : }
796 :
797 16 : IMPL_FIXEDMEMPOOL_NEWDEL( XclExpFormulaCell )
798 :
799 2206 : XclExpFormulaCell::XclExpFormulaCell(
800 : const XclExpRoot& rRoot, const XclAddress& rXclPos,
801 : const ScPatternAttr* pPattern, sal_uInt32 nForcedXFId,
802 : const ScFormulaCell& rScFmlaCell,
803 : XclExpArrayBuffer& rArrayBfr,
804 : XclExpShrfmlaBuffer& rShrfmlaBfr,
805 : XclExpTableopBuffer& rTableopBfr ) :
806 : XclExpSingleCellBase( EXC_ID2_FORMULA, 0, rXclPos, nForcedXFId ),
807 2206 : mrScFmlaCell( const_cast< ScFormulaCell& >( rScFmlaCell ) )
808 : {
809 : // *** Find result number format overwriting cell number format *** -------
810 :
811 2206 : if( GetXFId() == EXC_XFID_NOTFOUND )
812 : {
813 2206 : SvNumberFormatter& rFormatter = rRoot.GetFormatter();
814 2206 : XclExpNumFmtBuffer& rNumFmtBfr = rRoot.GetNumFmtBuffer();
815 :
816 : // current cell number format
817 : sal_uLong nScNumFmt = pPattern ?
818 710 : GETITEMVALUE( pPattern->GetItemSet(), SfxUInt32Item, ATTR_VALUE_FORMAT, sal_uLong ) :
819 2916 : rNumFmtBfr.GetStandardFormat();
820 :
821 : // alternative number format passed to XF buffer
822 2206 : sal_uLong nAltScNumFmt = NUMBERFORMAT_ENTRY_NOT_FOUND;
823 : /* Xcl doesn't know Boolean number formats, we write
824 : "TRUE";"FALSE" (language dependent). Don't do it for automatic
825 : formula formats, because Excel gets them right. */
826 : /* #i8640# Don't set text format, if we have string results. */
827 2206 : short nFormatType = mrScFmlaCell.GetFormatType();
828 2206 : if( ((nScNumFmt % SV_COUNTRY_LANGUAGE_OFFSET) == 0) &&
829 1888 : (nFormatType != NUMBERFORMAT_LOGICAL) &&
830 : (nFormatType != NUMBERFORMAT_TEXT) )
831 1888 : nAltScNumFmt = nScNumFmt;
832 : /* If cell number format is Boolean and automatic formula
833 : format is Boolean don't write that ugly special format. */
834 320 : else if( (nFormatType == NUMBERFORMAT_LOGICAL) &&
835 2 : (rFormatter.GetType( nScNumFmt ) == NUMBERFORMAT_LOGICAL) )
836 0 : nAltScNumFmt = rNumFmtBfr.GetStandardFormat();
837 :
838 : // #i41420# find script type according to result type (always latin for numeric results)
839 2206 : sal_Int16 nScript = ApiScriptType::LATIN;
840 2206 : bool bForceLineBreak = false;
841 2206 : if( nFormatType == NUMBERFORMAT_TEXT )
842 : {
843 0 : OUString aResult = mrScFmlaCell.GetString().getString();
844 0 : bForceLineBreak = mrScFmlaCell.IsMultilineResult();
845 0 : nScript = XclExpStringHelper::GetLeadingScriptType( rRoot, aResult );
846 : }
847 2206 : SetXFId( rRoot.GetXFBuffer().InsertWithNumFmt( pPattern, nScript, nAltScNumFmt, bForceLineBreak ) );
848 : }
849 :
850 : // *** Convert the formula token array *** --------------------------------
851 :
852 2206 : ScAddress aScPos( static_cast< SCCOL >( rXclPos.mnCol ), static_cast< SCROW >( rXclPos.mnRow ), rRoot.GetCurrScTab() );
853 2206 : const ScTokenArray& rScTokArr = *mrScFmlaCell.GetCode();
854 :
855 : // first try to create multiple operations
856 2206 : mxAddRec = rTableopBfr.CreateOrExtendTableop( rScTokArr, aScPos );
857 :
858 : // no multiple operation found - try to create matrix formula
859 2206 : if( !mxAddRec ) switch( static_cast< ScMatrixMode >( mrScFmlaCell.GetMatrixFlag() ) )
860 : {
861 : case MM_FORMULA:
862 : {
863 : // origin of the matrix - find the used matrix range
864 : SCCOL nMatWidth;
865 : SCROW nMatHeight;
866 6 : mrScFmlaCell.GetMatColsRows( nMatWidth, nMatHeight );
867 : OSL_ENSURE( nMatWidth && nMatHeight, "XclExpFormulaCell::XclExpFormulaCell - empty matrix" );
868 6 : ScRange aMatScRange( aScPos );
869 6 : ScAddress& rMatEnd = aMatScRange.aEnd;
870 6 : rMatEnd.IncCol( static_cast< SCsCOL >( nMatWidth - 1 ) );
871 6 : rMatEnd.IncRow( static_cast< SCsROW >( nMatHeight - 1 ) );
872 : // reduce to valid range (range keeps valid, because start position IS valid)
873 6 : rRoot.GetAddressConverter().ValidateRange( aMatScRange, true );
874 : // create the ARRAY record
875 6 : mxAddRec = rArrayBfr.CreateArray( rScTokArr, aMatScRange );
876 : }
877 6 : break;
878 : case MM_REFERENCE:
879 : {
880 : // other formula cell covered by a matrix - find the ARRAY record
881 26 : mxAddRec = rArrayBfr.FindArray(rScTokArr, aScPos);
882 : // should always be found, if Calc document is not broken
883 : OSL_ENSURE( mxAddRec, "XclExpFormulaCell::XclExpFormulaCell - no matrix found" );
884 : }
885 26 : break;
886 : default:;
887 : }
888 :
889 : // no matrix found - try to create shared formula
890 2206 : if( !mxAddRec )
891 2174 : mxAddRec = rShrfmlaBfr.CreateOrExtendShrfmla(mrScFmlaCell, aScPos);
892 :
893 : // no shared formula found - create a simple cell formula
894 2206 : if( !mxAddRec )
895 670 : mxTokArr = rRoot.GetFormulaCompiler().CreateFormula( EXC_FMLATYPE_CELL, rScTokArr, &aScPos );
896 2206 : }
897 :
898 1108 : void XclExpFormulaCell::Save( XclExpStream& rStrm )
899 : {
900 : // create token array for FORMULA cells with additional record
901 1108 : if( mxAddRec )
902 772 : mxTokArr = mxAddRec->CreateCellTokenArray( rStrm.GetRoot() );
903 :
904 : // FORMULA record itself
905 : OSL_ENSURE( mxTokArr, "XclExpFormulaCell::Save - missing token array" );
906 1108 : if( !mxTokArr )
907 0 : mxTokArr = rStrm.GetRoot().GetFormulaCompiler().CreateErrorFormula( EXC_ERR_NA );
908 1108 : SetContSize( 16 + mxTokArr->GetSize() );
909 1108 : XclExpSingleCellBase::Save( rStrm );
910 :
911 : // additional record (ARRAY, SHRFMLA, or TABLEOP), only for first FORMULA record
912 1108 : if( mxAddRec && mxAddRec->IsBasePos( GetXclCol(), GetXclRow() ) )
913 130 : mxAddRec->Save( rStrm );
914 :
915 : // STRING record for string result
916 1108 : if( mxStringRec )
917 0 : mxStringRec->Save( rStrm );
918 1108 : }
919 :
920 1098 : void XclExpFormulaCell::SaveXml( XclExpXmlStream& rStrm )
921 : {
922 1098 : const char* sType = NULL;
923 1098 : OUString sValue;
924 :
925 1098 : XclXmlUtils::GetFormulaTypeAndValue( mrScFmlaCell, sType, sValue );
926 1098 : sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
927 : rWorksheet->startElement( XML_c,
928 1098 : XML_r, XclXmlUtils::ToOString( GetXclPos() ).getStr(),
929 : XML_s, lcl_GetStyleId( rStrm, *this ).getStr(),
930 : XML_t, sType,
931 : // OOXTODO: XML_cm, XML_vm, XML_ph
932 2196 : FSEND );
933 :
934 : rWorksheet->startElement( XML_f,
935 : // OOXTODO: XML_t, ST_CellFormulaType
936 1098 : XML_aca, XclXmlUtils::ToPsz( (mxTokArr && mxTokArr->IsVolatile()) || (mxAddRec && mxAddRec->IsVolatile()) ),
937 : // OOXTODO: XML_ref, ST_Ref
938 : // OOXTODO: XML_dt2D, bool
939 : // OOXTODO: XML_dtr, bool
940 : // OOXTODO: XML_del1, bool
941 : // OOXTODO: XML_del2, bool
942 : // OOXTODO: XML_r1, ST_CellRef
943 : // OOXTODO: XML_r2, ST_CellRef
944 : // OOXTODO: XML_ca, bool
945 : // OOXTODO: XML_si, uint
946 : // OOXTODO: XML_bx bool
947 1098 : FSEND );
948 : rWorksheet->writeEscaped( XclXmlUtils::ToOUString(
949 1098 : rStrm.GetRoot().GetCompileFormulaContext(), mrScFmlaCell.aPos, mrScFmlaCell.GetCode()));
950 1098 : rWorksheet->endElement( XML_f );
951 1098 : if( strcmp( sType, "inlineStr" ) == 0 )
952 : {
953 0 : rWorksheet->startElement( XML_is, FSEND );
954 0 : rWorksheet->startElement( XML_t, FSEND );
955 0 : rWorksheet->writeEscaped( sValue );
956 0 : rWorksheet->endElement( XML_t );
957 0 : rWorksheet->endElement( XML_is );
958 : }
959 : else
960 : {
961 1098 : rWorksheet->startElement( XML_v, FSEND );
962 1098 : rWorksheet->writeEscaped( sValue );
963 1098 : rWorksheet->endElement( XML_v );
964 : }
965 1098 : rWorksheet->endElement( XML_c );
966 1098 : }
967 :
968 1108 : void XclExpFormulaCell::WriteContents( XclExpStream& rStrm )
969 : {
970 1108 : sal_uInt16 nScErrCode = mrScFmlaCell.GetErrCode();
971 1108 : if( nScErrCode )
972 : {
973 2 : rStrm << EXC_FORMULA_RES_ERROR << sal_uInt8( 0 )
974 4 : << XclTools::GetXclErrorCode( nScErrCode )
975 2 : << sal_uInt8( 0 ) << sal_uInt16( 0 )
976 2 : << sal_uInt16( 0xFFFF );
977 : }
978 : else
979 : {
980 : // result of the formula
981 1106 : switch( mrScFmlaCell.GetFormatType() )
982 : {
983 : case NUMBERFORMAT_NUMBER:
984 : {
985 : // either value or error code
986 1104 : rStrm << mrScFmlaCell.GetValue();
987 : }
988 1104 : break;
989 :
990 : case NUMBERFORMAT_TEXT:
991 : {
992 0 : OUString aResult = mrScFmlaCell.GetString().getString();
993 0 : if( !aResult.isEmpty() || (rStrm.GetRoot().GetBiff() <= EXC_BIFF5) )
994 : {
995 0 : rStrm << EXC_FORMULA_RES_STRING;
996 0 : mxStringRec.reset( new XclExpStringRec( rStrm.GetRoot(), aResult ) );
997 : }
998 : else
999 0 : rStrm << EXC_FORMULA_RES_EMPTY; // BIFF8 only
1000 0 : rStrm << sal_uInt8( 0 ) << sal_uInt32( 0 ) << sal_uInt16( 0xFFFF );
1001 : }
1002 0 : break;
1003 :
1004 : case NUMBERFORMAT_LOGICAL:
1005 : {
1006 2 : sal_uInt8 nXclValue = (mrScFmlaCell.GetValue() == 0.0) ? 0 : 1;
1007 2 : rStrm << EXC_FORMULA_RES_BOOL << sal_uInt8( 0 )
1008 4 : << nXclValue << sal_uInt8( 0 ) << sal_uInt16( 0 )
1009 2 : << sal_uInt16( 0xFFFF );
1010 : }
1011 2 : break;
1012 :
1013 : default:
1014 0 : rStrm << mrScFmlaCell.GetValue();
1015 : }
1016 : }
1017 :
1018 : // flags and formula token array
1019 1108 : sal_uInt16 nFlags = EXC_FORMULA_DEFAULTFLAGS;
1020 1108 : ::set_flag( nFlags, EXC_FORMULA_RECALC_ALWAYS, mxTokArr->IsVolatile() || (mxAddRec && mxAddRec->IsVolatile()) );
1021 1108 : ::set_flag( nFlags, EXC_FORMULA_SHARED, mxAddRec && (mxAddRec->GetRecId() == EXC_ID_SHRFMLA) );
1022 1108 : rStrm << nFlags << sal_uInt32( 0 ) << *mxTokArr;
1023 1108 : }
1024 :
1025 : // Multiple cell records ======================================================
1026 :
1027 4616 : XclExpMultiCellBase::XclExpMultiCellBase(
1028 : sal_uInt16 nRecId, sal_uInt16 nMulRecId, sal_Size nContSize, const XclAddress& rXclPos ) :
1029 : XclExpCellBase( nRecId, 0, rXclPos ),
1030 : mnMulRecId( nMulRecId ),
1031 4616 : mnContSize( nContSize )
1032 : {
1033 4616 : }
1034 :
1035 9036 : sal_uInt16 XclExpMultiCellBase::GetLastXclCol() const
1036 : {
1037 9036 : return GetXclCol() + GetCellCount() - 1;
1038 : }
1039 :
1040 0 : sal_uInt32 XclExpMultiCellBase::GetFirstXFId() const
1041 : {
1042 0 : return maXFIds.empty() ? XclExpXFBuffer::GetDefCellXFId() : maXFIds.front().mnXFId;
1043 : }
1044 :
1045 3058 : bool XclExpMultiCellBase::IsEmpty() const
1046 : {
1047 3058 : return maXFIds.empty();
1048 : }
1049 :
1050 1864 : void XclExpMultiCellBase::ConvertXFIndexes( const XclExpRoot& rRoot )
1051 : {
1052 4624 : for( XclExpMultiXFIdDeq::iterator aIt = maXFIds.begin(), aEnd = maXFIds.end(); aIt != aEnd; ++aIt )
1053 2760 : aIt->ConvertXFIndex( rRoot );
1054 1864 : }
1055 :
1056 550 : void XclExpMultiCellBase::Save( XclExpStream& rStrm )
1057 : {
1058 : OSL_ENSURE_BIFF( rStrm.GetRoot().GetBiff() >= EXC_BIFF3 );
1059 :
1060 550 : XclExpMultiXFIdDeq::const_iterator aEnd = maXFIds.end();
1061 550 : XclExpMultiXFIdDeq::const_iterator aRangeBeg = maXFIds.begin();
1062 550 : XclExpMultiXFIdDeq::const_iterator aRangeEnd = aRangeBeg;
1063 550 : sal_uInt16 nBegXclCol = GetXclCol();
1064 550 : sal_uInt16 nEndXclCol = nBegXclCol;
1065 :
1066 1676 : while( aRangeEnd != aEnd )
1067 : {
1068 : // find begin of next used XF range
1069 576 : aRangeBeg = aRangeEnd;
1070 576 : nBegXclCol = nEndXclCol;
1071 1178 : while( (aRangeBeg != aEnd) && (aRangeBeg->mnXFIndex == EXC_XF_NOTFOUND) )
1072 : {
1073 26 : nBegXclCol = nBegXclCol + aRangeBeg->mnCount;
1074 26 : ++aRangeBeg;
1075 : }
1076 : // find end of next used XF range
1077 576 : aRangeEnd = aRangeBeg;
1078 576 : nEndXclCol = nBegXclCol;
1079 2064 : while( (aRangeEnd != aEnd) && (aRangeEnd->mnXFIndex != EXC_XF_NOTFOUND) )
1080 : {
1081 912 : nEndXclCol = nEndXclCol + aRangeEnd->mnCount;
1082 912 : ++aRangeEnd;
1083 : }
1084 :
1085 : // export this range as a record
1086 576 : if( aRangeBeg != aRangeEnd )
1087 : {
1088 576 : sal_uInt16 nCount = nEndXclCol - nBegXclCol;
1089 576 : bool bIsMulti = nCount > 1;
1090 576 : sal_Size nTotalSize = GetRecSize() + (2 + mnContSize) * nCount;
1091 576 : if( bIsMulti ) nTotalSize += 2;
1092 :
1093 576 : rStrm.StartRecord( bIsMulti ? mnMulRecId : GetRecId(), nTotalSize );
1094 576 : rStrm << static_cast<sal_uInt16> (GetXclRow()) << nBegXclCol;
1095 :
1096 576 : sal_uInt16 nRelCol = nBegXclCol - GetXclCol();
1097 1488 : for( XclExpMultiXFIdDeq::const_iterator aIt = aRangeBeg; aIt != aRangeEnd; ++aIt )
1098 : {
1099 2094 : for( sal_uInt16 nIdx = 0; nIdx < aIt->mnCount; ++nIdx )
1100 : {
1101 1182 : rStrm << aIt->mnXFIndex;
1102 1182 : WriteContents( rStrm, nRelCol );
1103 1182 : ++nRelCol;
1104 : }
1105 : }
1106 576 : if( bIsMulti )
1107 236 : rStrm << static_cast< sal_uInt16 >( nEndXclCol - 1 );
1108 576 : rStrm.EndRecord();
1109 : }
1110 : }
1111 550 : }
1112 :
1113 1014 : void XclExpMultiCellBase::SaveXml( XclExpXmlStream& rStrm )
1114 : {
1115 1014 : XclExpMultiXFIdDeq::const_iterator aEnd = maXFIds.end();
1116 1014 : XclExpMultiXFIdDeq::const_iterator aRangeBeg = maXFIds.begin();
1117 1014 : XclExpMultiXFIdDeq::const_iterator aRangeEnd = aRangeBeg;
1118 1014 : sal_uInt16 nBegXclCol = GetXclCol();
1119 1014 : sal_uInt16 nEndXclCol = nBegXclCol;
1120 :
1121 3044 : while( aRangeEnd != aEnd )
1122 : {
1123 : // find begin of next used XF range
1124 1016 : aRangeBeg = aRangeEnd;
1125 1016 : nBegXclCol = nEndXclCol;
1126 2034 : while( (aRangeBeg != aEnd) && (aRangeBeg->mnXFIndex == EXC_XF_NOTFOUND) )
1127 : {
1128 2 : nBegXclCol = nBegXclCol + aRangeBeg->mnCount;
1129 2 : ++aRangeBeg;
1130 : }
1131 : // find end of next used XF range
1132 1016 : aRangeEnd = aRangeBeg;
1133 1016 : nEndXclCol = nBegXclCol;
1134 3432 : while( (aRangeEnd != aEnd) && (aRangeEnd->mnXFIndex != EXC_XF_NOTFOUND) )
1135 : {
1136 1400 : nEndXclCol = nEndXclCol + aRangeEnd->mnCount;
1137 1400 : ++aRangeEnd;
1138 : }
1139 :
1140 : // export this range as a record
1141 1016 : if( aRangeBeg != aRangeEnd )
1142 : {
1143 1016 : sal_uInt16 nRelColIdx = nBegXclCol - GetXclCol();
1144 1016 : sal_Int32 nRelCol = 0;
1145 2416 : for( XclExpMultiXFIdDeq::const_iterator aIt = aRangeBeg; aIt != aRangeEnd; ++aIt )
1146 : {
1147 3068 : for( sal_uInt16 nIdx = 0; nIdx < aIt->mnCount; ++nIdx )
1148 : {
1149 : WriteXmlContents(
1150 : rStrm,
1151 : XclAddress( static_cast<sal_uInt16>(nBegXclCol + nRelCol), GetXclRow() ),
1152 1668 : aIt->mnXFIndex,
1153 3336 : nRelColIdx );
1154 1668 : ++nRelCol;
1155 1668 : ++nRelColIdx;
1156 : }
1157 : }
1158 : }
1159 : }
1160 1014 : }
1161 :
1162 9036 : sal_uInt16 XclExpMultiCellBase::GetCellCount() const
1163 : {
1164 9036 : sal_uInt16 nCount = 0;
1165 25094 : for( XclExpMultiXFIdDeq::const_iterator aIt = maXFIds.begin(), aEnd = maXFIds.end(); aIt != aEnd; ++aIt )
1166 16058 : nCount = nCount + aIt->mnCount;
1167 9036 : return nCount;
1168 : }
1169 :
1170 775556 : void XclExpMultiCellBase::AppendXFId( const XclExpMultiXFId& rXFId )
1171 : {
1172 775556 : if( maXFIds.empty() || (maXFIds.back().mnXFId != rXFId.mnXFId) )
1173 7268 : maXFIds.push_back( rXFId );
1174 : else
1175 768288 : maXFIds.back().mnCount = maXFIds.back().mnCount + rXFId.mnCount;
1176 775556 : }
1177 :
1178 2760 : void XclExpMultiCellBase::AppendXFId( const XclExpRoot& rRoot,
1179 : const ScPatternAttr* pPattern, sal_uInt16 nScript, sal_uInt32 nForcedXFId, sal_uInt16 nCount )
1180 : {
1181 : sal_uInt32 nXFId = (nForcedXFId == EXC_XFID_NOTFOUND) ?
1182 2760 : rRoot.GetXFBuffer().Insert( pPattern, nScript ) : nForcedXFId;
1183 2760 : AppendXFId( XclExpMultiXFId( nXFId, nCount ) );
1184 2760 : }
1185 :
1186 1890 : bool XclExpMultiCellBase::TryMergeXFIds( const XclExpMultiCellBase& rCell )
1187 : {
1188 1890 : if( GetLastXclCol() + 1 == rCell.GetXclCol() )
1189 : {
1190 1558 : maXFIds.insert( maXFIds.end(), rCell.maXFIds.begin(), rCell.maXFIds.end() );
1191 1558 : return true;
1192 : }
1193 332 : return false;
1194 : }
1195 :
1196 814 : void XclExpMultiCellBase::GetXFIndexes( ScfUInt16Vec& rXFIndexes ) const
1197 : {
1198 : OSL_ENSURE( GetLastXclCol() < rXFIndexes.size(), "XclExpMultiCellBase::GetXFIndexes - vector too small" );
1199 814 : ScfUInt16Vec::iterator aDestIt = rXFIndexes.begin() + GetXclCol();
1200 1814 : for( XclExpMultiXFIdDeq::const_iterator aIt = maXFIds.begin(), aEnd = maXFIds.end(); aIt != aEnd; ++aIt )
1201 : {
1202 1000 : ::std::fill( aDestIt, aDestIt + aIt->mnCount, aIt->mnXFIndex );
1203 1000 : aDestIt += aIt->mnCount;
1204 : }
1205 814 : }
1206 :
1207 2008 : void XclExpMultiCellBase::RemoveUnusedXFIndexes( const ScfUInt16Vec& rXFIndexes )
1208 : {
1209 : // save last column before calling maXFIds.clear()
1210 2008 : sal_uInt16 nLastXclCol = GetLastXclCol();
1211 : OSL_ENSURE( nLastXclCol < rXFIndexes.size(), "XclExpMultiCellBase::RemoveUnusedXFIndexes - XF index vector too small" );
1212 :
1213 : // build new XF index vector, containing passed XF indexes
1214 2008 : maXFIds.clear();
1215 2008 : XclExpMultiXFId aXFId( 0 );
1216 772948 : for( ScfUInt16Vec::const_iterator aIt = rXFIndexes.begin() + GetXclCol(), aEnd = rXFIndexes.begin() + nLastXclCol + 1; aIt != aEnd; ++aIt )
1217 : {
1218 : // AppendXFId() tests XclExpXFIndex::mnXFId, set it too
1219 770940 : aXFId.mnXFId = aXFId.mnXFIndex = *aIt;
1220 770940 : AppendXFId( aXFId );
1221 : }
1222 :
1223 : // remove leading and trailing unused XF indexes
1224 2008 : if( !maXFIds.empty() && (maXFIds.front().mnXFIndex == EXC_XF_NOTFOUND) )
1225 : {
1226 1676 : SetXclCol( GetXclCol() + maXFIds.front().mnCount );
1227 1676 : maXFIds.pop_front();
1228 : }
1229 2008 : if( !maXFIds.empty() && (maXFIds.back().mnXFIndex == EXC_XF_NOTFOUND) )
1230 396 : maXFIds.pop_back();
1231 :
1232 : // The Save() function will skip all XF indexes equal to EXC_XF_NOTFOUND.
1233 2008 : }
1234 :
1235 16 : IMPL_FIXEDMEMPOOL_NEWDEL( XclExpBlankCell )
1236 :
1237 1856 : XclExpBlankCell::XclExpBlankCell( const XclAddress& rXclPos, const XclExpMultiXFId& rXFId ) :
1238 1856 : XclExpMultiCellBase( EXC_ID3_BLANK, EXC_ID_MULBLANK, 0, rXclPos )
1239 : {
1240 : OSL_ENSURE( rXFId.mnCount > 0, "XclExpBlankCell::XclExpBlankCell - invalid count" );
1241 1856 : AppendXFId( rXFId );
1242 1856 : }
1243 :
1244 1000 : XclExpBlankCell::XclExpBlankCell(
1245 : const XclExpRoot& rRoot, const XclAddress& rXclPos, sal_uInt16 nLastXclCol,
1246 : const ScPatternAttr* pPattern, sal_uInt32 nForcedXFId ) :
1247 1000 : XclExpMultiCellBase( EXC_ID3_BLANK, EXC_ID_MULBLANK, 0, rXclPos )
1248 : {
1249 : OSL_ENSURE( rXclPos.mnCol <= nLastXclCol, "XclExpBlankCell::XclExpBlankCell - invalid column range" );
1250 : // #i46627# use default script type instead of ApiScriptType::WEAK
1251 1000 : AppendXFId( rRoot, pPattern, rRoot.GetDefApiScript(), nForcedXFId, nLastXclCol - rXclPos.mnCol + 1 );
1252 1000 : }
1253 :
1254 1814 : bool XclExpBlankCell::TryMerge( const XclExpCellBase& rCell )
1255 : {
1256 1814 : const XclExpBlankCell* pBlankCell = dynamic_cast< const XclExpBlankCell* >( &rCell );
1257 1814 : return pBlankCell && TryMergeXFIds( *pBlankCell );
1258 : }
1259 :
1260 814 : void XclExpBlankCell::GetBlankXFIndexes( ScfUInt16Vec& rXFIndexes ) const
1261 : {
1262 814 : GetXFIndexes( rXFIndexes );
1263 814 : }
1264 :
1265 2008 : void XclExpBlankCell::RemoveUnusedBlankCells( const ScfUInt16Vec& rXFIndexes )
1266 : {
1267 2008 : RemoveUnusedXFIndexes( rXFIndexes );
1268 2008 : }
1269 :
1270 558 : void XclExpBlankCell::WriteContents( XclExpStream& /*rStrm*/, sal_uInt16 /*nRelCol*/ )
1271 : {
1272 558 : }
1273 :
1274 532 : void XclExpBlankCell::WriteXmlContents( XclExpXmlStream& rStrm, const XclAddress& rAddress, sal_uInt32 nXFId, sal_uInt16 /* nRelCol */ )
1275 : {
1276 532 : sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
1277 : rWorksheet->singleElement( XML_c,
1278 : XML_r, XclXmlUtils::ToOString( rAddress ).getStr(),
1279 : XML_s, lcl_GetStyleId( rStrm, nXFId ).getStr(),
1280 532 : FSEND );
1281 532 : }
1282 :
1283 16 : IMPL_FIXEDMEMPOOL_NEWDEL( XclExpRkCell )
1284 :
1285 1760 : XclExpRkCell::XclExpRkCell(
1286 : const XclExpRoot& rRoot, const XclAddress& rXclPos,
1287 : const ScPatternAttr* pPattern, sal_uInt32 nForcedXFId, sal_Int32 nRkValue ) :
1288 1760 : XclExpMultiCellBase( EXC_ID_RK, EXC_ID_MULRK, 4, rXclPos )
1289 : {
1290 : // #i41210# always use latin script for number cells - may look wrong for special number formats...
1291 1760 : AppendXFId( rRoot, pPattern, ApiScriptType::LATIN, nForcedXFId );
1292 1760 : maRkValues.push_back( nRkValue );
1293 1760 : }
1294 :
1295 2086 : bool XclExpRkCell::TryMerge( const XclExpCellBase& rCell )
1296 : {
1297 2086 : const XclExpRkCell* pRkCell = dynamic_cast< const XclExpRkCell* >( &rCell );
1298 2086 : if( pRkCell && TryMergeXFIds( *pRkCell ) )
1299 : {
1300 710 : maRkValues.insert( maRkValues.end(), pRkCell->maRkValues.begin(), pRkCell->maRkValues.end() );
1301 710 : return true;
1302 : }
1303 1376 : return false;
1304 : }
1305 :
1306 1136 : void XclExpRkCell::WriteXmlContents( XclExpXmlStream& rStrm, const XclAddress& rAddress, sal_uInt32 nXFId, sal_uInt16 nRelCol )
1307 : {
1308 1136 : sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
1309 : rWorksheet->startElement( XML_c,
1310 : XML_r, XclXmlUtils::ToOString( rAddress ).getStr(),
1311 : XML_s, lcl_GetStyleId( rStrm, nXFId ).getStr(),
1312 : XML_t, "n",
1313 : // OOXTODO: XML_cm, XML_vm, XML_ph
1314 1136 : FSEND );
1315 1136 : rWorksheet->startElement( XML_v, FSEND );
1316 1136 : rWorksheet->write( XclTools::GetDoubleFromRK( maRkValues[ nRelCol ] ) );
1317 1136 : rWorksheet->endElement( XML_v );
1318 1136 : rWorksheet->endElement( XML_c );
1319 1136 : }
1320 :
1321 624 : void XclExpRkCell::WriteContents( XclExpStream& rStrm, sal_uInt16 nRelCol )
1322 : {
1323 : OSL_ENSURE( nRelCol < maRkValues.size(), "XclExpRkCell::WriteContents - overflow error" );
1324 624 : rStrm << maRkValues[ nRelCol ];
1325 624 : }
1326 :
1327 : // Rows and Columns
1328 :
1329 248 : XclExpOutlineBuffer::XclExpOutlineBuffer( const XclExpRoot& rRoot, bool bRows ) :
1330 : mpScOLArray( 0 ),
1331 : maLevelInfos( SC_OL_MAXDEPTH ),
1332 : mnCurrLevel( 0 ),
1333 248 : mbCurrCollapse( false )
1334 : {
1335 248 : if( const ScOutlineTable* pOutlineTable = rRoot.GetDoc().GetOutlineTable( rRoot.GetCurrScTab() ) )
1336 52 : mpScOLArray = &(bRows ? pOutlineTable->GetRowArray() : pOutlineTable->GetColArray());
1337 :
1338 248 : if( mpScOLArray )
1339 416 : for( size_t nLevel = 0; nLevel < SC_OL_MAXDEPTH; ++nLevel )
1340 364 : if( const ScOutlineEntry* pEntry = mpScOLArray->GetEntryByPos( nLevel, 0 ) )
1341 0 : maLevelInfos[ nLevel ].mnScEndPos = pEntry->GetEnd();
1342 248 : }
1343 :
1344 89944 : void XclExpOutlineBuffer::UpdateColRow( SCCOLROW nScPos )
1345 : {
1346 89944 : if( mpScOLArray )
1347 : {
1348 : // find open level index for passed position
1349 6844 : size_t nNewOpenScLevel = 0; // new open level (0-based Calc index)
1350 6844 : sal_uInt8 nNewLevel = 0; // new open level (1-based Excel index)
1351 :
1352 6844 : if( mpScOLArray->FindTouchedLevel( nScPos, nScPos, nNewOpenScLevel ) )
1353 0 : nNewLevel = static_cast< sal_uInt8 >( nNewOpenScLevel + 1 );
1354 : // else nNewLevel keeps 0 to show that there are no groups
1355 :
1356 6844 : mbCurrCollapse = false;
1357 6844 : if( nNewLevel >= mnCurrLevel )
1358 : {
1359 : // new level(s) opened, or no level closed - update all level infos
1360 13688 : for( sal_uInt16 nScLevel = 0; nScLevel <= nNewOpenScLevel; ++nScLevel )
1361 : {
1362 : /* In each level: check if a new group is started (there may be
1363 : neighbored groups without gap - therefore check ALL levels). */
1364 6844 : if( maLevelInfos[ nScLevel ].mnScEndPos < nScPos )
1365 : {
1366 6792 : if( const ScOutlineEntry* pEntry = mpScOLArray->GetEntryByPos( nScLevel, nScPos ) )
1367 : {
1368 0 : maLevelInfos[ nScLevel ].mnScEndPos = pEntry->GetEnd();
1369 0 : maLevelInfos[ nScLevel ].mbHidden = pEntry->IsHidden();
1370 : }
1371 : }
1372 : }
1373 : }
1374 : else
1375 : {
1376 : // level(s) closed - check if any of the closed levels are collapsed
1377 : // Calc uses 0-based level indexes
1378 0 : sal_uInt16 nOldOpenScLevel = mnCurrLevel - 1;
1379 0 : for( sal_uInt16 nScLevel = nNewOpenScLevel + 1; !mbCurrCollapse && (nScLevel <= nOldOpenScLevel); ++nScLevel )
1380 0 : mbCurrCollapse = maLevelInfos[ nScLevel ].mbHidden;
1381 : }
1382 :
1383 : // cache new opened level
1384 6844 : mnCurrLevel = nNewLevel;
1385 : }
1386 89944 : }
1387 :
1388 124 : XclExpGuts::XclExpGuts( const XclExpRoot& rRoot ) :
1389 : XclExpRecord( EXC_ID_GUTS, 8 ),
1390 : mnColLevels( 0 ),
1391 : mnColWidth( 0 ),
1392 : mnRowLevels( 0 ),
1393 124 : mnRowWidth( 0 )
1394 : {
1395 124 : if( const ScOutlineTable* pOutlineTable = rRoot.GetDoc().GetOutlineTable( rRoot.GetCurrScTab() ) )
1396 : {
1397 : // column outline groups
1398 26 : const ScOutlineArray& rColArray = pOutlineTable->GetColArray();
1399 26 : mnColLevels = ulimit_cast< sal_uInt16 >( rColArray.GetDepth(), EXC_OUTLINE_MAX );
1400 26 : if( mnColLevels )
1401 : {
1402 0 : ++mnColLevels;
1403 0 : mnColWidth = 12 * mnColLevels + 5;
1404 : }
1405 :
1406 : // row outline groups
1407 26 : const ScOutlineArray& rRowArray = pOutlineTable->GetRowArray();
1408 26 : mnRowLevels = ulimit_cast< sal_uInt16 >( rRowArray.GetDepth(), EXC_OUTLINE_MAX );
1409 26 : if( mnRowLevels )
1410 : {
1411 0 : ++mnRowLevels;
1412 0 : mnRowWidth = 12 * mnRowLevels + 5;
1413 : }
1414 : }
1415 124 : }
1416 :
1417 50 : void XclExpGuts::WriteBody( XclExpStream& rStrm )
1418 : {
1419 50 : rStrm << mnRowWidth << mnColWidth << mnRowLevels << mnColLevels;
1420 50 : }
1421 :
1422 124 : XclExpDimensions::XclExpDimensions( const XclExpRoot& rRoot ) :
1423 : mnFirstUsedXclRow( 0 ),
1424 : mnFirstFreeXclRow( 0 ),
1425 : mnFirstUsedXclCol( 0 ),
1426 124 : mnFirstFreeXclCol( 0 )
1427 : {
1428 124 : switch( rRoot.GetBiff() )
1429 : {
1430 0 : case EXC_BIFF2: SetRecHeader( EXC_ID2_DIMENSIONS, 8 ); break;
1431 : case EXC_BIFF3:
1432 : case EXC_BIFF4:
1433 0 : case EXC_BIFF5: SetRecHeader( EXC_ID3_DIMENSIONS, 10 ); break;
1434 124 : case EXC_BIFF8: SetRecHeader( EXC_ID3_DIMENSIONS, 14 ); break;
1435 : default: DBG_ERROR_BIFF();
1436 : }
1437 124 : }
1438 :
1439 124 : void XclExpDimensions::SetDimensions(
1440 : sal_uInt16 nFirstUsedXclCol, sal_uInt32 nFirstUsedXclRow,
1441 : sal_uInt16 nFirstFreeXclCol, sal_uInt32 nFirstFreeXclRow )
1442 : {
1443 124 : mnFirstUsedXclRow = nFirstUsedXclRow;
1444 124 : mnFirstFreeXclRow = nFirstFreeXclRow;
1445 124 : mnFirstUsedXclCol = nFirstUsedXclCol;
1446 124 : mnFirstFreeXclCol = nFirstFreeXclCol;
1447 124 : }
1448 :
1449 74 : void XclExpDimensions::SaveXml( XclExpXmlStream& rStrm )
1450 : {
1451 74 : ScRange aRange;
1452 74 : aRange.aStart.SetRow( (SCROW) mnFirstUsedXclRow );
1453 74 : aRange.aStart.SetCol( (SCCOL) mnFirstUsedXclCol );
1454 :
1455 74 : if( mnFirstFreeXclRow != mnFirstUsedXclRow && mnFirstFreeXclCol != mnFirstUsedXclCol )
1456 : {
1457 52 : aRange.aEnd.SetRow( (SCROW) (mnFirstFreeXclRow-1) );
1458 52 : aRange.aEnd.SetCol( (SCCOL) (mnFirstFreeXclCol-1) );
1459 : }
1460 :
1461 74 : rStrm.GetCurrentStream()->singleElement( XML_dimension,
1462 : XML_ref, XclXmlUtils::ToOString( aRange ).getStr(),
1463 148 : FSEND );
1464 74 : }
1465 :
1466 50 : void XclExpDimensions::WriteBody( XclExpStream& rStrm )
1467 : {
1468 50 : XclBiff eBiff = rStrm.GetRoot().GetBiff();
1469 50 : if( eBiff == EXC_BIFF8 )
1470 50 : rStrm << mnFirstUsedXclRow << mnFirstFreeXclRow;
1471 : else
1472 0 : rStrm << static_cast< sal_uInt16 >( mnFirstUsedXclRow ) << static_cast< sal_uInt16 >( mnFirstFreeXclRow );
1473 50 : rStrm << mnFirstUsedXclCol << mnFirstFreeXclCol;
1474 50 : if( eBiff >= EXC_BIFF3 )
1475 50 : rStrm << sal_uInt16( 0 );
1476 50 : }
1477 :
1478 : namespace {
1479 :
1480 356 : double lclGetCorrectedColWidth( const XclExpRoot& rRoot, sal_uInt16 nXclColWidth )
1481 : {
1482 356 : long nFontHt = rRoot.GetFontBuffer().GetAppFontData().mnHeight;
1483 356 : return nXclColWidth - XclTools::GetXclDefColWidthCorrection( nFontHt );
1484 : }
1485 :
1486 : } // namespace
1487 :
1488 124 : XclExpDefcolwidth::XclExpDefcolwidth( const XclExpRoot& rRoot ) :
1489 : XclExpUInt16Record( EXC_ID_DEFCOLWIDTH, EXC_DEFCOLWIDTH_DEF ),
1490 124 : XclExpRoot( rRoot )
1491 : {
1492 124 : }
1493 :
1494 232 : bool XclExpDefcolwidth::IsDefWidth( sal_uInt16 nXclColWidth ) const
1495 : {
1496 232 : double fNewColWidth = lclGetCorrectedColWidth( GetRoot(), nXclColWidth );
1497 : // exactly matched, if difference is less than 1/16 of a character to the left or to the right
1498 232 : return std::abs( static_cast< long >( GetValue() * 256.0 - fNewColWidth + 0.5 ) ) < 16;
1499 : }
1500 :
1501 124 : void XclExpDefcolwidth::SetDefWidth( sal_uInt16 nXclColWidth )
1502 : {
1503 124 : double fNewColWidth = lclGetCorrectedColWidth( GetRoot(), nXclColWidth );
1504 124 : SetValue( limit_cast< sal_uInt16 >( fNewColWidth / 256.0 + 0.5 ) );
1505 124 : }
1506 :
1507 88576 : XclExpColinfo::XclExpColinfo( const XclExpRoot& rRoot,
1508 : SCCOL nScCol, SCROW nLastScRow, XclExpColOutlineBuffer& rOutlineBfr ) :
1509 : XclExpRecord( EXC_ID_COLINFO, 12 ),
1510 : XclExpRoot( rRoot ),
1511 : mnWidth( 0 ),
1512 : mnScWidth( 0 ),
1513 : mnFlags( 0 ),
1514 : mnFirstXclCol( static_cast< sal_uInt16 >( nScCol ) ),
1515 88576 : mnLastXclCol( static_cast< sal_uInt16 >( nScCol ) )
1516 : {
1517 88576 : ScDocument& rDoc = GetDoc();
1518 88576 : SCTAB nScTab = GetCurrScTab();
1519 :
1520 : // column default format
1521 88576 : maXFId.mnXFId = GetXFBuffer().Insert(
1522 177152 : rDoc.GetMostUsedPattern( nScCol, 0, nLastScRow, nScTab ), GetDefApiScript() );
1523 :
1524 : // column width
1525 88576 : sal_uInt16 nScWidth = rDoc.GetColWidth( nScCol, nScTab );
1526 88576 : mnWidth = XclTools::GetXclColumnWidth( nScWidth, GetCharWidth() );
1527 88576 : mnScWidth = sc::TwipsToHMM( nScWidth );
1528 : // column flags
1529 88576 : ::set_flag( mnFlags, EXC_COLINFO_HIDDEN, rDoc.ColHidden(nScCol, nScTab) );
1530 :
1531 : // outline data
1532 88576 : rOutlineBfr.Update( nScCol );
1533 88576 : ::set_flag( mnFlags, EXC_COLINFO_COLLAPSED, rOutlineBfr.IsCollapsed() );
1534 88576 : ::insert_value( mnFlags, rOutlineBfr.GetLevel(), 8, 3 );
1535 88576 : }
1536 :
1537 88576 : sal_uInt16 XclExpColinfo::ConvertXFIndexes()
1538 : {
1539 88576 : maXFId.ConvertXFIndex( GetRoot() );
1540 88576 : return maXFId.mnXFIndex;
1541 : }
1542 :
1543 234 : bool XclExpColinfo::IsDefault( const XclExpDefcolwidth& rDefColWidth ) const
1544 : {
1545 234 : return (maXFId.mnXFIndex == EXC_XF_DEFAULTCELL) && (mnFlags == 0) && rDefColWidth.IsDefWidth( mnWidth );
1546 : }
1547 :
1548 88452 : bool XclExpColinfo::TryMerge( const XclExpColinfo& rColInfo )
1549 : {
1550 176900 : if( (maXFId.mnXFIndex == rColInfo.maXFId.mnXFIndex) &&
1551 176790 : (mnWidth == rColInfo.mnWidth) &&
1552 176684 : (mnFlags == rColInfo.mnFlags) &&
1553 88342 : (mnLastXclCol + 1 == rColInfo.mnFirstXclCol) )
1554 : {
1555 88342 : mnLastXclCol = rColInfo.mnLastXclCol;
1556 88342 : return true;
1557 : }
1558 110 : return false;
1559 : }
1560 :
1561 70 : void XclExpColinfo::WriteBody( XclExpStream& rStrm )
1562 : {
1563 : // if last column is equal to last possible column, Excel adds one more
1564 70 : sal_uInt16 nLastXclCol = mnLastXclCol;
1565 70 : if( nLastXclCol == static_cast< sal_uInt16 >( rStrm.GetRoot().GetMaxPos().Col() ) )
1566 26 : ++nLastXclCol;
1567 :
1568 70 : rStrm << mnFirstXclCol
1569 140 : << nLastXclCol
1570 140 : << mnWidth
1571 140 : << maXFId.mnXFIndex
1572 140 : << mnFlags
1573 70 : << sal_uInt16( 0 );
1574 70 : }
1575 :
1576 136 : void XclExpColinfo::SaveXml( XclExpXmlStream& rStrm )
1577 : {
1578 : // if last column is equal to last possible column, Excel adds one more
1579 136 : sal_uInt16 nLastXclCol = mnLastXclCol;
1580 136 : if( nLastXclCol == static_cast< sal_uInt16 >( rStrm.GetRoot().GetMaxPos().Col() ) )
1581 74 : ++nLastXclCol;
1582 :
1583 136 : rStrm.GetCurrentStream()->singleElement( XML_col,
1584 : // OOXTODO: XML_bestFit,
1585 136 : XML_collapsed, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_COLINFO_COLLAPSED ) ),
1586 : // OOXTODO: XML_customWidth,
1587 136 : XML_hidden, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_COLINFO_HIDDEN ) ),
1588 : XML_max, OString::number( (nLastXclCol+1) ).getStr(),
1589 : XML_min, OString::number( (mnFirstXclCol+1) ).getStr(),
1590 : // OOXTODO: XML_outlineLevel,
1591 : // OOXTODO: XML_phonetic,
1592 : XML_style, lcl_GetStyleId( rStrm, maXFId.mnXFIndex ).getStr(),
1593 136 : XML_width, OString::number( (double) (mnScWidth / (double)sc::TwipsToHMM( GetCharWidth() )) ).getStr(),
1594 680 : FSEND );
1595 136 : }
1596 :
1597 124 : XclExpColinfoBuffer::XclExpColinfoBuffer( const XclExpRoot& rRoot ) :
1598 : XclExpRoot( rRoot ),
1599 : maDefcolwidth( rRoot ),
1600 124 : maOutlineBfr( rRoot )
1601 : {
1602 124 : }
1603 :
1604 124 : void XclExpColinfoBuffer::Initialize( SCROW nLastScRow )
1605 : {
1606 :
1607 88700 : for( sal_uInt16 nScCol = 0, nLastScCol = GetMaxPos().Col(); nScCol <= nLastScCol; ++nScCol )
1608 88576 : maColInfos.AppendNewRecord( new XclExpColinfo( GetRoot(), nScCol, nLastScRow, maOutlineBfr ) );
1609 124 : }
1610 :
1611 124 : void XclExpColinfoBuffer::Finalize( ScfUInt16Vec& rXFIndexes )
1612 : {
1613 124 : rXFIndexes.clear();
1614 124 : rXFIndexes.reserve( maColInfos.GetSize() );
1615 :
1616 : size_t nPos, nSize;
1617 :
1618 : // do not cache the record list size, it may change in the loop
1619 88700 : for( nPos = 0; nPos < maColInfos.GetSize(); ++nPos )
1620 : {
1621 88576 : XclExpColinfoRef xRec = maColInfos.GetRecord( nPos );
1622 88576 : xRec->ConvertXFIndexes();
1623 :
1624 : // try to merge with previous record
1625 88576 : if( nPos > 0 )
1626 : {
1627 88452 : XclExpColinfoRef xPrevRec = maColInfos.GetRecord( nPos - 1 );
1628 88452 : if( xPrevRec->TryMerge( *xRec ) )
1629 : // adjust nPos to get the next COLINFO record at the same position
1630 88342 : maColInfos.RemoveRecord( nPos-- );
1631 : }
1632 88576 : }
1633 :
1634 : // put XF indexes into passed vector, collect use count of all different widths
1635 : typedef ::std::map< sal_uInt16, sal_uInt16 > XclExpWidthMap;
1636 124 : XclExpWidthMap aWidthMap;
1637 124 : sal_uInt16 nMaxColCount = 0;
1638 124 : sal_uInt16 nMaxUsedWidth = 0;
1639 358 : for( nPos = 0, nSize = maColInfos.GetSize(); nPos < nSize; ++nPos )
1640 : {
1641 234 : XclExpColinfoRef xRec = maColInfos.GetRecord( nPos );
1642 234 : sal_uInt16 nColCount = xRec->GetColCount();
1643 :
1644 : // add XF index to passed vector
1645 234 : rXFIndexes.resize( rXFIndexes.size() + nColCount, xRec->GetXFIndex() );
1646 :
1647 : // collect use count of column width
1648 234 : sal_uInt16 nWidth = xRec->GetColWidth();
1649 234 : sal_uInt16& rnMapCount = aWidthMap[ nWidth ];
1650 234 : rnMapCount = rnMapCount + nColCount;
1651 234 : if( rnMapCount > nMaxColCount )
1652 : {
1653 162 : nMaxColCount = rnMapCount;
1654 162 : nMaxUsedWidth = nWidth;
1655 : }
1656 234 : }
1657 124 : maDefcolwidth.SetDefWidth( nMaxUsedWidth );
1658 :
1659 : // remove all default COLINFO records
1660 124 : nPos = 0;
1661 482 : while( nPos < maColInfos.GetSize() )
1662 : {
1663 234 : XclExpColinfoRef xRec = maColInfos.GetRecord( nPos );
1664 234 : if( xRec->IsDefault( maDefcolwidth ) )
1665 28 : maColInfos.RemoveRecord( nPos );
1666 : else
1667 206 : ++nPos;
1668 358 : }
1669 124 : }
1670 :
1671 50 : void XclExpColinfoBuffer::Save( XclExpStream& rStrm )
1672 : {
1673 : // DEFCOLWIDTH
1674 50 : maDefcolwidth.Save( rStrm );
1675 : // COLINFO records
1676 50 : maColInfos.Save( rStrm );
1677 50 : }
1678 :
1679 74 : void XclExpColinfoBuffer::SaveXml( XclExpXmlStream& rStrm )
1680 : {
1681 74 : if( maColInfos.IsEmpty() )
1682 74 : return;
1683 :
1684 74 : sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
1685 : rWorksheet->startElement( XML_cols,
1686 74 : FSEND );
1687 74 : maColInfos.SaveXml( rStrm );
1688 74 : rWorksheet->endElement( XML_cols );
1689 : }
1690 :
1691 372 : XclExpDefaultRowData::XclExpDefaultRowData() :
1692 : mnFlags( EXC_DEFROW_DEFAULTFLAGS ),
1693 372 : mnHeight( EXC_DEFROW_DEFAULTHEIGHT )
1694 : {
1695 372 : }
1696 :
1697 548 : XclExpDefaultRowData::XclExpDefaultRowData( const XclExpRow& rRow ) :
1698 : mnFlags( EXC_DEFROW_DEFAULTFLAGS ),
1699 548 : mnHeight( rRow.GetHeight() )
1700 : {
1701 548 : ::set_flag( mnFlags, EXC_DEFROW_HIDDEN, rRow.IsHidden() );
1702 548 : ::set_flag( mnFlags, EXC_DEFROW_UNSYNCED, rRow.IsUnsynced() );
1703 548 : }
1704 :
1705 978 : bool operator<( const XclExpDefaultRowData& rLeft, const XclExpDefaultRowData& rRight )
1706 : {
1707 1956 : return (rLeft.mnHeight < rRight.mnHeight) ||
1708 2624 : ((rLeft.mnHeight == rRight.mnHeight) && (rLeft.mnFlags < rRight.mnFlags));
1709 : }
1710 :
1711 124 : XclExpDefrowheight::XclExpDefrowheight() :
1712 124 : XclExpRecord( EXC_ID3_DEFROWHEIGHT, 4 )
1713 : {
1714 124 : }
1715 :
1716 124 : void XclExpDefrowheight::SetDefaultData( const XclExpDefaultRowData& rDefData )
1717 : {
1718 124 : maDefData = rDefData;
1719 124 : }
1720 :
1721 50 : void XclExpDefrowheight::WriteBody( XclExpStream& rStrm )
1722 : {
1723 : OSL_ENSURE_BIFF( rStrm.GetRoot().GetBiff() >= EXC_BIFF3 );
1724 50 : rStrm << maDefData.mnFlags << maDefData.mnHeight;
1725 50 : }
1726 :
1727 1368 : XclExpRow::XclExpRow( const XclExpRoot& rRoot, sal_uInt32 nXclRow,
1728 : XclExpRowOutlineBuffer& rOutlineBfr, bool bAlwaysEmpty ) :
1729 : XclExpRecord( EXC_ID3_ROW, 16 ),
1730 : XclExpRoot( rRoot ),
1731 : mnXclRow( nXclRow ),
1732 : mnHeight( 0 ),
1733 : mnFlags( EXC_ROW_DEFAULTFLAGS ),
1734 : mnXFIndex( EXC_XF_DEFAULTCELL ),
1735 : mnOutlineLevel( 0 ),
1736 : mnXclRowRpt( 1 ),
1737 : mnCurrentRow( nXclRow ),
1738 : mbAlwaysEmpty( bAlwaysEmpty ),
1739 1368 : mbEnabled( true )
1740 : {
1741 1368 : SCTAB nScTab = GetCurrScTab();
1742 1368 : SCROW nScRow = static_cast< SCROW >( mnXclRow );
1743 :
1744 : // *** Row flags *** ------------------------------------------------------
1745 :
1746 1368 : sal_uInt8 nRowFlags = GetDoc().GetRowFlags( nScRow, nScTab );
1747 1368 : bool bUserHeight = ::get_flag< sal_uInt8 >( nRowFlags, CR_MANUALSIZE );
1748 1368 : bool bHidden = GetDoc().RowHidden(nScRow, nScTab);
1749 1368 : ::set_flag( mnFlags, EXC_ROW_UNSYNCED, bUserHeight );
1750 1368 : ::set_flag( mnFlags, EXC_ROW_HIDDEN, bHidden );
1751 :
1752 : // *** Row height *** -----------------------------------------------------
1753 :
1754 : // Always get the actual row height even if the manual size flag is not set,
1755 : // to correctly export the heights of rows with wrapped texts.
1756 :
1757 1368 : mnHeight = GetDoc().GetRowHeight(nScRow, nScTab, false);
1758 :
1759 : // *** Outline data *** ---------------------------------------------------
1760 :
1761 1368 : rOutlineBfr.Update( nScRow );
1762 1368 : ::set_flag( mnFlags, EXC_ROW_COLLAPSED, rOutlineBfr.IsCollapsed() );
1763 1368 : ::insert_value( mnFlags, rOutlineBfr.GetLevel(), 0, 3 );
1764 1368 : mnOutlineLevel = rOutlineBfr.GetLevel();
1765 :
1766 : // *** Progress bar *** ---------------------------------------------------
1767 :
1768 1368 : XclExpProgressBar& rProgress = GetProgressBar();
1769 1368 : rProgress.IncRowRecordCount();
1770 1368 : rProgress.Progress();
1771 1368 : }
1772 :
1773 6252 : void XclExpRow::AppendCell( XclExpCellRef xCell, bool bIsMergedBase )
1774 : {
1775 : OSL_ENSURE( !mbAlwaysEmpty, "XclExpRow::AppendCell - row is marked to be always empty" );
1776 : // try to merge with last existing cell
1777 6252 : InsertCell( xCell, maCellList.GetSize(), bIsMergedBase );
1778 6252 : }
1779 :
1780 1368 : void XclExpRow::Finalize( const ScfUInt16Vec& rColXFIndexes )
1781 : {
1782 : size_t nPos, nSize;
1783 :
1784 : // *** Convert XF identifiers *** -----------------------------------------
1785 :
1786 : // additionally collect the blank XF indexes
1787 1368 : size_t nColCount = GetMaxPos().Col() + 1;
1788 : OSL_ENSURE( rColXFIndexes.size() == nColCount, "XclExpRow::Finalize - wrong column XF index count" );
1789 :
1790 1368 : ScfUInt16Vec aXFIndexes( nColCount, EXC_XF_NOTFOUND );
1791 6724 : for( nPos = 0, nSize = maCellList.GetSize(); nPos < nSize; ++nPos )
1792 : {
1793 5356 : XclExpCellRef xCell = maCellList.GetRecord( nPos );
1794 5356 : xCell->ConvertXFIndexes( GetRoot() );
1795 5356 : xCell->GetBlankXFIndexes( aXFIndexes );
1796 5356 : }
1797 :
1798 : // *** Fill gaps with BLANK/MULBLANK cell records *** ---------------------
1799 :
1800 : /* This is needed because nonexistant cells in Calc are not formatted at all,
1801 : but in Excel they would have the column default format. Blank cells that
1802 : are equal to the respective column default are removed later in this function. */
1803 1368 : if( !mbAlwaysEmpty )
1804 : {
1805 : // XF identifier representing default cell XF
1806 1106 : XclExpMultiXFId aXFId( XclExpXFBuffer::GetDefCellXFId() );
1807 1106 : aXFId.ConvertXFIndex( GetRoot() );
1808 :
1809 1106 : nPos = 0;
1810 11724 : while( nPos <= maCellList.GetSize() ) // don't cache list size, may change in the loop
1811 : {
1812 : // get column index that follows previous cell
1813 9512 : sal_uInt16 nFirstFreeXclCol = (nPos > 0) ? (maCellList.GetRecord( nPos - 1 )->GetLastXclCol() + 1) : 0;
1814 : // get own column index
1815 9512 : sal_uInt16 nNextUsedXclCol = (nPos < maCellList.GetSize()) ? maCellList.GetRecord( nPos )->GetXclCol() : (GetMaxPos().Col() + 1);
1816 :
1817 : // is there a gap?
1818 9512 : if( nFirstFreeXclCol < nNextUsedXclCol )
1819 : {
1820 1856 : aXFId.mnCount = nNextUsedXclCol - nFirstFreeXclCol;
1821 1856 : XclExpCellRef xNewCell( new XclExpBlankCell( XclAddress( nFirstFreeXclCol, mnXclRow ), aXFId ) );
1822 : // insert the cell, InsertCell() may merge it with existing BLANK records
1823 1856 : InsertCell( xNewCell, nPos, false );
1824 : // insert default XF indexes into aXFIndexes
1825 : ::std::fill( aXFIndexes.begin() + nFirstFreeXclCol,
1826 1856 : aXFIndexes.begin() + nNextUsedXclCol, aXFId.mnXFIndex );
1827 : // don't step forward with nPos, InsertCell() may remove records
1828 : }
1829 : else
1830 7656 : ++nPos;
1831 : }
1832 : }
1833 :
1834 : // *** Find default row format *** ----------------------------------------
1835 :
1836 1368 : ScfUInt16Vec::iterator aCellBeg = aXFIndexes.begin(), aCellEnd = aXFIndexes.end(), aCellIt;
1837 1368 : ScfUInt16Vec::const_iterator aColBeg = rColXFIndexes.begin(), aColIt;
1838 :
1839 : // find most used XF index in the row
1840 : typedef ::std::map< sal_uInt16, size_t > XclExpXFIndexMap;
1841 2736 : XclExpXFIndexMap aIndexMap;
1842 1368 : sal_uInt16 nRowXFIndex = EXC_XF_DEFAULTCELL;
1843 1368 : size_t nMaxXFCount = 0;
1844 962904 : for( aCellIt = aCellBeg; aCellIt != aCellEnd; ++aCellIt )
1845 : {
1846 961536 : if( *aCellIt != EXC_XF_NOTFOUND )
1847 : {
1848 770940 : size_t& rnCount = aIndexMap[ *aCellIt ];
1849 770940 : ++rnCount;
1850 770940 : if( rnCount > nMaxXFCount )
1851 : {
1852 769270 : nRowXFIndex = *aCellIt;
1853 769270 : nMaxXFCount = rnCount;
1854 : }
1855 : }
1856 : }
1857 :
1858 : // decide whether to use the row default XF index or column default XF indexes
1859 1368 : bool bUseColDefXFs = nRowXFIndex == EXC_XF_DEFAULTCELL;
1860 1368 : if( !bUseColDefXFs )
1861 : {
1862 : // count needed XF indexes for blank cells with and without row default XF index
1863 28 : size_t nXFCountWithRowDefXF = 0;
1864 28 : size_t nXFCountWithoutRowDefXF = 0;
1865 7196 : for( aCellIt = aCellBeg, aColIt = aColBeg; aCellIt != aCellEnd; ++aCellIt, ++aColIt )
1866 : {
1867 7168 : sal_uInt16 nXFIndex = *aCellIt;
1868 7168 : if( nXFIndex != EXC_XF_NOTFOUND )
1869 : {
1870 7098 : if( nXFIndex != nRowXFIndex )
1871 610 : ++nXFCountWithRowDefXF; // with row default XF index
1872 7098 : if( nXFIndex != *aColIt )
1873 2014 : ++nXFCountWithoutRowDefXF; // without row default XF index
1874 : }
1875 : }
1876 :
1877 : // use column XF indexes if this would cause less or equal number of BLANK records
1878 28 : bUseColDefXFs = nXFCountWithoutRowDefXF <= nXFCountWithRowDefXF;
1879 : }
1880 :
1881 : // *** Remove unused BLANK cell records *** -------------------------------
1882 :
1883 1368 : if( bUseColDefXFs )
1884 : {
1885 : // use column default XF indexes
1886 : // #i194#: remove cell XF indexes equal to column default XF indexes
1887 960848 : for( aCellIt = aCellBeg, aColIt = aColBeg; aCellIt != aCellEnd; ++aCellIt, ++aColIt )
1888 959488 : if( *aCellIt == *aColIt )
1889 767862 : *aCellIt = EXC_XF_NOTFOUND;
1890 : }
1891 : else
1892 : {
1893 : // use row default XF index
1894 8 : mnXFIndex = nRowXFIndex;
1895 8 : ::set_flag( mnFlags, EXC_ROW_USEDEFXF );
1896 : // #98133#, #i194#, #i27407#: remove cell XF indexes equal to row default XF index
1897 2056 : for( aCellIt = aCellBeg; aCellIt != aCellEnd; ++aCellIt )
1898 2048 : if( *aCellIt == nRowXFIndex )
1899 1988 : *aCellIt = EXC_XF_NOTFOUND;
1900 : }
1901 :
1902 : // remove unused parts of BLANK/MULBLANK cell records
1903 1368 : nPos = 0;
1904 9286 : while( nPos < maCellList.GetSize() ) // do not cache list size, may change in the loop
1905 : {
1906 6550 : XclExpCellRef xCell = maCellList.GetRecord( nPos );
1907 6550 : xCell->RemoveUnusedBlankCells( aXFIndexes );
1908 6550 : if( xCell->IsEmpty() )
1909 1494 : maCellList.RemoveRecord( nPos );
1910 : else
1911 5056 : ++nPos;
1912 6550 : }
1913 :
1914 : // progress bar includes disabled rows
1915 2736 : GetProgressBar().Progress();
1916 1368 : }
1917 :
1918 1532 : sal_uInt16 XclExpRow::GetFirstUsedXclCol() const
1919 : {
1920 1532 : return maCellList.IsEmpty() ? 0 : maCellList.GetFirstRecord()->GetXclCol();
1921 : }
1922 :
1923 1532 : sal_uInt16 XclExpRow::GetFirstFreeXclCol() const
1924 : {
1925 1532 : return maCellList.IsEmpty() ? 0 : (maCellList.GetLastRecord()->GetLastXclCol() + 1);
1926 : }
1927 :
1928 3980 : bool XclExpRow::IsDefaultable() const
1929 : {
1930 3980 : const sal_uInt16 nAllowedFlags = EXC_ROW_DEFAULTFLAGS | EXC_ROW_HIDDEN | EXC_ROW_UNSYNCED;
1931 3980 : return !::get_flag( mnFlags, static_cast< sal_uInt16 >( ~nAllowedFlags ) ) && IsEmpty();
1932 : }
1933 :
1934 1368 : void XclExpRow::DisableIfDefault( const XclExpDefaultRowData& rDefRowData )
1935 : {
1936 1704 : mbEnabled = !IsDefaultable() ||
1937 616 : (mnHeight != rDefRowData.mnHeight) ||
1938 1928 : (IsHidden() != rDefRowData.IsHidden()) ||
1939 1648 : (IsUnsynced() != rDefRowData.IsUnsynced());
1940 1368 : }
1941 :
1942 572 : void XclExpRow::WriteCellList( XclExpStream& rStrm )
1943 : {
1944 : OSL_ENSURE( mbEnabled || maCellList.IsEmpty(), "XclExpRow::WriteCellList - cells in disabled row" );
1945 572 : maCellList.Save( rStrm );
1946 572 : }
1947 :
1948 572 : void XclExpRow::Save( XclExpStream& rStrm )
1949 : {
1950 572 : if( mbEnabled )
1951 : {
1952 458 : mnCurrentRow = mnXclRow;
1953 958 : for ( sal_uInt32 i = 0; i < mnXclRowRpt; ++i, ++mnCurrentRow )
1954 500 : XclExpRecord::Save( rStrm );
1955 : }
1956 572 : }
1957 :
1958 8108 : void XclExpRow::InsertCell( XclExpCellRef xCell, size_t nPos, bool bIsMergedBase )
1959 : {
1960 : OSL_ENSURE( xCell, "XclExpRow::InsertCell - missing cell" );
1961 :
1962 : /* If we have a multi-line text in a merged cell, and the resulting
1963 : row height has not been confirmed, we need to force the EXC_ROW_UNSYNCED
1964 : flag to be true to ensure Excel works correctly. */
1965 8108 : if( bIsMergedBase && xCell->IsMultiLineText() )
1966 0 : ::set_flag( mnFlags, EXC_ROW_UNSYNCED );
1967 :
1968 : // try to merge with previous cell, insert the new cell if not successful
1969 8108 : XclExpCellRef xPrevCell = maCellList.GetRecord( nPos - 1 );
1970 8108 : if( xPrevCell && xPrevCell->TryMerge( *xCell ) )
1971 1344 : xCell = xPrevCell;
1972 : else
1973 6764 : maCellList.InsertRecord( xCell, nPos++ );
1974 : // nPos points now to following cell
1975 :
1976 : // try to merge with following cell, remove it if successful
1977 16216 : XclExpCellRef xNextCell = maCellList.GetRecord( nPos );
1978 8108 : if( xNextCell && xCell->TryMerge( *xNextCell ) )
1979 8322 : maCellList.RemoveRecord( nPos );
1980 8108 : }
1981 :
1982 500 : void XclExpRow::WriteBody( XclExpStream& rStrm )
1983 : {
1984 500 : rStrm << static_cast< sal_uInt16 >(mnCurrentRow)
1985 1000 : << GetFirstUsedXclCol()
1986 1000 : << GetFirstFreeXclCol()
1987 1000 : << mnHeight
1988 500 : << sal_uInt32( 0 )
1989 1000 : << mnFlags
1990 1000 : << mnXFIndex;
1991 500 : }
1992 :
1993 756 : void XclExpRow::SaveXml( XclExpXmlStream& rStrm )
1994 : {
1995 756 : if( !mbEnabled )
1996 882 : return;
1997 630 : sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
1998 630 : bool haveFormat = ::get_flag( mnFlags, EXC_ROW_USEDEFXF );
1999 630 : mnCurrentRow = mnXclRow + 1;
2000 1302 : for ( sal_uInt32 i=0; i<mnXclRowRpt; ++i )
2001 : {
2002 : rWorksheet->startElement( XML_row,
2003 : XML_r, OString::number( (mnCurrentRow++) ).getStr(),
2004 : // OOXTODO: XML_spans, optional
2005 672 : XML_s, haveFormat ? lcl_GetStyleId( rStrm, mnXFIndex ).getStr() : NULL,
2006 : XML_customFormat, XclXmlUtils::ToPsz( haveFormat ),
2007 : XML_ht, OString::number( (double) mnHeight / 20.0 ).getStr(),
2008 672 : XML_hidden, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_ROW_HIDDEN ) ),
2009 672 : XML_customHeight, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_ROW_UNSYNCED ) ),
2010 : XML_outlineLevel, OString::number( mnOutlineLevel ).getStr(),
2011 672 : XML_collapsed, XclXmlUtils::ToPsz( ::get_flag( mnFlags, EXC_ROW_COLLAPSED ) ),
2012 : // OOXTODO: XML_thickTop, bool
2013 : // OOXTODO: XML_thickBot, bool
2014 : // OOXTODO: XML_ph, bool
2015 2688 : FSEND );
2016 : // OOXTODO: XML_extLst
2017 672 : maCellList.SaveXml( rStrm );
2018 672 : rWorksheet->endElement( XML_row );
2019 : }
2020 : }
2021 :
2022 124 : XclExpRowBuffer::XclExpRowBuffer( const XclExpRoot& rRoot ) :
2023 : XclExpRoot( rRoot ),
2024 : maOutlineBfr( rRoot ),
2025 124 : maDimensions( rRoot )
2026 : {
2027 124 : }
2028 :
2029 6252 : void XclExpRowBuffer::AppendCell( XclExpCellRef xCell, bool bIsMergedBase )
2030 : {
2031 : OSL_ENSURE( xCell, "XclExpRowBuffer::AppendCell - missing cell" );
2032 6252 : GetOrCreateRow( xCell->GetXclRow(), false ).AppendCell( xCell, bIsMergedBase );
2033 6252 : }
2034 :
2035 124 : void XclExpRowBuffer::CreateRows( SCROW nFirstFreeScRow )
2036 : {
2037 124 : if( nFirstFreeScRow > 0 )
2038 124 : GetOrCreateRow( ::std::max ( nFirstFreeScRow - 1, GetMaxPos().Row() ), true );
2039 124 : }
2040 :
2041 124 : void XclExpRowBuffer::Finalize( XclExpDefaultRowData& rDefRowData, const ScfUInt16Vec& rColXFIndexes )
2042 : {
2043 : // *** Finalize all rows *** ----------------------------------------------
2044 :
2045 124 : GetProgressBar().ActivateFinalRowsSegment();
2046 :
2047 124 : RowMap::iterator itr, itrBeg = maRowMap.begin(), itrEnd = maRowMap.end();
2048 1492 : for (itr = itrBeg; itr != itrEnd; ++itr)
2049 1368 : itr->second->Finalize(rColXFIndexes);
2050 :
2051 : // *** Default row format *** ---------------------------------------------
2052 :
2053 : typedef ::std::map< XclExpDefaultRowData, size_t > XclExpDefRowDataMap;
2054 124 : XclExpDefRowDataMap aDefRowMap;
2055 :
2056 124 : XclExpDefaultRowData aMaxDefData;
2057 124 : size_t nMaxDefCount = 0;
2058 : // only look for default format in existing rows, if there are more than unused
2059 124 : XclExpRow* pPrev = NULL;
2060 : typedef std::vector< XclExpRow* > XclRepeatedRows;
2061 248 : XclRepeatedRows aRepeated;
2062 1492 : for (itr = itrBeg; itr != itrEnd; ++itr)
2063 : {
2064 1368 : const RowRef& rRow = itr->second;
2065 1368 : if (rRow->IsDefaultable())
2066 : {
2067 336 : XclExpDefaultRowData aDefData( *rRow );
2068 336 : size_t& rnDefCount = aDefRowMap[ aDefData ];
2069 336 : ++rnDefCount;
2070 336 : if( rnDefCount > nMaxDefCount )
2071 : {
2072 284 : nMaxDefCount = rnDefCount;
2073 284 : aMaxDefData = aDefData;
2074 : }
2075 : }
2076 1368 : if ( pPrev )
2077 : {
2078 1244 : if ( pPrev->IsDefaultable())
2079 : {
2080 : // if the previous row we processed is not
2081 : // defaultable then afaict the rows inbetween are
2082 : // not used ( and not repeatable )
2083 212 : sal_uInt32 nRpt = rRow->GetXclRow() - pPrev->GetXclRow();
2084 212 : if ( nRpt > 1 )
2085 128 : aRepeated.push_back( pPrev );
2086 212 : pPrev->SetXclRowRpt( nRpt );
2087 212 : XclExpDefaultRowData aDefData( *pPrev );
2088 212 : size_t& rnDefCount = aDefRowMap[ aDefData ];
2089 212 : rnDefCount += ( pPrev->GetXclRowRpt() - 1 );
2090 212 : if( rnDefCount > nMaxDefCount )
2091 : {
2092 116 : nMaxDefCount = rnDefCount;
2093 116 : aMaxDefData = aDefData;
2094 : }
2095 : }
2096 : }
2097 1368 : pPrev = rRow.get();
2098 : }
2099 : // return the default row format to caller
2100 124 : rDefRowData = aMaxDefData;
2101 :
2102 : // now disable repeating extra (empty) rows that are equal to
2103 : // default row height
2104 252 : for ( XclRepeatedRows::iterator it = aRepeated.begin(), it_end = aRepeated.end(); it != it_end; ++it)
2105 : {
2106 128 : if ( (*it)->GetXclRowRpt() > 1 && (*it)->GetHeight() == rDefRowData.mnHeight )
2107 104 : (*it)->SetXclRowRpt( 1 );
2108 : }
2109 :
2110 : // *** Disable unused ROW records, find used area *** ---------------------
2111 :
2112 124 : sal_uInt16 nFirstUsedXclCol = SAL_MAX_UINT16;
2113 124 : sal_uInt16 nFirstFreeXclCol = 0;
2114 124 : sal_uInt32 nFirstUsedXclRow = SAL_MAX_UINT32;
2115 124 : sal_uInt32 nFirstFreeXclRow = 0;
2116 :
2117 1492 : for (itr = itrBeg; itr != itrEnd; ++itr)
2118 : {
2119 1368 : const RowRef& rRow = itr->second;
2120 : // disable unused rows
2121 1368 : rRow->DisableIfDefault( aMaxDefData );
2122 :
2123 : // find used column range
2124 1368 : if( !rRow->IsEmpty() ) // empty rows return (0...0) as used range
2125 : {
2126 1032 : nFirstUsedXclCol = ::std::min( nFirstUsedXclCol, rRow->GetFirstUsedXclCol() );
2127 1032 : nFirstFreeXclCol = ::std::max( nFirstFreeXclCol, rRow->GetFirstFreeXclCol() );
2128 : }
2129 :
2130 : // find used row range
2131 1368 : if( rRow->IsEnabled() )
2132 : {
2133 1088 : sal_uInt16 nXclRow = rRow->GetXclRow();
2134 1088 : nFirstUsedXclRow = ::std::min< sal_uInt32 >( nFirstUsedXclRow, nXclRow );
2135 1088 : nFirstFreeXclRow = ::std::max< sal_uInt32 >( nFirstFreeXclRow, nXclRow + 1 );
2136 : }
2137 : }
2138 :
2139 : // adjust start position, if there are no or only empty/disabled ROW records
2140 124 : nFirstUsedXclCol = ::std::min( nFirstUsedXclCol, nFirstFreeXclCol );
2141 124 : nFirstUsedXclRow = ::std::min( nFirstUsedXclRow, nFirstFreeXclRow );
2142 :
2143 : // initialize the DIMENSIONS record
2144 : maDimensions.SetDimensions(
2145 248 : nFirstUsedXclCol, nFirstUsedXclRow, nFirstFreeXclCol, nFirstFreeXclRow );
2146 124 : }
2147 :
2148 50 : void XclExpRowBuffer::Save( XclExpStream& rStrm )
2149 : {
2150 : // DIMENSIONS record
2151 50 : maDimensions.Save( rStrm );
2152 :
2153 : // save in blocks of 32 rows, each block contains first all ROWs, then all cells
2154 50 : size_t nSize = maRowMap.size();
2155 50 : RowMap::iterator itr, itrBeg = maRowMap.begin(), itrEnd = maRowMap.end();
2156 50 : RowMap::iterator itrBlkStart = maRowMap.begin(), itrBlkEnd = maRowMap.begin();
2157 50 : sal_uInt16 nStartXclRow = (nSize == 0) ? 0 : itrBeg->second->GetXclRow();
2158 :
2159 622 : for (itr = itrBeg; itr != itrEnd; ++itr)
2160 : {
2161 : // find end of row block
2162 1656 : while( (itrBlkEnd != itrEnd) && (itrBlkEnd->second->GetXclRow() - nStartXclRow < EXC_ROW_ROWBLOCKSIZE) )
2163 512 : ++itrBlkEnd;
2164 :
2165 : // write the ROW records
2166 572 : RowMap::iterator itRow;
2167 1144 : for( itRow = itrBlkStart; itRow != itrBlkEnd; ++itRow )
2168 572 : itRow->second->Save( rStrm );
2169 :
2170 : // write the cell records
2171 1144 : for( itRow = itrBlkStart; itRow != itrBlkEnd; ++itRow )
2172 572 : itRow->second->WriteCellList( rStrm );
2173 :
2174 572 : itrBlkStart = (itrBlkEnd == itrEnd) ? itrBlkEnd : itrBlkEnd++;
2175 572 : nStartXclRow += EXC_ROW_ROWBLOCKSIZE;
2176 : }
2177 50 : }
2178 :
2179 74 : void XclExpRowBuffer::SaveXml( XclExpXmlStream& rStrm )
2180 : {
2181 74 : sal_Int32 nNonEmpty = 0;
2182 74 : RowMap::iterator itr = maRowMap.begin(), itrEnd = maRowMap.end();
2183 870 : for (; itr != itrEnd; ++itr)
2184 796 : if (itr->second->IsEnabled())
2185 630 : ++nNonEmpty;
2186 :
2187 74 : if (nNonEmpty == 0)
2188 : {
2189 20 : rStrm.GetCurrentStream()->singleElement( XML_sheetData, FSEND );
2190 94 : return;
2191 : }
2192 :
2193 54 : sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
2194 54 : rWorksheet->startElement( XML_sheetData, FSEND );
2195 810 : for (itr = maRowMap.begin(); itr != itrEnd; ++itr)
2196 756 : itr->second->SaveXml(rStrm);
2197 54 : rWorksheet->endElement( XML_sheetData );
2198 : }
2199 :
2200 6376 : XclExpRow& XclExpRowBuffer::GetOrCreateRow( sal_uInt32 nXclRow, bool bRowAlwaysEmpty )
2201 : {
2202 6376 : RowMap::iterator itr = maRowMap.begin();
2203 6376 : ScDocument& rDoc = GetRoot().GetDoc();
2204 6376 : SCTAB nScTab = GetRoot().GetCurrScTab();
2205 82851556 : for ( size_t nFrom = maRowMap.size(); nFrom <= nXclRow; ++nFrom )
2206 : {
2207 82845180 : itr = maRowMap.find(nFrom);
2208 82845180 : if ( itr == maRowMap.end() )
2209 : {
2210 : // only create RowMap entries for rows that differ from previous,
2211 : // or if it is the desired row
2212 82838778 : if ( !nFrom || ( nFrom == nXclRow ) || ( nFrom && ( rDoc.GetRowHeight(nFrom, nScTab, false) != rDoc.GetRowHeight(nFrom-1, nScTab, false) ) ) )
2213 : {
2214 1368 : RowRef p(new XclExpRow(GetRoot(), nFrom, maOutlineBfr, bRowAlwaysEmpty));
2215 1368 : maRowMap.insert(RowMap::value_type(nFrom, p));
2216 : }
2217 : }
2218 : }
2219 6376 : itr = maRowMap.find(nXclRow);
2220 6376 : return *itr->second;
2221 :
2222 : }
2223 :
2224 : // Cell Table
2225 :
2226 124 : XclExpCellTable::XclExpCellTable( const XclExpRoot& rRoot ) :
2227 : XclExpRoot( rRoot ),
2228 : maColInfoBfr( rRoot ),
2229 : maRowBfr( rRoot ),
2230 : maArrayBfr( rRoot ),
2231 : maShrfmlaBfr( rRoot ),
2232 : maTableopBfr( rRoot ),
2233 124 : mxDefrowheight( new XclExpDefrowheight ),
2234 124 : mxGuts( new XclExpGuts( rRoot ) ),
2235 124 : mxNoteList( new XclExpNoteList ),
2236 124 : mxMergedcells( new XclExpMergedcells( rRoot ) ),
2237 124 : mxHyperlinkList( new XclExpHyperlinkList ),
2238 124 : mxDval( new XclExpDval( rRoot ) ),
2239 868 : mxExtLst( new XclExtLst( rRoot ) )
2240 : {
2241 124 : ScDocument& rDoc = GetDoc();
2242 124 : SCTAB nScTab = GetCurrScTab();
2243 124 : SvNumberFormatter& rFormatter = GetFormatter();
2244 :
2245 : // maximum sheet limits
2246 124 : SCCOL nMaxScCol = GetMaxPos().Col();
2247 124 : SCROW nMaxScRow = GetMaxPos().Row();
2248 :
2249 : // find used area (non-empty cells)
2250 : SCCOL nLastUsedScCol;
2251 : SCROW nLastUsedScRow;
2252 124 : rDoc.GetTableArea( nScTab, nLastUsedScCol, nLastUsedScRow );
2253 :
2254 124 : if(nLastUsedScCol > nMaxScCol)
2255 0 : nLastUsedScCol = nMaxScCol;
2256 :
2257 124 : if(nLastUsedScRow > nMaxScRow)
2258 0 : nLastUsedScRow = nMaxScRow;
2259 :
2260 124 : ScRange aUsedRange( 0, 0, nScTab, nLastUsedScCol, nLastUsedScRow, nScTab );
2261 124 : GetAddressConverter().ValidateRange( aUsedRange, true );
2262 124 : nLastUsedScCol = aUsedRange.aEnd.Col();
2263 124 : nLastUsedScRow = aUsedRange.aEnd.Row();
2264 :
2265 : // first row without any set attributes (height/hidden/...)
2266 124 : SCROW nFirstUnflaggedScRow = rDoc.GetLastFlaggedRow( nScTab ) + 1;
2267 :
2268 : // find range of outlines
2269 124 : SCROW nFirstUngroupedScRow = 0;
2270 124 : if( const ScOutlineTable* pOutlineTable = rDoc.GetOutlineTable( nScTab ) )
2271 : {
2272 : SCCOLROW nScStartPos, nScEndPos;
2273 26 : const ScOutlineArray& rRowArray = pOutlineTable->GetRowArray();
2274 26 : rRowArray.GetRange( nScStartPos, nScEndPos );
2275 : // +1 because open/close button is in next row in Excel, +1 for "end->first unused"
2276 26 : nFirstUngroupedScRow = static_cast< SCROW >( nScEndPos + 2 );
2277 : }
2278 :
2279 : // column settings
2280 : /* #i30411# Files saved with SO7/OOo1.x with nonstandard default column
2281 : formatting cause big Excel files, because all rows from row 1 to row
2282 : 32000 are exported. Now, if the used area goes exactly to row 32000,
2283 : use this row as default and ignore all rows >32000.
2284 : #i59220# Tolerance of +-128 rows for inserted/removed rows. */
2285 124 : if( (31871 <= nLastUsedScRow) && (nLastUsedScRow <= 32127) && (nFirstUnflaggedScRow < nLastUsedScRow) && (nFirstUngroupedScRow <= nLastUsedScRow) )
2286 0 : nMaxScRow = nLastUsedScRow;
2287 124 : maColInfoBfr.Initialize( nMaxScRow );
2288 :
2289 : // range for cell iterator
2290 124 : SCCOL nLastIterScCol = nMaxScCol;
2291 124 : SCROW nLastIterScRow = ulimit_cast< SCROW >( nLastUsedScRow, nMaxScRow );
2292 124 : ScUsedAreaIterator aIt( &rDoc, nScTab, 0, 0, nLastIterScCol, nLastIterScRow );
2293 :
2294 : // activate the correct segment and sub segment at the progress bar
2295 124 : GetProgressBar().ActivateCreateRowsSegment();
2296 :
2297 6376 : for( bool bIt = aIt.GetNext(); bIt; bIt = aIt.GetNext() )
2298 : {
2299 6252 : SCCOL nScCol = aIt.GetStartCol();
2300 6252 : SCROW nScRow = aIt.GetRow();
2301 6252 : SCCOL nLastScCol = aIt.GetEndCol();
2302 6252 : ScAddress aScPos( nScCol, nScRow, nScTab );
2303 :
2304 6252 : XclAddress aXclPos( static_cast< sal_uInt16 >( nScCol ), static_cast< sal_uInt32 >( nScRow ) );
2305 6252 : sal_uInt16 nLastXclCol = static_cast< sal_uInt16 >( nLastScCol );
2306 :
2307 6252 : const ScRefCellValue& rScCell = aIt.GetCell();
2308 6252 : XclExpCellRef xCell;
2309 :
2310 6252 : const ScPatternAttr* pPattern = aIt.GetPattern();
2311 :
2312 : // handle overlapped merged cells before creating the cell record
2313 6252 : sal_uInt32 nMergeBaseXFId = EXC_XFID_NOTFOUND;
2314 6252 : bool bIsMergedBase = false;
2315 6252 : if( pPattern )
2316 : {
2317 3248 : const SfxItemSet& rItemSet = pPattern->GetItemSet();
2318 : // base cell in a merged range
2319 3248 : const ScMergeAttr& rMergeItem = GETITEM( rItemSet, ScMergeAttr, ATTR_MERGE );
2320 3248 : bIsMergedBase = rMergeItem.IsMerged();
2321 : /* overlapped cell in a merged range; in Excel all merged cells
2322 : must contain same XF index, for correct border */
2323 3248 : const ScMergeFlagAttr& rMergeFlagItem = GETITEM( rItemSet, ScMergeFlagAttr, ATTR_MERGE_FLAG );
2324 3248 : if( rMergeFlagItem.IsOverlapped() )
2325 68 : nMergeBaseXFId = mxMergedcells->GetBaseXFId( aScPos );
2326 : }
2327 :
2328 12504 : OUString aAddNoteText; // additional text to be appended to a note
2329 :
2330 6252 : switch (rScCell.meType)
2331 : {
2332 : case CELLTYPE_VALUE:
2333 : {
2334 2226 : double fValue = rScCell.mfValue;
2335 :
2336 : // try to create a Boolean cell
2337 2226 : if( pPattern && ((fValue == 0.0) || (fValue == 1.0)) )
2338 : {
2339 108 : sal_uLong nScNumFmt = GETITEMVALUE( pPattern->GetItemSet(), SfxUInt32Item, ATTR_VALUE_FORMAT, sal_uLong );
2340 108 : if( rFormatter.GetType( nScNumFmt ) == NUMBERFORMAT_LOGICAL )
2341 : xCell.reset( new XclExpBooleanCell(
2342 0 : GetRoot(), aXclPos, pPattern, nMergeBaseXFId, fValue != 0.0 ) );
2343 : }
2344 :
2345 : // try to create an RK value (compressed floating-point number)
2346 : sal_Int32 nRkValue;
2347 2226 : if( !xCell && XclTools::GetRKFromDouble( nRkValue, fValue ) )
2348 : xCell.reset( new XclExpRkCell(
2349 1760 : GetRoot(), aXclPos, pPattern, nMergeBaseXFId, nRkValue ) );
2350 :
2351 : // else: simple floating-point number cell
2352 2226 : if( !xCell )
2353 : xCell.reset( new XclExpNumberCell(
2354 466 : GetRoot(), aXclPos, pPattern, nMergeBaseXFId, fValue ) );
2355 : }
2356 2226 : break;
2357 :
2358 : case CELLTYPE_STRING:
2359 : {
2360 : xCell.reset(new XclExpLabelCell(
2361 820 : GetRoot(), aXclPos, pPattern, nMergeBaseXFId, rScCell.mpString->getString()));
2362 : }
2363 820 : break;
2364 :
2365 : case CELLTYPE_EDIT:
2366 : {
2367 0 : XclExpHyperlinkHelper aLinkHelper( GetRoot(), aScPos );
2368 : xCell.reset(new XclExpLabelCell(
2369 0 : GetRoot(), aXclPos, pPattern, nMergeBaseXFId, rScCell.mpEditText, aLinkHelper));
2370 :
2371 : // add a single created HLINK record to the record list
2372 0 : if( aLinkHelper.HasLinkRecord() )
2373 0 : mxHyperlinkList->AppendRecord( aLinkHelper.GetLinkRecord() );
2374 : // add list of multiple URLs to the additional cell note text
2375 0 : if( aLinkHelper.HasMultipleUrls() )
2376 0 : aAddNoteText = ScGlobal::addToken( aAddNoteText, aLinkHelper.GetUrlList(), '\n', 2 );
2377 : }
2378 0 : break;
2379 :
2380 : case CELLTYPE_FORMULA:
2381 : {
2382 : xCell.reset(new XclExpFormulaCell(
2383 2206 : GetRoot(), aXclPos, pPattern, nMergeBaseXFId,
2384 2206 : *rScCell.mpFormula, maArrayBfr, maShrfmlaBfr, maTableopBfr));
2385 : }
2386 2206 : break;
2387 :
2388 : default:
2389 : OSL_FAIL( "XclExpCellTable::XclExpCellTable - unknown cell type" );
2390 : // run-through!
2391 : case CELLTYPE_NONE:
2392 : {
2393 : xCell.reset( new XclExpBlankCell(
2394 1000 : GetRoot(), aXclPos, nLastXclCol, pPattern, nMergeBaseXFId ) );
2395 : }
2396 1000 : break;
2397 : }
2398 :
2399 : // insert the cell into the current row
2400 6252 : if( xCell )
2401 6252 : maRowBfr.AppendCell( xCell, bIsMergedBase );
2402 :
2403 6252 : if ( !aAddNoteText.isEmpty() )
2404 0 : mxNoteList->AppendNewRecord( new XclExpNote( GetRoot(), aScPos, NULL, aAddNoteText ) );
2405 :
2406 : // other sheet contents
2407 6252 : if( pPattern )
2408 : {
2409 3248 : const SfxItemSet& rItemSet = pPattern->GetItemSet();
2410 :
2411 : // base cell in a merged range
2412 3248 : if( bIsMergedBase )
2413 : {
2414 12 : const ScMergeAttr& rMergeItem = GETITEM( rItemSet, ScMergeAttr, ATTR_MERGE );
2415 12 : ScRange aScRange( aScPos );
2416 12 : aScRange.aEnd.IncCol( rMergeItem.GetColMerge() - 1 );
2417 12 : aScRange.aEnd.IncRow( rMergeItem.GetRowMerge() - 1 );
2418 12 : sal_uInt32 nXFId = xCell ? xCell->GetFirstXFId() : EXC_XFID_NOTFOUND;
2419 : // blank cells merged vertically may occur repeatedly
2420 : OSL_ENSURE( (aScRange.aStart.Col() == aScRange.aEnd.Col()) || (nScCol == nLastScCol),
2421 : "XclExpCellTable::XclExpCellTable - invalid repeated blank merged cell" );
2422 24 : for( SCCOL nIndex = nScCol; nIndex <= nLastScCol; ++nIndex )
2423 : {
2424 12 : mxMergedcells->AppendRange( aScRange, nXFId );
2425 12 : aScRange.aStart.IncCol();
2426 12 : aScRange.aEnd.IncCol();
2427 : }
2428 : }
2429 :
2430 : // data validation
2431 3248 : if( ScfTools::CheckItem( rItemSet, ATTR_VALIDDATA, false ) )
2432 : {
2433 0 : sal_uLong nScHandle = GETITEMVALUE( rItemSet, SfxUInt32Item, ATTR_VALIDDATA, sal_uLong );
2434 0 : ScRange aScRange( aScPos );
2435 0 : aScRange.aEnd.SetCol( nLastScCol );
2436 0 : mxDval->InsertCellRange( aScRange, nScHandle );
2437 : }
2438 : }
2439 6252 : }
2440 :
2441 : // create missing row settings for rows anyhow flagged or with outlines
2442 124 : maRowBfr.CreateRows( ::std::max( nFirstUnflaggedScRow, nFirstUngroupedScRow ) );
2443 124 : }
2444 :
2445 124 : void XclExpCellTable::Finalize()
2446 : {
2447 : // Finalize multiple operations.
2448 124 : maTableopBfr.Finalize();
2449 :
2450 : /* Finalize column buffer. This calculates column default XF indexes from
2451 : the XF identifiers and fills a vector with these XF indexes. */
2452 124 : ScfUInt16Vec aColXFIndexes;
2453 124 : maColInfoBfr.Finalize( aColXFIndexes );
2454 :
2455 : /* Finalize row buffer. This calculates all cell XF indexes from the XF
2456 : identifiers. Then the XF index vector aColXFIndexes (filled above) is
2457 : used to calculate the row default formats. With this, all unneeded blank
2458 : cell records (equal to row default or column default) will be removed.
2459 : The function returns the (most used) default row format in aDefRowData. */
2460 124 : XclExpDefaultRowData aDefRowData;
2461 124 : maRowBfr.Finalize( aDefRowData, aColXFIndexes );
2462 :
2463 : // Initialize the DEFROWHEIGHT record.
2464 124 : mxDefrowheight->SetDefaultData( aDefRowData );
2465 124 : }
2466 :
2467 694 : XclExpRecordRef XclExpCellTable::CreateRecord( sal_uInt16 nRecId ) const
2468 : {
2469 694 : XclExpRecordRef xRec;
2470 694 : switch( nRecId )
2471 : {
2472 74 : case EXC_ID3_DIMENSIONS: xRec.reset( new XclExpDelegatingRecord( &const_cast<XclExpRowBuffer*>(&maRowBfr)->GetDimensions() ) ); break;
2473 124 : case EXC_ID2_DEFROWHEIGHT: xRec = mxDefrowheight; break;
2474 124 : case EXC_ID_GUTS: xRec = mxGuts; break;
2475 0 : case EXC_ID_NOTE: xRec = mxNoteList; break;
2476 124 : case EXC_ID_MERGEDCELLS: xRec = mxMergedcells; break;
2477 124 : case EXC_ID_HLINK: xRec = mxHyperlinkList; break;
2478 124 : case EXC_ID_DVAL: xRec = mxDval; break;
2479 0 : case EXC_ID_EXTLST: xRec = mxExtLst; break;
2480 : default: OSL_FAIL( "XclExpCellTable::CreateRecord - unknown record id" );
2481 : }
2482 694 : return xRec;
2483 : }
2484 :
2485 50 : void XclExpCellTable::Save( XclExpStream& rStrm )
2486 : {
2487 : // DEFCOLWIDTH and COLINFOs
2488 50 : maColInfoBfr.Save( rStrm );
2489 : // ROWs and cell records
2490 50 : maRowBfr.Save( rStrm );
2491 50 : }
2492 :
2493 74 : void XclExpCellTable::SaveXml( XclExpXmlStream& rStrm )
2494 : {
2495 : // DEFAULT row height
2496 74 : XclExpDefaultRowData& rDefData = mxDefrowheight->GetDefaultData();
2497 74 : sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
2498 : rWorksheet->startElement( XML_sheetFormatPr,
2499 74 : XML_defaultRowHeight, OString::number( (double) rDefData.mnHeight / 20.0 ).getStr(), FSEND );
2500 74 : rWorksheet->endElement( XML_sheetFormatPr );
2501 :
2502 74 : maColInfoBfr.SaveXml( rStrm );
2503 74 : maRowBfr.SaveXml( rStrm );
2504 74 : mxExtLst->SaveXml( rStrm );
2505 122 : }
2506 :
2507 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|