xref: /trunk/main/sc/source/core/data/table4.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2011 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sc.hxx"
30 
31 // System - Includes -----------------------------------------------------
32 
33 
34 
35 #ifdef _MSC_VER
36 #pragma optimize("",off)
37                                         // sonst Absturz Win beim Fuellen
38 #endif
39 
40 // INCLUDE ---------------------------------------------------------------
41 
42 #include "scitems.hxx"
43 #include <svx/algitem.hxx>
44 #include <editeng/boxitem.hxx>
45 #include <editeng/brshitem.hxx>
46 #include <editeng/cntritem.hxx>
47 #include <editeng/colritem.hxx>
48 #include <editeng/crsditem.hxx>
49 #include <editeng/fhgtitem.hxx>
50 #include <editeng/fontitem.hxx>
51 #include <editeng/langitem.hxx>
52 #include <editeng/postitem.hxx>
53 #include <editeng/shdditem.hxx>
54 #include <editeng/udlnitem.hxx>
55 #include <editeng/wghtitem.hxx>
56 #include <svx/rotmodit.hxx>
57 #include <editeng/editobj.hxx>
58 #include <editeng/editeng.hxx>
59 #include <editeng/eeitem.hxx>
60 #include <editeng/escpitem.hxx>
61 #include <svl/zforlist.hxx>
62 #include <vcl/keycodes.hxx>
63 #include <rtl/math.hxx>
64 #include <unotools/charclass.hxx>
65 
66 #include "attrib.hxx"
67 #include "patattr.hxx"
68 #include "cell.hxx"
69 #include "table.hxx"
70 #include "globstr.hrc"
71 #include "global.hxx"
72 #include "document.hxx"
73 #include "autoform.hxx"
74 #include "userlist.hxx"
75 #include "zforauto.hxx"
76 #include "subtotal.hxx"
77 #include "formula/errorcodes.hxx"
78 #include "rangenam.hxx"
79 #include "docpool.hxx"
80 #include "progress.hxx"
81 #include "segmenttree.hxx"
82 
83 #include <math.h>
84 
85 // STATIC DATA -----------------------------------------------------------
86 
87 #define _D_MAX_LONG_  (double) 0x7fffffff
88 
89 extern sal_uInt16 nScFillModeMouseModifier;     // global.cxx
90 
91 // -----------------------------------------------------------------------
92 
93 short lcl_DecompValueString( String& aValue, sal_Int32& nVal, sal_uInt16* pMinDigits = NULL )
94 {
95     if ( !aValue.Len() )
96     {
97         nVal = 0;
98         return 0;
99     }
100     const sal_Unicode* p = aValue.GetBuffer();
101     xub_StrLen nNeg = 0;
102     xub_StrLen nNum = 0;
103     if ( p[nNum] == '-' )
104         nNum = nNeg = 1;
105     while ( p[nNum] && CharClass::isAsciiNumeric( p[nNum] ) )
106         nNum++;
107 
108     sal_Unicode cNext = p[nNum];            // 0 if at the end
109     sal_Unicode cLast = p[aValue.Len()-1];
110 
111     // #i5550# If there are numbers at the beginning and the end,
112     // prefer the one at the beginning only if it's followed by a space.
113     // Otherwise, use the number at the end, to enable things like IP addresses.
114     if ( nNum > nNeg && ( cNext == 0 || cNext == ' ' || !CharClass::isAsciiNumeric(cLast) ) )
115     {   // number at the beginning
116         nVal = aValue.Copy( 0, nNum ).ToInt32();
117         //  #60893# any number with a leading zero sets the minimum number of digits
118         if ( p[nNeg] == '0' && pMinDigits && ( nNum - nNeg > *pMinDigits ) )
119             *pMinDigits = nNum - nNeg;
120         aValue.Erase( 0, nNum );
121         return -1;
122     }
123     else
124     {
125         nNeg = 0;
126         xub_StrLen nEnd = nNum = aValue.Len() - 1;
127         while ( nNum && CharClass::isAsciiNumeric( p[nNum] ) )
128             nNum--;
129         if ( p[nNum] == '-' )
130         {
131             nNum--;
132             nNeg = 1;
133         }
134         if ( nNum < nEnd - nNeg )
135         {   // number at the end
136             nVal = aValue.Copy( nNum + 1 ).ToInt32();
137             //  #60893# any number with a leading zero sets the minimum number of digits
138             if ( p[nNum+1+nNeg] == '0' && pMinDigits && ( nEnd - nNum - nNeg > *pMinDigits ) )
139                 *pMinDigits = nEnd - nNum - nNeg;
140             aValue.Erase( nNum + 1 );
141             return 1;
142         }
143     }
144     nVal = 0;
145     return 0;
146 }
147 
148 String lcl_ValueString( sal_Int32 nValue, sal_uInt16 nMinDigits )
149 {
150     if ( nMinDigits <= 1 )
151         return String::CreateFromInt32( nValue );           // simple case...
152     else
153     {
154         String aStr = String::CreateFromInt32( Abs( nValue ) );
155         if ( aStr.Len() < nMinDigits )
156         {
157             String aZero;
158             aZero.Fill( nMinDigits - aStr.Len(), '0' );
159             aStr.Insert( aZero, 0 );
160         }
161         //  nMinDigits doesn't include the '-' sign -> add after inserting zeros
162         if ( nValue < 0 )
163             aStr.Insert( '-', 0 );
164         return aStr;
165     }
166 }
167 
168 static ScBaseCell * lcl_getSuffixCell( ScDocument* pDocument, sal_Int32 nValue,
169         sal_uInt16 nDigits, const String& rSuffix, CellType eCellType,
170         sal_Bool bIsOrdinalSuffix )
171 {
172     String aValue( lcl_ValueString( nValue, nDigits ));
173     if (!bIsOrdinalSuffix)
174         return new ScStringCell( aValue += rSuffix);
175 
176     String aOrdinalSuffix( ScGlobal::GetOrdinalSuffix( nValue));
177     if (eCellType != CELLTYPE_EDIT)
178         return new ScStringCell( aValue += aOrdinalSuffix);
179 
180     EditEngine aEngine( pDocument->GetEnginePool() );
181     SfxItemSet aAttr = aEngine.GetEmptyItemSet();
182     aAttr.Put( SvxEscapementItem( SVX_ESCAPEMENT_SUPERSCRIPT, EE_CHAR_ESCAPEMENT));
183     aEngine.SetText( aValue );
184     aEngine.QuickInsertText( aOrdinalSuffix, ESelection( 0, aValue.Len(), 0,
185                 aValue.Len() + aOrdinalSuffix.Len()));
186     aEngine.QuickSetAttribs( aAttr, ESelection( 0, aValue.Len(), 0, aValue.Len() +
187                 aOrdinalSuffix.Len()));
188     return new ScEditCell( aEngine.CreateTextObject(), pDocument, NULL );
189 }
190 
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)
195 {
196     DBG_ASSERT( nCol1==nCol2 || nRow1==nRow2, "FillAnalyse: falscher Bereich" );
197 
198     rInc = 0.0;
199     rMinDigits = 0;
200     rListData = NULL;
201     rCmd = FILL_SIMPLE;
202     if (( nScFillModeMouseModifier & KEY_MOD1 )||IsDataFiltered())  //i89232
203         return ;        // Ctrl-Taste: Copy
204 
205     SCCOL nAddX;
206     SCROW nAddY;
207     SCSIZE nCount;
208     if (nCol1 == nCol2)
209     {
210         nAddX = 0;
211         nAddY = 1;
212         nCount = static_cast<SCSIZE>(nRow2 - nRow1 + 1);
213     }
214     else
215     {
216         nAddX = 1;
217         nAddY = 0;
218         nCount = static_cast<SCSIZE>(nCol2 - nCol1 + 1);
219     }
220 
221     SCCOL nCol = nCol1;
222     SCROW nRow = nRow1;
223 
224     ScBaseCell* pFirstCell = GetCell( nCol, nRow );
225     CellType eCellType = pFirstCell ? pFirstCell->GetCellType() : CELLTYPE_NONE;
226 
227     if (eCellType == CELLTYPE_VALUE)
228     {
229         sal_uInt32 nFormat = ((const SfxUInt32Item*)GetAttr(nCol,nRow,ATTR_VALUE_FORMAT))->GetValue();
230         sal_Bool bDate = ( pDocument->GetFormatTable()->GetType(nFormat) == NUMBERFORMAT_DATE );
231         if (bDate)
232         {
233             if (nCount > 1)
234             {
235                 long nCmpInc = 0;
236                 double nVal;
237                 Date aNullDate = *pDocument->GetFormatTable()->GetNullDate();
238                 Date aDate1 = aNullDate;
239                 nVal = ((ScValueCell*)pFirstCell)->GetValue();
240                 aDate1 += (long)nVal;
241                 Date aDate2 = aNullDate;
242                 nVal = GetValue(nCol+nAddX, nRow+nAddY);
243                 aDate2 += (long)nVal;
244                 if ( aDate1 != aDate2 )
245                 {
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 )
251                     {
252                         eType = FILL_DAY;
253                         nCmpInc = aDate2 - aDate1;
254                     }
255                     else
256                     {
257                         eType = FILL_MONTH;
258                         nCmpInc = nMDiff + 12 * nYDiff;
259                     }
260 
261                     nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
262                     nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
263                     sal_Bool bVal = sal_True;
264                     for (sal_uInt16 i=1; i<nCount && bVal; i++)
265                     {
266                         ScBaseCell* pCell = GetCell(nCol,nRow);
267                         if (pCell && pCell->GetCellType() == CELLTYPE_VALUE)
268                         {
269                             nVal = ((ScValueCell*)pCell)->GetValue();
270                             aDate2 = aNullDate + (long) nVal;
271                             if ( eType == FILL_DAY )
272                             {
273                                 if ( aDate2-aDate1 != nCmpInc )
274                                     bVal = sal_False;
275                             }
276                             else
277                             {
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 = sal_False;
283                             }
284                             aDate1 = aDate2;
285                             nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
286                             nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
287                         }
288                         else
289                             bVal = sal_False;   // #50965# kein Datum passt auch nicht
290                     }
291                     if (bVal)
292                     {
293                         if ( eType == FILL_MONTH && ( nCmpInc % 12 == 0 ) )
294                         {
295                             eType = FILL_YEAR;
296                             nCmpInc /= 12;
297                         }
298                         rCmd = FILL_DATE;
299                         rDateCmd = eType;
300                         rInc = nCmpInc;
301                     }
302                 }
303             }
304             else                            // einzelnes Datum -> Tage hochzaehlen
305             {
306                 rCmd = FILL_DATE;
307                 rDateCmd = FILL_DAY;
308                 rInc = 1.0;
309             }
310         }
311         else
312         {
313             if (nCount > 1)
314             {
315                 double nVal1 = ((ScValueCell*)pFirstCell)->GetValue();
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                 sal_Bool bVal = sal_True;
321                 for (sal_uInt16 i=1; i<nCount && bVal; i++)
322                 {
323                     ScBaseCell* pCell = GetCell(nCol,nRow);
324                     if (pCell && pCell->GetCellType() == CELLTYPE_VALUE)
325                     {
326                         nVal2 = ((ScValueCell*)pCell)->GetValue();
327                         double nDiff = nVal2 - nVal1;
328                         if ( !::rtl::math::approxEqual( nDiff, rInc ) )
329                             bVal = sal_False;
330                         nVal1 = nVal2;
331                     }
332                     else
333                         bVal = sal_False;
334                     nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
335                     nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
336                 }
337                 if (bVal)
338                     rCmd = FILL_LINEAR;
339             }
340         }
341     }
342     else if (eCellType == CELLTYPE_STRING || eCellType == CELLTYPE_EDIT)
343     {
344         String aStr;
345         GetString(nCol, nRow, aStr);
346         rListData = (ScUserListData*)(ScGlobal::GetUserList()->GetData(aStr));
347         if (rListData)
348         {
349             rListData->GetSubIndex(aStr, rListIndex);
350             nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
351             nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
352             for (sal_uInt16 i=1; i<nCount && rListData; i++)
353             {
354                 GetString(nCol, nRow, aStr);
355                 if (!rListData->GetSubIndex(aStr, rListIndex))
356                     rListData = NULL;
357                 nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
358                 nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
359             }
360         }
361         else if ( nCount > 1 )
362         {
363             //  pass rMinDigits to all DecompValueString calls
364             //  -> longest number defines rMinDigits
365 
366             sal_Int32 nVal1;
367             short nFlag1 = lcl_DecompValueString( aStr, nVal1, &rMinDigits );
368             if ( nFlag1 )
369             {
370                 sal_Int32 nVal2;
371                 GetString( nCol+nAddX, nRow+nAddY, aStr );
372                 short nFlag2 = lcl_DecompValueString( aStr, nVal2, &rMinDigits );
373                 if ( nFlag1 == nFlag2 )
374                 {
375                     rInc = (double)nVal2 - (double)nVal1;
376                     nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
377                     nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
378                     sal_Bool bVal = sal_True;
379                     for (sal_uInt16 i=1; i<nCount && bVal; i++)
380                     {
381                         ScBaseCell* pCell = GetCell(nCol,nRow);
382                         CellType eType = pCell ? pCell->GetCellType() : CELLTYPE_NONE;
383                         if ( eType == CELLTYPE_STRING || eType == CELLTYPE_EDIT )
384                         {
385                             if ( eType == CELLTYPE_STRING )
386                                 ((ScStringCell*)pCell)->GetString( aStr );
387                             else
388                                 ((ScEditCell*)pCell)->GetString( aStr );
389                             nFlag2 = lcl_DecompValueString( aStr, nVal2, &rMinDigits );
390                             if ( nFlag1 == nFlag2 )
391                             {
392                                 double nDiff = (double)nVal2 - (double)nVal1;
393                                 if ( !::rtl::math::approxEqual( nDiff, rInc ) )
394                                     bVal = sal_False;
395                                 nVal1 = nVal2;
396                             }
397                             else
398                                 bVal = sal_False;
399                         }
400                         else
401                             bVal = sal_False;
402                         nCol = sal::static_int_cast<SCCOL>( nCol + nAddX );
403                         nRow = sal::static_int_cast<SCROW>( nRow + nAddY );
404                     }
405                     if (bVal)
406                         rCmd = FILL_LINEAR;
407                 }
408             }
409         }
410         else
411         {
412             //  call DecompValueString to set rMinDigits
413             sal_Int32 nDummy;
414             lcl_DecompValueString( aStr, nDummy, &rMinDigits );
415         }
416     }
417 }
418 
419 void ScTable::FillFormula(sal_uLong& /* nFormulaCounter */, sal_Bool /* bFirst */, ScFormulaCell* pSrcCell,
420                           SCCOL nDestCol, SCROW nDestRow, sal_Bool bLast )
421 {
422 /*  sal_uInt16 nTokArrLen = pSrcCell->GetTokenArrayLen();
423     if ( nTokArrLen > 15 )                          // mehr als =A1 oder =67
424     {
425         ScRangeName* pRangeName = pDocument->GetRangeName();
426         String aName("___SC_");                     // Wird dieser String veraendert,
427                                                     // auch in document2 EraseNonUsed...
428                                                     // mitaendern!!
429         aName += pRangeName->GetSharedMaxIndex() + 1;
430         aName += '_';
431         aName += nFormulaCounter;
432         nFormulaCounter++;
433         if (bFirst)
434         {
435             ScRangeData *pAktRange = new ScRangeData(
436                             pDocument, aName, pSrcCell->GetTokenArray(), nTokArrLen,
437                             pSrcCell->GetCol(), pSrcCell->GetRow(), nTab ,RT_SHARED);
438             if (!pRangeName->Insert( pAktRange ))
439                 delete pAktRange;
440             else
441                 bSharedNameInserted = sal_True;
442         }
443         sal_uInt16 nIndex;
444         pRangeName->SearchName(aName, nIndex);
445         if (!pRangeName)
446         {
447             DBG_ERROR("ScTable::FillFormula: Falscher Name");
448             return;
449         }
450         nIndex = ((ScRangeData*) ((*pRangeName)[nIndex]))->GetIndex();
451         ScTokenArray aArr;
452         aArr.AddName(nIndex);
453         aArr.AddOpCode(ocStop);
454         ScFormulaCell* pDestCell = new ScFormulaCell
455             (pDocument, ScAddress( nDestCol, nDestRow, nTab ), aArr );
456         aCol[nDestCol].Insert(nDestRow, pDestCell);
457     }
458     else
459 */  {
460         pDocument->SetNoListening( sal_True );  // noch falsche Referenzen
461         ScAddress aAddr( nDestCol, nDestRow, nTab );
462         ScFormulaCell* pDestCell = new ScFormulaCell( *pSrcCell, *pDocument, aAddr );
463         aCol[nDestCol].Insert(nDestRow, pDestCell);
464 #if 0
465 // mit RelRefs unnoetig
466         pDestCell->UpdateReference(URM_COPY,
467                          ScRange( aAddr, aAddr ),
468                          nDestCol - pSrcCell->aPos.Col(),
469                          nDestRow - pSrcCell->aPos.Row(), 0);
470 #endif
471         if ( bLast && pDestCell->GetMatrixFlag() )
472         {
473             ScAddress aOrg;
474             if ( pDestCell->GetMatrixOrigin( aOrg ) )
475             {
476                 if ( nDestCol >= aOrg.Col() && nDestRow >= aOrg.Row() )
477                 {
478                     ScBaseCell* pOrgCell = pDocument->GetCell( aOrg );
479                     if ( pOrgCell && pOrgCell->GetCellType() == CELLTYPE_FORMULA
480                       && ((ScFormulaCell*)pOrgCell)->GetMatrixFlag() == MM_FORMULA )
481                     {
482                         ((ScFormulaCell*)pOrgCell)->SetMatColsRows(
483                             nDestCol - aOrg.Col() + 1,
484                             nDestRow - aOrg.Row() + 1 );
485                     }
486                     else
487                     {
488                         DBG_ERRORFILE( "FillFormula: MatrixOrigin keine Formelzelle mit MM_FORMULA" );
489                     }
490                 }
491                 else
492                 {
493                     DBG_ERRORFILE( "FillFormula: MatrixOrigin rechts unten" );
494                 }
495             }
496             else
497             {
498                 DBG_ERRORFILE( "FillFormula: kein MatrixOrigin" );
499             }
500         }
501         pDocument->SetNoListening( sal_False );
502         pDestCell->StartListeningTo( pDocument );
503     }
504 }
505 
506 void ScTable::FillAuto( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
507                         sal_uLong nFillCount, FillDir eFillDir, ScProgress& rProgress )
508 {
509     if ( (nFillCount == 0) || !ValidColRow(nCol1, nRow1) || !ValidColRow(nCol2, nRow2) )
510         return;
511 
512     //
513     //  Richtung auswerten
514     //
515 
516     sal_Bool bVertical = (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_TOP);
517     sal_Bool bPositive = (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_RIGHT);
518 
519     sal_uLong nCol = 0;
520     sal_uLong nRow = 0;
521     sal_uLong& rInner = bVertical ? nRow : nCol;        // Schleifenvariablen
522     sal_uLong& rOuter = bVertical ? nCol : nRow;
523     sal_uLong nOStart;
524     sal_uLong nOEnd;
525     sal_uLong nIStart;
526     sal_uLong nIEnd;
527     sal_uLong nISrcStart;
528     sal_uLong nISrcEnd;
529 
530     if (bVertical)
531     {
532         nOStart = nCol1;
533         nOEnd = nCol2;
534         if (bPositive)
535         {
536             nISrcStart = nRow1;
537             nISrcEnd = nRow2;
538             nIStart = nRow2 + 1;
539             nIEnd = nRow2 + nFillCount;
540         }
541         else
542         {
543             nISrcStart = nRow2;
544             nISrcEnd = nRow1;
545             nIStart = nRow1 - 1;
546             nIEnd = nRow1 - nFillCount;
547         }
548     }
549     else
550     {
551         nOStart = nRow1;
552         nOEnd = nRow2;
553         if (bPositive)
554         {
555             nISrcStart = nCol1;
556             nISrcEnd = nCol2;
557             nIStart = nCol2 + 1;
558             nIEnd = nCol2 + nFillCount;
559         }
560         else
561         {
562             nISrcStart = nCol2;
563             nISrcEnd = nCol1;
564             nIStart = nCol1 - 1;
565             nIEnd = nCol1 - nFillCount;
566         }
567     }
568     sal_uLong nIMin = nIStart;
569     sal_uLong nIMax = nIEnd;
570     PutInOrder(nIMin,nIMax);
571     sal_Bool bHasFiltered = IsDataFiltered();
572     if (!bHasFiltered)  //modify for i89232
573     {
574         if (bVertical)
575             DeleteArea(nCol1, static_cast<SCROW>(nIMin), nCol2, static_cast<SCROW>(nIMax), IDF_AUTOFILL);
576         else
577             DeleteArea(static_cast<SCCOL>(nIMin), nRow1, static_cast<SCCOL>(nIMax), nRow2, IDF_AUTOFILL);
578     }
579     sal_uLong nProgress = rProgress.GetState();
580 
581     //
582     //  ausfuehren
583     //
584 
585     sal_uLong nActFormCnt = 0;
586     for (rOuter = nOStart; rOuter <= nOEnd; rOuter++)
587     {
588         sal_uLong nMaxFormCnt = 0;                      // fuer Formeln
589 
590         //  Attributierung uebertragen
591 
592         const ScPatternAttr* pSrcPattern = NULL;
593         const ScStyleSheet* pStyleSheet = NULL;
594         sal_uLong nAtSrc = nISrcStart;
595         ScPatternAttr* pNewPattern = NULL;
596         sal_Bool bGetPattern = sal_True;
597         rInner = nIStart;
598         while (true)        // #i53728# with "for (;;)" old solaris/x86 compiler mis-optimizes
599         {
600             if ( bGetPattern )
601             {
602                 if ( pNewPattern )
603                     delete pNewPattern;
604                 if (bVertical)      // rInner&:=nRow, rOuter&:=nCol
605                     pSrcPattern = aCol[nCol].GetPattern(static_cast<SCROW>(nAtSrc));
606                 else                // rInner&:=nCol, rOuter&:=nRow
607                     pSrcPattern = aCol[nAtSrc].GetPattern(static_cast<SCROW>(nRow));
608                 bGetPattern = sal_False;
609                 pStyleSheet = pSrcPattern->GetStyleSheet();
610                 //  Merge/Mergeflag nicht uebernehmen,
611                 const SfxItemSet& rSet = pSrcPattern->GetItemSet();
612                 if ( rSet.GetItemState(ATTR_MERGE, sal_False) == SFX_ITEM_SET
613                   || rSet.GetItemState(ATTR_MERGE_FLAG, sal_False) == SFX_ITEM_SET )
614                 {
615                     pNewPattern = new ScPatternAttr( *pSrcPattern );
616                     SfxItemSet& rNewSet = pNewPattern->GetItemSet();
617                     rNewSet.ClearItem(ATTR_MERGE);
618                     rNewSet.ClearItem(ATTR_MERGE_FLAG);
619                 }
620                 else
621                     pNewPattern = NULL;
622             }
623 
624             if ( bVertical && nISrcStart == nISrcEnd && !bHasFiltered )
625             {
626                 //  Attribute komplett am Stueck setzen
627                 if (pNewPattern || pSrcPattern != pDocument->GetDefPattern())
628                 {
629                     //  Default steht schon da (DeleteArea)
630                     SCROW nY1 = static_cast<SCROW>(Min( nIStart, nIEnd ));
631                     SCROW nY2 = static_cast<SCROW>(Max( nIStart, nIEnd ));
632                     if ( pStyleSheet )
633                         aCol[nCol].ApplyStyleArea( nY1, nY2, *pStyleSheet );
634                     if ( pNewPattern )
635                         aCol[nCol].ApplyPatternArea( nY1, nY2, *pNewPattern );
636                     else
637                         aCol[nCol].ApplyPatternArea( nY1, nY2, *pSrcPattern );
638                 }
639                 break;      // Schleife abbrechen
640             }
641 
642             if ( !RowFiltered(nRow) )
643             {
644                 if ( bHasFiltered )
645                     DeleteArea(static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow),
646                                static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), IDF_AUTOFILL);
647 
648                 if ( pSrcPattern != aCol[nCol].GetPattern( static_cast<SCROW>(nRow) ) )
649                 {
650                     //  Vorlage auch uebernehmen
651                     //! am AttrArray mit ApplyPattern zusammenfassen ??
652                     if ( pStyleSheet )
653                         aCol[nCol].ApplyStyle( static_cast<SCROW>(nRow), *pStyleSheet );
654 
655                     //  ApplyPattern statt SetPattern um alte MergeFlags stehenzulassen
656                     if ( pNewPattern )
657                         aCol[nCol].ApplyPattern( static_cast<SCROW>(nRow), *pNewPattern );
658                     else
659                         aCol[nCol].ApplyPattern( static_cast<SCROW>(nRow), *pSrcPattern );
660                 }
661 
662                 if (nAtSrc==nISrcEnd)
663                 {
664                     if ( nAtSrc != nISrcStart )
665                     {   // mehr als eine Source-Zelle
666                         nAtSrc = nISrcStart;
667                         bGetPattern = sal_True;
668                     }
669                 }
670                 else if (bPositive)
671                 {
672                     ++nAtSrc;
673                     bGetPattern = sal_True;
674                 }
675                 else
676                 {
677                     --nAtSrc;
678                     bGetPattern = sal_True;
679                 }
680             }
681 
682             if (rInner == nIEnd) break;
683             if (bPositive) ++rInner; else --rInner;
684         }
685         if ( pNewPattern )
686             delete pNewPattern;
687 
688         //  Analyse
689 
690         FillCmd eFillCmd;
691         FillDateCmd eDateCmd;
692         double nInc;
693         sal_uInt16 nMinDigits;
694         ScUserListData* pListData = NULL;
695         sal_uInt16 nListIndex;
696         if (bVertical)
697             FillAnalyse(static_cast<SCCOL>(nCol),nRow1,
698                     static_cast<SCCOL>(nCol),nRow2, eFillCmd,eDateCmd,
699                     nInc,nMinDigits, pListData,nListIndex);
700         else
701             FillAnalyse(nCol1,static_cast<SCROW>(nRow),
702                     nCol2,static_cast<SCROW>(nRow), eFillCmd,eDateCmd,
703                     nInc,nMinDigits, pListData,nListIndex);
704 
705         if (bVertical)
706             aCol[nCol].Resize( aCol[nCol].GetCellCount() + nFillCount );
707 
708         if (pListData)
709         {
710             sal_uInt16 nListCount = pListData->GetSubCount();
711             if ( !bPositive )
712             {
713                 //  nListIndex auf FillAnalyse zeigt auf den letzten Eintrag -> anpassen
714                 sal_uLong nSub = nISrcStart - nISrcEnd;
715                 for (sal_uLong i=0; i<nSub; i++)
716                 {
717                     if (nListIndex == 0) nListIndex = nListCount;
718                     --nListIndex;
719                 }
720             }
721 
722             rInner = nIStart;
723             while (true)        // #i53728# with "for (;;)" old solaris/x86 compiler mis-optimizes
724             {
725                 if (bPositive)
726                 {
727                     ++nListIndex;
728                     if (nListIndex >= nListCount) nListIndex = 0;
729                 }
730                 else
731                 {
732                     if (nListIndex == 0) nListIndex = nListCount;
733                     --nListIndex;
734                 }
735                 aCol[nCol].Insert(static_cast<SCROW>(nRow), new ScStringCell(pListData->GetSubStr(nListIndex)));
736 
737                 if (rInner == nIEnd) break;
738                 if (bPositive) ++rInner; else --rInner;
739             }
740             nProgress += nIMax - nIMin + 1;
741             rProgress.SetStateOnPercent( nProgress );
742         }
743         else if (eFillCmd == FILL_SIMPLE)           // Auffuellen mit Muster
744         {
745             sal_uLong nSource = nISrcStart;
746             double nDelta;
747             if (( nScFillModeMouseModifier & KEY_MOD1 )||bHasFiltered) //i89232
748                 nDelta = 0.0;
749             else if ( bPositive )
750                 nDelta = 1.0;
751             else
752                 nDelta = -1.0;
753             double nVal = 0.0;
754             sal_uLong nFormulaCounter = nActFormCnt;
755             sal_Bool bFirst = sal_True;
756             sal_Bool bGetCell = sal_True;
757             sal_uInt16 nCellDigits = 0;
758             short nHeadNoneTail = 0;
759             sal_Int32 nStringValue = 0;
760             String aValue;
761             ScBaseCell* pSrcCell = NULL;
762             CellType eCellType = CELLTYPE_NONE;
763             sal_Bool bIsOrdinalSuffix = sal_False;
764             sal_Bool bRowFiltered = sal_False; //i89232
765 
766             rInner = nIStart;
767             while (true)        // #i53728# with "for (;;)" old solaris/x86 compiler mis-optimizes
768             {
769                 if ( bGetCell )
770                 {
771                     if (bVertical)      // rInner&:=nRow, rOuter&:=nCol
772                         pSrcCell = aCol[nCol].GetCell( static_cast<SCROW>(nSource) );
773                     else                // rInner&:=nCol, rOuter&:=nRow
774                         pSrcCell = aCol[nSource].GetCell( static_cast<SCROW>(nRow) );
775                     bGetCell = sal_False;
776                     if ( pSrcCell )
777                     {
778                         eCellType = pSrcCell->GetCellType();
779                         switch ( eCellType )
780                         {
781                             case CELLTYPE_VALUE:
782                                 nVal = ((ScValueCell*)pSrcCell)->GetValue();
783                             break;
784                             case CELLTYPE_STRING:
785                             case CELLTYPE_EDIT:
786                                 if ( eCellType == CELLTYPE_STRING )
787                                     ((ScStringCell*)pSrcCell)->GetString( aValue );
788                                 else
789                                     ((ScEditCell*)pSrcCell)->GetString( aValue );
790                                 if ( !(nScFillModeMouseModifier & KEY_MOD1) && !bHasFiltered)   //i89232
791                                 {
792                                     nCellDigits = 0;    // look at each source cell individually
793                                     nHeadNoneTail = lcl_DecompValueString(
794                                         aValue, nStringValue, &nCellDigits );
795 
796                                     bIsOrdinalSuffix = aValue.Equals(
797                                             ScGlobal::GetOrdinalSuffix( nStringValue));
798                                 }
799                             break;
800                             default:
801                             {
802                                 // added to avoid warnings
803                             }
804                         }
805                     }
806                     else
807                         eCellType = CELLTYPE_NONE;
808                 }
809 
810                 //Modify for i89232
811                 bRowFiltered = mpFilteredRows->getValue(nRow);
812 
813                 if (!bRowFiltered)
814                 {
815                 //End of i89232
816 
817                     switch (eCellType)
818                     {
819                         case CELLTYPE_VALUE:
820                             aCol[nCol].Insert(static_cast<SCROW>(nRow), new ScValueCell(nVal + nDelta));
821                             break;
822                         case CELLTYPE_STRING:
823                         case CELLTYPE_EDIT:
824                             if ( nHeadNoneTail )
825                             {
826                                 // #i48009# with the "nStringValue+(long)nDelta" expression within the
827                                 // lcl_ValueString calls, gcc 3.4.1 makes wrong optimizations (ok in 3.4.3),
828                                 // so nNextValue is now calculated ahead.
829                                 sal_Int32 nNextValue = nStringValue+(sal_Int32)nDelta;
830 
831                                 String aStr;
832                                 if ( nHeadNoneTail < 0 )
833                                 {
834                                     aCol[nCol].Insert( static_cast<SCROW>(nRow),
835                                             lcl_getSuffixCell( pDocument,
836                                                 nNextValue, nCellDigits, aValue,
837                                                 eCellType, bIsOrdinalSuffix));
838                                 }
839                                 else
840                                 {
841                                     aStr = aValue;
842                                     aStr += lcl_ValueString( nNextValue, nCellDigits );
843                                     aCol[nCol].Insert( static_cast<SCROW>(nRow),
844                                             new ScStringCell( aStr));
845                                 }
846                             }
847                             else
848                             {
849                                 ScAddress aDestPos( static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), nTab );
850                                 switch ( eCellType )
851                                 {
852                                     case CELLTYPE_STRING:
853                                     case CELLTYPE_EDIT:
854                                         aCol[nCol].Insert( aDestPos.Row(), pSrcCell->CloneWithoutNote( *pDocument ) );
855                                     break;
856                                     default:
857                                     {
858                                         // added to avoid warnings
859                                     }
860                                 }
861                             }
862                             break;
863                         case CELLTYPE_FORMULA :
864                             FillFormula( nFormulaCounter, bFirst,
865                                     (ScFormulaCell*) pSrcCell,
866                                     static_cast<SCCOL>(nCol),
867                                     static_cast<SCROW>(nRow), (rInner == nIEnd) );
868                             if (nFormulaCounter - nActFormCnt > nMaxFormCnt)
869                                 nMaxFormCnt = nFormulaCounter - nActFormCnt;
870                             break;
871                         default:
872                         {
873                             // added to avoid warnings
874                         }
875                     }
876 
877                     if (nSource==nISrcEnd)
878                     {
879                         if ( nSource != nISrcStart )
880                         {   // mehr als eine Source-Zelle
881                             nSource = nISrcStart;
882                             bGetCell = sal_True;
883                         }
884                         if ( !(nScFillModeMouseModifier & KEY_MOD1) && !bHasFiltered ) //i89232
885                         {
886                             if ( bPositive )
887                                 nDelta += 1.0;
888                             else
889                                 nDelta -= 1.0;
890                         }
891                         nFormulaCounter = nActFormCnt;
892                         bFirst = sal_False;
893                     }
894                     else if (bPositive)
895                     {
896                         ++nSource;
897                         bGetCell = sal_True;
898                     }
899                     else
900                     {
901                         --nSource;
902                         bGetCell = sal_True;
903                     }
904                 }
905 
906                 //  Progress in der inneren Schleife nur bei teuren Zellen,
907                 //  und auch dann nicht fuer jede einzelne
908 
909                 ++nProgress;
910                 if ( eCellType == CELLTYPE_FORMULA || eCellType == CELLTYPE_EDIT )
911                     rProgress.SetStateOnPercent( nProgress );
912 
913                 if (rInner == nIEnd) break;
914                 if (bPositive) ++rInner; else --rInner;
915             }
916             rProgress.SetStateOnPercent( nProgress );
917         }
918         else
919         {
920             if (!bPositive)
921                 nInc = -nInc;
922             double nEndVal = (nInc>=0.0) ? MAXDOUBLE : -MAXDOUBLE;
923             if (bVertical)
924                 FillSeries( static_cast<SCCOL>(nCol), nRow1,
925                         static_cast<SCCOL>(nCol), nRow2, nFillCount, eFillDir,
926                         eFillCmd, eDateCmd, nInc, nEndVal, nMinDigits, sal_False,
927                         rProgress );
928             else
929                 FillSeries( nCol1, static_cast<SCROW>(nRow), nCol2,
930                         static_cast<SCROW>(nRow), nFillCount, eFillDir,
931                         eFillCmd, eDateCmd, nInc, nEndVal, nMinDigits, sal_False,
932                         rProgress );
933             nProgress = rProgress.GetState();
934         }
935 
936         nActFormCnt += nMaxFormCnt;
937     }
938 }
939 
940 String ScTable::GetAutoFillPreview( const ScRange& rSource, SCCOL nEndX, SCROW nEndY )
941 {
942     String aValue;
943 
944     SCCOL nCol1 = rSource.aStart.Col();
945     SCROW nRow1 = rSource.aStart.Row();
946     SCCOL nCol2 = rSource.aEnd.Col();
947     SCROW nRow2 = rSource.aEnd.Row();
948     sal_Bool bOk = sal_True;
949     long nIndex = 0;
950     sal_uLong nSrcCount = 0;
951     FillDir eFillDir = FILL_TO_BOTTOM;
952     if ( nEndX == nCol2 && nEndY == nRow2 )     // leer
953         bOk = sal_False;
954     else if ( nEndX == nCol2 )                  // nach oben/unten
955     {
956         nEndX = nCol2 = nCol1;                  // nur erste Spalte ansehen
957         nSrcCount = nRow2 - nRow1 + 1;
958         nIndex = ((long)nEndY) - nRow1;         // kann negativ werden
959         if ( nEndY >= nRow1 )
960             eFillDir = FILL_TO_BOTTOM;
961         else
962             eFillDir = FILL_TO_TOP;
963     }
964     else if ( nEndY == nRow2 )                  // nach links/rechts
965     {
966         nEndY = nRow2 = nRow1;                  // nur erste Zeile ansehen
967         nSrcCount = nCol2 - nCol1 + 1;
968         nIndex = ((long)nEndX) - nCol1;         // kann negativ werden
969         if ( nEndX >= nCol1 )
970             eFillDir = FILL_TO_RIGHT;
971         else
972             eFillDir = FILL_TO_LEFT;
973     }
974     else                                        // Richtung nicht eindeutig
975         bOk = sal_False;
976 
977     if ( bOk )
978     {
979         FillCmd eFillCmd;
980         FillDateCmd eDateCmd;
981         double nInc;
982         sal_uInt16 nMinDigits;
983         ScUserListData* pListData = NULL;
984         sal_uInt16 nListIndex;
985 
986         FillAnalyse(nCol1,nRow1, nCol2,nRow2, eFillCmd,eDateCmd, nInc,nMinDigits, pListData,nListIndex);
987 
988         if ( pListData )                            // benutzerdefinierte Liste
989         {
990             sal_uInt16 nListCount = pListData->GetSubCount();
991             if ( nListCount )
992             {
993                 sal_uLong nSub = nSrcCount - 1; //  nListIndex ist vom letzten Source-Eintrag
994                 while ( nIndex < sal::static_int_cast<long>(nSub) )
995                     nIndex += nListCount;
996                 sal_uLong nPos = ( nListIndex + nIndex - nSub ) % nListCount;
997                 aValue = pListData->GetSubStr(sal::static_int_cast<sal_uInt16>(nPos));
998             }
999         }
1000         else if ( eFillCmd == FILL_SIMPLE )         // Auffuellen mit Muster
1001         {
1002             //Add for i89232
1003             if ((eFillDir == FILL_TO_BOTTOM)||(eFillDir == FILL_TO_TOP))
1004             {
1005                 long nBegin = 0;
1006                 long nEnd = 0;
1007                 if (nEndY > nRow1)
1008                 {
1009                     nBegin = nRow2+1;
1010                     nEnd = nEndY;
1011                 }
1012                 else
1013                 {
1014                     nBegin = nEndY;
1015                     nEnd = nRow1 -1;
1016                 }
1017                 long nNonFiltered = CountNonFilteredRows(nBegin, nEnd);
1018                 long nFiltered = nEnd + 1 - nBegin - nNonFiltered;
1019                 if (nIndex >0)
1020                     nIndex = nIndex - nFiltered;
1021                 else
1022                     nIndex = nIndex + nFiltered;
1023             }
1024             //End of i89232
1025 
1026             long nPosIndex = nIndex;
1027             while ( nPosIndex < 0 )
1028                 nPosIndex += nSrcCount;
1029             sal_uLong nPos = nPosIndex % nSrcCount;
1030             SCCOL nSrcX = nCol1;
1031             SCROW nSrcY = nRow1;
1032             if ( eFillDir == FILL_TO_TOP || eFillDir == FILL_TO_BOTTOM )
1033                 nSrcY = sal::static_int_cast<SCROW>( nSrcY + static_cast<SCROW>(nPos) );
1034             else
1035                 nSrcX = sal::static_int_cast<SCCOL>( nSrcX + static_cast<SCCOL>(nPos) );
1036 
1037             ScBaseCell* pCell = GetCell( nSrcX, nSrcY );
1038             if ( pCell )
1039             {
1040                 sal_Int32 nDelta;
1041                 if (nIndex >= 0)
1042                     nDelta = nIndex / nSrcCount;
1043                 else
1044                     nDelta = ( nIndex - nSrcCount + 1 ) / nSrcCount;    // -1 -> -1
1045 
1046                 CellType eType = pCell->GetCellType();
1047                 switch ( eType )
1048                 {
1049                     case CELLTYPE_STRING:
1050                     case CELLTYPE_EDIT:
1051                     {
1052                         if ( eType == CELLTYPE_STRING )
1053                             ((ScStringCell*)pCell)->GetString( aValue );
1054                         else
1055                             ((ScEditCell*)pCell)->GetString( aValue );
1056                         if ( !(nScFillModeMouseModifier & KEY_MOD1) && !IsDataFiltered() )  //i89232
1057                         {
1058                             sal_Int32 nVal;
1059                             sal_uInt16 nCellDigits = 0; // look at each source cell individually
1060                             short nFlag = lcl_DecompValueString( aValue, nVal, &nCellDigits );
1061                             if ( nFlag < 0 )
1062                             {
1063                                 if (aValue.Equals( ScGlobal::GetOrdinalSuffix( nVal)))
1064                                     aValue = ScGlobal::GetOrdinalSuffix( nVal + nDelta);
1065 
1066                                 aValue.Insert( lcl_ValueString( nVal + nDelta, nCellDigits ), 0 );
1067                             }
1068                             else if ( nFlag > 0 )
1069                                 aValue += lcl_ValueString( nVal + nDelta, nCellDigits );
1070                         }
1071                     }
1072                     break;
1073                     case CELLTYPE_VALUE:
1074                     {
1075                         //  dabei kann's keinen Ueberlauf geben...
1076                         double nVal = ((ScValueCell*)pCell)->GetValue();
1077                         if ( !(nScFillModeMouseModifier & KEY_MOD1) && !IsDataFiltered() )  //i89232
1078                             nVal += (double) nDelta;
1079 
1080                         Color* pColor;
1081                         sal_uLong nNumFmt = GetNumberFormat( nSrcX, nSrcY );
1082                         pDocument->GetFormatTable()->
1083                             GetOutputString( nVal, nNumFmt, aValue, &pColor );
1084                     }
1085                     break;
1086                     //  Formeln nicht
1087                     default:
1088                     {
1089                         // added to avoid warnings
1090                     }
1091                 }
1092             }
1093         }
1094         else if ( eFillCmd == FILL_LINEAR || eFillCmd == FILL_DATE )        // Werte
1095         {
1096             sal_Bool bValueOk;
1097             double nStart;
1098             sal_Int32 nVal = 0;
1099             short nHeadNoneTail = 0;
1100             ScBaseCell* pCell = GetCell( nCol1, nRow1 );
1101             if ( pCell )
1102             {
1103                 CellType eType = pCell->GetCellType();
1104                 switch ( eType )
1105                 {
1106                     case CELLTYPE_STRING:
1107                     case CELLTYPE_EDIT:
1108                     {
1109                         if ( eType == CELLTYPE_STRING )
1110                             ((ScStringCell*)pCell)->GetString( aValue );
1111                         else
1112                             ((ScEditCell*)pCell)->GetString( aValue );
1113                         nHeadNoneTail = lcl_DecompValueString( aValue, nVal );
1114                         if ( nHeadNoneTail )
1115                             nStart = (double)nVal;
1116                         else
1117                             nStart = 0.0;
1118                     }
1119                     break;
1120                     case CELLTYPE_VALUE:
1121                         nStart = ((ScValueCell*)pCell)->GetValue();
1122                     break;
1123                     case CELLTYPE_FORMULA:
1124                         nStart = ((ScFormulaCell*)pCell)->GetValue();
1125                     break;
1126                     default:
1127                         nStart = 0.0;
1128                 }
1129             }
1130             else
1131                 nStart = 0.0;
1132             if ( eFillCmd == FILL_LINEAR )
1133             {
1134                 double nAdd = nInc;
1135                 bValueOk = ( SubTotal::SafeMult( nAdd, (double) nIndex ) &&
1136                              SubTotal::SafePlus( nStart, nAdd ) );
1137             }
1138             else        // Datum
1139             {
1140                 bValueOk = sal_True;
1141                 sal_uInt16 nDayOfMonth = 0;
1142                 if ( nIndex < 0 )
1143                 {
1144                     nIndex = -nIndex;
1145                     nInc = -nInc;
1146                 }
1147                 for (long i=0; i<nIndex; i++)
1148                     IncDate( nStart, nDayOfMonth, nInc, eDateCmd );
1149             }
1150 
1151             if (bValueOk)
1152             {
1153                 if ( nHeadNoneTail )
1154                 {
1155                     if ( nHeadNoneTail < 0 )
1156                     {
1157                         if (aValue.Equals( ScGlobal::GetOrdinalSuffix( nVal)))
1158                             aValue = ScGlobal::GetOrdinalSuffix( (sal_Int32)nStart );
1159 
1160                         aValue.Insert( lcl_ValueString( (sal_Int32)nStart, nMinDigits ), 0 );
1161                     }
1162                     else
1163                         aValue += lcl_ValueString( (sal_Int32)nStart, nMinDigits );
1164                 }
1165                 else
1166                 {
1167                     //! Zahlformat je nach Index holen?
1168                     Color* pColor;
1169                     sal_uLong nNumFmt = GetNumberFormat( nCol1, nRow1 );
1170                     pDocument->GetFormatTable()->
1171                         GetOutputString( nStart, nNumFmt, aValue, &pColor );
1172                 }
1173             }
1174         }
1175         else
1176         {
1177             DBG_ERROR("GetAutoFillPreview: falscher Modus");
1178         }
1179     }
1180 
1181     return aValue;
1182 }
1183 
1184 void ScTable::IncDate(double& rVal, sal_uInt16& nDayOfMonth, double nStep, FillDateCmd eCmd)
1185 {
1186     if (eCmd == FILL_DAY)
1187     {
1188         rVal += nStep;
1189         return;
1190     }
1191 
1192     // class Date Grenzen
1193     const sal_uInt16 nMinYear = 1583;
1194     const sal_uInt16 nMaxYear = 9956;
1195 
1196     long nInc = (long) nStep;       // nach oben/unten begrenzen ?
1197     Date aNullDate = *pDocument->GetFormatTable()->GetNullDate();
1198     Date aDate = aNullDate;
1199     aDate += (long)rVal;
1200     switch (eCmd)
1201     {
1202         case FILL_WEEKDAY:
1203             {
1204                 aDate += nInc;
1205                 DayOfWeek eWeekDay = aDate.GetDayOfWeek();
1206                 if (nInc >= 0)
1207                 {
1208                     if (eWeekDay == SATURDAY)
1209                         aDate += 2;
1210                     else if (eWeekDay == SUNDAY)
1211                         aDate += 1;
1212                 }
1213                 else
1214                 {
1215                     if (eWeekDay == SATURDAY)
1216                         aDate -= 1;
1217                     else if (eWeekDay == SUNDAY)
1218                         aDate -= 2;
1219                 }
1220             }
1221             break;
1222         case FILL_MONTH:
1223             {
1224                 if ( nDayOfMonth == 0 )
1225                     nDayOfMonth = aDate.GetDay();       // init
1226                 long nMonth = aDate.GetMonth();
1227                 long nYear = aDate.GetYear();
1228 
1229                 nMonth += nInc;
1230 
1231                 if (nInc >= 0)
1232                 {
1233                     if (nMonth > 12)
1234                     {
1235                         long nYAdd = (nMonth-1) / 12;
1236                         nMonth -= nYAdd * 12;
1237                         nYear += nYAdd;
1238                     }
1239                 }
1240                 else
1241                 {
1242                     if (nMonth < 1)
1243                     {
1244                         long nYAdd = 1 - nMonth / 12;       // positiv
1245                         nMonth += nYAdd * 12;
1246                         nYear -= nYAdd;
1247                     }
1248                 }
1249 
1250                 if ( nYear < nMinYear )
1251                     aDate = Date( 1,1, nMinYear );
1252                 else if ( nYear > nMaxYear )
1253                     aDate = Date( 31,12, nMaxYear );
1254                 else
1255                 {
1256                     aDate.SetMonth((sal_uInt16) nMonth);
1257                     aDate.SetYear((sal_uInt16) nYear);
1258                     if ( nDayOfMonth > 28 )
1259                         aDate.SetDay( Min( aDate.GetDaysInMonth(), nDayOfMonth ) );
1260                 }
1261             }
1262             break;
1263         case FILL_YEAR:
1264             {
1265                 long nYear = aDate.GetYear();
1266                 nYear += nInc;
1267                 if ( nYear < nMinYear )
1268                     aDate = Date( 1,1, nMinYear );
1269                 else if ( nYear > nMaxYear )
1270                     aDate = Date( 31,12, nMaxYear );
1271                 else
1272                     aDate.SetYear((sal_uInt16) nYear);
1273             }
1274             break;
1275         default:
1276         {
1277             // added to avoid warnings
1278         }
1279     }
1280 
1281     rVal = aDate - aNullDate;
1282 }
1283 
1284 void ScTable::FillSeries( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
1285                     sal_uLong nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd,
1286                     double nStepValue, double nMaxValue, sal_uInt16 nArgMinDigits,
1287                     sal_Bool bAttribs, ScProgress& rProgress )
1288 {
1289     //
1290     //  Richtung auswerten
1291     //
1292 
1293     sal_Bool bVertical = (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_TOP);
1294     sal_Bool bPositive = (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_RIGHT);
1295 
1296     sal_uLong nCol = 0;
1297     sal_uLong nRow = 0;
1298     sal_uLong& rInner = bVertical ? nRow : nCol;        // Schleifenvariablen
1299     sal_uLong& rOuter = bVertical ? nCol : nRow;
1300     sal_uLong nOStart;
1301     sal_uLong nOEnd;
1302     sal_uLong nIStart;
1303     sal_uLong nIEnd;
1304     sal_uLong nISource;
1305 
1306     if (bVertical)
1307     {
1308         nFillCount += (nRow2 - nRow1);
1309         if (nFillCount == 0)
1310             return;
1311         nOStart = nCol1;
1312         nOEnd = nCol2;
1313         if (bPositive)
1314         {
1315             nISource = nRow1;
1316             nIStart = nRow1 + 1;
1317             nIEnd = nRow1 + nFillCount;
1318         }
1319         else
1320         {
1321             nISource = nRow2;
1322             nIStart = nRow2 - 1;
1323             nIEnd = nRow2 - nFillCount;
1324         }
1325     }
1326     else
1327     {
1328         nFillCount += (nCol2 - nCol1);
1329         if (nFillCount == 0)
1330             return;
1331         nOStart = nRow1;
1332         nOEnd = nRow2;
1333         if (bPositive)
1334         {
1335             nISource = nCol1;
1336             nIStart = nCol1 + 1;
1337             nIEnd = nCol1 + nFillCount;
1338         }
1339         else
1340         {
1341             nISource = nCol2;
1342             nIStart = nCol2 - 1;
1343             nIEnd = nCol2 - nFillCount;
1344         }
1345     }
1346 
1347     sal_uLong nIMin = nIStart;
1348     sal_uLong nIMax = nIEnd;
1349     PutInOrder(nIMin,nIMax);
1350     sal_uInt16 nDel = bAttribs ? IDF_AUTOFILL : (IDF_AUTOFILL & IDF_CONTENTS);
1351     if (bVertical)
1352         DeleteArea(nCol1, static_cast<SCROW>(nIMin), nCol2, static_cast<SCROW>(nIMax), nDel);
1353     else
1354         DeleteArea(static_cast<SCCOL>(nIMin), nRow1, static_cast<SCCOL>(nIMax), nRow2, nDel);
1355 
1356     sal_uLong nProgress = rProgress.GetState();
1357 
1358     //
1359     //  ausfuehren
1360     //
1361 
1362     sal_uLong nActFormCnt = 0;
1363     for (rOuter = nOStart; rOuter <= nOEnd; rOuter++)
1364     {
1365         sal_Bool bFirst = sal_True;
1366         rInner = nISource;
1367         ScBaseCell* pSrcCell = aCol[nCol].GetCell(static_cast<SCROW>(nRow));
1368 
1369         if (bVertical && bAttribs)
1370             aCol[nCol].Resize( aCol[nCol].GetCellCount() + nFillCount );
1371 
1372         if (bAttribs)
1373         {
1374             const ScPatternAttr* pSrcPattern = aCol[nCol].GetPattern(static_cast<SCROW>(nRow));
1375             if (bVertical)
1376                 aCol[nCol].SetPatternArea( static_cast<SCROW>(nIMin),
1377                         static_cast<SCROW>(nIMax), *pSrcPattern, sal_True );
1378             else
1379                 for (SCCOL nAtCol = static_cast<SCCOL>(nIMin); nAtCol <= sal::static_int_cast<SCCOL>(nIMax); nAtCol++)
1380                     aCol[nAtCol].SetPattern(static_cast<SCROW>(nRow), *pSrcPattern, sal_True);
1381         }
1382 
1383         if (pSrcCell)
1384         {
1385             CellType eCellType = pSrcCell->GetCellType();
1386 
1387             if (eFillCmd == FILL_SIMPLE)                // kopieren
1388             {
1389                 if (eCellType == CELLTYPE_FORMULA)
1390                 {
1391                     for (rInner = nIMin; rInner <= nIMax; rInner++)
1392                     {
1393                         sal_uLong nInd = nActFormCnt;
1394                         FillFormula(nInd, bFirst, (ScFormulaCell*)pSrcCell,
1395                             static_cast<SCCOL>(nCol), nRow, (rInner == nIEnd) );
1396                         bFirst = sal_False;
1397                         rProgress.SetStateOnPercent( ++nProgress );
1398                     }
1399                 }
1400                 else if (eCellType != CELLTYPE_NOTE)
1401                 {
1402                     for (rInner = nIMin; rInner <= nIMax; rInner++)
1403                     {
1404                         ScAddress aDestPos( static_cast<SCCOL>(nCol), static_cast<SCROW>(nRow), nTab );
1405                         aCol[nCol].Insert( aDestPos.Row(), pSrcCell->CloneWithoutNote( *pDocument ) );
1406                     }
1407                     nProgress += nIMax - nIMin + 1;
1408                     rProgress.SetStateOnPercent( nProgress );
1409                 }
1410             }
1411             else if (eCellType == CELLTYPE_VALUE || eCellType == CELLTYPE_FORMULA)
1412             {
1413                 double nStartVal;
1414                 if (eCellType == CELLTYPE_VALUE)
1415                     nStartVal = ((ScValueCell*)pSrcCell)->GetValue();
1416                 else
1417                     nStartVal = ((ScFormulaCell*)pSrcCell)->GetValue();
1418                 double nVal = nStartVal;
1419                 long nIndex = 0;
1420 
1421                 sal_Bool bError = sal_False;
1422                 sal_Bool bOverflow = sal_False;
1423 
1424                 sal_uInt16 nDayOfMonth = 0;
1425                 rInner = nIStart;
1426                 while (true)        // #i53728# with "for (;;)" old solaris/x86 compiler mis-optimizes
1427                 {
1428                     if (!bError && !bOverflow)
1429                     {
1430                         switch (eFillCmd)
1431                         {
1432                             case FILL_LINEAR:
1433                                 {
1434                                     //  #86365# use multiplication instead of repeated addition
1435                                     //  to avoid accumulating rounding errors
1436                                     nVal = nStartVal;
1437                                     double nAdd = nStepValue;
1438                                     if ( !SubTotal::SafeMult( nAdd, (double) ++nIndex ) ||
1439                                          !SubTotal::SafePlus( nVal, nAdd ) )
1440                                         bError = sal_True;
1441                                 }
1442                                 break;
1443                             case FILL_GROWTH:
1444                                 if (!SubTotal::SafeMult(nVal, nStepValue))
1445                                     bError = sal_True;
1446                                 break;
1447                             case FILL_DATE:
1448                                 if (fabs(nVal) > _D_MAX_LONG_)
1449                                     bError = sal_True;
1450                                 else
1451                                     IncDate(nVal, nDayOfMonth, nStepValue, eFillDateCmd);
1452                                 break;
1453                             default:
1454                             {
1455                                 // added to avoid warnings
1456                             }
1457                         }
1458 
1459                         if (nStepValue >= 0)
1460                         {
1461                             if (nVal > nMaxValue)           // Zielwert erreicht?
1462                             {
1463                                 nVal = nMaxValue;
1464                                 bOverflow = sal_True;
1465                             }
1466                         }
1467                         else
1468                         {
1469                             if (nVal < nMaxValue)
1470                             {
1471                                 nVal = nMaxValue;
1472                                 bOverflow = sal_True;
1473                             }
1474                         }
1475                     }
1476 
1477                     if (bError)
1478                         aCol[nCol].SetError(static_cast<SCROW>(nRow), errNoValue);
1479                     else if (!bOverflow)
1480                         aCol[nCol].SetValue(static_cast<SCROW>(nRow), nVal);
1481 
1482                     if (rInner == nIEnd) break;
1483                     if (bPositive) ++rInner; else --rInner;
1484                 }
1485                 nProgress += nIMax - nIMin + 1;
1486                 rProgress.SetStateOnPercent( nProgress );
1487             }
1488             else if (eCellType == CELLTYPE_STRING || eCellType == CELLTYPE_EDIT)
1489             {
1490                 if ( nStepValue >= 0 )
1491                 {
1492                     if ( nMaxValue >= (double)LONG_MAX )
1493                         nMaxValue = (double)LONG_MAX - 1;
1494                 }
1495                 else
1496                 {
1497                     if ( nMaxValue <= (double)LONG_MIN )
1498                         nMaxValue = (double)LONG_MIN + 1;
1499                 }
1500                 String aValue;
1501                 if (eCellType == CELLTYPE_STRING)
1502                     ((ScStringCell*)pSrcCell)->GetString( aValue );
1503                 else
1504                     ((ScEditCell*)pSrcCell)->GetString( aValue );
1505                 sal_Int32 nStringValue;
1506                 sal_uInt16 nMinDigits = nArgMinDigits;
1507                 short nHeadNoneTail = lcl_DecompValueString( aValue, nStringValue, &nMinDigits );
1508                 if ( nHeadNoneTail )
1509                 {
1510                     double nStartVal = (double)nStringValue;
1511                     double nVal = nStartVal;
1512                     long nIndex = 0;
1513                     sal_Bool bError = sal_False;
1514                     sal_Bool bOverflow = sal_False;
1515 
1516                     sal_Bool bIsOrdinalSuffix = aValue.Equals( ScGlobal::GetOrdinalSuffix(
1517                                 (sal_Int32)nStartVal));
1518 
1519                     rInner = nIStart;
1520                     while (true)        // #i53728# with "for (;;)" old solaris/x86 compiler mis-optimizes
1521                     {
1522                         if (!bError && !bOverflow)
1523                         {
1524                             switch (eFillCmd)
1525                             {
1526                                 case FILL_LINEAR:
1527                                     {
1528                                         //  #86365# use multiplication instead of repeated addition
1529                                         //  to avoid accumulating rounding errors
1530                                         nVal = nStartVal;
1531                                         double nAdd = nStepValue;
1532                                         if ( !SubTotal::SafeMult( nAdd, (double) ++nIndex ) ||
1533                                              !SubTotal::SafePlus( nVal, nAdd ) )
1534                                             bError = sal_True;
1535                                     }
1536                                     break;
1537                                 case FILL_GROWTH:
1538                                     if (!SubTotal::SafeMult(nVal, nStepValue))
1539                                         bError = sal_True;
1540                                     break;
1541                                 default:
1542                                 {
1543                                     // added to avoid warnings
1544                                 }
1545                             }
1546 
1547                             if (nStepValue >= 0)
1548                             {
1549                                 if (nVal > nMaxValue)           // Zielwert erreicht?
1550                                 {
1551                                     nVal = nMaxValue;
1552                                     bOverflow = sal_True;
1553                                 }
1554                             }
1555                             else
1556                             {
1557                                 if (nVal < nMaxValue)
1558                                 {
1559                                     nVal = nMaxValue;
1560                                     bOverflow = sal_True;
1561                                 }
1562                             }
1563                         }
1564 
1565                         if (bError)
1566                             aCol[nCol].SetError(static_cast<SCROW>(nRow), errNoValue);
1567                         else if (!bOverflow)
1568                         {
1569                             nStringValue = (sal_Int32)nVal;
1570                             String aStr;
1571                             if ( nHeadNoneTail < 0 )
1572                             {
1573                                 aCol[nCol].Insert( static_cast<SCROW>(nRow),
1574                                         lcl_getSuffixCell( pDocument,
1575                                             nStringValue, nMinDigits, aValue,
1576                                             eCellType, bIsOrdinalSuffix ));
1577                             }
1578                             else
1579                             {
1580                                 aStr = aValue;
1581                                 aStr += lcl_ValueString( nStringValue, nMinDigits );
1582                                 ScStringCell* pCell = new ScStringCell( aStr );
1583                                 aCol[nCol].Insert( static_cast<SCROW>(nRow), pCell );
1584                             }
1585                         }
1586 
1587                         if (rInner == nIEnd) break;
1588                         if (bPositive) ++rInner; else --rInner;
1589                     }
1590                 }
1591                 nProgress += nIMax - nIMin + 1;
1592                 rProgress.SetStateOnPercent( nProgress );
1593             }
1594         }
1595         else
1596         {
1597             nProgress += nIMax - nIMin + 1;
1598             rProgress.SetStateOnPercent( nProgress );
1599         }
1600         ++nActFormCnt;
1601     }
1602 }
1603 
1604 void ScTable::Fill( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
1605                     sal_uLong nFillCount, FillDir eFillDir, FillCmd eFillCmd, FillDateCmd eFillDateCmd,
1606                     double nStepValue, double nMaxValue)
1607 {
1608     sal_uLong nProgCount;
1609     if (eFillDir == FILL_TO_BOTTOM || eFillDir == FILL_TO_TOP)
1610         nProgCount = nCol2 - nCol1 + 1;
1611     else
1612         nProgCount = nRow2 - nRow1 + 1;
1613     nProgCount *= nFillCount;
1614     ScProgress aProgress( pDocument->GetDocumentShell(),
1615                             ScGlobal::GetRscString(STR_FILL_SERIES_PROGRESS), nProgCount );
1616 
1617     bSharedNameInserted = sal_False;
1618 
1619     if (eFillCmd == FILL_AUTO)
1620         FillAuto(nCol1, nRow1, nCol2, nRow2, nFillCount, eFillDir, aProgress);
1621     else
1622         FillSeries(nCol1, nRow1, nCol2, nRow2, nFillCount, eFillDir,
1623                     eFillCmd, eFillDateCmd, nStepValue, nMaxValue, 0, sal_True, aProgress);
1624 
1625     if (bSharedNameInserted)                        // Wurde Shared-Name eingefuegt?
1626         pDocument->GetRangeName()->SetSharedMaxIndex(
1627             pDocument->GetRangeName()->GetSharedMaxIndex()+1);  // dann hochzaehlen
1628 }
1629 
1630 
1631 void ScTable::AutoFormatArea(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
1632                                 const ScPatternAttr& rAttr, sal_uInt16 nFormatNo)
1633 {
1634     ScAutoFormat* pAutoFormat = ScGlobal::GetAutoFormat();
1635     if (pAutoFormat)
1636     {
1637         ScAutoFormatData* pData = (*pAutoFormat)[nFormatNo];
1638         if (pData)
1639         {
1640 //          ScPatternAttr aPattern(pDocument->GetPool());
1641 //            pData->FillToItemSet(nIndex, aPattern.GetItemSet(), *pDocument);
1642             ApplyPatternArea(nStartCol, nStartRow, nEndCol, nEndRow, rAttr);
1643         }
1644     }
1645 }
1646 
1647 void ScTable::AutoFormat( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
1648                             sal_uInt16 nFormatNo )
1649 {
1650     if (ValidColRow(nStartCol, nStartRow) && ValidColRow(nEndCol, nEndRow))
1651     {
1652         ScAutoFormat* pAutoFormat = ScGlobal::GetAutoFormat();
1653         if (pAutoFormat)
1654         {
1655             ScAutoFormatData* pData = (*pAutoFormat)[nFormatNo];
1656             if (pData)
1657             {
1658                 ScPatternAttr* pPatternAttrs[16];
1659                 for (sal_uInt8 i = 0; i < 16; ++i)
1660                 {
1661                     pPatternAttrs[i] = new ScPatternAttr(pDocument->GetPool());
1662                     pData->FillToItemSet(i, pPatternAttrs[i]->GetItemSet(), *pDocument);
1663                 }
1664 
1665                 SCCOL nCol = nStartCol;
1666                 SCROW nRow = nStartRow;
1667                 sal_uInt16 nIndex = 0;
1668                 // Linke obere Ecke
1669                 AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
1670                 // Linke Spalte
1671                 if (pData->IsEqualData(4, 8))
1672                     AutoFormatArea(nStartCol, nStartRow + 1, nStartCol, nEndRow - 1, *pPatternAttrs[4], nFormatNo);
1673                 else
1674                 {
1675                     nIndex = 4;
1676                     for (nRow = nStartRow + 1; nRow < nEndRow; nRow++)
1677                     {
1678                         AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
1679                         if (nIndex == 4)
1680                             nIndex = 8;
1681                         else
1682                             nIndex = 4;
1683                     }
1684                 }
1685                 // Linke untere Ecke
1686                 nRow = nEndRow;
1687                 nIndex = 12;
1688                 AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
1689                 // Rechte obere Ecke
1690                 nCol = nEndCol;
1691                 nRow = nStartRow;
1692                 nIndex = 3;
1693                 AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
1694                 // Rechte Spalte
1695                 if (pData->IsEqualData(7, 11))
1696                     AutoFormatArea(nEndCol, nStartRow + 1, nEndCol, nEndRow - 1, *pPatternAttrs[7], nFormatNo);
1697                 else
1698                 {
1699                     nIndex = 7;
1700                     for (nRow = nStartRow + 1; nRow < nEndRow; nRow++)
1701                     {
1702                         AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
1703                         if (nIndex == 7)
1704                             nIndex = 11;
1705                         else
1706                             nIndex = 7;
1707                     }
1708                 }
1709                 // Rechte untere Ecke
1710                 nRow = nEndRow;
1711                 nIndex = 15;
1712                 AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
1713                 nRow = nStartRow;
1714                 nIndex = 1;
1715                 for (nCol = nStartCol + 1; nCol < nEndCol; nCol++)
1716                 {
1717                     AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
1718                     if (nIndex == 1)
1719                         nIndex = 2;
1720                     else
1721                         nIndex = 1;
1722                 }
1723                 // Untere Zeile
1724                 nRow = nEndRow;
1725                 nIndex = 13;
1726                 for (nCol = nStartCol + 1; nCol < nEndCol; nCol++)
1727                 {
1728                     AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
1729                     if (nIndex == 13)
1730                         nIndex = 14;
1731                     else
1732                         nIndex = 13;
1733                 }
1734                 // Boddy
1735                 if ((pData->IsEqualData(5, 6)) && (pData->IsEqualData(9, 10)) && (pData->IsEqualData(5, 9)))
1736                     AutoFormatArea(nStartCol + 1, nStartRow + 1, nEndCol-1, nEndRow - 1, *pPatternAttrs[5], nFormatNo);
1737                 else
1738                 {
1739                     if ((pData->IsEqualData(5, 9)) && (pData->IsEqualData(6, 10)))
1740                     {
1741                         nIndex = 5;
1742                         for (nCol = nStartCol + 1; nCol < nEndCol; nCol++)
1743                         {
1744                             AutoFormatArea(nCol, nStartRow + 1, nCol, nEndRow - 1, *pPatternAttrs[nIndex], nFormatNo);
1745                             if (nIndex == 5)
1746                                 nIndex = 6;
1747                             else
1748                                 nIndex = 5;
1749                         }
1750                     }
1751                     else
1752                     {
1753                         nIndex = 5;
1754                         for (nCol = nStartCol + 1; nCol < nEndCol; nCol++)
1755                         {
1756                             for (nRow = nStartRow + 1; nRow < nEndRow; nRow++)
1757                             {
1758                                 AutoFormatArea(nCol, nRow, nCol, nRow, *pPatternAttrs[nIndex], nFormatNo);
1759                                 if ((nIndex == 5) || (nIndex == 9))
1760                                 {
1761                                     if (nIndex == 5)
1762                                         nIndex = 9;
1763                                     else
1764                                         nIndex = 5;
1765                                 }
1766                                 else
1767                                 {
1768                                     if (nIndex == 6)
1769                                         nIndex = 10;
1770                                     else
1771                                         nIndex = 6;
1772                                 }
1773                             } // for nRow
1774                             if ((nIndex == 5) || (nIndex == 9))
1775                                 nIndex = 6;
1776                             else
1777                                 nIndex = 5;
1778                         } // for nCol
1779                     } // if not equal Column
1780                 } // if not all equal
1781 
1782                 for (sal_uInt8 j = 0; j < 16; ++j)
1783                     delete pPatternAttrs[j];
1784             } // if AutoFormatData != NULL
1785         } // if AutoFormat != NULL
1786     } // if ValidColRow
1787 }
1788 
1789 void ScTable::GetAutoFormatAttr(SCCOL nCol, SCROW nRow, sal_uInt16 nIndex, ScAutoFormatData& rData)
1790 {
1791     sal_uInt32 nFormatIndex = GetNumberFormat( nCol, nRow );
1792     ScNumFormatAbbrev   aNumFormat( nFormatIndex, *pDocument->GetFormatTable() );
1793     rData.GetFromItemSet( nIndex, GetPattern( nCol, nRow )->GetItemSet(), aNumFormat );
1794 }
1795 
1796 #define LF_LEFT         1
1797 #define LF_TOP          2
1798 #define LF_RIGHT        4
1799 #define LF_BOTTOM       8
1800 #define LF_ALL          (LF_LEFT | LF_TOP | LF_RIGHT | LF_BOTTOM)
1801 
1802 void ScTable::GetAutoFormatFrame(SCCOL nCol, SCROW nRow, sal_uInt16 nFlags, sal_uInt16 nIndex, ScAutoFormatData& rData)
1803 {
1804     const SvxBoxItem* pTheBox = (SvxBoxItem*)GetAttr(nCol, nRow, ATTR_BORDER);
1805     const SvxBoxItem* pLeftBox = (SvxBoxItem*)GetAttr(nCol - 1, nRow, ATTR_BORDER);
1806     const SvxBoxItem* pTopBox = (SvxBoxItem*)GetAttr(nCol, nRow - 1, ATTR_BORDER);
1807     const SvxBoxItem* pRightBox = (SvxBoxItem*)GetAttr(nCol + 1, nRow, ATTR_BORDER);
1808     const SvxBoxItem* pBottomBox = (SvxBoxItem*)GetAttr(nCol, nRow + 1, ATTR_BORDER);
1809 
1810     SvxBoxItem aBox( ATTR_BORDER );
1811     if (nFlags & LF_LEFT)
1812     {
1813         if (pLeftBox)
1814         {
1815             if (ScHasPriority(pTheBox->GetLeft(), pLeftBox->GetRight()))
1816                 aBox.SetLine(pTheBox->GetLeft(), BOX_LINE_LEFT);
1817             else
1818                 aBox.SetLine(pLeftBox->GetRight(), BOX_LINE_LEFT);
1819         }
1820         else
1821             aBox.SetLine(pTheBox->GetLeft(), BOX_LINE_LEFT);
1822     }
1823     if (nFlags & LF_TOP)
1824     {
1825         if (pTopBox)
1826         {
1827             if (ScHasPriority(pTheBox->GetTop(), pTopBox->GetBottom()))
1828                 aBox.SetLine(pTheBox->GetTop(), BOX_LINE_TOP);
1829             else
1830                 aBox.SetLine(pTopBox->GetBottom(), BOX_LINE_TOP);
1831         }
1832         else
1833             aBox.SetLine(pTheBox->GetTop(), BOX_LINE_TOP);
1834     }
1835     if (nFlags & LF_RIGHT)
1836     {
1837         if (pRightBox)
1838         {
1839             if (ScHasPriority(pTheBox->GetRight(), pRightBox->GetLeft()))
1840                 aBox.SetLine(pTheBox->GetRight(), BOX_LINE_RIGHT);
1841             else
1842                 aBox.SetLine(pRightBox->GetLeft(), BOX_LINE_RIGHT);
1843         }
1844         else
1845             aBox.SetLine(pTheBox->GetRight(), BOX_LINE_RIGHT);
1846     }
1847     if (nFlags & LF_BOTTOM)
1848     {
1849         if (pBottomBox)
1850         {
1851             if (ScHasPriority(pTheBox->GetBottom(), pBottomBox->GetTop()))
1852                 aBox.SetLine(pTheBox->GetBottom(), BOX_LINE_BOTTOM);
1853             else
1854                 aBox.SetLine(pBottomBox->GetTop(), BOX_LINE_BOTTOM);
1855         }
1856         else
1857             aBox.SetLine(pTheBox->GetBottom(), BOX_LINE_BOTTOM);
1858     }
1859     rData.PutItem( nIndex, aBox );
1860 }
1861 
1862 void ScTable::GetAutoFormatData(SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow, ScAutoFormatData& rData)
1863 {
1864     if (ValidColRow(nStartCol, nStartRow) && ValidColRow(nEndCol, nEndRow))
1865     {
1866         if ((nEndCol - nStartCol >= 3) && (nEndRow - nStartRow >= 3))
1867         {
1868             // Linke obere Ecke
1869             GetAutoFormatAttr(nStartCol, nStartRow, 0, rData);
1870             GetAutoFormatFrame(nStartCol, nStartRow, LF_ALL, 0, rData);
1871             // Linke Spalte
1872             GetAutoFormatAttr(nStartCol, nStartRow + 1, 4, rData);
1873             GetAutoFormatAttr(nStartCol, nStartRow + 2, 8, rData);
1874             GetAutoFormatFrame(nStartCol, nStartRow + 1, LF_LEFT | LF_RIGHT | LF_BOTTOM, 4, rData);
1875             if (nEndRow - nStartRow >= 4)
1876                 GetAutoFormatFrame(nStartCol, nStartRow + 2, LF_LEFT | LF_RIGHT | LF_BOTTOM, 8, rData);
1877             else
1878                 rData.CopyItem( 8, 4, ATTR_BORDER );
1879             // Linke untere Ecke
1880             GetAutoFormatAttr(nStartCol, nEndRow, 12, rData);
1881             GetAutoFormatFrame(nStartCol, nEndRow, LF_ALL, 12, rData);
1882             // Rechte obere Ecke
1883             GetAutoFormatAttr(nEndCol, nStartRow, 3, rData);
1884             GetAutoFormatFrame(nEndCol, nStartRow, LF_ALL, 3, rData);
1885             // Rechte Spalte
1886             GetAutoFormatAttr(nEndCol, nStartRow + 1, 7, rData);
1887             GetAutoFormatAttr(nEndCol, nStartRow + 2, 11, rData);
1888             GetAutoFormatFrame(nEndCol, nStartRow + 1, LF_LEFT | LF_RIGHT | LF_BOTTOM, 7, rData);
1889             if (nEndRow - nStartRow >= 4)
1890                 GetAutoFormatFrame(nEndCol, nStartRow + 2, LF_LEFT | LF_RIGHT | LF_BOTTOM, 11, rData);
1891             else
1892                 rData.CopyItem( 11, 7, ATTR_BORDER );
1893             // Rechte untere Ecke
1894             GetAutoFormatAttr(nEndCol, nEndRow, 15, rData);
1895             GetAutoFormatFrame(nEndCol, nEndRow, LF_ALL, 15, rData);
1896             // Ober Zeile
1897             GetAutoFormatAttr(nStartCol + 1, nStartRow, 1, rData);
1898             GetAutoFormatAttr(nStartCol + 2, nStartRow, 2, rData);
1899             GetAutoFormatFrame(nStartCol + 1, nStartRow, LF_TOP | LF_BOTTOM | LF_RIGHT, 1, rData);
1900             if (nEndCol - nStartCol >= 4)
1901                 GetAutoFormatFrame(nStartCol + 2, nStartRow, LF_TOP | LF_BOTTOM | LF_RIGHT, 2, rData);
1902             else
1903                 rData.CopyItem( 2, 1, ATTR_BORDER );
1904             // Untere Zeile
1905             GetAutoFormatAttr(nStartCol + 1, nEndRow, 13, rData);
1906             GetAutoFormatAttr(nStartCol + 2, nEndRow, 14, rData);
1907             GetAutoFormatFrame(nStartCol + 1, nEndRow, LF_TOP | LF_BOTTOM | LF_RIGHT, 13, rData);
1908             if (nEndCol - nStartCol >= 4)
1909                 GetAutoFormatFrame(nStartCol + 2, nEndRow, LF_TOP | LF_BOTTOM | LF_RIGHT, 14, rData);
1910             else
1911                 rData.CopyItem( 14, 13, ATTR_BORDER );
1912             // Body
1913             GetAutoFormatAttr(nStartCol + 1, nStartRow + 1, 5, rData);
1914             GetAutoFormatAttr(nStartCol + 2, nStartRow + 1, 6, rData);
1915             GetAutoFormatAttr(nStartCol + 1, nStartRow + 2, 9, rData);
1916             GetAutoFormatAttr(nStartCol + 2, nStartRow + 2, 10, rData);
1917             GetAutoFormatFrame(nStartCol + 1, nStartRow + 1, LF_RIGHT | LF_BOTTOM, 5, rData);
1918             if ((nEndCol - nStartCol >= 4) && (nEndRow - nStartRow >= 4))
1919             {
1920                 GetAutoFormatFrame(nStartCol + 2, nStartRow + 1, LF_RIGHT | LF_BOTTOM, 6, rData);
1921                 GetAutoFormatFrame(nStartCol + 1, nStartRow + 2, LF_RIGHT | LF_BOTTOM, 9, rData);
1922                 GetAutoFormatFrame(nStartCol + 2, nStartRow + 2, LF_RIGHT | LF_BOTTOM, 10, rData);
1923             }
1924             else
1925             {
1926                 rData.CopyItem( 6, 5, ATTR_BORDER );
1927                 rData.CopyItem( 9, 5, ATTR_BORDER );
1928                 rData.CopyItem( 10, 5, ATTR_BORDER );
1929             }
1930         }
1931     }
1932 }
1933 
1934 void ScTable::SetError( SCCOL nCol, SCROW nRow, sal_uInt16 nError)
1935 {
1936     if (ValidColRow(nCol, nRow))
1937         aCol[nCol].SetError( nRow, nError );
1938 }
1939 
1940 void ScTable::UpdateInsertTabAbs(SCTAB nTable)
1941 {
1942     for (SCCOL i=0; i <= MAXCOL; i++)
1943         aCol[i].UpdateInsertTabAbs(nTable);
1944 }
1945 
1946 //UNUSED2008-05  sal_uInt16 ScTable::GetErrorData( SCCOL nCol, SCROW nRow ) const
1947 //UNUSED2008-05  {
1948 //UNUSED2008-05      if (ValidColRow(nCol,nRow))
1949 //UNUSED2008-05          return aCol[nCol].GetErrorData( nRow );
1950 //UNUSED2008-05      else
1951 //UNUSED2008-05          return 0;
1952 //UNUSED2008-05  }
1953 
1954 sal_Bool ScTable::GetNextSpellingCell(SCCOL& rCol, SCROW& rRow, sal_Bool bInSel,
1955                                     const ScMarkData& rMark) const
1956 {
1957     if (rRow == MAXROW+2)                       // Tabellenende
1958     {
1959         rRow = 0;
1960         rCol = 0;
1961     }
1962     else
1963     {
1964         rRow++;
1965         if (rRow == MAXROW+1)
1966         {
1967             rCol++;
1968             rRow = 0;
1969         }
1970     }
1971     if (rCol == MAXCOL+1)
1972         return sal_True;
1973     else
1974     {
1975         sal_Bool bStop = sal_False;
1976         while (!bStop)
1977         {
1978             if (ValidCol(rCol))
1979             {
1980                 bStop = aCol[rCol].GetNextSpellingCell(rRow, bInSel, rMark);
1981                 if (bStop)
1982                     return sal_True;
1983                 else /*if (rRow == MAXROW+1) */
1984                 {
1985                     rCol++;
1986                     rRow = 0;
1987                 }
1988             }
1989             else
1990                 return sal_True;
1991         }
1992     }
1993     return sal_False;
1994 }
1995 
1996 void ScTable::RemoveAutoSpellObj()
1997 {
1998     for (SCCOL i=0; i <= MAXCOL; i++)
1999         aCol[i].RemoveAutoSpellObj();
2000 }
2001 
2002 sal_Bool ScTable::TestTabRefAbs(SCTAB nTable)
2003 {
2004     sal_Bool bRet = sal_False;
2005     for (SCCOL i=0; i <= MAXCOL; i++)
2006         if (aCol[i].TestTabRefAbs(nTable))
2007             bRet = sal_True;
2008     return bRet;
2009 }
2010 
2011 void ScTable::CompileDBFormula()
2012 {
2013     for (SCCOL i=0; i<=MAXCOL; i++) aCol[i].CompileDBFormula();
2014 }
2015 
2016 void ScTable::CompileDBFormula( sal_Bool bCreateFormulaString )
2017 {
2018     for (SCCOL i=0; i<=MAXCOL; i++) aCol[i].CompileDBFormula( bCreateFormulaString );
2019 }
2020 
2021 void ScTable::CompileNameFormula( sal_Bool bCreateFormulaString )
2022 {
2023     for (SCCOL i=0; i<=MAXCOL; i++) aCol[i].CompileNameFormula( bCreateFormulaString );
2024 }
2025 
2026 void ScTable::CompileColRowNameFormula()
2027 {
2028     for (SCCOL i=0; i<=MAXCOL; i++) aCol[i].CompileColRowNameFormula();
2029 }
2030 
2031 
2032 
2033 
2034 
2035 
2036