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