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