1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
46 #include "patattr.hxx"
47 #include "formulacell.hxx"
49 #include "globstr.hrc"
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"
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
)
81 const sal_Unicode
* p
= aValue
.GetBuffer();
86 while ( p
[nNum
] && CharClass::isAsciiNumeric( OUString(p
[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
);
107 xub_StrLen nEnd
= nNum
= aValue
.Len() - 1;
108 while ( nNum
&& CharClass::isAsciiNumeric( OUString(p
[nNum
]) ) )
110 if ( p
[nNum
] == '-' )
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 );
129 static OUString
lcl_ValueString( sal_Int32 nValue
, sal_uInt16 nMinDigits
)
131 if ( nMinDigits
<= 1 )
132 return OUString::number( nValue
); // simple case...
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
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" );
187 if ( (nScFillModeMouseModifier
& KEY_MOD1
) )
188 return ; // Ctrl-key: Copy
197 nCount
= static_cast<SCSIZE
>(nRow2
- nRow1
+ 1);
203 nCount
= static_cast<SCSIZE
>(nCol2
- nCol1
+ 1);
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
);
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
)
232 long nDDiff
= aDate2
.GetDay() - (long) aDate1
.GetDay();
233 long nMDiff
= aDate2
.GetMonth() - (long) aDate1
.GetMonth();
234 long nYDiff
= aDate2
.GetYear() - (long) aDate1
.GetYear();
238 nCmpInc
= aDate2
- aDate1
;
243 nCmpInc
= nMDiff
+ 12 * nYDiff
;
246 nCol
= sal::static_int_cast
<SCCOL
>( nCol
+ nAddX
);
247 nRow
= sal::static_int_cast
<SCROW
>( nRow
+ nAddY
);
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
)
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
))
270 nCol
= sal::static_int_cast
<SCCOL
>( nCol
+ nAddX
);
271 nRow
= sal::static_int_cast
<SCROW
>( nRow
+ nAddY
);
274 bVal
= false; // kein Datum passt auch nicht
278 if ( eType
== FILL_MONTH
&& ( nCmpInc
% 12 == 0 ) )
289 else // single date -> increment by days
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
);
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 ) )
319 nCol
= sal::static_int_cast
<SCCOL
>( nCol
+ nAddX
);
320 nRow
= sal::static_int_cast
<SCROW
>( nRow
+ nAddY
);
327 else if (eCellType
== CELLTYPE_STRING
|| eCellType
== CELLTYPE_EDIT
)
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
)
337 GetString(static_cast<SCCOL
>(nCol
+ i
* nAddX
), static_cast<SCROW
>(nRow
+ i
* nAddY
), aTestStr
);
344 if(bAllSame
&& nCount
> 1)
347 rListData
= (ScUserListData
*)(ScGlobal::GetUserList()->GetData(aStr
));
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
))
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
368 String aString
= aStr
;
369 short nFlag1
= lcl_DecompValueString( aString
, nVal1
, &rMinDigits
);
374 GetString( nCol
+nAddX
, nRow
+nAddY
, aStr
);
376 short nFlag2
= lcl_DecompValueString( aString
, nVal2
, &rMinDigits
);
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
);
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();
393 aStr
= ((ScEditCell
*)pCell
)->GetString();
395 nFlag2
= lcl_DecompValueString( aString
, nVal2
, &rMinDigits
);
397 if ( nFlag1
== nFlag2
)
399 double nDiff
= (double)nVal2
- (double)nVal1
;
400 if ( !::rtl::math::approxEqual( nDiff
, rInc
, 13 ) )
409 nCol
= sal::static_int_cast
<SCCOL
>( nCol
+ nAddX
);
410 nRow
= sal::static_int_cast
<SCROW
>( nRow
+ nAddY
);
419 // call DecompValueString to set rMinDigits
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() )
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 );
452 OSL_FAIL( "FillFormula: MatrixOrigin no forumla cell with MM_FORMULA" );
457 OSL_FAIL( "FillFormula: MatrixOrigin bottom right" );
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
) )
480 bool bVertical
= (eFillDir
== FILL_TO_BOTTOM
|| eFillDir
== FILL_TO_TOP
);
481 bool bPositive
= (eFillDir
== FILL_TO_BOTTOM
|| eFillDir
== FILL_TO_RIGHT
);
485 sal_uLong
& rInner
= bVertical
? nRow
: nCol
; // loop variables
486 sal_uLong
& rOuter
= bVertical
? nCol
: nRow
;
491 sal_uLong nISrcStart
;
504 nIEnd
= nRow2
+ nFillCount
;
505 aFillRange
= ScRange(nCol1
, nRow2
+1, 0, nCol2
, nRow2
+ nFillCount
, 0);
512 nIEnd
= nRow1
- nFillCount
;
513 aFillRange
= ScRange(nCol1
, nRow1
-1, 0, nCol2
, nRow2
- nFillCount
, 0);
525 nIEnd
= nCol2
+ nFillCount
;
526 aFillRange
= ScRange(nCol2
+ 1, nRow1
, 0, nCol2
+ nFillCount
, nRow2
, 0);
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
);
545 DeleteArea(nCol1
, static_cast<SCROW
>(nIMin
), nCol2
, static_cast<SCROW
>(nIMax
), IDF_AUTOFILL
);
547 DeleteArea(static_cast<SCCOL
>(nIMin
), nRow1
, static_cast<SCCOL
>(nIMax
), nRow2
, IDF_AUTOFILL
);
550 sal_uLong nProgress
= 0;
552 nProgress
= pProgress
->GetState();
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;
571 while (true) // #i53728# with "for (;;)" old solaris/x86 compiler mis-optimizes
573 if (!ColHidden(nCol
) && !RowHidden(nRow
))
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
));
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
);
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
));
610 aCol
[nCol
].ApplyStyleArea( nY1
, nY2
, *pStyleSheet
);
612 aCol
[nCol
].ApplyPatternArea( nY1
, nY2
, *pNewPattern
);
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
);
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 ??
639 aCol
[nCol
].ApplyStyle( static_cast<SCROW
>(nRow
), *pStyleSheet
);
641 // Use ApplyPattern instead of SetPattern to keep old MergeFlags
643 aCol
[nCol
].ApplyPattern( static_cast<SCROW
>(nRow
), *pNewPattern
);
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
677 if (rInner
== nIEnd
) break;
678 if (bPositive
) ++rInner
; else --rInner
;
686 FillDateCmd eDateCmd
;
688 sal_uInt16 nMinDigits
;
689 ScUserListData
* pListData
= NULL
;
690 sal_uInt16 nListIndex
;
692 FillAnalyse(static_cast<SCCOL
>(nCol
),nRow1
,
693 static_cast<SCCOL
>(nCol
),nRow2
, eFillCmd
,eDateCmd
,
694 nInc
,nMinDigits
, pListData
,nListIndex
);
696 FillAnalyse(nCol1
,static_cast<SCROW
>(nRow
),
697 nCol2
,static_cast<SCROW
>(nRow
), eFillCmd
,eDateCmd
,
698 nInc
,nMinDigits
, pListData
,nListIndex
);
701 aCol
[nCol
].ReserveSize(aCol
[nCol
].GetCellCount() + nFillCount
);
705 sal_uInt16 nListCount
= pListData
->GetSubCount();
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
;
718 while (true) // #i53728# with "for (;;)" old solaris/x86 compiler mis-optimizes
720 if(!ColHidden(nCol
) && !RowHidden(nRow
))
725 if (nListIndex
>= nListCount
) nListIndex
= 0;
729 if (nListIndex
== 0) nListIndex
= nListCount
;
732 aCol
[nCol
].Insert(static_cast<SCROW
>(nRow
), new ScStringCell(pListData
->GetSubStr(nListIndex
)));
735 if (rInner
== nIEnd
) break;
736 if (bPositive
) ++rInner
; else --rInner
;
740 nProgress
+= nIMax
- nIMin
+ 1;
741 pProgress
->SetStateOnPercent( nProgress
);
744 else if (eFillCmd
== FILL_SIMPLE
) // fill with pattern/sample
746 sal_uLong nSource
= nISrcStart
;
748 if ( (nScFillModeMouseModifier
& KEY_MOD1
) )
750 else if ( bPositive
)
755 sal_uLong nFormulaCounter
= nActFormCnt
;
757 bool bGetCell
= true;
758 sal_uInt16 nCellDigits
= 0;
759 short nHeadNoneTail
= 0;
760 sal_Int32 nStringValue
= 0;
762 ScBaseCell
* pSrcCell
= NULL
;
763 CellType eCellType
= CELLTYPE_NONE
;
764 bool bIsOrdinalSuffix
= false;
767 while (true) // #i53728# with "for (;;)" old solaris/x86 compiler mis-optimizes
769 if(!ColHidden(nCol
) && !RowHidden(nRow
))
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
) );
780 eCellType
= pSrcCell
->GetCellType();
784 nVal
= ((ScValueCell
*)pSrcCell
)->GetValue();
786 case CELLTYPE_STRING
:
788 if ( eCellType
== CELLTYPE_STRING
)
789 aValue
= ((ScStringCell
*)pSrcCell
)->GetString();
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
));
804 // added to avoid warnings
809 eCellType
= CELLTYPE_NONE
;
815 aCol
[nCol
].Insert(static_cast<SCROW
>(nRow
), new ScValueCell(nVal
+ nDelta
));
817 case CELLTYPE_STRING
:
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
;
827 if ( nHeadNoneTail
< 0 )
829 aCol
[nCol
].Insert( static_cast<SCROW
>(nRow
),
830 lcl_getSuffixCell( pDocument
,
831 nNextValue
, nCellDigits
, aValue
,
832 eCellType
, bIsOrdinalSuffix
));
836 aStr
= aValue
+ lcl_ValueString( nNextValue
, nCellDigits
);
837 aCol
[nCol
].Insert( static_cast<SCROW
>(nRow
),
838 new ScStringCell( aStr
));
843 ScAddress
aDestPos( static_cast<SCCOL
>(nCol
), static_cast<SCROW
>(nRow
), nTab
);
846 case CELLTYPE_STRING
:
848 aCol
[nCol
].Insert( aDestPos
.Row(), pSrcCell
->Clone( *pDocument
) );
852 // added to avoid warnings
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
;
867 // added to avoid warnings
871 if (nSource
==nISrcEnd
)
873 if ( nSource
!= nISrcStart
)
874 { // More than one source cell
875 nSource
= nISrcStart
;
878 if ( !(nScFillModeMouseModifier
& KEY_MOD1
) )
885 nFormulaCounter
= nActFormCnt
;
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
907 if ( pProgress
&& (eCellType
== CELLTYPE_FORMULA
|| eCellType
== CELLTYPE_EDIT
) )
908 pProgress
->SetStateOnPercent( nProgress
);
912 pProgress
->SetStateOnPercent( nProgress
);
918 double nEndVal
= (nInc
>=0.0) ? MAXDOUBLE
: -MAXDOUBLE
;
920 FillSeries( static_cast<SCCOL
>(nCol
), nRow1
,
921 static_cast<SCCOL
>(nCol
), nRow2
, nFillCount
, eFillDir
,
922 eFillCmd
, eDateCmd
, nInc
, nEndVal
, nMinDigits
, false,
925 FillSeries( nCol1
, static_cast<SCROW
>(nRow
), nCol2
,
926 static_cast<SCROW
>(nRow
), nFillCount
, eFillDir
,
927 eFillCmd
, eDateCmd
, nInc
, nEndVal
, nMinDigits
, false,
930 nProgress
= pProgress
->GetState();
933 nActFormCnt
+= nMaxFormCnt
;
937 String
ScTable::GetAutoFillPreview( const ScRange
& rSource
, SCCOL nEndX
, SCROW nEndY
)
941 SCCOL nCol1
= rSource
.aStart
.Col();
942 SCROW nRow1
= rSource
.aStart
.Row();
943 SCCOL nCol2
= rSource
.aEnd
.Col();
944 SCROW nRow2
= rSource
.aEnd
.Row();
947 sal_uLong nSrcCount
= 0;
948 FillDir eFillDir
= FILL_TO_BOTTOM
;
949 if ( nEndX
== nCol2
&& nEndY
== nRow2
) // empty
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
;
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
;
969 eFillDir
= FILL_TO_LEFT
;
971 else // direction not clear
977 FillDateCmd eDateCmd
;
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();
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
))
1014 long nNonFiltered
= CountNonFilteredRows(nBegin
, nEnd
);
1015 long nFiltered
= nEnd
+ 1 - nBegin
- nNonFiltered
;
1018 nIndex
= nIndex
- nFiltered
;
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
) );
1032 nSrcX
= sal::static_int_cast
<SCCOL
>( nSrcX
+ static_cast<SCCOL
>(nPos
) );
1034 ScBaseCell
* pCell
= GetCell( nSrcX
, nSrcY
);
1039 nDelta
= nIndex
/ nSrcCount
;
1041 nDelta
= ( nIndex
- nSrcCount
+ 1 ) / nSrcCount
; // -1 -> -1
1043 CellType eType
= pCell
->GetCellType();
1046 case CELLTYPE_STRING
:
1049 if ( eType
== CELLTYPE_STRING
)
1050 aValue
= ((ScStringCell
*)pCell
)->GetString();
1052 aValue
= ((ScEditCell
*)pCell
)->GetString();
1053 if ( !(nScFillModeMouseModifier
& KEY_MOD1
) )
1056 sal_uInt16 nCellDigits
= 0; // look at each source cell individually
1057 short nFlag
= lcl_DecompValueString( aValue
, nVal
, &nCellDigits
);
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
);
1070 case CELLTYPE_VALUE
:
1072 // overflow is possible...
1073 double nVal
= ((ScValueCell
*)pCell
)->GetValue();
1074 if ( !(nScFillModeMouseModifier
& KEY_MOD1
) )
1075 nVal
+= (double) nDelta
;
1078 sal_uLong nNumFmt
= GetNumberFormat( nSrcX
, nSrcY
);
1079 pDocument
->GetFormatTable()->
1080 GetOutputString( nVal
, nNumFmt
, aValue
, &pColor
);
1086 // added to avoid warnings
1091 else if ( eFillCmd
== FILL_LINEAR
|| eFillCmd
== FILL_DATE
) // values
1096 short nHeadNoneTail
= 0;
1097 ScBaseCell
* pCell
= GetCell( nCol1
, nRow1
);
1100 CellType eType
= pCell
->GetCellType();
1103 case CELLTYPE_STRING
:
1106 if ( eType
== CELLTYPE_STRING
)
1107 aValue
= ((ScStringCell
*)pCell
)->GetString();
1109 aValue
= ((ScEditCell
*)pCell
)->GetString();
1110 nHeadNoneTail
= lcl_DecompValueString( aValue
, nVal
);
1111 if ( nHeadNoneTail
)
1112 nStart
= (double)nVal
;
1117 case CELLTYPE_VALUE
:
1118 nStart
= ((ScValueCell
*)pCell
)->GetValue();
1120 case CELLTYPE_FORMULA
:
1121 nStart
= ((ScFormulaCell
*)pCell
)->GetValue();
1129 if ( eFillCmd
== FILL_LINEAR
)
1132 bValueOk
= ( SubTotal::SafeMult( nAdd
, (double) nIndex
) &&
1133 SubTotal::SafePlus( nStart
, nAdd
) );
1138 sal_uInt16 nDayOfMonth
= 0;
1144 for (long i
=0; i
<nIndex
; i
++)
1145 IncDate( nStart
, nDayOfMonth
, nInc
, eDateCmd
);
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 );
1160 aValue
+= lcl_ValueString( (sal_Int32
)nStart
, nMinDigits
);
1164 //! Zahlformat je nach Index holen?
1166 sal_uLong nNumFmt
= GetNumberFormat( nCol1
, nRow1
);
1167 pDocument
->GetFormatTable()->
1168 GetOutputString( nStart
, nNumFmt
, aValue
, &pColor
);
1174 OSL_FAIL("GetAutoFillPreview: invalid mode");
1181 void ScTable::IncDate(double& rVal
, sal_uInt16
& nDayOfMonth
, double nStep
, FillDateCmd eCmd
)
1183 if (eCmd
== FILL_DAY
)
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
;
1202 DayOfWeek eWeekDay
= aDate
.GetDayOfWeek();
1205 if (eWeekDay
== SATURDAY
)
1207 else if (eWeekDay
== SUNDAY
)
1212 if (eWeekDay
== SATURDAY
)
1214 else if (eWeekDay
== SUNDAY
)
1221 if ( nDayOfMonth
== 0 )
1222 nDayOfMonth
= aDate
.GetDay(); // init
1223 long nMonth
= aDate
.GetMonth();
1224 long nYear
= aDate
.GetYear();
1232 long nYAdd
= (nMonth
-1) / 12;
1233 nMonth
-= nYAdd
* 12;
1241 long nYAdd
= 1 - nMonth
/ 12; // positive
1242 nMonth
+= nYAdd
* 12;
1247 if ( nYear
< nMinYear
)
1248 aDate
= Date( 1,1, nMinYear
);
1249 else if ( nYear
> nMaxYear
)
1250 aDate
= Date( 31,12, nMaxYear
);
1253 aDate
.SetMonth((sal_uInt16
) nMonth
);
1254 aDate
.SetYear((sal_uInt16
) nYear
);
1255 aDate
.SetDay( std::min( Date::GetDaysInMonth( nMonth
, nYear
), nDayOfMonth
) );
1261 long nYear
= aDate
.GetYear();
1263 if ( nYear
< nMinYear
)
1264 aDate
= Date( 1,1, nMinYear
);
1265 else if ( nYear
> nMaxYear
)
1266 aDate
= Date( 31,12, nMaxYear
);
1268 aDate
.SetYear((sal_uInt16
) nYear
);
1273 // added to avoid warnings
1277 rVal
= aDate
- aNullDate
;
1283 bool HiddenRowColumn(sal_uLong nRowColumn
, bool bVertical
, ScTable
* pTable
)
1287 return pTable
->RowHidden(static_cast<SCROW
>(nRowColumn
));
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
)
1306 bool bVertical
= (eFillDir
== FILL_TO_BOTTOM
|| eFillDir
== FILL_TO_TOP
);
1307 bool bPositive
= (eFillDir
== FILL_TO_BOTTOM
|| eFillDir
== FILL_TO_RIGHT
);
1311 sal_uLong
& rInner
= bVertical
? nRow
: nCol
; // loop variables
1312 sal_uLong
& rOuter
= bVertical
? nCol
: nRow
;
1322 nFillCount
+= (nRow2
- nRow1
);
1323 if (nFillCount
== 0)
1330 nIStart
= nRow1
+ 1;
1331 nIEnd
= nRow1
+ nFillCount
;
1332 aFillRange
= ScRange(nCol1
, nRow1
+ 1, nTab
, nCol2
, nRow1
+ nFillCount
, nTab
);
1337 nIStart
= nRow2
- 1;
1338 nIEnd
= nRow2
- nFillCount
;
1339 aFillRange
= ScRange(nCol1
, nRow2
-1, nTab
, nCol2
, nRow2
- nFillCount
, nTab
);
1344 nFillCount
+= (nCol2
- nCol1
);
1345 if (nFillCount
== 0)
1352 nIStart
= nCol1
+ 1;
1353 nIEnd
= nCol1
+ nFillCount
;
1354 aFillRange
= ScRange(nCol1
+ 1, nRow1
, nTab
, nCol1
+ nFillCount
, nRow2
, nTab
);
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
);
1374 DeleteArea(nCol1
, static_cast<SCROW
>(nIMin
), nCol2
, static_cast<SCROW
>(nIMax
), nDel
);
1376 DeleteArea(static_cast<SCCOL
>(nIMin
), nRow1
, static_cast<SCCOL
>(nIMax
), nRow2
, nDel
);
1379 sal_uLong nProgress
= 0;
1381 nProgress
= pProgress
->GetState();
1387 sal_uLong nActFormCnt
= 0;
1388 for (rOuter
= nOStart
; rOuter
<= nOEnd
; rOuter
++)
1391 ScBaseCell
* pSrcCell
= aCol
[nCol
].GetCell(static_cast<SCROW
>(nRow
));
1393 if (bVertical
&& bAttribs
)
1394 aCol
[nCol
].ReserveSize(aCol
[nCol
].GetCellCount() + nFillCount
);
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();
1405 // if not filtered use the faster method
1406 // hidden cols/rows should be skiped
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
);
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
);
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
);
1460 CellType eCellType
= pSrcCell
->GetCellType();
1462 if (eFillCmd
== FILL_SIMPLE
) // copy
1464 if (eCellType
== CELLTYPE_FORMULA
)
1467 for (rInner
= nIMin
; rInner
<= nIMax
; rInner
++)
1469 if(HiddenRowColumn(rInner
, bVertical
, this))
1471 sal_uLong nInd
= nActFormCnt
;
1472 FillFormula(nInd
, bFirst
, (ScFormulaCell
*)pSrcCell
,
1473 static_cast<SCCOL
>(nCol
), nRow
, (rInner
== nIEnd
) );
1476 pProgress
->SetStateOnPercent( ++nProgress
);
1481 for (rInner
= nIMin
; rInner
<= nIMax
; rInner
++)
1483 if(HiddenRowColumn(rInner
, bVertical
, this))
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;
1490 pProgress
->SetStateOnPercent( nProgress
);
1493 else if (eCellType
== CELLTYPE_VALUE
|| eCellType
== CELLTYPE_FORMULA
)
1496 if (eCellType
== CELLTYPE_VALUE
)
1497 nStartVal
= ((ScValueCell
*)pSrcCell
)->GetValue();
1499 nStartVal
= ((ScFormulaCell
*)pSrcCell
)->GetValue();
1500 double nVal
= nStartVal
;
1503 bool bError
= false;
1504 bool bOverflow
= false;
1506 sal_uInt16 nDayOfMonth
= 0;
1508 while (true) // #i53728# with "for (;;)" old solaris/x86 compiler mis-optimizes
1510 if(!ColHidden(nCol
) && !RowHidden(nRow
))
1512 if (!bError
&& !bOverflow
)
1518 // use multiplication instead of repeated addition
1519 // to avoid accumulating rounding errors
1521 double nAdd
= nStepValue
;
1522 if ( !SubTotal::SafeMult( nAdd
, (double) ++nIndex
) ||
1523 !SubTotal::SafePlus( nVal
, nAdd
) )
1528 if (!SubTotal::SafeMult(nVal
, nStepValue
))
1532 if (fabs(nVal
) > _D_MAX_LONG_
)
1535 IncDate(nVal
, nDayOfMonth
, nStepValue
, eFillDateCmd
);
1539 // added to avoid warnings
1543 if (nStepValue
>= 0)
1545 if (nVal
> nMaxValue
) // target value reached ?
1553 if (nVal
< nMaxValue
)
1562 aCol
[nCol
].SetError(static_cast<SCROW
>(nRow
), errNoValue
);
1564 aCol
[nCol
].SetError(static_cast<SCROW
>(nRow
), errIllegalFPOperation
);
1566 aCol
[nCol
].SetValue(static_cast<SCROW
>(nRow
), nVal
);
1569 if (rInner
== nIEnd
)
1580 nProgress
+= nIMax
- nIMin
+ 1;
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;
1593 if ( nMaxValue
<= (double)LONG_MIN
)
1594 nMaxValue
= (double)LONG_MIN
+ 1;
1597 if (eCellType
== CELLTYPE_STRING
)
1598 aValue
= ((ScStringCell
*)pSrcCell
)->GetString();
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
;
1609 bool bError
= false;
1610 bool bOverflow
= false;
1612 bool bIsOrdinalSuffix
= aValue
.Equals( ScGlobal::GetOrdinalSuffix(
1613 (sal_Int32
)nStartVal
));
1616 while (true) // #i53728# with "for (;;)" old solaris/x86 compiler mis-optimizes
1618 if(!ColHidden(nCol
) && !RowHidden(nRow
))
1620 if (!bError
&& !bOverflow
)
1626 // use multiplication instead of repeated addition
1627 // to avoid accumulating rounding errors
1629 double nAdd
= nStepValue
;
1630 if ( !SubTotal::SafeMult( nAdd
, (double) ++nIndex
) ||
1631 !SubTotal::SafePlus( nVal
, nAdd
) )
1636 if (!SubTotal::SafeMult(nVal
, nStepValue
))
1641 // added to avoid warnings
1645 if (nStepValue
>= 0)
1647 if (nVal
> nMaxValue
) // target value reached ?
1655 if (nVal
< nMaxValue
)
1664 aCol
[nCol
].SetError(static_cast<SCROW
>(nRow
), errNoValue
);
1666 aCol
[nCol
].SetError(static_cast<SCROW
>(nRow
), errIllegalFPOperation
);
1669 nStringValue
= (sal_Int32
)nVal
;
1671 if ( nHeadNoneTail
< 0 )
1673 aCol
[nCol
].Insert( static_cast<SCROW
>(nRow
),
1674 lcl_getSuffixCell( pDocument
,
1675 nStringValue
, nMinDigits
, aValue
,
1676 eCellType
, bIsOrdinalSuffix
));
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
;
1694 nProgress
+= nIMax
- nIMin
+ 1;
1695 pProgress
->SetStateOnPercent( nProgress
);
1701 nProgress
+= nIMax
- nIMin
+ 1;
1702 pProgress
->SetStateOnPercent( nProgress
);
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
);
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
);
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
);
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;
1751 AutoFormatArea(nCol
, nRow
, nCol
, nRow
, *pPatternAttrs
[nIndex
], nFormatNo
);
1753 if (pData
->IsEqualData(4, 8))
1754 AutoFormatArea(nStartCol
, nStartRow
+ 1, nStartCol
, nEndRow
- 1, *pPatternAttrs
[4], nFormatNo
);
1758 for (nRow
= nStartRow
+ 1; nRow
< nEndRow
; nRow
++)
1760 AutoFormatArea(nCol
, nRow
, nCol
, nRow
, *pPatternAttrs
[nIndex
], nFormatNo
);
1767 // Left bottom corner
1770 AutoFormatArea(nCol
, nRow
, nCol
, nRow
, *pPatternAttrs
[nIndex
], nFormatNo
);
1775 AutoFormatArea(nCol
, nRow
, nCol
, nRow
, *pPatternAttrs
[nIndex
], nFormatNo
);
1777 if (pData
->IsEqualData(7, 11))
1778 AutoFormatArea(nEndCol
, nStartRow
+ 1, nEndCol
, nEndRow
- 1, *pPatternAttrs
[7], nFormatNo
);
1782 for (nRow
= nStartRow
+ 1; nRow
< nEndRow
; nRow
++)
1784 AutoFormatArea(nCol
, nRow
, nCol
, nRow
, *pPatternAttrs
[nIndex
], nFormatNo
);
1791 // Right bottom corner
1794 AutoFormatArea(nCol
, nRow
, nCol
, nRow
, *pPatternAttrs
[nIndex
], nFormatNo
);
1797 for (nCol
= nStartCol
+ 1; nCol
< nEndCol
; nCol
++)
1799 AutoFormatArea(nCol
, nRow
, nCol
, nRow
, *pPatternAttrs
[nIndex
], nFormatNo
);
1808 for (nCol
= nStartCol
+ 1; nCol
< nEndCol
; nCol
++)
1810 AutoFormatArea(nCol
, nRow
, nCol
, nRow
, *pPatternAttrs
[nIndex
], nFormatNo
);
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
);
1821 if ((pData
->IsEqualData(5, 9)) && (pData
->IsEqualData(6, 10)))
1824 for (nCol
= nStartCol
+ 1; nCol
< nEndCol
; nCol
++)
1826 AutoFormatArea(nCol
, nStartRow
+ 1, nCol
, nEndRow
- 1, *pPatternAttrs
[nIndex
], nFormatNo
);
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))
1856 if ((nIndex
== 5) || (nIndex
== 9))
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
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
);
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
)
1896 if (ScHasPriority(pTheBox
->GetLeft(), pLeftBox
->GetRight()))
1897 aBox
.SetLine(pTheBox
->GetLeft(), BOX_LINE_LEFT
);
1899 aBox
.SetLine(pLeftBox
->GetRight(), BOX_LINE_LEFT
);
1902 aBox
.SetLine(pTheBox
->GetLeft(), BOX_LINE_LEFT
);
1904 if (nFlags
& LF_TOP
)
1908 if (ScHasPriority(pTheBox
->GetTop(), pTopBox
->GetBottom()))
1909 aBox
.SetLine(pTheBox
->GetTop(), BOX_LINE_TOP
);
1911 aBox
.SetLine(pTopBox
->GetBottom(), BOX_LINE_TOP
);
1914 aBox
.SetLine(pTheBox
->GetTop(), BOX_LINE_TOP
);
1916 if (nFlags
& LF_RIGHT
)
1920 if (ScHasPriority(pTheBox
->GetRight(), pRightBox
->GetLeft()))
1921 aBox
.SetLine(pTheBox
->GetRight(), BOX_LINE_RIGHT
);
1923 aBox
.SetLine(pRightBox
->GetLeft(), BOX_LINE_RIGHT
);
1926 aBox
.SetLine(pTheBox
->GetRight(), BOX_LINE_RIGHT
);
1928 if (nFlags
& LF_BOTTOM
)
1932 if (ScHasPriority(pTheBox
->GetBottom(), pBottomBox
->GetTop()))
1933 aBox
.SetLine(pTheBox
->GetBottom(), BOX_LINE_BOTTOM
);
1935 aBox
.SetLine(pBottomBox
->GetTop(), BOX_LINE_BOTTOM
);
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))
1950 GetAutoFormatAttr(nStartCol
, nStartRow
, 0, rData
);
1951 GetAutoFormatFrame(nStartCol
, nStartRow
, LF_ALL
, 0, rData
);
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
);
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
);
1964 GetAutoFormatAttr(nEndCol
, nStartRow
, 3, rData
);
1965 GetAutoFormatFrame(nEndCol
, nStartRow
, LF_ALL
, 3, rData
);
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
);
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
);
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
);
1984 rData
.CopyItem( 2, 1, ATTR_BORDER
);
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
);
1992 rData
.CopyItem( 14, 13, ATTR_BORDER
);
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
);
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
2038 if (rRow
== MAXROW
+1)
2044 if (rCol
== MAXCOL
+1)
2053 bStop
= aCol
[rCol
].GetNextSpellingCell(rRow
, bInSel
, rMark
);
2056 else /*if (rRow == MAXROW+1) */
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
))
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: */