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