fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / core / data / table4.cxx
blob2a2c150d24058fc85cf5d9b5f2aa11dd467bc7bd
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"
62 #include "editutil.hxx"
63 #include <columnspanset.hxx>
64 #include <listenercontext.hxx>
66 #include <math.h>
67 #include <boost/scoped_ptr.hpp>
69 // STATIC DATA -----------------------------------------------------------
71 #define _D_MAX_LONG_ (double) 0x7fffffff
73 extern sal_uInt16 nScFillModeMouseModifier; // global.cxx
75 namespace {
77 short lcl_DecompValueString( OUString& rValue, sal_Int32& nVal, sal_uInt16* pMinDigits = NULL )
79 if ( rValue.isEmpty() )
81 nVal = 0;
82 return 0;
84 const sal_Unicode* p = rValue.getStr();
85 sal_Int32 nNeg = 0;
86 sal_Int32 nNum = 0;
87 if ( p[nNum] == '-' )
88 nNum = nNeg = 1;
89 while ( p[nNum] && CharClass::isAsciiNumeric( OUString(p[nNum]) ) )
90 nNum++;
92 sal_Unicode cNext = p[nNum]; // 0 if at the end
93 sal_Unicode cLast = p[rValue.getLength()-1];
95 // #i5550# If there are numbers at the beginning and the end,
96 // prefer the one at the beginning only if it's followed by a space.
97 // Otherwise, use the number at the end, to enable things like IP addresses.
98 if ( nNum > nNeg && ( cNext == 0 || cNext == ' ' || !CharClass::isAsciiNumeric(OUString(cLast)) ) )
99 { // number at the beginning
100 nVal = rValue.copy( 0, nNum ).toInt32();
101 // any number with a leading zero sets the minimum number of digits
102 if ( p[nNeg] == '0' && pMinDigits && ( nNum - nNeg > *pMinDigits ) )
103 *pMinDigits = nNum - nNeg;
104 rValue = rValue.copy(nNum);
105 return -1;
107 else
109 nNeg = 0;
110 sal_Int32 nEnd = nNum = rValue.getLength() - 1;
111 while ( nNum && CharClass::isAsciiNumeric( OUString(p[nNum]) ) )
112 nNum--;
113 if ( p[nNum] == '-' )
115 nNum--;
116 nNeg = 1;
118 if ( nNum < nEnd - nNeg )
119 { // number at the end
120 nVal = rValue.copy( nNum + 1 ).toInt32();
121 // any number with a leading zero sets the minimum number of digits
122 if ( p[nNum+1+nNeg] == '0' && pMinDigits && ( nEnd - nNum - nNeg > *pMinDigits ) )
123 *pMinDigits = nEnd - nNum - nNeg;
124 rValue = rValue.copy(0, nNum + 1);
125 return 1;
128 nVal = 0;
129 return 0;
132 OUString lcl_ValueString( sal_Int32 nValue, sal_uInt16 nMinDigits )
134 if ( nMinDigits <= 1 )
135 return OUString::number( nValue ); // simple case...
136 else
138 OUString aStr = OUString::number( std::abs( nValue ) );
139 if ( aStr.getLength() < nMinDigits )
141 OUStringBuffer aZero;
142 comphelper::string::padToLength(aZero, nMinDigits - aStr.getLength(), '0');
143 aStr = aZero.makeStringAndClear() + aStr;
145 // nMinDigits doesn't include the '-' sign -> add after inserting zeros
146 if ( nValue < 0 )
147 aStr = "-" + aStr;
148 return aStr;
152 void setSuffixCell(
153 ScColumn& rColumn, SCROW nRow, sal_Int32 nValue, sal_uInt16 nDigits, const OUString& rSuffix,
154 CellType eCellType, bool bIsOrdinalSuffix )
156 ScDocument& rDoc = rColumn.GetDoc();
157 OUString aValue = lcl_ValueString(nValue, nDigits);
158 if (!bIsOrdinalSuffix)
160 rColumn.SetRawString(nRow, aValue += rSuffix);
161 return;
164 OUString aOrdinalSuffix = ScGlobal::GetOrdinalSuffix(nValue);
165 if (eCellType != CELLTYPE_EDIT)
167 rColumn.SetRawString(nRow, aValue += aOrdinalSuffix);
168 return;
171 EditEngine aEngine(rDoc.GetEnginePool());
172 aEngine.SetEditTextObjectPool(rDoc.GetEditPool());
174 SfxItemSet aAttr = aEngine.GetEmptyItemSet();
175 aAttr.Put( SvxEscapementItem( SVX_ESCAPEMENT_SUPERSCRIPT, EE_CHAR_ESCAPEMENT));
176 aEngine.SetText( aValue );
177 aEngine.QuickInsertText(
178 aOrdinalSuffix,
179 ESelection(0, aValue.getLength(), 0, aValue.getLength() + aOrdinalSuffix.getLength()));
181 aEngine.QuickSetAttribs(
182 aAttr,
183 ESelection(0, aValue.getLength(), 0, aValue.getLength() + aOrdinalSuffix.getLength()));
185 // Text object instance will be owned by the cell.
186 rColumn.SetEditText(nRow, aEngine.CreateTextObject());
191 void ScTable::FillAnalyse( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
192 FillCmd& rCmd, FillDateCmd& rDateCmd,
193 double& rInc, sal_uInt16& rMinDigits,
194 ScUserListData*& rListData, sal_uInt16& rListIndex)
196 OSL_ENSURE( nCol1==nCol2 || nRow1==nRow2, "FillAnalyse: invalid range" );
198 rInc = 0.0;
199 rMinDigits = 0;
200 rListData = NULL;
201 rCmd = FILL_SIMPLE;
202 if ( (nScFillModeMouseModifier & KEY_MOD1) )
203 return ; // Ctrl-key: Copy
205 SCCOL nAddX;
206 SCROW nAddY;
207 SCSIZE nCount;
208 if (nCol1 == nCol2)
210 nAddX = 0;
211 nAddY = 1;
212 nCount = static_cast<SCSIZE>(nRow2 - nRow1 + 1);
214 else
216 nAddX = 1;
217 nAddY = 0;
218 nCount = static_cast<SCSIZE>(nCol2 - nCol1 + 1);
221 SCCOL nCol = nCol1;
222 SCROW nRow = nRow1;
224 ScRefCellValue aFirstCell = GetCellValue(nCol, nRow);
225 CellType eCellType = aFirstCell.meType;
227 if (eCellType == CELLTYPE_VALUE)
229 sal_uInt32 nFormat = static_cast<const SfxUInt32Item*>(GetAttr(nCol,nRow,ATTR_VALUE_FORMAT))->GetValue();
230 bool bDate = ( pDocument->GetFormatTable()->GetType(nFormat) == css::util::NumberFormat::DATE );
231 if (bDate)
233 if (nCount > 1)
235 double nVal;
236 Date aNullDate = *pDocument->GetFormatTable()->GetNullDate();
237 Date aDate1 = aNullDate;
238 nVal = aFirstCell.mfValue;
239 aDate1 += (long)nVal;
240 Date aDate2 = aNullDate;
241 nVal = GetValue(nCol+nAddX, nRow+nAddY);
242 aDate2 += (long)nVal;
243 if ( aDate1 != aDate2 )
245 long nCmpInc = 0;
246 FillDateCmd eType;
247 long nDDiff = aDate2.GetDay() - (long) aDate1.GetDay();
248 long nMDiff = aDate2.GetMonth() - (long) aDate1.GetMonth();
249 long nYDiff = aDate2.GetYear() - (long) aDate1.GetYear();
250 if ( nDDiff )
252 eType = FILL_DAY;
253 nCmpInc = aDate2 - aDate1;
255 else
257 eType = FILL_MONTH;
258 nCmpInc = nMDiff + 12 * nYDiff;
261 nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
262 nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
263 bool bVal = true;
264 for (sal_uInt16 i=1; i<nCount && bVal; i++)
266 ScRefCellValue aCell = GetCellValue(nCol,nRow);
267 if (aCell.meType == CELLTYPE_VALUE)
269 nVal = aCell.mfValue;
270 aDate2 = aNullDate + (long) nVal;
271 if ( eType == FILL_DAY )
273 if ( aDate2-aDate1 != nCmpInc )
274 bVal = false;
276 else
278 nDDiff = aDate2.GetDay() - (long) aDate1.GetDay();
279 nMDiff = aDate2.GetMonth() - (long) aDate1.GetMonth();
280 nYDiff = aDate2.GetYear() - (long) aDate1.GetYear();
281 if (nDDiff || ( nMDiff + 12 * nYDiff != nCmpInc ))
282 bVal = false;
284 aDate1 = aDate2;
285 nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
286 nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
288 else
289 bVal = false; // No date is also not ok
291 if (bVal)
293 if ( eType == FILL_MONTH && ( nCmpInc % 12 == 0 ) )
295 eType = FILL_YEAR;
296 nCmpInc /= 12;
298 rCmd = FILL_DATE;
299 rDateCmd = eType;
300 rInc = nCmpInc;
304 else // single date -> increment by days
306 rCmd = FILL_DATE;
307 rDateCmd = FILL_DAY;
308 rInc = 1.0;
311 else
313 if (nCount > 1)
315 double nVal1 = aFirstCell.mfValue;
316 double nVal2 = GetValue(nCol+nAddX, nRow+nAddY);
317 rInc = nVal2 - nVal1;
318 nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
319 nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
320 bool bVal = true;
321 for (sal_uInt16 i=1; i<nCount && bVal; i++)
323 ScRefCellValue aCell = GetCellValue(nCol,nRow);
324 if (aCell.meType == CELLTYPE_VALUE)
326 nVal2 = aCell.mfValue;
327 double nDiff = nVal2 - nVal1;
328 if ( !::rtl::math::approxEqual( nDiff, rInc, 13 ) )
329 bVal = false;
330 nVal1 = nVal2;
332 else
333 bVal = false;
334 nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
335 nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
337 if (bVal)
338 rCmd = FILL_LINEAR;
342 else if (eCellType == CELLTYPE_STRING || eCellType == CELLTYPE_EDIT)
344 OUString aStr;
345 GetString(nCol, nRow, aStr);
347 // fdo#39500 don't deduce increment from multiple equal list entries
348 bool bAllSame = true;
349 for (sal_uInt16 i = 0; i < nCount; ++i)
351 OUString aTestStr;
352 GetString(static_cast<SCCOL>(nCol + i* nAddX), static_cast<SCROW>(nRow + i * nAddY), aTestStr);
353 if(aStr != aTestStr)
355 bAllSame = false;
356 break;
359 if(bAllSame && nCount > 1)
360 return;
362 rListData = const_cast<ScUserListData*>(ScGlobal::GetUserList()->GetData(aStr));
363 if (rListData)
365 (void)rListData->GetSubIndex(aStr, rListIndex);
366 nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
367 nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
368 for (sal_uInt16 i=1; i<nCount && rListData; i++)
370 (void)GetString(nCol, nRow, aStr);
371 if (!rListData->GetSubIndex(aStr, rListIndex))
372 rListData = NULL;
373 nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
374 nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
377 else if ( nCount > 1 )
379 // pass rMinDigits to all DecompValueString calls
380 // -> longest number defines rMinDigits
382 sal_Int32 nVal1;
383 short nFlag1 = lcl_DecompValueString( aStr, nVal1, &rMinDigits );
384 if ( nFlag1 )
386 sal_Int32 nVal2;
387 GetString( nCol+nAddX, nRow+nAddY, aStr );
388 short nFlag2 = lcl_DecompValueString( aStr, nVal2, &rMinDigits );
389 if ( nFlag1 == nFlag2 )
391 rInc = (double)nVal2 - (double)nVal1;
392 nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
393 nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
394 bool bVal = true;
395 for (sal_uInt16 i=1; i<nCount && bVal; i++)
397 ScRefCellValue aCell = GetCellValue(nCol, nRow);
398 CellType eType = aCell.meType;
399 if ( eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT )
401 aStr = aCell.getString(pDocument);
402 nFlag2 = lcl_DecompValueString( aStr, nVal2, &rMinDigits );
403 if ( nFlag1 == nFlag2 )
405 double nDiff = (double)nVal2 - (double)nVal1;
406 if ( !::rtl::math::approxEqual( nDiff, rInc, 13 ) )
407 bVal = false;
408 nVal1 = nVal2;
410 else
411 bVal = false;
413 else
414 bVal = false;
415 nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
416 nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
418 if (bVal)
419 rCmd = FILL_LINEAR;
423 else
425 // call DecompValueString to set rMinDigits
426 sal_Int32 nDummy;
427 lcl_DecompValueString( aStr, nDummy, &rMinDigits );
432 void ScTable::FillFormula(
433 ScFormulaCell* pSrcCell, SCCOL nDestCol, SCROW nDestRow, bool bLast )
436 pDocument->SetNoListening( true ); // still the wrong reference
437 ScAddress aAddr( nDestCol, nDestRow, nTab );
438 ScFormulaCell* pDestCell = new ScFormulaCell( *pSrcCell, *pDocument, aAddr );
439 aCol[nDestCol].SetFormulaCell(nDestRow, pDestCell);
441 if ( bLast && pDestCell->GetMatrixFlag() )
443 ScAddress aOrg;
444 if ( pDestCell->GetMatrixOrigin( aOrg ) )
446 if ( nDestCol >= aOrg.Col() && nDestRow >= aOrg.Row() )
448 ScFormulaCell* pOrgCell = pDocument->GetFormulaCell(aOrg);
449 if (pOrgCell && pOrgCell->GetMatrixFlag() == MM_FORMULA)
451 pOrgCell->SetMatColsRows(
452 nDestCol - aOrg.Col() + 1,
453 nDestRow - aOrg.Row() + 1 );
455 else
457 OSL_FAIL( "FillFormula: MatrixOrigin no forumla cell with MM_FORMULA" );
460 else
462 OSL_FAIL( "FillFormula: MatrixOrigin bottom right" );
465 else
467 OSL_FAIL( "FillFormula: no MatrixOrigin" );
470 pDocument->SetNoListening( false );
471 pDestCell->StartListeningTo( pDocument );
475 void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
476 sal_uLong nFillCount, FillDir eFillDir, ScProgress* pProgress )
478 if ( (nFillCount == 0) || !ValidColRow(nCol1, nRow1) || !ValidColRow(nCol2, nRow2) )
479 return;
481 // Detect direction
483 bool bVertical = (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_TOP);
484 bool bPositive = (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_RIGHT);
486 SCCOLROW nCol = 0;
487 SCCOLROW nRow = 0;
488 SCCOLROW& rInner = bVertical ? nRow : nCol; // loop variables
489 SCCOLROW& rOuter = bVertical ? nCol : nRow;
490 SCCOLROW nOStart;
491 SCCOLROW nOEnd;
492 SCCOLROW nIStart;
493 SCCOLROW nIEnd;
494 SCCOLROW nISrcStart;
495 SCCOLROW nISrcEnd;
496 ScRange aFillRange;
498 if (bVertical)
500 nOStart = nCol1;
501 nOEnd = nCol2;
502 if (bPositive)
504 nISrcStart = nRow1;
505 nISrcEnd = nRow2;
506 nIStart = nRow2 + 1;
507 nIEnd = nRow2 + nFillCount;
508 aFillRange = ScRange(nCol1, nRow2+1, 0, nCol2, nRow2 + nFillCount, 0);
510 else
512 nISrcStart = nRow2;
513 nISrcEnd = nRow1;
514 nIStart = nRow1 - 1;
515 nIEnd = nRow1 - nFillCount;
516 aFillRange = ScRange(nCol1, nRow1-1, 0, nCol2, nRow2 - nFillCount, 0);
519 else
521 nOStart = nRow1;
522 nOEnd = nRow2;
523 if (bPositive)
525 nISrcStart = nCol1;
526 nISrcEnd = nCol2;
527 nIStart = nCol2 + 1;
528 nIEnd = nCol2 + nFillCount;
529 aFillRange = ScRange(nCol2 + 1, nRow1, 0, nCol2 + nFillCount, nRow2, 0);
531 else
533 nISrcStart = nCol2;
534 nISrcEnd = nCol1;
535 nIStart = nCol1 - 1;
536 nIEnd = nCol1 - nFillCount;
537 aFillRange = ScRange(nCol1 - 1, nRow1, 0, nCol1 - nFillCount, nRow2, 0);
540 sal_uLong nIMin = nIStart;
541 sal_uLong nIMax = nIEnd;
542 PutInOrder(nIMin,nIMax);
543 bool bHasFiltered = IsDataFiltered(aFillRange);
545 if (!bHasFiltered)
547 if (bVertical)
548 DeleteArea(nCol1, static_cast<SCROW>(nIMin), nCol2, static_cast<SCROW>(nIMax), IDF_AUTOFILL);
549 else
550 DeleteArea(static_cast<SCCOL>(nIMin), nRow1, static_cast<SCCOL>(nIMax), nRow2, IDF_AUTOFILL);
553 sal_uLong nProgress = 0;
554 if (pProgress)
555 nProgress = pProgress->GetState();
557 // execute
559 sal_uLong nActFormCnt = 0;
560 for (rOuter = nOStart; rOuter <= nOEnd; rOuter++)
562 sal_uLong nMaxFormCnt = 0; // for formulas
564 // transfer attributes
566 const ScPatternAttr* pSrcPattern = NULL;
567 const ScStyleSheet* pStyleSheet = NULL;
568 SCCOLROW nAtSrc = nISrcStart;
569 ScPatternAttr* pNewPattern = NULL;
570 bool bGetPattern = true;
571 rInner = nIStart;
572 while (true) // #i53728# with "for (;;)" old solaris/x86 compiler mis-optimizes
574 if (!ColHidden(nCol) && !RowHidden(nRow))
576 if ( bGetPattern )
578 delete pNewPattern;
579 if (bVertical) // rInner&:=nRow, rOuter&:=nCol
580 pSrcPattern = aCol[nCol].GetPattern(static_cast<SCROW>(nAtSrc));
581 else // rInner&:=nCol, rOuter&:=nRow
582 pSrcPattern = aCol[nAtSrc].GetPattern(static_cast<SCROW>(nRow));
583 bGetPattern = false;
584 pStyleSheet = pSrcPattern->GetStyleSheet();
585 // do not transfer ATTR_MERGE / ATTR_MERGE_FLAG
586 const SfxItemSet& rSet = pSrcPattern->GetItemSet();
587 if ( rSet.GetItemState(ATTR_MERGE, false) == SfxItemState::SET
588 || rSet.GetItemState(ATTR_MERGE_FLAG, false) == SfxItemState::SET )
590 pNewPattern = new ScPatternAttr( *pSrcPattern );
591 SfxItemSet& rNewSet = pNewPattern->GetItemSet();
592 rNewSet.ClearItem(ATTR_MERGE);
593 rNewSet.ClearItem(ATTR_MERGE_FLAG);
595 else
596 pNewPattern = NULL;
599 const ScCondFormatItem& rCondFormatItem = static_cast<const ScCondFormatItem&>(pSrcPattern->GetItem(ATTR_CONDITIONAL));
600 const std::vector<sal_uInt32>& rCondFormatIndex = rCondFormatItem.GetCondFormatData();
602 if ( bVertical && nISrcStart == nISrcEnd && !bHasFiltered )
604 // set all attributes at once (en bloc)
605 if (pNewPattern || pSrcPattern != pDocument->GetDefPattern())
607 // Default is already present (DeleteArea)
608 SCROW nY1 = static_cast<SCROW>(std::min( nIStart, nIEnd ));
609 SCROW nY2 = static_cast<SCROW>(std::max( nIStart, nIEnd ));
610 if ( pStyleSheet )
611 aCol[nCol].ApplyStyleArea( nY1, nY2, *pStyleSheet );
612 if ( pNewPattern )
613 aCol[nCol].ApplyPatternArea( nY1, nY2, *pNewPattern );
614 else
615 aCol[nCol].ApplyPatternArea( nY1, nY2, *pSrcPattern );
617 for(std::vector<sal_uInt32>::const_iterator itr = rCondFormatIndex.begin(), itrEnd = rCondFormatIndex.end();
618 itr != itrEnd; ++itr)
620 ScConditionalFormat* pCondFormat = mpCondFormatList->GetFormat(*itr);
621 ScRangeList aRange = pCondFormat->GetRange();
622 aRange.Join(ScRange(nCol, nY1, nTab, nCol, nY2, nTab));
623 pCondFormat->SetRange(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 //TODO: 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->SetRange(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 (pListData)
702 sal_uInt16 nListCount = pListData->GetSubCount();
703 if ( !bPositive )
705 // nListIndex of FillAnalyse points to the last entry -> adjust
706 sal_uLong nSub = nISrcStart - nISrcEnd;
707 for (sal_uLong i=0; i<nSub; i++)
709 if (nListIndex == 0) nListIndex = nListCount;
710 --nListIndex;
714 rInner = nIStart;
715 while (true) // #i53728# with "for (;;)" old solaris/x86 compiler mis-optimizes
717 if(!ColHidden(nCol) && !RowHidden(nRow))
719 if (bPositive)
721 ++nListIndex;
722 if (nListIndex >= nListCount) nListIndex = 0;
724 else
726 if (nListIndex == 0) nListIndex = nListCount;
727 --nListIndex;
729 aCol[nCol].SetRawString(static_cast<SCROW>(nRow), pListData->GetSubStr(nListIndex));
732 if (rInner == nIEnd) break;
733 if (bPositive) ++rInner; else --rInner;
735 if(pProgress)
737 nProgress += nIMax - nIMin + 1;
738 pProgress->SetStateOnPercent( nProgress );
741 else if (eFillCmd == FILL_SIMPLE) // fill with pattern/sample
743 FillAutoSimple(
744 nISrcStart, nISrcEnd, nIStart, nIEnd, rInner, nCol, nRow,
745 nActFormCnt, nMaxFormCnt, bHasFiltered, bVertical, bPositive, pProgress, nProgress);
747 else
749 if (!bPositive)
750 nInc = -nInc;
751 double nEndVal = (nInc>=0.0) ? MAXDOUBLE : -MAXDOUBLE;
752 if (bVertical)
753 FillSeries( static_cast<SCCOL>(nCol), nRow1,
754 static_cast<SCCOL>(nCol), nRow2, nFillCount, eFillDir,
755 eFillCmd, eDateCmd, nInc, nEndVal, nMinDigits, false,
756 pProgress );
757 else
758 FillSeries( nCol1, static_cast<SCROW>(nRow), nCol2,
759 static_cast<SCROW>(nRow), nFillCount, eFillDir,
760 eFillCmd, eDateCmd, nInc, nEndVal, nMinDigits, false,
761 pProgress );
762 if (pProgress)
763 nProgress = pProgress->GetState();
766 nActFormCnt += nMaxFormCnt;
770 OUString ScTable::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW nEndY )
772 OUString aValue;
774 SCCOL nCol1 = rSource.aStart.Col();
775 SCROW nRow1 = rSource.aStart.Row();
776 SCCOL nCol2 = rSource.aEnd.Col();
777 SCROW nRow2 = rSource.aEnd.Row();
778 bool bOk = true;
779 long nIndex = 0;
780 sal_uLong nSrcCount = 0;
781 FillDir eFillDir = FILL_TO_BOTTOM;
782 if ( nEndX == nCol2 && nEndY == nRow2 ) // empty
783 bOk = false;
784 else if ( nEndX == nCol2 ) // to up / down
786 nEndX = nCol2 = nCol1; // use only first column
787 nSrcCount = nRow2 - nRow1 + 1;
788 nIndex = ((long)nEndY) - nRow1; // can be negative
789 if ( nEndY >= nRow1 )
790 eFillDir = FILL_TO_BOTTOM;
791 else
792 eFillDir = FILL_TO_TOP;
794 else if ( nEndY == nRow2 ) // to left / right
796 nEndY = nRow2 = nRow1; // use only first row
797 nSrcCount = nCol2 - nCol1 + 1;
798 nIndex = ((long)nEndX) - nCol1; // can be negative
799 if ( nEndX >= nCol1 )
800 eFillDir = FILL_TO_RIGHT;
801 else
802 eFillDir = FILL_TO_LEFT;
804 else // direction not clear
805 bOk = false;
807 if ( bOk )
809 FillCmd eFillCmd;
810 FillDateCmd eDateCmd;
811 double nInc;
812 sal_uInt16 nMinDigits;
813 ScUserListData* pListData = NULL;
814 sal_uInt16 nListIndex;
816 FillAnalyse(nCol1,nRow1, nCol2,nRow2, eFillCmd,eDateCmd, nInc,nMinDigits, pListData,nListIndex);
818 if ( pListData ) // user defined list
820 sal_uInt16 nListCount = pListData->GetSubCount();
821 if ( nListCount )
823 sal_uLong nSub = nSrcCount - 1; // nListIndex is from last source entry
824 while ( nIndex < sal::static_int_cast<long>(nSub) )
825 nIndex += nListCount;
826 sal_uLong nPos = ( nListIndex + nIndex - nSub ) % nListCount;
827 aValue = pListData->GetSubStr(sal::static_int_cast<sal_uInt16>(nPos));
830 else if ( eFillCmd == FILL_SIMPLE ) // fill with pattern/sample
832 if ((eFillDir == FILL_TO_BOTTOM)||(eFillDir == FILL_TO_TOP))
834 long nBegin = 0;
835 long nEnd = 0;
836 if (nEndY > nRow1)
838 nBegin = nRow2+1;
839 nEnd = nEndY;
841 else
843 nBegin = nEndY;
844 nEnd = nRow1 -1;
847 long nNonFiltered = CountNonFilteredRows(nBegin, nEnd);
848 long nFiltered = nEnd + 1 - nBegin - nNonFiltered;
850 if (nIndex > 0)
851 nIndex = nIndex - nFiltered;
852 else
853 nIndex = nIndex + nFiltered;
856 long nPosIndex = nIndex;
857 while ( nPosIndex < 0 )
858 nPosIndex += nSrcCount;
859 sal_uLong nPos = nPosIndex % nSrcCount;
860 SCCOL nSrcX = nCol1;
861 SCROW nSrcY = nRow1;
862 if ( eFillDir == FILL_TO_TOP || eFillDir == FILL_TO_BOTTOM )
863 nSrcY = sal::static_int_cast<SCROW>( nSrcY + static_cast<SCROW>(nPos) );
864 else
865 nSrcX = sal::static_int_cast<SCCOL>( nSrcX + static_cast<SCCOL>(nPos) );
867 ScRefCellValue aCell = GetCellValue(nSrcX, nSrcY);
868 if (!aCell.isEmpty())
870 sal_Int32 nDelta;
871 if (nIndex >= 0)
872 nDelta = nIndex / nSrcCount;
873 else
874 nDelta = ( nIndex - nSrcCount + 1 ) / nSrcCount; // -1 -> -1
876 CellType eType = aCell.meType;
877 switch ( eType )
879 case CELLTYPE_STRING:
880 case CELLTYPE_EDIT:
882 aValue = aCell.getString(pDocument);
884 if ( !(nScFillModeMouseModifier & KEY_MOD1) )
886 sal_Int32 nVal;
887 sal_uInt16 nCellDigits = 0; // look at each source cell individually
888 short nFlag = lcl_DecompValueString( aValue, nVal, &nCellDigits );
889 if ( nFlag < 0 )
891 if (aValue.equals( ScGlobal::GetOrdinalSuffix( nVal)))
892 aValue = ScGlobal::GetOrdinalSuffix( nVal + nDelta);
894 aValue = lcl_ValueString( nVal + nDelta, nCellDigits ) + aValue;
896 else if ( nFlag > 0 )
897 aValue += lcl_ValueString( nVal + nDelta, nCellDigits );
900 break;
901 case CELLTYPE_VALUE:
903 // overflow is possible...
904 double nVal = aCell.mfValue;
905 if ( !(nScFillModeMouseModifier & KEY_MOD1) )
906 nVal += (double) nDelta;
908 Color* pColor;
909 sal_uLong nNumFmt = GetNumberFormat( nSrcX, nSrcY );
910 pDocument->GetFormatTable()->GetOutputString( nVal, nNumFmt, aValue, &pColor );
912 break;
913 // not for formulas
914 default:
916 // added to avoid warnings
921 else if ( eFillCmd == FILL_LINEAR || eFillCmd == FILL_DATE ) // values
923 bool bValueOk;
924 double nStart;
925 sal_Int32 nVal = 0;
926 short nHeadNoneTail = 0;
927 ScRefCellValue aCell = GetCellValue(nCol1, nRow1);
928 if (!aCell.isEmpty())
930 CellType eType = aCell.meType;
931 switch ( eType )
933 case CELLTYPE_STRING:
934 case CELLTYPE_EDIT:
936 aValue = aCell.getString(pDocument);
937 nHeadNoneTail = lcl_DecompValueString( aValue, nVal );
938 if ( nHeadNoneTail )
939 nStart = (double)nVal;
940 else
941 nStart = 0.0;
943 break;
944 case CELLTYPE_VALUE:
945 nStart = aCell.mfValue;
946 break;
947 case CELLTYPE_FORMULA:
948 nStart = aCell.mpFormula->GetValue();
949 break;
950 default:
951 nStart = 0.0;
954 else
955 nStart = 0.0;
956 if ( eFillCmd == FILL_LINEAR )
958 double nAdd = nInc;
959 bValueOk = ( SubTotal::SafeMult( nAdd, (double) nIndex ) &&
960 SubTotal::SafePlus( nStart, nAdd ) );
962 else // date
964 bValueOk = true;
965 sal_uInt16 nDayOfMonth = 0;
966 if ( nIndex < 0 )
968 nIndex = -nIndex;
969 nInc = -nInc;
971 for (long i=0; i<nIndex; i++)
972 IncDate( nStart, nDayOfMonth, nInc, eDateCmd );
975 if (bValueOk)
977 if ( nHeadNoneTail )
979 if ( nHeadNoneTail < 0 )
981 if (aValue.equals( ScGlobal::GetOrdinalSuffix( nVal)))
982 aValue = ScGlobal::GetOrdinalSuffix( (sal_Int32)nStart );
984 aValue = lcl_ValueString( (sal_Int32)nStart, nMinDigits ) + aValue;
986 else
987 aValue += lcl_ValueString( (sal_Int32)nStart, nMinDigits );
989 else
991 //TODO: get number format according to Index?
992 Color* pColor;
993 sal_uLong nNumFmt = GetNumberFormat( nCol1, nRow1 );
994 pDocument->GetFormatTable()->GetOutputString( nStart, nNumFmt, aValue, &pColor );
998 else
1000 OSL_FAIL("GetAutoFillPreview: invalid mode");
1004 return aValue;
1007 void ScTable::IncDate(double& rVal, sal_uInt16& nDayOfMonth, double nStep, FillDateCmd eCmd)
1009 if (eCmd == FILL_DAY)
1011 rVal += nStep;
1012 return;
1015 // class Date limits
1016 const sal_uInt16 nMinYear = 1583;
1017 const sal_uInt16 nMaxYear = 9956;
1019 long nInc = (long) nStep; // upper/lower limits ?
1020 Date aNullDate = *pDocument->GetFormatTable()->GetNullDate();
1021 Date aDate = aNullDate;
1022 aDate += (long)rVal;
1023 switch (eCmd)
1025 case FILL_WEEKDAY:
1027 aDate += nInc;
1028 DayOfWeek eWeekDay = aDate.GetDayOfWeek();
1029 if (nInc >= 0)
1031 if (eWeekDay == SATURDAY)
1032 aDate += 2;
1033 else if (eWeekDay == SUNDAY)
1034 aDate += 1;
1036 else
1038 if (eWeekDay == SATURDAY)
1039 aDate -= 1;
1040 else if (eWeekDay == SUNDAY)
1041 aDate -= 2;
1044 break;
1045 case FILL_MONTH:
1047 if ( nDayOfMonth == 0 )
1048 nDayOfMonth = aDate.GetDay(); // init
1049 long nMonth = aDate.GetMonth();
1050 long nYear = aDate.GetYear();
1052 nMonth += nInc;
1054 if (nInc >= 0)
1056 if (nMonth > 12)
1058 long nYAdd = (nMonth-1) / 12;
1059 nMonth -= nYAdd * 12;
1060 nYear += nYAdd;
1063 else
1065 if (nMonth < 1)
1067 long nYAdd = 1 - nMonth / 12; // positive
1068 nMonth += nYAdd * 12;
1069 nYear -= nYAdd;
1073 if ( nYear < nMinYear )
1074 aDate = Date( 1,1, nMinYear );
1075 else if ( nYear > nMaxYear )
1076 aDate = Date( 31,12, nMaxYear );
1077 else
1079 aDate.SetMonth((sal_uInt16) nMonth);
1080 aDate.SetYear((sal_uInt16) nYear);
1081 aDate.SetDay( std::min( Date::GetDaysInMonth( nMonth, nYear), nDayOfMonth ) );
1084 break;
1085 case FILL_YEAR:
1087 long nYear = aDate.GetYear();
1088 nYear += nInc;
1089 if ( nYear < nMinYear )
1090 aDate = Date( 1,1, nMinYear );
1091 else if ( nYear > nMaxYear )
1092 aDate = Date( 31,12, nMaxYear );
1093 else
1094 aDate.SetYear((sal_uInt16) nYear);
1096 break;
1097 default:
1099 // added to avoid warnings
1103 rVal = aDate - aNullDate;
1106 namespace {
1108 bool HiddenRowColumn(ScTable* pTable, SCCOLROW nRowColumn, bool bVertical, SCCOLROW& rLastPos)
1110 bool bHidden = false;
1111 if(bVertical)
1113 SCROW nLast;
1114 bHidden = pTable->RowHidden(nRowColumn, NULL, &nLast);
1115 rLastPos = nLast;
1117 else
1119 SCCOL nLast;
1120 bHidden = pTable->ColHidden(static_cast<SCCOL>(nRowColumn), NULL, &nLast);
1121 rLastPos = nLast;
1123 return bHidden;
1128 void ScTable::FillFormulaVertical(
1129 const ScFormulaCell& rSrcCell,
1130 SCCOLROW& rInner, SCCOL nCol, SCROW nRow1, SCROW nRow2,
1131 ScProgress* pProgress, sal_uLong& rProgress )
1133 // rInner is the row position when filling vertically. Also, when filling
1134 // across hidden regions, it may create multiple dis-jointed spans of
1135 // formula cells.
1137 bool bHidden = false;
1138 SCCOLROW nHiddenLast = -1;
1140 SCCOLROW nRowStart = -1, nRowEnd = -1;
1141 std::vector<sc::RowSpan> aSpans;
1142 PutInOrder(nRow1, nRow2);
1143 for (rInner = nRow1; rInner <= nRow2; ++rInner)
1145 if (rInner > nHiddenLast)
1146 bHidden = HiddenRowColumn(this, rInner, true, nHiddenLast);
1148 if (bHidden)
1150 if (nRowStart >= 0)
1152 nRowEnd = rInner - 1;
1153 aSpans.push_back(sc::RowSpan(nRowStart, nRowEnd));
1154 nRowStart = -1;
1156 rInner = nHiddenLast;
1157 continue;
1160 if (nRowStart < 0)
1161 nRowStart = rInner;
1164 if (nRowStart >= 0)
1166 nRowEnd = rInner - 1;
1167 aSpans.push_back(sc::RowSpan(nRowStart, nRowEnd));
1170 if (aSpans.empty())
1171 return;
1173 aCol[nCol].DeleteRanges(aSpans, IDF_VALUE | IDF_DATETIME | IDF_STRING | IDF_FORMULA | IDF_OUTLINE, false);
1174 aCol[nCol].CloneFormulaCell(rSrcCell, sc::CellTextAttr(), aSpans, NULL);
1176 boost::shared_ptr<sc::ColumnBlockPositionSet> pSet(new sc::ColumnBlockPositionSet(*pDocument));
1177 sc::StartListeningContext aStartCxt(*pDocument, pSet);
1178 sc::EndListeningContext aEndCxt(*pDocument, pSet);
1180 SCROW nStartRow = aSpans.front().mnRow1;
1181 SCROW nEndRow = aSpans.back().mnRow2;
1182 aCol[nCol].EndListeningFormulaCells(aEndCxt, nStartRow, nEndRow, &nStartRow, &nEndRow);
1183 aCol[nCol].StartListeningFormulaCells(aStartCxt, aEndCxt, nStartRow, nEndRow);
1185 std::vector<sc::RowSpan>::const_iterator it = aSpans.begin(), itEnd = aSpans.end();
1186 for (; it != itEnd; ++it)
1187 aCol[nCol].SetDirty(it->mnRow1, it->mnRow2, ScColumn::BROADCAST_NONE);
1189 rProgress += nRow2 - nRow1 + 1;
1190 if (pProgress)
1191 pProgress->SetStateOnPercent(rProgress);
1194 void ScTable::FillSeriesSimple(
1195 ScCellValue& rSrcCell, SCCOLROW& rInner, SCCOLROW nIMin, SCCOLROW nIMax,
1196 SCCOLROW& rCol, SCCOLROW& rRow, bool bVertical, ScProgress* pProgress, sal_uLong& rProgress )
1198 bool bHidden = false;
1199 SCCOLROW nHiddenLast = -1;
1201 if (bVertical)
1203 switch (rSrcCell.meType)
1205 case CELLTYPE_FORMULA:
1207 FillFormulaVertical(
1208 *rSrcCell.mpFormula, rInner, rCol, nIMin, nIMax, pProgress, rProgress);
1210 break;
1211 default:
1213 for (rInner = nIMin; rInner <= nIMax; ++rInner)
1215 if (rInner > nHiddenLast)
1216 bHidden = HiddenRowColumn(this, rInner, bVertical, nHiddenLast);
1218 if (bHidden)
1220 rInner = nHiddenLast;
1221 continue;
1224 ScAddress aDestPos(rCol, rRow, nTab);
1225 rSrcCell.commit(aCol[rCol], aDestPos.Row());
1227 rProgress += nIMax - nIMin + 1;
1228 if (pProgress)
1229 pProgress->SetStateOnPercent(rProgress);
1233 else
1235 switch (rSrcCell.meType)
1237 case CELLTYPE_FORMULA:
1239 for (rInner = nIMin; rInner <= nIMax; ++rInner)
1241 if (rInner > nHiddenLast)
1242 bHidden = HiddenRowColumn(this, rInner, bVertical, nHiddenLast);
1244 if (bHidden)
1245 continue;
1247 FillFormula(rSrcCell.mpFormula, rCol, rRow, (rInner == nIMax));
1248 if (pProgress)
1249 pProgress->SetStateOnPercent(++rProgress);
1252 break;
1253 default:
1255 for (rInner = nIMin; rInner <= nIMax; ++rInner)
1257 if (rInner > nHiddenLast)
1258 bHidden = HiddenRowColumn(this, rInner, bVertical, nHiddenLast);
1260 if (bHidden)
1261 continue;
1263 ScAddress aDestPos(rCol, rRow, nTab);
1264 rSrcCell.commit(aCol[rCol], aDestPos.Row());
1266 rProgress += nIMax - nIMin + 1;
1267 if (pProgress)
1268 pProgress->SetStateOnPercent(rProgress);
1274 void ScTable::FillAutoSimple(
1275 SCCOLROW nISrcStart, SCCOLROW nISrcEnd, SCCOLROW nIStart, SCCOLROW nIEnd,
1276 SCCOLROW& rInner, SCCOLROW& rCol, SCCOLROW& rRow, sal_uLong nActFormCnt,
1277 sal_uLong nMaxFormCnt, bool bHasFiltered, bool bVertical, bool bPositive,
1278 ScProgress* pProgress, sal_uLong& rProgress )
1280 SCCOLROW nSource = nISrcStart;
1281 double nDelta;
1282 if ( (nScFillModeMouseModifier & KEY_MOD1) )
1283 nDelta = 0.0;
1284 else if ( bPositive )
1285 nDelta = 1.0;
1286 else
1287 nDelta = -1.0;
1288 sal_uLong nFormulaCounter = nActFormCnt;
1289 bool bGetCell = true;
1290 sal_uInt16 nCellDigits = 0;
1291 short nHeadNoneTail = 0;
1292 sal_Int32 nStringValue = 0;
1293 OUString aValue;
1294 ScCellValue aSrcCell;
1295 bool bIsOrdinalSuffix = false;
1297 bool bColHidden = false, bRowHidden = false;
1298 SCCOL nColHiddenLast = -1;
1299 SCROW nRowHiddenLast = -1;
1301 rInner = nIStart;
1302 while (true) // #i53728# with "for (;;)" old solaris/x86 compiler mis-optimizes
1304 if (rCol > nColHiddenLast)
1305 bColHidden = ColHidden(rCol, NULL, &nColHiddenLast);
1306 if (rRow > nRowHiddenLast)
1307 bRowHidden = RowHidden(rRow, NULL, &nRowHiddenLast);
1309 if (!bColHidden && !bRowHidden)
1311 if ( bGetCell )
1313 if (bVertical) // rInner&:=nRow, rOuter&:=nCol
1315 aSrcCell = aCol[rCol].GetCellValue(nSource);
1316 if (nISrcStart == nISrcEnd && aSrcCell.meType == CELLTYPE_FORMULA)
1318 FillFormulaVertical(*aSrcCell.mpFormula, rInner, rCol, nIStart, nIEnd, pProgress, rProgress);
1319 return;
1322 else // rInner&:=nCol, rOuter&:=nRow
1323 aSrcCell = aCol[nSource].GetCellValue(rRow);
1325 bGetCell = false;
1326 if (!aSrcCell.isEmpty())
1328 switch (aSrcCell.meType)
1330 case CELLTYPE_STRING:
1331 case CELLTYPE_EDIT:
1332 if (aSrcCell.meType == CELLTYPE_STRING)
1333 aValue = aSrcCell.mpString->getString();
1334 else
1335 aValue = ScEditUtil::GetString(*aSrcCell.mpEditText, pDocument);
1336 if ( !(nScFillModeMouseModifier & KEY_MOD1) && !bHasFiltered )
1338 nCellDigits = 0; // look at each source cell individually
1339 nHeadNoneTail = lcl_DecompValueString(
1340 aValue, nStringValue, &nCellDigits );
1342 bIsOrdinalSuffix = aValue.equals(
1343 ScGlobal::GetOrdinalSuffix( nStringValue));
1345 break;
1346 default:
1348 // added to avoid warnings
1354 switch (aSrcCell.meType)
1356 case CELLTYPE_VALUE:
1357 aCol[rCol].SetValue(rRow, aSrcCell.mfValue + nDelta);
1358 break;
1359 case CELLTYPE_STRING:
1360 case CELLTYPE_EDIT:
1361 if ( nHeadNoneTail )
1363 // #i48009# with the "nStringValue+(long)nDelta" expression within the
1364 // lcl_ValueString calls, gcc 3.4.1 makes wrong optimizations (ok in 3.4.3),
1365 // so nNextValue is now calculated ahead.
1366 sal_Int32 nNextValue = nStringValue+(sal_Int32)nDelta;
1368 OUString aStr;
1369 if ( nHeadNoneTail < 0 )
1371 setSuffixCell(
1372 aCol[rCol], rRow,
1373 nNextValue, nCellDigits, aValue,
1374 aSrcCell.meType, bIsOrdinalSuffix);
1376 else
1378 aStr = aValue + lcl_ValueString( nNextValue, nCellDigits );
1379 aCol[rCol].SetRawString(rRow, aStr);
1382 else
1383 aSrcCell.commit(aCol[rCol], rRow);
1385 break;
1386 case CELLTYPE_FORMULA :
1387 FillFormula(
1388 aSrcCell.mpFormula, rCol, rRow, (rInner == nIEnd));
1389 if (nFormulaCounter - nActFormCnt > nMaxFormCnt)
1390 nMaxFormCnt = nFormulaCounter - nActFormCnt;
1391 break;
1392 default:
1394 // added to avoid warnings
1398 if (nSource == nISrcEnd)
1400 if ( nSource != nISrcStart )
1401 { // More than one source cell
1402 nSource = nISrcStart;
1403 bGetCell = true;
1405 if ( !(nScFillModeMouseModifier & KEY_MOD1) )
1407 if ( bPositive )
1408 nDelta += 1.0;
1409 else
1410 nDelta -= 1.0;
1412 nFormulaCounter = nActFormCnt;
1414 else if (bPositive)
1416 ++nSource;
1417 bGetCell = true;
1419 else
1421 --nSource;
1422 bGetCell = true;
1426 if (rInner == nIEnd)
1427 break;
1428 if (bPositive)
1429 ++rInner;
1430 else
1431 --rInner;
1433 // Progress in inner loop only for expensive cells,
1434 // and even then not individually for each one
1436 ++rProgress;
1437 if ( pProgress && (aSrcCell.meType == CELLTYPE_FORMULA || aSrcCell.meType == CELLTYPE_EDIT) )
1438 pProgress->SetStateOnPercent( rProgress );
1441 if (pProgress)
1442 pProgress->SetStateOnPercent( rProgress );
1445 void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
1446 sal_uLong nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd,
1447 double nStepValue, double nMaxValue, sal_uInt16 nArgMinDigits,
1448 bool bAttribs, ScProgress* pProgress )
1450 // The term 'inner' here refers to the loop in the filling direction i.e.
1451 // when filling vertically, the inner position is the row position whereas
1452 // when filling horizontally the column position becomes the inner
1453 // position. The term 'outer' refers to the column position when filling
1454 // vertically, or the row position when filling horizontally. The fill is
1455 // performed once in each 'outer' position e.g. when filling vertically,
1456 // we perform the fill once in each column.
1458 // Detect direction
1460 bool bVertical = (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_TOP);
1461 bool bPositive = (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_RIGHT);
1463 SCCOLROW nCol = 0;
1464 SCCOLROW nRow = 0;
1465 SCCOLROW& rInner = bVertical ? nRow : nCol; // loop variables
1466 SCCOLROW& rOuter = bVertical ? nCol : nRow;
1467 SCCOLROW nOStart;
1468 SCCOLROW nOEnd;
1469 SCCOLROW nIStart;
1470 SCCOLROW nIEnd;
1471 SCCOLROW nISource;
1472 ScRange aFillRange;
1474 if (bVertical)
1476 nFillCount += (nRow2 - nRow1);
1477 if (nFillCount == 0)
1478 return;
1479 nOStart = nCol1;
1480 nOEnd = nCol2;
1481 if (bPositive)
1483 // downward fill
1484 nISource = nRow1; // top row of the source range.
1485 nIStart = nRow1 + 1; // first row where we start filling.
1486 nIEnd = nRow1 + nFillCount;
1487 aFillRange = ScRange(nCol1, nRow1 + 1, nTab, nCol2, nRow1 + nFillCount, nTab);
1489 else
1491 // upward fill
1492 nISource = nRow2;
1493 nIStart = nRow2 - 1;
1494 nIEnd = nRow2 - nFillCount;
1495 aFillRange = ScRange(nCol1, nRow2 -1, nTab, nCol2, nRow2 - nFillCount, nTab);
1498 else
1500 nFillCount += (nCol2 - nCol1);
1501 if (nFillCount == 0)
1502 return;
1503 nOStart = nRow1;
1504 nOEnd = nRow2;
1505 if (bPositive)
1507 // to the right
1508 nISource = nCol1;
1509 nIStart = nCol1 + 1;
1510 nIEnd = nCol1 + nFillCount;
1511 aFillRange = ScRange(nCol1 + 1, nRow1, nTab, nCol1 + nFillCount, nRow2, nTab);
1513 else
1515 // to the left
1516 nISource = nCol2;
1517 nIStart = nCol2 - 1;
1518 nIEnd = nCol2 - nFillCount;
1519 aFillRange = ScRange(nCol2 - 1, nRow1, nTab, nCol2 - nFillCount, nRow2, nTab);
1523 SCCOLROW nIMin = nIStart;
1524 SCCOLROW nIMax = nIEnd;
1525 PutInOrder(nIMin,nIMax);
1526 InsertDeleteFlags nDel = bAttribs ? IDF_AUTOFILL : (IDF_AUTOFILL & IDF_CONTENTS);
1528 bool bIsFiltered = IsDataFiltered(aFillRange);
1529 if (!bIsFiltered)
1531 if (bVertical)
1532 DeleteArea(nCol1, static_cast<SCROW>(nIMin), nCol2, static_cast<SCROW>(nIMax), nDel);
1533 else
1534 DeleteArea(static_cast<SCCOL>(nIMin), nRow1, static_cast<SCCOL>(nIMax), nRow2, nDel);
1537 sal_uLong nProgress = 0;
1538 if (pProgress)
1539 nProgress = pProgress->GetState();
1541 // Perform the fill once per each 'outer' position i.e. one per column
1542 // when filling vertically.
1544 sal_uLong nActFormCnt = 0;
1545 for (rOuter = nOStart; rOuter <= nOEnd; rOuter++)
1547 rInner = nISource;
1549 // Source cell value. We need to clone the value since it may be inserted repeatedly.
1550 ScCellValue aSrcCell = aCol[nCol].GetCellValue(static_cast<SCROW>(nRow));
1552 if (bAttribs)
1554 const ScPatternAttr* pSrcPattern = aCol[nCol].GetPattern(static_cast<SCROW>(nRow));
1556 const ScCondFormatItem& rCondFormatItem = static_cast<const ScCondFormatItem&>(pSrcPattern->GetItem(ATTR_CONDITIONAL));
1557 const std::vector<sal_uInt32>& rCondFormatIndex = rCondFormatItem.GetCondFormatData();
1559 if (bVertical)
1561 // if not filtered use the faster method
1562 // hidden cols/rows should be skipped
1563 if(!bIsFiltered)
1565 aCol[nCol].SetPatternArea( static_cast<SCROW>(nIMin),
1566 static_cast<SCROW>(nIMax), *pSrcPattern, true );
1568 for(std::vector<sal_uInt32>::const_iterator itr = rCondFormatIndex.begin(), itrEnd = rCondFormatIndex.end();
1569 itr != itrEnd; ++itr)
1571 ScConditionalFormat* pCondFormat = mpCondFormatList->GetFormat(*itr);
1572 ScRangeList aRange = pCondFormat->GetRange();
1573 aRange.Join(ScRange(nCol, nIMin, nTab, nCol, nIMax, nTab));
1574 pCondFormat->SetRange(aRange);
1577 else
1579 for(SCROW nAtRow = static_cast<SCROW>(nIMin); nAtRow <= static_cast<SCROW>(nIMax); ++nAtRow)
1581 if(!RowHidden(nAtRow))
1583 aCol[nCol].SetPatternArea( static_cast<SCROW>(nAtRow),
1584 static_cast<SCROW>(nAtRow), *pSrcPattern, true);
1585 for(std::vector<sal_uInt32>::const_iterator itr = rCondFormatIndex.begin(), itrEnd = rCondFormatIndex.end();
1586 itr != itrEnd; ++itr)
1588 ScConditionalFormat* pCondFormat = mpCondFormatList->GetFormat(*itr);
1589 ScRangeList aRange = pCondFormat->GetRange();
1590 aRange.Join(ScRange(nCol, nAtRow, nTab, nCol, nAtRow, nTab));
1591 pCondFormat->SetRange(aRange);
1598 else
1599 for (SCCOL nAtCol = static_cast<SCCOL>(nIMin); nAtCol <= sal::static_int_cast<SCCOL>(nIMax); nAtCol++)
1600 if(!ColHidden(nAtCol))
1602 aCol[nAtCol].SetPattern(static_cast<SCROW>(nRow), *pSrcPattern, true);
1603 for(std::vector<sal_uInt32>::const_iterator itr = rCondFormatIndex.begin(), itrEnd = rCondFormatIndex.end();
1604 itr != itrEnd; ++itr)
1606 ScConditionalFormat* pCondFormat = mpCondFormatList->GetFormat(*itr);
1607 ScRangeList aRange = pCondFormat->GetRange();
1608 aRange.Join(ScRange(nAtCol, static_cast<SCROW>(nRow), nTab, nAtCol, static_cast<SCROW>(nRow), nTab));
1609 pCondFormat->SetRange(aRange);
1614 if (!aSrcCell.isEmpty())
1616 CellType eCellType = aSrcCell.meType;
1618 if (eFillCmd == FILL_SIMPLE) // copy
1620 FillSeriesSimple(aSrcCell, rInner, nIMin, nIMax, nCol, nRow, bVertical, pProgress, nProgress);
1622 else if (eCellType == CELLTYPE_VALUE || eCellType == CELLTYPE_FORMULA)
1624 double nStartVal;
1625 if (eCellType == CELLTYPE_VALUE)
1626 nStartVal = aSrcCell.mfValue;
1627 else
1628 nStartVal = aSrcCell.mpFormula->GetValue();
1629 double nVal = nStartVal;
1630 long nIndex = 0;
1632 bool bError = false;
1633 bool bOverflow = false;
1635 sal_uInt16 nDayOfMonth = 0;
1636 rInner = nIStart;
1637 while (true) // #i53728# with "for (;;)" old solaris/x86 compiler mis-optimizes
1639 if(!ColHidden(nCol) && !RowHidden(nRow))
1641 if (!bError && !bOverflow)
1643 switch (eFillCmd)
1645 case FILL_LINEAR:
1647 // use multiplication instead of repeated addition
1648 // to avoid accumulating rounding errors
1649 nVal = nStartVal;
1650 double nAdd = nStepValue;
1651 if ( !SubTotal::SafeMult( nAdd, (double) ++nIndex ) ||
1652 !SubTotal::SafePlus( nVal, nAdd ) )
1653 bError = true;
1655 break;
1656 case FILL_GROWTH:
1657 if (!SubTotal::SafeMult(nVal, nStepValue))
1658 bError = true;
1659 break;
1660 case FILL_DATE:
1661 if (fabs(nVal) > _D_MAX_LONG_)
1662 bError = true;
1663 else
1664 IncDate(nVal, nDayOfMonth, nStepValue, eFillDateCmd);
1665 break;
1666 default:
1668 // added to avoid warnings
1672 if (nStepValue >= 0)
1674 if (nVal > nMaxValue) // target value reached ?
1676 nVal = nMaxValue;
1677 bOverflow = true;
1680 else
1682 if (nVal < nMaxValue)
1684 nVal = nMaxValue;
1685 bOverflow = true;
1690 if (bError)
1691 aCol[nCol].SetError(static_cast<SCROW>(nRow), errNoValue);
1692 else if (bOverflow)
1693 aCol[nCol].SetError(static_cast<SCROW>(nRow), errIllegalFPOperation);
1694 else
1695 aCol[nCol].SetValue(static_cast<SCROW>(nRow), nVal);
1698 if (rInner == nIEnd)
1699 break;
1700 if (bPositive)
1702 ++rInner;
1704 else
1706 --rInner;
1709 nProgress += nIMax - nIMin + 1;
1710 if(pProgress)
1711 pProgress->SetStateOnPercent( nProgress );
1713 else if (eCellType == CELLTYPE_STRING || eCellType == CELLTYPE_EDIT)
1715 if ( nStepValue >= 0 )
1717 if ( nMaxValue >= (double)LONG_MAX )
1718 nMaxValue = (double)LONG_MAX - 1;
1720 else
1722 if ( nMaxValue <= (double)LONG_MIN )
1723 nMaxValue = (double)LONG_MIN + 1;
1725 OUString aValue;
1726 if (eCellType == CELLTYPE_STRING)
1727 aValue = aSrcCell.mpString->getString();
1728 else
1729 aValue = ScEditUtil::GetString(*aSrcCell.mpEditText, pDocument);
1730 sal_Int32 nStringValue;
1731 sal_uInt16 nMinDigits = nArgMinDigits;
1732 short nHeadNoneTail = lcl_DecompValueString( aValue, nStringValue, &nMinDigits );
1733 if ( nHeadNoneTail )
1735 double nStartVal = (double)nStringValue;
1736 double nVal = nStartVal;
1737 long nIndex = 0;
1738 bool bError = false;
1739 bool bOverflow = false;
1741 bool bIsOrdinalSuffix = aValue.equals( ScGlobal::GetOrdinalSuffix(
1742 (sal_Int32)nStartVal));
1744 rInner = nIStart;
1745 while (true) // #i53728# with "for (;;)" old solaris/x86 compiler mis-optimizes
1747 if(!ColHidden(nCol) && !RowHidden(nRow))
1749 if (!bError && !bOverflow)
1751 switch (eFillCmd)
1753 case FILL_LINEAR:
1755 // use multiplication instead of repeated addition
1756 // to avoid accumulating rounding errors
1757 nVal = nStartVal;
1758 double nAdd = nStepValue;
1759 if ( !SubTotal::SafeMult( nAdd, (double) ++nIndex ) ||
1760 !SubTotal::SafePlus( nVal, nAdd ) )
1761 bError = true;
1763 break;
1764 case FILL_GROWTH:
1765 if (!SubTotal::SafeMult(nVal, nStepValue))
1766 bError = true;
1767 break;
1768 default:
1770 // added to avoid warnings
1774 if (nStepValue >= 0)
1776 if (nVal > nMaxValue) // target value reached ?
1778 nVal = nMaxValue;
1779 bOverflow = true;
1782 else
1784 if (nVal < nMaxValue)
1786 nVal = nMaxValue;
1787 bOverflow = true;
1792 if (bError)
1793 aCol[nCol].SetError(static_cast<SCROW>(nRow), errNoValue);
1794 else if (bOverflow)
1795 aCol[nCol].SetError(static_cast<SCROW>(nRow), errIllegalFPOperation);
1796 else
1798 nStringValue = (sal_Int32)nVal;
1799 OUString aStr;
1800 if ( nHeadNoneTail < 0 )
1802 setSuffixCell(
1803 aCol[nCol], static_cast<SCROW>(nRow),
1804 nStringValue, nMinDigits, aValue,
1805 eCellType, bIsOrdinalSuffix);
1807 else
1809 aStr = aValue;
1810 aStr += lcl_ValueString( nStringValue, nMinDigits );
1811 aCol[nCol].SetRawString(static_cast<SCROW>(nRow), aStr);
1816 if (rInner == nIEnd) break;
1817 if (bPositive) ++rInner; else --rInner;
1820 if(pProgress)
1822 nProgress += nIMax - nIMin + 1;
1823 pProgress->SetStateOnPercent( nProgress );
1827 else if(pProgress)
1829 nProgress += nIMax - nIMin + 1;
1830 pProgress->SetStateOnPercent( nProgress );
1832 ++nActFormCnt;
1836 void ScTable::Fill( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
1837 sal_uLong nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd,
1838 double nStepValue, double nMaxValue, ScProgress* pProgress)
1840 if (eFillCmd == FILL_AUTO)
1841 FillAuto(nCol1, nRow1, nCol2, nRow2, nFillCount, eFillDir, pProgress);
1842 else
1843 FillSeries(nCol1, nRow1, nCol2, nRow2, nFillCount, eFillDir,
1844 eFillCmd, eFillDateCmd, nStepValue, nMaxValue, 0, true, pProgress);
1847 void ScTable::AutoFormatArea(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
1848 const ScPatternAttr& rAttr, sal_uInt16 nFormatNo)
1850 ScAutoFormat& rFormat = *ScGlobal::GetOrCreateAutoFormat();
1851 ScAutoFormatData* pData = rFormat.findByIndex(nFormatNo);
1852 if (pData)
1854 ApplyPatternArea(nStartCol, nStartRow, nEndCol, nEndRow, rAttr);
1858 void ScTable::AutoFormat( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
1859 sal_uInt16 nFormatNo )
1861 if (ValidColRow(nStartCol, nStartRow) && ValidColRow(nEndCol, nEndRow))
1863 ScAutoFormat& rFormat = *ScGlobal::GetOrCreateAutoFormat();
1864 ScAutoFormatData* pData = rFormat.findByIndex(nFormatNo);
1865 if (pData)
1867 ScPatternAttr* pPatternAttrs[16];
1868 for (sal_uInt8 i = 0; i < 16; ++i)
1870 pPatternAttrs[i] = new ScPatternAttr(pDocument->GetPool());
1871 pData->FillToItemSet(i, pPatternAttrs[i]->GetItemSet(), *pDocument);
1874 SCCOL nCol = nStartCol;
1875 SCROW nRow = nStartRow;
1876 sal_uInt16 nIndex = 0;
1877 // Left top corner
1878 AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
1879 // Left column
1880 if (pData->IsEqualData(4, 8))
1881 AutoFormatArea(nStartCol, nStartRow + 1, nStartCol, nEndRow - 1, *pPatternAttrs[4], nFormatNo);
1882 else
1884 nIndex = 4;
1885 for (nRow = nStartRow + 1; nRow < nEndRow; nRow++)
1887 AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
1888 if (nIndex == 4)
1889 nIndex = 8;
1890 else
1891 nIndex = 4;
1894 // Left bottom corner
1895 nRow = nEndRow;
1896 nIndex = 12;
1897 AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
1898 // Right top corner
1899 nCol = nEndCol;
1900 nRow = nStartRow;
1901 nIndex = 3;
1902 AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
1903 // Right column
1904 if (pData->IsEqualData(7, 11))
1905 AutoFormatArea(nEndCol, nStartRow + 1, nEndCol, nEndRow - 1, *pPatternAttrs[7], nFormatNo);
1906 else
1908 nIndex = 7;
1909 for (nRow = nStartRow + 1; nRow < nEndRow; nRow++)
1911 AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
1912 if (nIndex == 7)
1913 nIndex = 11;
1914 else
1915 nIndex = 7;
1918 // Right bottom corner
1919 nRow = nEndRow;
1920 nIndex = 15;
1921 AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
1922 nRow = nStartRow;
1923 nIndex = 1;
1924 for (nCol = nStartCol + 1; nCol < nEndCol; nCol++)
1926 AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
1927 if (nIndex == 1)
1928 nIndex = 2;
1929 else
1930 nIndex = 1;
1932 // Bottom row
1933 nRow = nEndRow;
1934 nIndex = 13;
1935 for (nCol = nStartCol + 1; nCol < nEndCol; nCol++)
1937 AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
1938 if (nIndex == 13)
1939 nIndex = 14;
1940 else
1941 nIndex = 13;
1943 // Boddy
1944 if ((pData->IsEqualData(5, 6)) && (pData->IsEqualData(9, 10)) && (pData->IsEqualData(5, 9)))
1945 AutoFormatArea(nStartCol + 1, nStartRow + 1, nEndCol-1, nEndRow - 1, *pPatternAttrs[5], nFormatNo);
1946 else
1948 if ((pData->IsEqualData(5, 9)) && (pData->IsEqualData(6, 10)))
1950 nIndex = 5;
1951 for (nCol = nStartCol + 1; nCol < nEndCol; nCol++)
1953 AutoFormatArea(nCol, nStartRow + 1, nCol, nEndRow - 1, *pPatternAttrs[nIndex], nFormatNo);
1954 if (nIndex == 5)
1955 nIndex = 6;
1956 else
1957 nIndex = 5;
1960 else
1962 nIndex = 5;
1963 for (nCol = nStartCol + 1; nCol < nEndCol; nCol++)
1965 for (nRow = nStartRow + 1; nRow < nEndRow; nRow++)
1967 AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
1968 if ((nIndex == 5) || (nIndex == 9))
1970 if (nIndex == 5)
1971 nIndex = 9;
1972 else
1973 nIndex = 5;
1975 else
1977 if (nIndex == 6)
1978 nIndex = 10;
1979 else
1980 nIndex = 6;
1982 } // for nRow
1983 if ((nIndex == 5) || (nIndex == 9))
1984 nIndex = 6;
1985 else
1986 nIndex = 5;
1987 } // for nCol
1988 } // if not equal Column
1989 } // if not all equal
1991 for (sal_uInt8 j = 0; j < 16; ++j)
1992 delete pPatternAttrs[j];
1993 } // if AutoFormatData != NULL
1994 } // if ValidColRow
1997 void ScTable::GetAutoFormatAttr(SCCOL nCol, SCROW nRow, sal_uInt16 nIndex, ScAutoFormatData& rData)
1999 sal_uInt32 nFormatIndex = GetNumberFormat( nCol, nRow );
2000 ScNumFormatAbbrev aNumFormat( nFormatIndex, *pDocument->GetFormatTable() );
2001 rData.GetFromItemSet( nIndex, GetPattern( nCol, nRow )->GetItemSet(), aNumFormat );
2004 #define LF_LEFT 1
2005 #define LF_TOP 2
2006 #define LF_RIGHT 4
2007 #define LF_BOTTOM 8
2008 #define LF_ALL (LF_LEFT | LF_TOP | LF_RIGHT | LF_BOTTOM)
2010 void ScTable::GetAutoFormatFrame(SCCOL nCol, SCROW nRow, sal_uInt16 nFlags, sal_uInt16 nIndex, ScAutoFormatData& rData)
2012 const SvxBoxItem* pTheBox = static_cast<const SvxBoxItem*>(GetAttr(nCol, nRow, ATTR_BORDER));
2013 const SvxBoxItem* pLeftBox = static_cast<const SvxBoxItem*>(GetAttr(nCol - 1, nRow, ATTR_BORDER));
2014 const SvxBoxItem* pTopBox = static_cast<const SvxBoxItem*>(GetAttr(nCol, nRow - 1, ATTR_BORDER));
2015 const SvxBoxItem* pRightBox = static_cast<const SvxBoxItem*>(GetAttr(nCol + 1, nRow, ATTR_BORDER));
2016 const SvxBoxItem* pBottomBox = static_cast<const SvxBoxItem*>(GetAttr(nCol, nRow + 1, ATTR_BORDER));
2018 SvxBoxItem aBox( ATTR_BORDER );
2019 if (nFlags & LF_LEFT)
2021 if (pLeftBox)
2023 if (ScHasPriority(pTheBox->GetLeft(), pLeftBox->GetRight()))
2024 aBox.SetLine(pTheBox->GetLeft(), SvxBoxItemLine::LEFT);
2025 else
2026 aBox.SetLine(pLeftBox->GetRight(), SvxBoxItemLine::LEFT);
2028 else
2029 aBox.SetLine(pTheBox->GetLeft(), SvxBoxItemLine::LEFT);
2031 if (nFlags & LF_TOP)
2033 if (pTopBox)
2035 if (ScHasPriority(pTheBox->GetTop(), pTopBox->GetBottom()))
2036 aBox.SetLine(pTheBox->GetTop(), SvxBoxItemLine::TOP);
2037 else
2038 aBox.SetLine(pTopBox->GetBottom(), SvxBoxItemLine::TOP);
2040 else
2041 aBox.SetLine(pTheBox->GetTop(), SvxBoxItemLine::TOP);
2043 if (nFlags & LF_RIGHT)
2045 if (pRightBox)
2047 if (ScHasPriority(pTheBox->GetRight(), pRightBox->GetLeft()))
2048 aBox.SetLine(pTheBox->GetRight(), SvxBoxItemLine::RIGHT);
2049 else
2050 aBox.SetLine(pRightBox->GetLeft(), SvxBoxItemLine::RIGHT);
2052 else
2053 aBox.SetLine(pTheBox->GetRight(), SvxBoxItemLine::RIGHT);
2055 if (nFlags & LF_BOTTOM)
2057 if (pBottomBox)
2059 if (ScHasPriority(pTheBox->GetBottom(), pBottomBox->GetTop()))
2060 aBox.SetLine(pTheBox->GetBottom(), SvxBoxItemLine::BOTTOM);
2061 else
2062 aBox.SetLine(pBottomBox->GetTop(), SvxBoxItemLine::BOTTOM);
2064 else
2065 aBox.SetLine(pTheBox->GetBottom(), SvxBoxItemLine::BOTTOM);
2067 rData.PutItem( nIndex, aBox );
2070 void ScTable::GetAutoFormatData(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, ScAutoFormatData& rData)
2072 if (ValidColRow(nStartCol, nStartRow) && ValidColRow(nEndCol, nEndRow))
2074 if ((nEndCol - nStartCol >= 3) && (nEndRow - nStartRow >= 3))
2076 // Left top corner
2077 GetAutoFormatAttr(nStartCol, nStartRow, 0, rData);
2078 GetAutoFormatFrame(nStartCol, nStartRow, LF_ALL, 0, rData);
2079 // Left column
2080 GetAutoFormatAttr(nStartCol, nStartRow + 1, 4, rData);
2081 GetAutoFormatAttr(nStartCol, nStartRow + 2, 8, rData);
2082 GetAutoFormatFrame(nStartCol, nStartRow + 1, LF_LEFT | LF_RIGHT | LF_BOTTOM, 4, rData);
2083 if (nEndRow - nStartRow >= 4)
2084 GetAutoFormatFrame(nStartCol, nStartRow + 2, LF_LEFT | LF_RIGHT | LF_BOTTOM, 8, rData);
2085 else
2086 rData.CopyItem( 8, 4, ATTR_BORDER );
2087 // Left bottom corner
2088 GetAutoFormatAttr(nStartCol, nEndRow, 12, rData);
2089 GetAutoFormatFrame(nStartCol, nEndRow, LF_ALL, 12, rData);
2090 // Right top corner
2091 GetAutoFormatAttr(nEndCol, nStartRow, 3, rData);
2092 GetAutoFormatFrame(nEndCol, nStartRow, LF_ALL, 3, rData);
2093 // Right column
2094 GetAutoFormatAttr(nEndCol, nStartRow + 1, 7, rData);
2095 GetAutoFormatAttr(nEndCol, nStartRow + 2, 11, rData);
2096 GetAutoFormatFrame(nEndCol, nStartRow + 1, LF_LEFT | LF_RIGHT | LF_BOTTOM, 7, rData);
2097 if (nEndRow - nStartRow >= 4)
2098 GetAutoFormatFrame(nEndCol, nStartRow + 2, LF_LEFT | LF_RIGHT | LF_BOTTOM, 11, rData);
2099 else
2100 rData.CopyItem( 11, 7, ATTR_BORDER );
2101 // Right bottom corner
2102 GetAutoFormatAttr(nEndCol, nEndRow, 15, rData);
2103 GetAutoFormatFrame(nEndCol, nEndRow, LF_ALL, 15, rData);
2104 // Top row
2105 GetAutoFormatAttr(nStartCol + 1, nStartRow, 1, rData);
2106 GetAutoFormatAttr(nStartCol + 2, nStartRow, 2, rData);
2107 GetAutoFormatFrame(nStartCol + 1, nStartRow, LF_TOP | LF_BOTTOM | LF_RIGHT, 1, rData);
2108 if (nEndCol - nStartCol >= 4)
2109 GetAutoFormatFrame(nStartCol + 2, nStartRow, LF_TOP | LF_BOTTOM | LF_RIGHT, 2, rData);
2110 else
2111 rData.CopyItem( 2, 1, ATTR_BORDER );
2112 // Bottom row
2113 GetAutoFormatAttr(nStartCol + 1, nEndRow, 13, rData);
2114 GetAutoFormatAttr(nStartCol + 2, nEndRow, 14, rData);
2115 GetAutoFormatFrame(nStartCol + 1, nEndRow, LF_TOP | LF_BOTTOM | LF_RIGHT, 13, rData);
2116 if (nEndCol - nStartCol >= 4)
2117 GetAutoFormatFrame(nStartCol + 2, nEndRow, LF_TOP | LF_BOTTOM | LF_RIGHT, 14, rData);
2118 else
2119 rData.CopyItem( 14, 13, ATTR_BORDER );
2120 // Body
2121 GetAutoFormatAttr(nStartCol + 1, nStartRow + 1, 5, rData);
2122 GetAutoFormatAttr(nStartCol + 2, nStartRow + 1, 6, rData);
2123 GetAutoFormatAttr(nStartCol + 1, nStartRow + 2, 9, rData);
2124 GetAutoFormatAttr(nStartCol + 2, nStartRow + 2, 10, rData);
2125 GetAutoFormatFrame(nStartCol + 1, nStartRow + 1, LF_RIGHT | LF_BOTTOM, 5, rData);
2126 if ((nEndCol - nStartCol >= 4) && (nEndRow - nStartRow >= 4))
2128 GetAutoFormatFrame(nStartCol + 2, nStartRow + 1, LF_RIGHT | LF_BOTTOM, 6, rData);
2129 GetAutoFormatFrame(nStartCol + 1, nStartRow + 2, LF_RIGHT | LF_BOTTOM, 9, rData);
2130 GetAutoFormatFrame(nStartCol + 2, nStartRow + 2, LF_RIGHT | LF_BOTTOM, 10, rData);
2132 else
2134 rData.CopyItem( 6, 5, ATTR_BORDER );
2135 rData.CopyItem( 9, 5, ATTR_BORDER );
2136 rData.CopyItem( 10, 5, ATTR_BORDER );
2142 void ScTable::SetError( SCCOL nCol, SCROW nRow, sal_uInt16 nError)
2144 if (ValidColRow(nCol, nRow))
2145 aCol[nCol].SetError( nRow, nError );
2148 void ScTable::UpdateInsertTabAbs(SCTAB nTable)
2150 for (SCCOL i=0; i <= MAXCOL; i++)
2151 aCol[i].UpdateInsertTabAbs(nTable);
2154 bool ScTable::GetNextSpellingCell(SCCOL& rCol, SCROW& rRow, bool bInSel,
2155 const ScMarkData& rMark) const
2157 if (rRow == MAXROW+2) // end of table
2159 rRow = 0;
2160 rCol = 0;
2162 else
2164 rRow++;
2165 if (rRow == MAXROW+1)
2167 rCol++;
2168 rRow = 0;
2171 if (rCol == MAXCOL+1)
2172 return true;
2173 else
2175 bool bStop = false;
2176 while (!bStop)
2178 if (ValidCol(rCol))
2180 bStop = aCol[rCol].GetNextSpellingCell(rRow, bInSel, rMark);
2181 if (bStop)
2182 return true;
2183 else /*if (rRow == MAXROW+1) */
2185 rCol++;
2186 rRow = 0;
2189 else
2190 return true;
2193 return false;
2196 bool ScTable::TestTabRefAbs(SCTAB nTable) const
2198 for (SCCOL i=0; i <= MAXCOL; i++)
2199 if (aCol[i].TestTabRefAbs(nTable))
2200 return true;
2201 return false;
2204 void ScTable::CompileDBFormula( sc::CompileFormulaContext& rCxt )
2206 for (SCCOL i = 0; i <= MAXCOL; ++i)
2207 aCol[i].CompileDBFormula(rCxt);
2210 void ScTable::CompileColRowNameFormula( sc::CompileFormulaContext& rCxt )
2212 for (SCCOL i = 0; i <= MAXCOL; ++i)
2213 aCol[i].CompileColRowNameFormula(rCxt);
2216 SCSIZE ScTable::GetPatternCount( SCCOL nCol ) const
2218 if( ValidCol( nCol ) )
2219 return aCol[nCol].GetPatternCount();
2220 else
2221 return 0;
2224 SCSIZE ScTable::GetPatternCount( SCCOL nCol, SCROW nRow1, SCROW nRow2 ) const
2226 if( ValidCol( nCol ) && ValidRow( nRow1 ) && ValidRow( nRow2 ) )
2227 return aCol[nCol].GetPatternCount( nRow1, nRow2 );
2228 else
2229 return 0;
2232 bool ScTable::ReservePatternCount( SCCOL nCol, SCSIZE nReserve )
2234 if( ValidCol( nCol ) )
2235 return aCol[nCol].ReservePatternCount( nReserve );
2236 else
2237 return false;
2240 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */