re-enabled user-defined numeric fields for dBase export
[LibreOffice.git] / sc / source / core / data / table4.cxx
blobdf6f52cb502b0d364a74eca91af6bcbd89b280c2
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "scitems.hxx"
21 #include <comphelper/string.hxx>
22 #include <svx/algitem.hxx>
23 #include <editeng/boxitem.hxx>
24 #include <editeng/brushitem.hxx>
25 #include <editeng/contouritem.hxx>
26 #include <editeng/colritem.hxx>
27 #include <editeng/crossedoutitem.hxx>
28 #include <editeng/fhgtitem.hxx>
29 #include <editeng/fontitem.hxx>
30 #include <editeng/langitem.hxx>
31 #include <editeng/postitem.hxx>
32 #include <editeng/shdditem.hxx>
33 #include <editeng/udlnitem.hxx>
34 #include <editeng/wghtitem.hxx>
35 #include <svx/rotmodit.hxx>
36 #include <editeng/editobj.hxx>
37 #include <editeng/editeng.hxx>
38 #include <editeng/eeitem.hxx>
39 #include <editeng/escapementitem.hxx>
40 #include <svl/zforlist.hxx>
41 #include <vcl/keycodes.hxx>
42 #include <rtl/math.hxx>
43 #include <unotools/charclass.hxx>
45 #include "attrib.hxx"
46 #include "patattr.hxx"
47 #include "formulacell.hxx"
48 #include "table.hxx"
49 #include "globstr.hrc"
50 #include "global.hxx"
51 #include "document.hxx"
52 #include "autoform.hxx"
53 #include "userlist.hxx"
54 #include "zforauto.hxx"
55 #include "subtotal.hxx"
56 #include "formula/errorcodes.hxx"
57 #include "rangenam.hxx"
58 #include "docpool.hxx"
59 #include "progress.hxx"
60 #include "segmenttree.hxx"
61 #include "conditio.hxx"
63 #include <math.h>
64 #include <boost/scoped_ptr.hpp>
66 // STATIC DATA -----------------------------------------------------------
68 #define _D_MAX_LONG_ (double) 0x7fffffff
70 extern sal_uInt16 nScFillModeMouseModifier; // global.cxx
72 // -----------------------------------------------------------------------
74 static short lcl_DecompValueString( String& aValue, sal_Int32& nVal, sal_uInt16* pMinDigits = NULL )
76 if ( !aValue.Len() )
78 nVal = 0;
79 return 0;
81 const sal_Unicode* p = aValue.GetBuffer();
82 xub_StrLen nNeg = 0;
83 xub_StrLen nNum = 0;
84 if ( p[nNum] == '-' )
85 nNum = nNeg = 1;
86 while ( p[nNum] && CharClass::isAsciiNumeric( OUString(p[nNum]) ) )
87 nNum++;
89 sal_Unicode cNext = p[nNum]; // 0 if at the end
90 sal_Unicode cLast = p[aValue.Len()-1];
92 // #i5550# If there are numbers at the beginning and the end,
93 // prefer the one at the beginning only if it's followed by a space.
94 // Otherwise, use the number at the end, to enable things like IP addresses.
95 if ( nNum > nNeg && ( cNext == 0 || cNext == ' ' || !CharClass::isAsciiNumeric(OUString(cLast)) ) )
96 { // number at the beginning
97 nVal = aValue.Copy( 0, nNum ).ToInt32();
98 // any number with a leading zero sets the minimum number of digits
99 if ( p[nNeg] == '0' && pMinDigits && ( nNum - nNeg > *pMinDigits ) )
100 *pMinDigits = nNum - nNeg;
101 aValue.Erase( 0, nNum );
102 return -1;
104 else
106 nNeg = 0;
107 xub_StrLen nEnd = nNum = aValue.Len() - 1;
108 while ( nNum && CharClass::isAsciiNumeric( OUString(p[nNum]) ) )
109 nNum--;
110 if ( p[nNum] == '-' )
112 nNum--;
113 nNeg = 1;
115 if ( nNum < nEnd - nNeg )
116 { // number at the end
117 nVal = aValue.Copy( nNum + 1 ).ToInt32();
118 // any number with a leading zero sets the minimum number of digits
119 if ( p[nNum+1+nNeg] == '0' && pMinDigits && ( nEnd - nNum - nNeg > *pMinDigits ) )
120 *pMinDigits = nEnd - nNum - nNeg;
121 aValue.Erase( nNum + 1 );
122 return 1;
125 nVal = 0;
126 return 0;
129 static OUString lcl_ValueString( sal_Int32 nValue, sal_uInt16 nMinDigits )
131 if ( nMinDigits <= 1 )
132 return OUString::number( nValue ); // simple case...
133 else
135 OUString aStr = OUString::number( std::abs( nValue ) );
136 if ( aStr.getLength() < nMinDigits )
138 OUStringBuffer aZero;
139 comphelper::string::padToLength(aZero, nMinDigits - aStr.getLength(), '0');
140 aStr = aZero.makeStringAndClear() + aStr;
142 // nMinDigits doesn't include the '-' sign -> add after inserting zeros
143 if ( nValue < 0 )
144 aStr = "-" + aStr;
145 return aStr;
149 static ScBaseCell * lcl_getSuffixCell( ScDocument* pDocument, sal_Int32 nValue,
150 sal_uInt16 nDigits, const String& rSuffix, CellType eCellType,
151 bool bIsOrdinalSuffix )
153 String aValue( lcl_ValueString( nValue, nDigits ));
154 if (!bIsOrdinalSuffix)
155 return new ScStringCell( aValue += rSuffix);
157 String aOrdinalSuffix( ScGlobal::GetOrdinalSuffix( nValue));
158 if (eCellType != CELLTYPE_EDIT)
159 return new ScStringCell( aValue += aOrdinalSuffix);
161 EditEngine aEngine( pDocument->GetEnginePool() );
162 aEngine.SetEditTextObjectPool(pDocument->GetEditPool());
164 SfxItemSet aAttr = aEngine.GetEmptyItemSet();
165 aAttr.Put( SvxEscapementItem( SVX_ESCAPEMENT_SUPERSCRIPT, EE_CHAR_ESCAPEMENT));
166 aEngine.SetText( aValue );
167 aEngine.QuickInsertText( aOrdinalSuffix, ESelection( 0, aValue.Len(), 0,
168 aValue.Len() + aOrdinalSuffix.Len()));
169 aEngine.QuickSetAttribs( aAttr, ESelection( 0, aValue.Len(), 0, aValue.Len() +
170 aOrdinalSuffix.Len()));
172 // Text object instance will be owned by the cell.
173 return new ScEditCell(aEngine.CreateTextObject(), pDocument);
176 void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
177 FillCmd& rCmd, FillDateCmd& rDateCmd,
178 double& rInc, sal_uInt16& rMinDigits,
179 ScUserListData*& rListData, sal_uInt16& rListIndex)
181 OSL_ENSURE( nCol1==nCol2 || nRow1==nRow2, "FillAnalyse: invalid range" );
183 rInc = 0.0;
184 rMinDigits = 0;
185 rListData = NULL;
186 rCmd = FILL_SIMPLE;
187 if ( (nScFillModeMouseModifier & KEY_MOD1) )
188 return ; // Ctrl-key: Copy
190 SCCOL nAddX;
191 SCROW nAddY;
192 SCSIZE nCount;
193 if (nCol1 == nCol2)
195 nAddX = 0;
196 nAddY = 1;
197 nCount = static_cast<SCSIZE>(nRow2 - nRow1 + 1);
199 else
201 nAddX = 1;
202 nAddY = 0;
203 nCount = static_cast<SCSIZE>(nCol2 - nCol1 + 1);
206 SCCOL nCol = nCol1;
207 SCROW nRow = nRow1;
209 ScBaseCell* pFirstCell = GetCell( nCol, nRow );
210 CellType eCellType = pFirstCell ? pFirstCell->GetCellType() : CELLTYPE_NONE;
212 if (eCellType == CELLTYPE_VALUE)
214 sal_uInt32 nFormat = ((const SfxUInt32Item*)GetAttr(nCol,nRow,ATTR_VALUE_FORMAT))->GetValue();
215 bool bDate = ( pDocument->GetFormatTable()->GetType(nFormat) == NUMBERFORMAT_DATE );
216 if (bDate)
218 if (nCount > 1)
220 double nVal;
221 Date aNullDate = *pDocument->GetFormatTable()->GetNullDate();
222 Date aDate1 = aNullDate;
223 nVal = ((ScValueCell*)pFirstCell)->GetValue();
224 aDate1 += (long)nVal;
225 Date aDate2 = aNullDate;
226 nVal = GetValue(nCol+nAddX, nRow+nAddY);
227 aDate2 += (long)nVal;
228 if ( aDate1 != aDate2 )
230 long nCmpInc = 0;
231 FillDateCmd eType;
232 long nDDiff = aDate2.GetDay() - (long) aDate1.GetDay();
233 long nMDiff = aDate2.GetMonth() - (long) aDate1.GetMonth();
234 long nYDiff = aDate2.GetYear() - (long) aDate1.GetYear();
235 if ( nDDiff )
237 eType = FILL_DAY;
238 nCmpInc = aDate2 - aDate1;
240 else
242 eType = FILL_MONTH;
243 nCmpInc = nMDiff + 12 * nYDiff;
246 nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
247 nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
248 bool bVal = true;
249 for (sal_uInt16 i=1; i<nCount && bVal; i++)
251 ScBaseCell* pCell = GetCell(nCol,nRow);
252 if (pCell && pCell->GetCellType() == CELLTYPE_VALUE)
254 nVal = ((ScValueCell*)pCell)->GetValue();
255 aDate2 = aNullDate + (long) nVal;
256 if ( eType == FILL_DAY )
258 if ( aDate2-aDate1 != nCmpInc )
259 bVal = false;
261 else
263 nDDiff = aDate2.GetDay() - (long) aDate1.GetDay();
264 nMDiff = aDate2.GetMonth() - (long) aDate1.GetMonth();
265 nYDiff = aDate2.GetYear() - (long) aDate1.GetYear();
266 if (nDDiff || ( nMDiff + 12 * nYDiff != nCmpInc ))
267 bVal = false;
269 aDate1 = aDate2;
270 nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
271 nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
273 else
274 bVal = false; // kein Datum passt auch nicht
276 if (bVal)
278 if ( eType == FILL_MONTH && ( nCmpInc % 12 == 0 ) )
280 eType = FILL_YEAR;
281 nCmpInc /= 12;
283 rCmd = FILL_DATE;
284 rDateCmd = eType;
285 rInc = nCmpInc;
289 else // single date -> increment by days
291 rCmd = FILL_DATE;
292 rDateCmd = FILL_DAY;
293 rInc = 1.0;
296 else
298 if (nCount > 1)
300 double nVal1 = ((ScValueCell*)pFirstCell)->GetValue();
301 double nVal2 = GetValue(nCol+nAddX, nRow+nAddY);
302 rInc = nVal2 - nVal1;
303 nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
304 nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
305 bool bVal = true;
306 for (sal_uInt16 i=1; i<nCount && bVal; i++)
308 ScBaseCell* pCell = GetCell(nCol,nRow);
309 if (pCell && pCell->GetCellType() == CELLTYPE_VALUE)
311 nVal2 = ((ScValueCell*)pCell)->GetValue();
312 double nDiff = nVal2 - nVal1;
313 if ( !::rtl::math::approxEqual( nDiff, rInc, 13 ) )
314 bVal = false;
315 nVal1 = nVal2;
317 else
318 bVal = false;
319 nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
320 nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
322 if (bVal)
323 rCmd = FILL_LINEAR;
327 else if (eCellType == CELLTYPE_STRING || eCellType == CELLTYPE_EDIT)
329 OUString aStr;
330 GetString(nCol, nRow, aStr);
332 // fdo#39500 don't deduce increment from multiple equal list entries
333 bool bAllSame = true;
334 for (sal_uInt16 i = 0; i < nCount; ++i)
336 OUString aTestStr;
337 GetString(static_cast<SCCOL>(nCol + i* nAddX), static_cast<SCROW>(nRow + i * nAddY), aTestStr);
338 if(aStr != aTestStr)
340 bAllSame = false;
341 break;
344 if(bAllSame && nCount > 1)
345 return;
347 rListData = (ScUserListData*)(ScGlobal::GetUserList()->GetData(aStr));
348 if (rListData)
350 rListData->GetSubIndex(aStr, rListIndex);
351 nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
352 nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
353 for (sal_uInt16 i=1; i<nCount && rListData; i++)
355 GetString(nCol, nRow, aStr);
356 if (!rListData->GetSubIndex(aStr, rListIndex))
357 rListData = NULL;
358 nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
359 nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
362 else if ( nCount > 1 )
364 // pass rMinDigits to all DecompValueString calls
365 // -> longest number defines rMinDigits
367 sal_Int32 nVal1;
368 String aString = aStr;
369 short nFlag1 = lcl_DecompValueString( aString, nVal1, &rMinDigits );
370 aStr = aString;
371 if ( nFlag1 )
373 sal_Int32 nVal2;
374 GetString( nCol+nAddX, nRow+nAddY, aStr );
375 aString = aStr;
376 short nFlag2 = lcl_DecompValueString( aString, nVal2, &rMinDigits );
377 aStr = aString;
378 if ( nFlag1 == nFlag2 )
380 rInc = (double)nVal2 - (double)nVal1;
381 nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
382 nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
383 bool bVal = true;
384 for (sal_uInt16 i=1; i<nCount && bVal; i++)
386 ScBaseCell* pCell = GetCell(nCol,nRow);
387 CellType eType = pCell ? pCell->GetCellType() : CELLTYPE_NONE;
388 if ( eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT )
390 if ( eType == CELLTYPE_STRING )
391 aStr = ((ScStringCell*)pCell)->GetString();
392 else
393 aStr = ((ScEditCell*)pCell)->GetString();
394 aString = aStr;
395 nFlag2 = lcl_DecompValueString( aString, nVal2, &rMinDigits );
396 aStr = aString;
397 if ( nFlag1 == nFlag2 )
399 double nDiff = (double)nVal2 - (double)nVal1;
400 if ( !::rtl::math::approxEqual( nDiff, rInc, 13 ) )
401 bVal = false;
402 nVal1 = nVal2;
404 else
405 bVal = false;
407 else
408 bVal = false;
409 nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
410 nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
412 if (bVal)
413 rCmd = FILL_LINEAR;
417 else
419 // call DecompValueString to set rMinDigits
420 sal_Int32 nDummy;
421 String aString = aStr;
422 lcl_DecompValueString( aString, nDummy, &rMinDigits );
427 void ScTable::FillFormula(sal_uLong& /* nFormulaCounter */, bool /* bFirst */, ScFormulaCell* pSrcCell,
428 SCCOL nDestCol, SCROW nDestRow, bool bLast )
431 pDocument->SetNoListening( true ); // still the wrong reference
432 ScAddress aAddr( nDestCol, nDestRow, nTab );
433 ScFormulaCell* pDestCell = new ScFormulaCell( *pSrcCell, *pDocument, aAddr );
434 aCol[nDestCol].Insert(nDestRow, pDestCell);
436 if ( bLast && pDestCell->GetMatrixFlag() )
438 ScAddress aOrg;
439 if ( pDestCell->GetMatrixOrigin( aOrg ) )
441 if ( nDestCol >= aOrg.Col() && nDestRow >= aOrg.Row() )
443 ScFormulaCell* pOrgCell = pDocument->GetFormulaCell(aOrg);
444 if (pOrgCell && pOrgCell->GetMatrixFlag() == MM_FORMULA)
446 ((ScFormulaCell*)pOrgCell)->SetMatColsRows(
447 nDestCol - aOrg.Col() + 1,
448 nDestRow - aOrg.Row() + 1 );
450 else
452 OSL_FAIL( "FillFormula: MatrixOrigin no forumla cell with MM_FORMULA" );
455 else
457 OSL_FAIL( "FillFormula: MatrixOrigin bottom right" );
460 else
462 OSL_FAIL( "FillFormula: no MatrixOrigin" );
465 pDocument->SetNoListening( false );
466 pDestCell->StartListeningTo( pDocument );
470 void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
471 sal_uLong nFillCount, FillDir eFillDir, ScProgress* pProgress )
473 if ( (nFillCount == 0) || !ValidColRow(nCol1, nRow1) || !ValidColRow(nCol2, nRow2) )
474 return;
477 // Detect direction
480 bool bVertical = (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_TOP);
481 bool bPositive = (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_RIGHT);
483 sal_uLong nCol = 0;
484 sal_uLong nRow = 0;
485 sal_uLong& rInner = bVertical ? nRow : nCol; // loop variables
486 sal_uLong& rOuter = bVertical ? nCol : nRow;
487 sal_uLong nOStart;
488 sal_uLong nOEnd;
489 sal_uLong nIStart;
490 sal_uLong nIEnd;
491 sal_uLong nISrcStart;
492 sal_uLong nISrcEnd;
493 ScRange aFillRange;
495 if (bVertical)
497 nOStart = nCol1;
498 nOEnd = nCol2;
499 if (bPositive)
501 nISrcStart = nRow1;
502 nISrcEnd = nRow2;
503 nIStart = nRow2 + 1;
504 nIEnd = nRow2 + nFillCount;
505 aFillRange = ScRange(nCol1, nRow2+1, 0, nCol2, nRow2 + nFillCount, 0);
507 else
509 nISrcStart = nRow2;
510 nISrcEnd = nRow1;
511 nIStart = nRow1 - 1;
512 nIEnd = nRow1 - nFillCount;
513 aFillRange = ScRange(nCol1, nRow1-1, 0, nCol2, nRow2 - nFillCount, 0);
516 else
518 nOStart = nRow1;
519 nOEnd = nRow2;
520 if (bPositive)
522 nISrcStart = nCol1;
523 nISrcEnd = nCol2;
524 nIStart = nCol2 + 1;
525 nIEnd = nCol2 + nFillCount;
526 aFillRange = ScRange(nCol2 + 1, nRow1, 0, nCol2 + nFillCount, nRow2, 0);
528 else
530 nISrcStart = nCol2;
531 nISrcEnd = nCol1;
532 nIStart = nCol1 - 1;
533 nIEnd = nCol1 - nFillCount;
534 aFillRange = ScRange(nCol1 - 1, nRow1, 0, nCol1 - nFillCount, nRow2, 0);
537 sal_uLong nIMin = nIStart;
538 sal_uLong nIMax = nIEnd;
539 PutInOrder(nIMin,nIMax);
540 bool bHasFiltered = IsDataFiltered(aFillRange);
542 if (!bHasFiltered)
544 if (bVertical)
545 DeleteArea(nCol1, static_cast<SCROW>(nIMin), nCol2, static_cast<SCROW>(nIMax), IDF_AUTOFILL);
546 else
547 DeleteArea(static_cast<SCCOL>(nIMin), nRow1, static_cast<SCCOL>(nIMax), nRow2, IDF_AUTOFILL);
550 sal_uLong nProgress = 0;
551 if (pProgress)
552 nProgress = pProgress->GetState();
555 // execute
558 sal_uLong nActFormCnt = 0;
559 for (rOuter = nOStart; rOuter <= nOEnd; rOuter++)
561 sal_uLong nMaxFormCnt = 0; // for formulas
563 // transfer attributes
565 const ScPatternAttr* pSrcPattern = NULL;
566 const ScStyleSheet* pStyleSheet = NULL;
567 sal_uLong nAtSrc = nISrcStart;
568 ScPatternAttr* pNewPattern = NULL;
569 bool bGetPattern = true;
570 rInner = nIStart;
571 while (true) // #i53728# with "for (;;)" old solaris/x86 compiler mis-optimizes
573 if (!ColHidden(nCol) && !RowHidden(nRow))
575 if ( bGetPattern )
577 delete pNewPattern;
578 if (bVertical) // rInner&:=nRow, rOuter&:=nCol
579 pSrcPattern = aCol[nCol].GetPattern(static_cast<SCROW>(nAtSrc));
580 else // rInner&:=nCol, rOuter&:=nRow
581 pSrcPattern = aCol[nAtSrc].GetPattern(static_cast<SCROW>(nRow));
582 bGetPattern = false;
583 pStyleSheet = pSrcPattern->GetStyleSheet();
584 // do not transfer ATTR_MERGE / ATTR_MERGE_FLAG
585 const SfxItemSet& rSet = pSrcPattern->GetItemSet();
586 if ( rSet.GetItemState(ATTR_MERGE, false) == SFX_ITEM_SET
587 || rSet.GetItemState(ATTR_MERGE_FLAG, false) == SFX_ITEM_SET )
589 pNewPattern = new ScPatternAttr( *pSrcPattern );
590 SfxItemSet& rNewSet = pNewPattern->GetItemSet();
591 rNewSet.ClearItem(ATTR_MERGE);
592 rNewSet.ClearItem(ATTR_MERGE_FLAG);
594 else
595 pNewPattern = NULL;
598 const ScCondFormatItem& rCondFormatItem = static_cast<const ScCondFormatItem&>(pSrcPattern->GetItem(ATTR_CONDITIONAL));
599 const std::vector<sal_uInt32>& rCondFormatIndex = rCondFormatItem.GetCondFormatData();
601 if ( bVertical && nISrcStart == nISrcEnd && !bHasFiltered )
603 // set all attributes at once (en bloc)
604 if (pNewPattern || pSrcPattern != pDocument->GetDefPattern())
606 // Default is already present (DeleteArea)
607 SCROW nY1 = static_cast<SCROW>(std::min( nIStart, nIEnd ));
608 SCROW nY2 = static_cast<SCROW>(std::max( nIStart, nIEnd ));
609 if ( pStyleSheet )
610 aCol[nCol].ApplyStyleArea( nY1, nY2, *pStyleSheet );
611 if ( pNewPattern )
612 aCol[nCol].ApplyPatternArea( nY1, nY2, *pNewPattern );
613 else
614 aCol[nCol].ApplyPatternArea( nY1, nY2, *pSrcPattern );
616 for(std::vector<sal_uInt32>::const_iterator itr = rCondFormatIndex.begin(), itrEnd = rCondFormatIndex.end();
617 itr != itrEnd; ++itr)
619 ScConditionalFormat* pCondFormat = mpCondFormatList->GetFormat(*itr);
620 ScRangeList aRange = pCondFormat->GetRange();
621 aRange.Join(ScRange(nCol, nY1, nTab, nCol, nY2, nTab));
622 pCondFormat->AddRange(aRange);
627 break;
630 if ( bHasFiltered )
631 DeleteArea(static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow),
632 static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), IDF_AUTOFILL);
634 if ( pSrcPattern != aCol[nCol].GetPattern( static_cast<SCROW>(nRow) ) )
636 // Transfer template too
637 //! Merge ApplyPattern to AttrArray ??
638 if ( pStyleSheet )
639 aCol[nCol].ApplyStyle( static_cast<SCROW>(nRow), *pStyleSheet );
641 // Use ApplyPattern instead of SetPattern to keep old MergeFlags
642 if ( pNewPattern )
643 aCol[nCol].ApplyPattern( static_cast<SCROW>(nRow), *pNewPattern );
644 else
645 aCol[nCol].ApplyPattern( static_cast<SCROW>(nRow), *pSrcPattern );
647 for(std::vector<sal_uInt32>::const_iterator itr = rCondFormatIndex.begin(), itrEnd = rCondFormatIndex.end();
648 itr != itrEnd; ++itr)
650 ScConditionalFormat* pCondFormat = mpCondFormatList->GetFormat(*itr);
651 ScRangeList aRange = pCondFormat->GetRange();
652 aRange.Join(ScRange(nCol, nRow, nTab, nCol, nRow, nTab));
653 pCondFormat->AddRange(aRange);
657 if (nAtSrc==nISrcEnd)
659 if ( nAtSrc != nISrcStart )
660 { // More than one source cell
661 nAtSrc = nISrcStart;
662 bGetPattern = true;
665 else if (bPositive)
667 ++nAtSrc;
668 bGetPattern = true;
670 else
672 --nAtSrc;
673 bGetPattern = true;
677 if (rInner == nIEnd) break;
678 if (bPositive) ++rInner; else --rInner;
680 if ( pNewPattern )
681 delete pNewPattern;
683 // Analyse
685 FillCmd eFillCmd;
686 FillDateCmd eDateCmd;
687 double nInc;
688 sal_uInt16 nMinDigits;
689 ScUserListData* pListData = NULL;
690 sal_uInt16 nListIndex;
691 if (bVertical)
692 FillAnalyse(static_cast<SCCOL>(nCol),nRow1,
693 static_cast<SCCOL>(nCol),nRow2, eFillCmd,eDateCmd,
694 nInc,nMinDigits, pListData,nListIndex);
695 else
696 FillAnalyse(nCol1,static_cast<SCROW>(nRow),
697 nCol2,static_cast<SCROW>(nRow), eFillCmd,eDateCmd,
698 nInc,nMinDigits, pListData,nListIndex);
700 if (bVertical)
701 aCol[nCol].ReserveSize(aCol[nCol].GetCellCount() + nFillCount);
703 if (pListData)
705 sal_uInt16 nListCount = pListData->GetSubCount();
706 if ( !bPositive )
708 // nListIndex of FillAnalyse points to the last entry -> adjust
709 sal_uLong nSub = nISrcStart - nISrcEnd;
710 for (sal_uLong i=0; i<nSub; i++)
712 if (nListIndex == 0) nListIndex = nListCount;
713 --nListIndex;
717 rInner = nIStart;
718 while (true) // #i53728# with "for (;;)" old solaris/x86 compiler mis-optimizes
720 if(!ColHidden(nCol) && !RowHidden(nRow))
722 if (bPositive)
724 ++nListIndex;
725 if (nListIndex >= nListCount) nListIndex = 0;
727 else
729 if (nListIndex == 0) nListIndex = nListCount;
730 --nListIndex;
732 aCol[nCol].Insert(static_cast<SCROW>(nRow), new ScStringCell(pListData->GetSubStr(nListIndex)));
735 if (rInner == nIEnd) break;
736 if (bPositive) ++rInner; else --rInner;
738 if(pProgress)
740 nProgress += nIMax - nIMin + 1;
741 pProgress->SetStateOnPercent( nProgress );
744 else if (eFillCmd == FILL_SIMPLE) // fill with pattern/sample
746 sal_uLong nSource = nISrcStart;
747 double nDelta;
748 if ( (nScFillModeMouseModifier & KEY_MOD1) )
749 nDelta = 0.0;
750 else if ( bPositive )
751 nDelta = 1.0;
752 else
753 nDelta = -1.0;
754 double nVal = 0.0;
755 sal_uLong nFormulaCounter = nActFormCnt;
756 bool bFirst = true;
757 bool bGetCell = true;
758 sal_uInt16 nCellDigits = 0;
759 short nHeadNoneTail = 0;
760 sal_Int32 nStringValue = 0;
761 String aValue;
762 ScBaseCell* pSrcCell = NULL;
763 CellType eCellType = CELLTYPE_NONE;
764 bool bIsOrdinalSuffix = false;
766 rInner = nIStart;
767 while (true) // #i53728# with "for (;;)" old solaris/x86 compiler mis-optimizes
769 if(!ColHidden(nCol) && !RowHidden(nRow))
771 if ( bGetCell )
773 if (bVertical) // rInner&:=nRow, rOuter&:=nCol
774 pSrcCell = aCol[nCol].GetCell( static_cast<SCROW>(nSource) );
775 else // rInner&:=nCol, rOuter&:=nRow
776 pSrcCell = aCol[nSource].GetCell( static_cast<SCROW>(nRow) );
777 bGetCell = false;
778 if ( pSrcCell )
780 eCellType = pSrcCell->GetCellType();
781 switch ( eCellType )
783 case CELLTYPE_VALUE:
784 nVal = ((ScValueCell*)pSrcCell)->GetValue();
785 break;
786 case CELLTYPE_STRING:
787 case CELLTYPE_EDIT:
788 if ( eCellType == CELLTYPE_STRING )
789 aValue = ((ScStringCell*)pSrcCell)->GetString();
790 else
791 aValue = ((ScEditCell*)pSrcCell)->GetString();
792 if ( !(nScFillModeMouseModifier & KEY_MOD1) && !bHasFiltered )
794 nCellDigits = 0; // look at each source cell individually
795 nHeadNoneTail = lcl_DecompValueString(
796 aValue, nStringValue, &nCellDigits );
798 bIsOrdinalSuffix = aValue.Equals(
799 ScGlobal::GetOrdinalSuffix( nStringValue));
801 break;
802 default:
804 // added to avoid warnings
808 else
809 eCellType = CELLTYPE_NONE;
812 switch (eCellType)
814 case CELLTYPE_VALUE:
815 aCol[nCol].Insert(static_cast<SCROW>(nRow), new ScValueCell(nVal + nDelta));
816 break;
817 case CELLTYPE_STRING:
818 case CELLTYPE_EDIT:
819 if ( nHeadNoneTail )
821 // #i48009# with the "nStringValue+(long)nDelta" expression within the
822 // lcl_ValueString calls, gcc 3.4.1 makes wrong optimizations (ok in 3.4.3),
823 // so nNextValue is now calculated ahead.
824 sal_Int32 nNextValue = nStringValue+(sal_Int32)nDelta;
826 OUString aStr;
827 if ( nHeadNoneTail < 0 )
829 aCol[nCol].Insert( static_cast<SCROW>(nRow),
830 lcl_getSuffixCell( pDocument,
831 nNextValue, nCellDigits, aValue,
832 eCellType, bIsOrdinalSuffix));
834 else
836 aStr = aValue + lcl_ValueString( nNextValue, nCellDigits );
837 aCol[nCol].Insert( static_cast<SCROW>(nRow),
838 new ScStringCell( aStr));
841 else
843 ScAddress aDestPos( static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), nTab );
844 switch ( eCellType )
846 case CELLTYPE_STRING:
847 case CELLTYPE_EDIT:
848 aCol[nCol].Insert( aDestPos.Row(), pSrcCell->Clone( *pDocument ) );
849 break;
850 default:
852 // added to avoid warnings
856 break;
857 case CELLTYPE_FORMULA :
858 FillFormula( nFormulaCounter, bFirst,
859 (ScFormulaCell*) pSrcCell,
860 static_cast<SCCOL>(nCol),
861 static_cast<SCROW>(nRow), (rInner == nIEnd) );
862 if (nFormulaCounter - nActFormCnt > nMaxFormCnt)
863 nMaxFormCnt = nFormulaCounter - nActFormCnt;
864 break;
865 default:
867 // added to avoid warnings
871 if (nSource==nISrcEnd)
873 if ( nSource != nISrcStart )
874 { // More than one source cell
875 nSource = nISrcStart;
876 bGetCell = true;
878 if ( !(nScFillModeMouseModifier & KEY_MOD1) )
880 if ( bPositive )
881 nDelta += 1.0;
882 else
883 nDelta -= 1.0;
885 nFormulaCounter = nActFormCnt;
886 bFirst = false;
888 else if (bPositive)
890 ++nSource;
891 bGetCell = true;
893 else
895 --nSource;
896 bGetCell = true;
900 if (rInner == nIEnd) break;
901 if (bPositive) ++rInner; else --rInner;
903 // Progress in inner loop only for expensive cells,
904 // and even then not individually for each one
906 ++nProgress;
907 if ( pProgress && (eCellType == CELLTYPE_FORMULA || eCellType == CELLTYPE_EDIT) )
908 pProgress->SetStateOnPercent( nProgress );
911 if (pProgress)
912 pProgress->SetStateOnPercent( nProgress );
914 else
916 if (!bPositive)
917 nInc = -nInc;
918 double nEndVal = (nInc>=0.0) ? MAXDOUBLE : -MAXDOUBLE;
919 if (bVertical)
920 FillSeries( static_cast<SCCOL>(nCol), nRow1,
921 static_cast<SCCOL>(nCol), nRow2, nFillCount, eFillDir,
922 eFillCmd, eDateCmd, nInc, nEndVal, nMinDigits, false,
923 pProgress );
924 else
925 FillSeries( nCol1, static_cast<SCROW>(nRow), nCol2,
926 static_cast<SCROW>(nRow), nFillCount, eFillDir,
927 eFillCmd, eDateCmd, nInc, nEndVal, nMinDigits, false,
928 pProgress );
929 if (pProgress)
930 nProgress = pProgress->GetState();
933 nActFormCnt += nMaxFormCnt;
937 String ScTable::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW nEndY )
939 String aValue;
941 SCCOL nCol1 = rSource.aStart.Col();
942 SCROW nRow1 = rSource.aStart.Row();
943 SCCOL nCol2 = rSource.aEnd.Col();
944 SCROW nRow2 = rSource.aEnd.Row();
945 bool bOk = true;
946 long nIndex = 0;
947 sal_uLong nSrcCount = 0;
948 FillDir eFillDir = FILL_TO_BOTTOM;
949 if ( nEndX == nCol2 && nEndY == nRow2 ) // empty
950 bOk = false;
951 else if ( nEndX == nCol2 ) // to up / down
953 nEndX = nCol2 = nCol1; // use only first column
954 nSrcCount = nRow2 - nRow1 + 1;
955 nIndex = ((long)nEndY) - nRow1; // can be negative
956 if ( nEndY >= nRow1 )
957 eFillDir = FILL_TO_BOTTOM;
958 else
959 eFillDir = FILL_TO_TOP;
961 else if ( nEndY == nRow2 ) // to left / right
963 nEndY = nRow2 = nRow1; // use only first row
964 nSrcCount = nCol2 - nCol1 + 1;
965 nIndex = ((long)nEndX) - nCol1; // can be negative
966 if ( nEndX >= nCol1 )
967 eFillDir = FILL_TO_RIGHT;
968 else
969 eFillDir = FILL_TO_LEFT;
971 else // direction not clear
972 bOk = false;
974 if ( bOk )
976 FillCmd eFillCmd;
977 FillDateCmd eDateCmd;
978 double nInc;
979 sal_uInt16 nMinDigits;
980 ScUserListData* pListData = NULL;
981 sal_uInt16 nListIndex;
983 FillAnalyse(nCol1,nRow1, nCol2,nRow2, eFillCmd,eDateCmd, nInc,nMinDigits, pListData,nListIndex);
985 if ( pListData ) // user defined list
987 sal_uInt16 nListCount = pListData->GetSubCount();
988 if ( nListCount )
990 sal_uLong nSub = nSrcCount - 1; // nListIndex is from last source entry
991 while ( nIndex < sal::static_int_cast<long>(nSub) )
992 nIndex += nListCount;
993 sal_uLong nPos = ( nListIndex + nIndex - nSub ) % nListCount;
994 aValue = pListData->GetSubStr(sal::static_int_cast<sal_uInt16>(nPos));
997 else if ( eFillCmd == FILL_SIMPLE ) // fill with pattern/sample
999 if ((eFillDir == FILL_TO_BOTTOM)||(eFillDir == FILL_TO_TOP))
1001 long nBegin = 0;
1002 long nEnd = 0;
1003 if (nEndY > nRow1)
1005 nBegin = nRow2+1;
1006 nEnd = nEndY;
1008 else
1010 nBegin = nEndY;
1011 nEnd = nRow1 -1;
1014 long nNonFiltered = CountNonFilteredRows(nBegin, nEnd);
1015 long nFiltered = nEnd + 1 - nBegin - nNonFiltered;
1017 if (nIndex > 0)
1018 nIndex = nIndex - nFiltered;
1019 else
1020 nIndex = nIndex + nFiltered;
1023 long nPosIndex = nIndex;
1024 while ( nPosIndex < 0 )
1025 nPosIndex += nSrcCount;
1026 sal_uLong nPos = nPosIndex % nSrcCount;
1027 SCCOL nSrcX = nCol1;
1028 SCROW nSrcY = nRow1;
1029 if ( eFillDir == FILL_TO_TOP || eFillDir == FILL_TO_BOTTOM )
1030 nSrcY = sal::static_int_cast<SCROW>( nSrcY + static_cast<SCROW>(nPos) );
1031 else
1032 nSrcX = sal::static_int_cast<SCCOL>( nSrcX + static_cast<SCCOL>(nPos) );
1034 ScBaseCell* pCell = GetCell( nSrcX, nSrcY );
1035 if ( pCell )
1037 sal_Int32 nDelta;
1038 if (nIndex >= 0)
1039 nDelta = nIndex / nSrcCount;
1040 else
1041 nDelta = ( nIndex - nSrcCount + 1 ) / nSrcCount; // -1 -> -1
1043 CellType eType = pCell->GetCellType();
1044 switch ( eType )
1046 case CELLTYPE_STRING:
1047 case CELLTYPE_EDIT:
1049 if ( eType == CELLTYPE_STRING )
1050 aValue = ((ScStringCell*)pCell)->GetString();
1051 else
1052 aValue = ((ScEditCell*)pCell)->GetString();
1053 if ( !(nScFillModeMouseModifier & KEY_MOD1) )
1055 sal_Int32 nVal;
1056 sal_uInt16 nCellDigits = 0; // look at each source cell individually
1057 short nFlag = lcl_DecompValueString( aValue, nVal, &nCellDigits );
1058 if ( nFlag < 0 )
1060 if (aValue.Equals( ScGlobal::GetOrdinalSuffix( nVal)))
1061 aValue = ScGlobal::GetOrdinalSuffix( nVal + nDelta);
1063 aValue.Insert( lcl_ValueString( nVal + nDelta, nCellDigits ), 0 );
1065 else if ( nFlag > 0 )
1066 aValue += lcl_ValueString( nVal + nDelta, nCellDigits );
1069 break;
1070 case CELLTYPE_VALUE:
1072 // overflow is possible...
1073 double nVal = ((ScValueCell*)pCell)->GetValue();
1074 if ( !(nScFillModeMouseModifier & KEY_MOD1) )
1075 nVal += (double) nDelta;
1077 Color* pColor;
1078 sal_uLong nNumFmt = GetNumberFormat( nSrcX, nSrcY );
1079 pDocument->GetFormatTable()->
1080 GetOutputString( nVal, nNumFmt, aValue, &pColor );
1082 break;
1083 // not for formulas
1084 default:
1086 // added to avoid warnings
1091 else if ( eFillCmd == FILL_LINEAR || eFillCmd == FILL_DATE ) // values
1093 bool bValueOk;
1094 double nStart;
1095 sal_Int32 nVal = 0;
1096 short nHeadNoneTail = 0;
1097 ScBaseCell* pCell = GetCell( nCol1, nRow1 );
1098 if ( pCell )
1100 CellType eType = pCell->GetCellType();
1101 switch ( eType )
1103 case CELLTYPE_STRING:
1104 case CELLTYPE_EDIT:
1106 if ( eType == CELLTYPE_STRING )
1107 aValue = ((ScStringCell*)pCell)->GetString();
1108 else
1109 aValue = ((ScEditCell*)pCell)->GetString();
1110 nHeadNoneTail = lcl_DecompValueString( aValue, nVal );
1111 if ( nHeadNoneTail )
1112 nStart = (double)nVal;
1113 else
1114 nStart = 0.0;
1116 break;
1117 case CELLTYPE_VALUE:
1118 nStart = ((ScValueCell*)pCell)->GetValue();
1119 break;
1120 case CELLTYPE_FORMULA:
1121 nStart = ((ScFormulaCell*)pCell)->GetValue();
1122 break;
1123 default:
1124 nStart = 0.0;
1127 else
1128 nStart = 0.0;
1129 if ( eFillCmd == FILL_LINEAR )
1131 double nAdd = nInc;
1132 bValueOk = ( SubTotal::SafeMult( nAdd, (double) nIndex ) &&
1133 SubTotal::SafePlus( nStart, nAdd ) );
1135 else // date
1137 bValueOk = true;
1138 sal_uInt16 nDayOfMonth = 0;
1139 if ( nIndex < 0 )
1141 nIndex = -nIndex;
1142 nInc = -nInc;
1144 for (long i=0; i<nIndex; i++)
1145 IncDate( nStart, nDayOfMonth, nInc, eDateCmd );
1148 if (bValueOk)
1150 if ( nHeadNoneTail )
1152 if ( nHeadNoneTail < 0 )
1154 if (aValue.Equals( ScGlobal::GetOrdinalSuffix( nVal)))
1155 aValue = ScGlobal::GetOrdinalSuffix( (sal_Int32)nStart );
1157 aValue.Insert( lcl_ValueString( (sal_Int32)nStart, nMinDigits ), 0 );
1159 else
1160 aValue += lcl_ValueString( (sal_Int32)nStart, nMinDigits );
1162 else
1164 //! Zahlformat je nach Index holen?
1165 Color* pColor;
1166 sal_uLong nNumFmt = GetNumberFormat( nCol1, nRow1 );
1167 pDocument->GetFormatTable()->
1168 GetOutputString( nStart, nNumFmt, aValue, &pColor );
1172 else
1174 OSL_FAIL("GetAutoFillPreview: invalid mode");
1178 return aValue;
1181 void ScTable::IncDate(double& rVal, sal_uInt16& nDayOfMonth, double nStep, FillDateCmd eCmd)
1183 if (eCmd == FILL_DAY)
1185 rVal += nStep;
1186 return;
1189 // class Date limits
1190 const sal_uInt16 nMinYear = 1583;
1191 const sal_uInt16 nMaxYear = 9956;
1193 long nInc = (long) nStep; // upper/lower limits ?
1194 Date aNullDate = *pDocument->GetFormatTable()->GetNullDate();
1195 Date aDate = aNullDate;
1196 aDate += (long)rVal;
1197 switch (eCmd)
1199 case FILL_WEEKDAY:
1201 aDate += nInc;
1202 DayOfWeek eWeekDay = aDate.GetDayOfWeek();
1203 if (nInc >= 0)
1205 if (eWeekDay == SATURDAY)
1206 aDate += 2;
1207 else if (eWeekDay == SUNDAY)
1208 aDate += 1;
1210 else
1212 if (eWeekDay == SATURDAY)
1213 aDate -= 1;
1214 else if (eWeekDay == SUNDAY)
1215 aDate -= 2;
1218 break;
1219 case FILL_MONTH:
1221 if ( nDayOfMonth == 0 )
1222 nDayOfMonth = aDate.GetDay(); // init
1223 long nMonth = aDate.GetMonth();
1224 long nYear = aDate.GetYear();
1226 nMonth += nInc;
1228 if (nInc >= 0)
1230 if (nMonth > 12)
1232 long nYAdd = (nMonth-1) / 12;
1233 nMonth -= nYAdd * 12;
1234 nYear += nYAdd;
1237 else
1239 if (nMonth < 1)
1241 long nYAdd = 1 - nMonth / 12; // positive
1242 nMonth += nYAdd * 12;
1243 nYear -= nYAdd;
1247 if ( nYear < nMinYear )
1248 aDate = Date( 1,1, nMinYear );
1249 else if ( nYear > nMaxYear )
1250 aDate = Date( 31,12, nMaxYear );
1251 else
1253 aDate.SetMonth((sal_uInt16) nMonth);
1254 aDate.SetYear((sal_uInt16) nYear);
1255 aDate.SetDay( std::min( Date::GetDaysInMonth( nMonth, nYear), nDayOfMonth ) );
1258 break;
1259 case FILL_YEAR:
1261 long nYear = aDate.GetYear();
1262 nYear += nInc;
1263 if ( nYear < nMinYear )
1264 aDate = Date( 1,1, nMinYear );
1265 else if ( nYear > nMaxYear )
1266 aDate = Date( 31,12, nMaxYear );
1267 else
1268 aDate.SetYear((sal_uInt16) nYear);
1270 break;
1271 default:
1273 // added to avoid warnings
1277 rVal = aDate - aNullDate;
1280 namespace
1283 bool HiddenRowColumn(sal_uLong nRowColumn, bool bVertical, ScTable* pTable)
1285 if(bVertical)
1287 return pTable->RowHidden(static_cast<SCROW>(nRowColumn));
1289 else
1291 return pTable->ColHidden(static_cast<SCCOL>(nRowColumn));
1297 void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
1298 sal_uLong nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd,
1299 double nStepValue, double nMaxValue, sal_uInt16 nArgMinDigits,
1300 bool bAttribs, ScProgress* pProgress )
1303 // Detect direction
1306 bool bVertical = (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_TOP);
1307 bool bPositive = (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_RIGHT);
1309 sal_uLong nCol = 0;
1310 sal_uLong nRow = 0;
1311 sal_uLong& rInner = bVertical ? nRow : nCol; // loop variables
1312 sal_uLong& rOuter = bVertical ? nCol : nRow;
1313 sal_uLong nOStart;
1314 sal_uLong nOEnd;
1315 sal_uLong nIStart;
1316 sal_uLong nIEnd;
1317 sal_uLong nISource;
1318 ScRange aFillRange;
1320 if (bVertical)
1322 nFillCount += (nRow2 - nRow1);
1323 if (nFillCount == 0)
1324 return;
1325 nOStart = nCol1;
1326 nOEnd = nCol2;
1327 if (bPositive)
1329 nISource = nRow1;
1330 nIStart = nRow1 + 1;
1331 nIEnd = nRow1 + nFillCount;
1332 aFillRange = ScRange(nCol1, nRow1 + 1, nTab, nCol2, nRow1 + nFillCount, nTab);
1334 else
1336 nISource = nRow2;
1337 nIStart = nRow2 - 1;
1338 nIEnd = nRow2 - nFillCount;
1339 aFillRange = ScRange(nCol1, nRow2 -1, nTab, nCol2, nRow2 - nFillCount, nTab);
1342 else
1344 nFillCount += (nCol2 - nCol1);
1345 if (nFillCount == 0)
1346 return;
1347 nOStart = nRow1;
1348 nOEnd = nRow2;
1349 if (bPositive)
1351 nISource = nCol1;
1352 nIStart = nCol1 + 1;
1353 nIEnd = nCol1 + nFillCount;
1354 aFillRange = ScRange(nCol1 + 1, nRow1, nTab, nCol1 + nFillCount, nRow2, nTab);
1356 else
1358 nISource = nCol2;
1359 nIStart = nCol2 - 1;
1360 nIEnd = nCol2 - nFillCount;
1361 aFillRange = ScRange(nCol2 - 1, nRow1, nTab, nCol2 - nFillCount, nRow2, nTab);
1365 sal_uLong nIMin = nIStart;
1366 sal_uLong nIMax = nIEnd;
1367 PutInOrder(nIMin,nIMax);
1368 sal_uInt16 nDel = bAttribs ? IDF_AUTOFILL : (IDF_AUTOFILL & IDF_CONTENTS);
1370 bool bIsFiltered = IsDataFiltered(aFillRange);
1371 if (!bIsFiltered)
1373 if (bVertical)
1374 DeleteArea(nCol1, static_cast<SCROW>(nIMin), nCol2, static_cast<SCROW>(nIMax), nDel);
1375 else
1376 DeleteArea(static_cast<SCCOL>(nIMin), nRow1, static_cast<SCCOL>(nIMax), nRow2, nDel);
1379 sal_uLong nProgress = 0;
1380 if (pProgress)
1381 nProgress = pProgress->GetState();
1384 // execute
1387 sal_uLong nActFormCnt = 0;
1388 for (rOuter = nOStart; rOuter <= nOEnd; rOuter++)
1390 rInner = nISource;
1391 ScBaseCell* pSrcCell = aCol[nCol].GetCell(static_cast<SCROW>(nRow));
1393 if (bVertical && bAttribs)
1394 aCol[nCol].ReserveSize(aCol[nCol].GetCellCount() + nFillCount);
1396 if (bAttribs)
1398 const ScPatternAttr* pSrcPattern = aCol[nCol].GetPattern(static_cast<SCROW>(nRow));
1400 const ScCondFormatItem& rCondFormatItem = static_cast<const ScCondFormatItem&>(pSrcPattern->GetItem(ATTR_CONDITIONAL));
1401 const std::vector<sal_uInt32>& rCondFormatIndex = rCondFormatItem.GetCondFormatData();
1403 if (bVertical)
1405 // if not filtered use the faster method
1406 // hidden cols/rows should be skiped
1407 if(!bIsFiltered)
1409 aCol[nCol].SetPatternArea( static_cast<SCROW>(nIMin),
1410 static_cast<SCROW>(nIMax), *pSrcPattern, true );
1412 for(std::vector<sal_uInt32>::const_iterator itr = rCondFormatIndex.begin(), itrEnd = rCondFormatIndex.end();
1413 itr != itrEnd; ++itr)
1415 ScConditionalFormat* pCondFormat = mpCondFormatList->GetFormat(*itr);
1416 ScRangeList aRange = pCondFormat->GetRange();
1417 aRange.Join(ScRange(nCol, nIMin, nTab, nCol, nIMax, nTab));
1418 pCondFormat->AddRange(aRange);
1421 else
1423 for(SCROW nAtRow = static_cast<SCROW>(nIMin); nAtRow <= static_cast<SCROW>(nIMax); ++nAtRow)
1425 if(!RowHidden(nAtRow))
1427 aCol[nCol].SetPatternArea( static_cast<SCROW>(nAtRow),
1428 static_cast<SCROW>(nAtRow), *pSrcPattern, true);
1429 for(std::vector<sal_uInt32>::const_iterator itr = rCondFormatIndex.begin(), itrEnd = rCondFormatIndex.end();
1430 itr != itrEnd; ++itr)
1432 ScConditionalFormat* pCondFormat = mpCondFormatList->GetFormat(*itr);
1433 ScRangeList aRange = pCondFormat->GetRange();
1434 aRange.Join(ScRange(nCol, nAtRow, nTab, nCol, nAtRow, nTab));
1435 pCondFormat->AddRange(aRange);
1442 else
1443 for (SCCOL nAtCol = static_cast<SCCOL>(nIMin); nAtCol <= sal::static_int_cast<SCCOL>(nIMax); nAtCol++)
1444 if(!ColHidden(nAtCol))
1446 aCol[nAtCol].SetPattern(static_cast<SCROW>(nRow), *pSrcPattern, true);
1447 for(std::vector<sal_uInt32>::const_iterator itr = rCondFormatIndex.begin(), itrEnd = rCondFormatIndex.end();
1448 itr != itrEnd; ++itr)
1450 ScConditionalFormat* pCondFormat = mpCondFormatList->GetFormat(*itr);
1451 ScRangeList aRange = pCondFormat->GetRange();
1452 aRange.Join(ScRange(nAtCol, static_cast<SCROW>(nRow), nTab, nAtCol, static_cast<SCROW>(nRow), nTab));
1453 pCondFormat->AddRange(aRange);
1458 if (pSrcCell)
1460 CellType eCellType = pSrcCell->GetCellType();
1462 if (eFillCmd == FILL_SIMPLE) // copy
1464 if (eCellType == CELLTYPE_FORMULA)
1466 bool bFirst = true;
1467 for (rInner = nIMin; rInner <= nIMax; rInner++)
1469 if(HiddenRowColumn(rInner, bVertical, this))
1470 continue;
1471 sal_uLong nInd = nActFormCnt;
1472 FillFormula(nInd, bFirst, (ScFormulaCell*)pSrcCell,
1473 static_cast<SCCOL>(nCol), nRow, (rInner == nIEnd) );
1474 bFirst = false;
1475 if(pProgress)
1476 pProgress->SetStateOnPercent( ++nProgress );
1479 else
1481 for (rInner = nIMin; rInner <= nIMax; rInner++)
1483 if(HiddenRowColumn(rInner, bVertical, this))
1484 continue;
1485 ScAddress aDestPos( static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), nTab );
1486 aCol[nCol].Insert( aDestPos.Row(), pSrcCell->Clone( *pDocument ) );
1488 nProgress += nIMax - nIMin + 1;
1489 if(pProgress)
1490 pProgress->SetStateOnPercent( nProgress );
1493 else if (eCellType == CELLTYPE_VALUE || eCellType == CELLTYPE_FORMULA)
1495 double nStartVal;
1496 if (eCellType == CELLTYPE_VALUE)
1497 nStartVal = ((ScValueCell*)pSrcCell)->GetValue();
1498 else
1499 nStartVal = ((ScFormulaCell*)pSrcCell)->GetValue();
1500 double nVal = nStartVal;
1501 long nIndex = 0;
1503 bool bError = false;
1504 bool bOverflow = false;
1506 sal_uInt16 nDayOfMonth = 0;
1507 rInner = nIStart;
1508 while (true) // #i53728# with "for (;;)" old solaris/x86 compiler mis-optimizes
1510 if(!ColHidden(nCol) && !RowHidden(nRow))
1512 if (!bError && !bOverflow)
1514 switch (eFillCmd)
1516 case FILL_LINEAR:
1518 // use multiplication instead of repeated addition
1519 // to avoid accumulating rounding errors
1520 nVal = nStartVal;
1521 double nAdd = nStepValue;
1522 if ( !SubTotal::SafeMult( nAdd, (double) ++nIndex ) ||
1523 !SubTotal::SafePlus( nVal, nAdd ) )
1524 bError = true;
1526 break;
1527 case FILL_GROWTH:
1528 if (!SubTotal::SafeMult(nVal, nStepValue))
1529 bError = true;
1530 break;
1531 case FILL_DATE:
1532 if (fabs(nVal) > _D_MAX_LONG_)
1533 bError = true;
1534 else
1535 IncDate(nVal, nDayOfMonth, nStepValue, eFillDateCmd);
1536 break;
1537 default:
1539 // added to avoid warnings
1543 if (nStepValue >= 0)
1545 if (nVal > nMaxValue) // target value reached ?
1547 nVal = nMaxValue;
1548 bOverflow = true;
1551 else
1553 if (nVal < nMaxValue)
1555 nVal = nMaxValue;
1556 bOverflow = true;
1561 if (bError)
1562 aCol[nCol].SetError(static_cast<SCROW>(nRow), errNoValue);
1563 else if (bOverflow)
1564 aCol[nCol].SetError(static_cast<SCROW>(nRow), errIllegalFPOperation);
1565 else
1566 aCol[nCol].SetValue(static_cast<SCROW>(nRow), nVal);
1569 if (rInner == nIEnd)
1570 break;
1571 if (bPositive)
1573 ++rInner;
1575 else
1577 --rInner;
1580 nProgress += nIMax - nIMin + 1;
1581 if(pProgress)
1582 pProgress->SetStateOnPercent( nProgress );
1584 else if (eCellType == CELLTYPE_STRING || eCellType == CELLTYPE_EDIT)
1586 if ( nStepValue >= 0 )
1588 if ( nMaxValue >= (double)LONG_MAX )
1589 nMaxValue = (double)LONG_MAX - 1;
1591 else
1593 if ( nMaxValue <= (double)LONG_MIN )
1594 nMaxValue = (double)LONG_MIN + 1;
1596 String aValue;
1597 if (eCellType == CELLTYPE_STRING)
1598 aValue = ((ScStringCell*)pSrcCell)->GetString();
1599 else
1600 aValue = ((ScEditCell*)pSrcCell)->GetString();
1601 sal_Int32 nStringValue;
1602 sal_uInt16 nMinDigits = nArgMinDigits;
1603 short nHeadNoneTail = lcl_DecompValueString( aValue, nStringValue, &nMinDigits );
1604 if ( nHeadNoneTail )
1606 double nStartVal = (double)nStringValue;
1607 double nVal = nStartVal;
1608 long nIndex = 0;
1609 bool bError = false;
1610 bool bOverflow = false;
1612 bool bIsOrdinalSuffix = aValue.Equals( ScGlobal::GetOrdinalSuffix(
1613 (sal_Int32)nStartVal));
1615 rInner = nIStart;
1616 while (true) // #i53728# with "for (;;)" old solaris/x86 compiler mis-optimizes
1618 if(!ColHidden(nCol) && !RowHidden(nRow))
1620 if (!bError && !bOverflow)
1622 switch (eFillCmd)
1624 case FILL_LINEAR:
1626 // use multiplication instead of repeated addition
1627 // to avoid accumulating rounding errors
1628 nVal = nStartVal;
1629 double nAdd = nStepValue;
1630 if ( !SubTotal::SafeMult( nAdd, (double) ++nIndex ) ||
1631 !SubTotal::SafePlus( nVal, nAdd ) )
1632 bError = true;
1634 break;
1635 case FILL_GROWTH:
1636 if (!SubTotal::SafeMult(nVal, nStepValue))
1637 bError = true;
1638 break;
1639 default:
1641 // added to avoid warnings
1645 if (nStepValue >= 0)
1647 if (nVal > nMaxValue) // target value reached ?
1649 nVal = nMaxValue;
1650 bOverflow = true;
1653 else
1655 if (nVal < nMaxValue)
1657 nVal = nMaxValue;
1658 bOverflow = true;
1663 if (bError)
1664 aCol[nCol].SetError(static_cast<SCROW>(nRow), errNoValue);
1665 else if (bOverflow)
1666 aCol[nCol].SetError(static_cast<SCROW>(nRow), errIllegalFPOperation);
1667 else
1669 nStringValue = (sal_Int32)nVal;
1670 String aStr;
1671 if ( nHeadNoneTail < 0 )
1673 aCol[nCol].Insert( static_cast<SCROW>(nRow),
1674 lcl_getSuffixCell( pDocument,
1675 nStringValue, nMinDigits, aValue,
1676 eCellType, bIsOrdinalSuffix ));
1678 else
1680 aStr = aValue;
1681 aStr += lcl_ValueString( nStringValue, nMinDigits );
1682 ScStringCell* pCell = new ScStringCell( aStr );
1683 aCol[nCol].Insert( static_cast<SCROW>(nRow), pCell );
1688 if (rInner == nIEnd) break;
1689 if (bPositive) ++rInner; else --rInner;
1692 if(pProgress)
1694 nProgress += nIMax - nIMin + 1;
1695 pProgress->SetStateOnPercent( nProgress );
1699 else if(pProgress)
1701 nProgress += nIMax - nIMin + 1;
1702 pProgress->SetStateOnPercent( nProgress );
1704 ++nActFormCnt;
1708 void ScTable::Fill( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
1709 sal_uLong nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd,
1710 double nStepValue, double nMaxValue, ScProgress* pProgress)
1712 if (eFillCmd == FILL_AUTO)
1713 FillAuto(nCol1, nRow1, nCol2, nRow2, nFillCount, eFillDir, pProgress);
1714 else
1715 FillSeries(nCol1, nRow1, nCol2, nRow2, nFillCount, eFillDir,
1716 eFillCmd, eFillDateCmd, nStepValue, nMaxValue, 0, true, pProgress);
1720 void ScTable::AutoFormatArea(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
1721 const ScPatternAttr& rAttr, sal_uInt16 nFormatNo)
1723 ScAutoFormat& rFormat = *ScGlobal::GetOrCreateAutoFormat();
1724 ScAutoFormatData* pData = rFormat.findByIndex(nFormatNo);
1725 if (pData)
1727 ApplyPatternArea(nStartCol, nStartRow, nEndCol, nEndRow, rAttr);
1731 void ScTable::AutoFormat( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
1732 sal_uInt16 nFormatNo )
1734 if (ValidColRow(nStartCol, nStartRow) && ValidColRow(nEndCol, nEndRow))
1736 ScAutoFormat& rFormat = *ScGlobal::GetOrCreateAutoFormat();
1737 ScAutoFormatData* pData = rFormat.findByIndex(nFormatNo);
1738 if (pData)
1740 ScPatternAttr* pPatternAttrs[16];
1741 for (sal_uInt8 i = 0; i < 16; ++i)
1743 pPatternAttrs[i] = new ScPatternAttr(pDocument->GetPool());
1744 pData->FillToItemSet(i, pPatternAttrs[i]->GetItemSet(), *pDocument);
1747 SCCOL nCol = nStartCol;
1748 SCROW nRow = nStartRow;
1749 sal_uInt16 nIndex = 0;
1750 // Left top corner
1751 AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
1752 // Left column
1753 if (pData->IsEqualData(4, 8))
1754 AutoFormatArea(nStartCol, nStartRow + 1, nStartCol, nEndRow - 1, *pPatternAttrs[4], nFormatNo);
1755 else
1757 nIndex = 4;
1758 for (nRow = nStartRow + 1; nRow < nEndRow; nRow++)
1760 AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
1761 if (nIndex == 4)
1762 nIndex = 8;
1763 else
1764 nIndex = 4;
1767 // Left bottom corner
1768 nRow = nEndRow;
1769 nIndex = 12;
1770 AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
1771 // Right top corner
1772 nCol = nEndCol;
1773 nRow = nStartRow;
1774 nIndex = 3;
1775 AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
1776 // Right column
1777 if (pData->IsEqualData(7, 11))
1778 AutoFormatArea(nEndCol, nStartRow + 1, nEndCol, nEndRow - 1, *pPatternAttrs[7], nFormatNo);
1779 else
1781 nIndex = 7;
1782 for (nRow = nStartRow + 1; nRow < nEndRow; nRow++)
1784 AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
1785 if (nIndex == 7)
1786 nIndex = 11;
1787 else
1788 nIndex = 7;
1791 // Right bottom corner
1792 nRow = nEndRow;
1793 nIndex = 15;
1794 AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
1795 nRow = nStartRow;
1796 nIndex = 1;
1797 for (nCol = nStartCol + 1; nCol < nEndCol; nCol++)
1799 AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
1800 if (nIndex == 1)
1801 nIndex = 2;
1802 else
1803 nIndex = 1;
1805 // Bottom row
1806 nRow = nEndRow;
1807 nIndex = 13;
1808 for (nCol = nStartCol + 1; nCol < nEndCol; nCol++)
1810 AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
1811 if (nIndex == 13)
1812 nIndex = 14;
1813 else
1814 nIndex = 13;
1816 // Boddy
1817 if ((pData->IsEqualData(5, 6)) && (pData->IsEqualData(9, 10)) && (pData->IsEqualData(5, 9)))
1818 AutoFormatArea(nStartCol + 1, nStartRow + 1, nEndCol-1, nEndRow - 1, *pPatternAttrs[5], nFormatNo);
1819 else
1821 if ((pData->IsEqualData(5, 9)) && (pData->IsEqualData(6, 10)))
1823 nIndex = 5;
1824 for (nCol = nStartCol + 1; nCol < nEndCol; nCol++)
1826 AutoFormatArea(nCol, nStartRow + 1, nCol, nEndRow - 1, *pPatternAttrs[nIndex], nFormatNo);
1827 if (nIndex == 5)
1828 nIndex = 6;
1829 else
1830 nIndex = 5;
1833 else
1835 nIndex = 5;
1836 for (nCol = nStartCol + 1; nCol < nEndCol; nCol++)
1838 for (nRow = nStartRow + 1; nRow < nEndRow; nRow++)
1840 AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
1841 if ((nIndex == 5) || (nIndex == 9))
1843 if (nIndex == 5)
1844 nIndex = 9;
1845 else
1846 nIndex = 5;
1848 else
1850 if (nIndex == 6)
1851 nIndex = 10;
1852 else
1853 nIndex = 6;
1855 } // for nRow
1856 if ((nIndex == 5) || (nIndex == 9))
1857 nIndex = 6;
1858 else
1859 nIndex = 5;
1860 } // for nCol
1861 } // if not equal Column
1862 } // if not all equal
1864 for (sal_uInt8 j = 0; j < 16; ++j)
1865 delete pPatternAttrs[j];
1866 } // if AutoFormatData != NULL
1867 } // if ValidColRow
1870 void ScTable::GetAutoFormatAttr(SCCOL nCol, SCROW nRow, sal_uInt16 nIndex, ScAutoFormatData& rData)
1872 sal_uInt32 nFormatIndex = GetNumberFormat( nCol, nRow );
1873 ScNumFormatAbbrev aNumFormat( nFormatIndex, *pDocument->GetFormatTable() );
1874 rData.GetFromItemSet( nIndex, GetPattern( nCol, nRow )->GetItemSet(), aNumFormat );
1877 #define LF_LEFT 1
1878 #define LF_TOP 2
1879 #define LF_RIGHT 4
1880 #define LF_BOTTOM 8
1881 #define LF_ALL (LF_LEFT | LF_TOP | LF_RIGHT | LF_BOTTOM)
1883 void ScTable::GetAutoFormatFrame(SCCOL nCol, SCROW nRow, sal_uInt16 nFlags, sal_uInt16 nIndex, ScAutoFormatData& rData)
1885 const SvxBoxItem* pTheBox = (SvxBoxItem*)GetAttr(nCol, nRow, ATTR_BORDER);
1886 const SvxBoxItem* pLeftBox = (SvxBoxItem*)GetAttr(nCol - 1, nRow, ATTR_BORDER);
1887 const SvxBoxItem* pTopBox = (SvxBoxItem*)GetAttr(nCol, nRow - 1, ATTR_BORDER);
1888 const SvxBoxItem* pRightBox = (SvxBoxItem*)GetAttr(nCol + 1, nRow, ATTR_BORDER);
1889 const SvxBoxItem* pBottomBox = (SvxBoxItem*)GetAttr(nCol, nRow + 1, ATTR_BORDER);
1891 SvxBoxItem aBox( ATTR_BORDER );
1892 if (nFlags & LF_LEFT)
1894 if (pLeftBox)
1896 if (ScHasPriority(pTheBox->GetLeft(), pLeftBox->GetRight()))
1897 aBox.SetLine(pTheBox->GetLeft(), BOX_LINE_LEFT);
1898 else
1899 aBox.SetLine(pLeftBox->GetRight(), BOX_LINE_LEFT);
1901 else
1902 aBox.SetLine(pTheBox->GetLeft(), BOX_LINE_LEFT);
1904 if (nFlags & LF_TOP)
1906 if (pTopBox)
1908 if (ScHasPriority(pTheBox->GetTop(), pTopBox->GetBottom()))
1909 aBox.SetLine(pTheBox->GetTop(), BOX_LINE_TOP);
1910 else
1911 aBox.SetLine(pTopBox->GetBottom(), BOX_LINE_TOP);
1913 else
1914 aBox.SetLine(pTheBox->GetTop(), BOX_LINE_TOP);
1916 if (nFlags & LF_RIGHT)
1918 if (pRightBox)
1920 if (ScHasPriority(pTheBox->GetRight(), pRightBox->GetLeft()))
1921 aBox.SetLine(pTheBox->GetRight(), BOX_LINE_RIGHT);
1922 else
1923 aBox.SetLine(pRightBox->GetLeft(), BOX_LINE_RIGHT);
1925 else
1926 aBox.SetLine(pTheBox->GetRight(), BOX_LINE_RIGHT);
1928 if (nFlags & LF_BOTTOM)
1930 if (pBottomBox)
1932 if (ScHasPriority(pTheBox->GetBottom(), pBottomBox->GetTop()))
1933 aBox.SetLine(pTheBox->GetBottom(), BOX_LINE_BOTTOM);
1934 else
1935 aBox.SetLine(pBottomBox->GetTop(), BOX_LINE_BOTTOM);
1937 else
1938 aBox.SetLine(pTheBox->GetBottom(), BOX_LINE_BOTTOM);
1940 rData.PutItem( nIndex, aBox );
1943 void ScTable::GetAutoFormatData(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, ScAutoFormatData& rData)
1945 if (ValidColRow(nStartCol, nStartRow) && ValidColRow(nEndCol, nEndRow))
1947 if ((nEndCol - nStartCol >= 3) && (nEndRow - nStartRow >= 3))
1949 // Left top corner
1950 GetAutoFormatAttr(nStartCol, nStartRow, 0, rData);
1951 GetAutoFormatFrame(nStartCol, nStartRow, LF_ALL, 0, rData);
1952 // Left column
1953 GetAutoFormatAttr(nStartCol, nStartRow + 1, 4, rData);
1954 GetAutoFormatAttr(nStartCol, nStartRow + 2, 8, rData);
1955 GetAutoFormatFrame(nStartCol, nStartRow + 1, LF_LEFT | LF_RIGHT | LF_BOTTOM, 4, rData);
1956 if (nEndRow - nStartRow >= 4)
1957 GetAutoFormatFrame(nStartCol, nStartRow + 2, LF_LEFT | LF_RIGHT | LF_BOTTOM, 8, rData);
1958 else
1959 rData.CopyItem( 8, 4, ATTR_BORDER );
1960 // Left bottom corner
1961 GetAutoFormatAttr(nStartCol, nEndRow, 12, rData);
1962 GetAutoFormatFrame(nStartCol, nEndRow, LF_ALL, 12, rData);
1963 // Right top corner
1964 GetAutoFormatAttr(nEndCol, nStartRow, 3, rData);
1965 GetAutoFormatFrame(nEndCol, nStartRow, LF_ALL, 3, rData);
1966 // Right column
1967 GetAutoFormatAttr(nEndCol, nStartRow + 1, 7, rData);
1968 GetAutoFormatAttr(nEndCol, nStartRow + 2, 11, rData);
1969 GetAutoFormatFrame(nEndCol, nStartRow + 1, LF_LEFT | LF_RIGHT | LF_BOTTOM, 7, rData);
1970 if (nEndRow - nStartRow >= 4)
1971 GetAutoFormatFrame(nEndCol, nStartRow + 2, LF_LEFT | LF_RIGHT | LF_BOTTOM, 11, rData);
1972 else
1973 rData.CopyItem( 11, 7, ATTR_BORDER );
1974 // Right bottom corner
1975 GetAutoFormatAttr(nEndCol, nEndRow, 15, rData);
1976 GetAutoFormatFrame(nEndCol, nEndRow, LF_ALL, 15, rData);
1977 // Top row
1978 GetAutoFormatAttr(nStartCol + 1, nStartRow, 1, rData);
1979 GetAutoFormatAttr(nStartCol + 2, nStartRow, 2, rData);
1980 GetAutoFormatFrame(nStartCol + 1, nStartRow, LF_TOP | LF_BOTTOM | LF_RIGHT, 1, rData);
1981 if (nEndCol - nStartCol >= 4)
1982 GetAutoFormatFrame(nStartCol + 2, nStartRow, LF_TOP | LF_BOTTOM | LF_RIGHT, 2, rData);
1983 else
1984 rData.CopyItem( 2, 1, ATTR_BORDER );
1985 // Bottom row
1986 GetAutoFormatAttr(nStartCol + 1, nEndRow, 13, rData);
1987 GetAutoFormatAttr(nStartCol + 2, nEndRow, 14, rData);
1988 GetAutoFormatFrame(nStartCol + 1, nEndRow, LF_TOP | LF_BOTTOM | LF_RIGHT, 13, rData);
1989 if (nEndCol - nStartCol >= 4)
1990 GetAutoFormatFrame(nStartCol + 2, nEndRow, LF_TOP | LF_BOTTOM | LF_RIGHT, 14, rData);
1991 else
1992 rData.CopyItem( 14, 13, ATTR_BORDER );
1993 // Body
1994 GetAutoFormatAttr(nStartCol + 1, nStartRow + 1, 5, rData);
1995 GetAutoFormatAttr(nStartCol + 2, nStartRow + 1, 6, rData);
1996 GetAutoFormatAttr(nStartCol + 1, nStartRow + 2, 9, rData);
1997 GetAutoFormatAttr(nStartCol + 2, nStartRow + 2, 10, rData);
1998 GetAutoFormatFrame(nStartCol + 1, nStartRow + 1, LF_RIGHT | LF_BOTTOM, 5, rData);
1999 if ((nEndCol - nStartCol >= 4) && (nEndRow - nStartRow >= 4))
2001 GetAutoFormatFrame(nStartCol + 2, nStartRow + 1, LF_RIGHT | LF_BOTTOM, 6, rData);
2002 GetAutoFormatFrame(nStartCol + 1, nStartRow + 2, LF_RIGHT | LF_BOTTOM, 9, rData);
2003 GetAutoFormatFrame(nStartCol + 2, nStartRow + 2, LF_RIGHT | LF_BOTTOM, 10, rData);
2005 else
2007 rData.CopyItem( 6, 5, ATTR_BORDER );
2008 rData.CopyItem( 9, 5, ATTR_BORDER );
2009 rData.CopyItem( 10, 5, ATTR_BORDER );
2015 void ScTable::SetError( SCCOL nCol, SCROW nRow, sal_uInt16 nError)
2017 if (ValidColRow(nCol, nRow))
2018 aCol[nCol].SetError( nRow, nError );
2021 void ScTable::UpdateInsertTabAbs(SCTAB nTable)
2023 for (SCCOL i=0; i <= MAXCOL; i++)
2024 aCol[i].UpdateInsertTabAbs(nTable);
2027 bool ScTable::GetNextSpellingCell(SCCOL& rCol, SCROW& rRow, bool bInSel,
2028 const ScMarkData& rMark) const
2030 if (rRow == MAXROW+2) // end of table
2032 rRow = 0;
2033 rCol = 0;
2035 else
2037 rRow++;
2038 if (rRow == MAXROW+1)
2040 rCol++;
2041 rRow = 0;
2044 if (rCol == MAXCOL+1)
2045 return true;
2046 else
2048 bool bStop = false;
2049 while (!bStop)
2051 if (ValidCol(rCol))
2053 bStop = aCol[rCol].GetNextSpellingCell(rRow, bInSel, rMark);
2054 if (bStop)
2055 return true;
2056 else /*if (rRow == MAXROW+1) */
2058 rCol++;
2059 rRow = 0;
2062 else
2063 return true;
2066 return false;
2069 void ScTable::RemoveAutoSpellObj()
2071 for (SCCOL i=0; i <= MAXCOL; i++)
2072 aCol[i].RemoveAutoSpellObj();
2075 bool ScTable::TestTabRefAbs(SCTAB nTable) const
2077 for (SCCOL i=0; i <= MAXCOL; i++)
2078 if (aCol[i].TestTabRefAbs(nTable))
2079 return true;
2080 return false;
2083 void ScTable::CompileDBFormula()
2085 for (SCCOL i=0; i<=MAXCOL; i++) aCol[i].CompileDBFormula();
2088 void ScTable::CompileDBFormula( bool bCreateFormulaString )
2090 for (SCCOL i=0; i<=MAXCOL; i++) aCol[i].CompileDBFormula( bCreateFormulaString );
2093 void ScTable::CompileNameFormula( bool bCreateFormulaString )
2095 for (SCCOL i=0; i<=MAXCOL; i++) aCol[i].CompileNameFormula( bCreateFormulaString );
2098 void ScTable::CompileColRowNameFormula()
2100 for (SCCOL i=0; i<=MAXCOL; i++) aCol[i].CompileColRowNameFormula();
2108 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */