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