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