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