1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sc.hxx"
26
27 // INCLUDE ---------------------------------------------------------------
28
29 #include <svl/zforlist.hxx>
30
31 #include "scitems.hxx"
32 #include "global.hxx"
33 #include "dociter.hxx"
34 #include "document.hxx"
35 #include "table.hxx"
36 #include "column.hxx"
37 #include "cell.hxx"
38 #include "attarray.hxx"
39 #include "patattr.hxx"
40 #include "docoptio.hxx"
41 #include "cellform.hxx"
42
43 #include <vector>
44
45 using ::rtl::math::approxEqual;
46 using ::std::vector;
47 using ::rtl::OUString;
48 using ::std::set;
49
50 // STATIC DATA -----------------------------------------------------------
51
52 namespace {
53
lcl_toUpper(OUString & rStr)54 void lcl_toUpper(OUString& rStr)
55 {
56 rStr = ScGlobal::pCharClass->toUpper(rStr.trim(), 0, static_cast<sal_uInt16>(rStr.getLength()));
57 }
58
59 }
60
ScDocumentIterator(ScDocument * pDocument,SCTAB nStartTable,SCTAB nEndTable)61 ScDocumentIterator::ScDocumentIterator( ScDocument* pDocument,
62 SCTAB nStartTable, SCTAB nEndTable ) :
63 pDoc( pDocument ),
64 nStartTab( nStartTable ),
65 nEndTab( nEndTable )
66 {
67 PutInOrder( nStartTab, nEndTab );
68 if (!ValidTab(nStartTab)) nStartTab = MAXTAB;
69 if (!ValidTab(nEndTab)) nEndTab = MAXTAB;
70
71 pDefPattern = pDoc->GetDefPattern();
72
73 nCol = 0;
74 nRow = 0;
75 nTab = nStartTab;
76
77 nColPos = 0;
78 nAttrPos = 0;
79 }
80
~ScDocumentIterator()81 ScDocumentIterator::~ScDocumentIterator()
82 {
83 }
84
GetThisCol()85 sal_Bool ScDocumentIterator::GetThisCol()
86 {
87 ScTable* pTab;
88 while ( (pTab = pDoc->pTab[nTab]) == NULL )
89 {
90 if ( nTab == nEndTab )
91 {
92 nCol = MAXCOL;
93 nRow = MAXROW;
94 return sal_False;
95 }
96 ++nTab;
97 }
98 ScColumn* pCol = &pTab->aCol[nCol];
99 ScAttrArray* pAtt = pCol->pAttrArray;
100
101 sal_Bool bFound = sal_False;
102 do
103 {
104 SCROW nColRow;
105 SCROW nAttrEnd;
106
107 do
108 {
109 nAttrEnd = pAtt->pData[nAttrPos].nRow;
110 if (nAttrEnd < nRow)
111 ++nAttrPos;
112 }
113 while (nAttrEnd < nRow);
114
115 do
116 {
117 nColRow = (nColPos < pCol->nCount) ? pCol->pItems[nColPos].nRow : MAXROW+1;
118 if (nColRow < nRow)
119 ++nColPos;
120 }
121 while (nColRow < nRow);
122
123 if (nColRow == nRow)
124 {
125 bFound = sal_True;
126 pCell = pCol->pItems[nColPos].pCell;
127 pPattern = pAtt->pData[nAttrPos].pPattern;
128 }
129 else if ( pAtt->pData[nAttrPos].pPattern != pDefPattern )
130 {
131 bFound = sal_True;
132 pCell = NULL;
133 pPattern = pAtt->pData[nAttrPos].pPattern;
134 }
135 else
136 {
137 nRow = Min( (SCROW)nColRow, (SCROW)(nAttrEnd+1) );
138 }
139 }
140 while (!bFound && nRow <= MAXROW);
141
142 return bFound;
143 }
144
GetThis()145 sal_Bool ScDocumentIterator::GetThis()
146 {
147 sal_Bool bEnd = sal_False;
148 sal_Bool bSuccess = sal_False;
149
150 while ( !bSuccess && !bEnd )
151 {
152 if ( nRow > MAXROW )
153 bSuccess = sal_False;
154 else
155 bSuccess = GetThisCol();
156
157 if ( !bSuccess )
158 {
159 ++nCol;
160 if (nCol > MAXCOL)
161 {
162 nCol = 0;
163 ++nTab;
164 if (nTab > nEndTab)
165 bEnd = sal_True;
166 }
167 nRow = 0;
168 nColPos = 0;
169 nAttrPos = 0;
170 }
171 }
172
173 return !bEnd;
174 }
175
GetFirst()176 sal_Bool ScDocumentIterator::GetFirst()
177 {
178 nCol = 0;
179 nTab = nStartTab;
180
181 nRow = 0;
182 nColPos = 0;
183 nAttrPos = 0;
184
185 return GetThis();
186 }
187
GetNext()188 sal_Bool ScDocumentIterator::GetNext()
189 {
190 ++nRow;
191
192 return GetThis();
193 }
194
195 //------------------------------------------------------------------------
196
GetCell()197 ScBaseCell* ScDocumentIterator::GetCell()
198 {
199 return pCell;
200 }
201
GetPattern()202 const ScPatternAttr* ScDocumentIterator::GetPattern()
203 {
204 return pPattern;
205 }
206
GetPos(SCCOL & rCol,SCROW & rRow,SCTAB & rTab)207 void ScDocumentIterator::GetPos( SCCOL& rCol, SCROW& rRow, SCTAB& rTab )
208 {
209 rCol = nCol;
210 rRow = nRow;
211 rTab = nTab;
212 }
213
214
215 //------------------------------------------------------------------------
216 //------------------------------------------------------------------------
lcl_IterGetNumberFormat(sal_uLong & nFormat,const ScAttrArray * & rpArr,SCROW & nAttrEndRow,const ScAttrArray * pNewArr,SCROW nRow,ScDocument * pDoc)217 void lcl_IterGetNumberFormat( sal_uLong& nFormat, const ScAttrArray*& rpArr,
218 SCROW& nAttrEndRow, const ScAttrArray* pNewArr, SCROW nRow,
219 ScDocument* pDoc )
220 {
221 if ( rpArr != pNewArr || nAttrEndRow < nRow )
222 {
223 SCSIZE nPos;
224 pNewArr->Search( nRow, nPos ); // nPos 0 gueltig wenn nicht gefunden
225 const ScPatternAttr* pPattern = pNewArr->pData[nPos].pPattern;
226 nFormat = pPattern->GetNumberFormat( pDoc->GetFormatTable() );
227 rpArr = pNewArr;
228 nAttrEndRow = pNewArr->pData[nPos].nRow;
229 }
230 }
231
232 //UNUSED2008-05 ScValueIterator::ScValueIterator( ScDocument* pDocument,
233 //UNUSED2008-05 SCCOL nSCol, SCROW nSRow, SCTAB nSTab,
234 //UNUSED2008-05 SCCOL nECol, SCROW nERow, SCTAB nETab,
235 //UNUSED2008-05 sal_Bool bSTotal, sal_Bool bTextZero ) :
236 //UNUSED2008-05 pDoc( pDocument ),
237 //UNUSED2008-05 nNumFmtIndex(0),
238 //UNUSED2008-05 nStartCol( nSCol),
239 //UNUSED2008-05 nStartRow( nSRow),
240 //UNUSED2008-05 nStartTab( nSTab ),
241 //UNUSED2008-05 nEndCol( nECol ),
242 //UNUSED2008-05 nEndRow( nERow),
243 //UNUSED2008-05 nEndTab( nETab ),
244 //UNUSED2008-05 nNumFmtType( NUMBERFORMAT_UNDEFINED ),
245 //UNUSED2008-05 bNumValid( sal_False ),
246 //UNUSED2008-05 bSubTotal(bSTotal),
247 //UNUSED2008-05 bNextValid( sal_False ),
248 //UNUSED2008-05 bCalcAsShown( pDocument->GetDocOptions().IsCalcAsShown() ),
249 //UNUSED2008-05 bTextAsZero( bTextZero )
250 //UNUSED2008-05 {
251 //UNUSED2008-05 PutInOrder( nStartCol, nEndCol);
252 //UNUSED2008-05 PutInOrder( nStartRow, nEndRow);
253 //UNUSED2008-05 PutInOrder( nStartTab, nEndTab );
254 //UNUSED2008-05
255 //UNUSED2008-05 if (!ValidCol(nStartCol)) nStartCol = MAXCOL;
256 //UNUSED2008-05 if (!ValidCol(nEndCol)) nEndCol = MAXCOL;
257 //UNUSED2008-05 if (!ValidRow(nStartRow)) nStartRow = MAXROW;
258 //UNUSED2008-05 if (!ValidRow(nEndRow)) nEndRow = MAXROW;
259 //UNUSED2008-05 if (!ValidTab(nStartTab)) nStartTab = MAXTAB;
260 //UNUSED2008-05 if (!ValidTab(nEndTab)) nEndTab = MAXTAB;
261 //UNUSED2008-05
262 //UNUSED2008-05 nCol = nStartCol;
263 //UNUSED2008-05 nRow = nStartRow;
264 //UNUSED2008-05 nTab = nStartTab;
265 //UNUSED2008-05
266 //UNUSED2008-05 nColRow = 0; // wird bei GetFirst initialisiert
267 //UNUSED2008-05
268 //UNUSED2008-05 nNumFormat = 0; // werden bei GetNumberFormat initialisiert
269 //UNUSED2008-05 pAttrArray = 0;
270 //UNUSED2008-05 nAttrEndRow = 0;
271 //UNUSED2008-05 }
272
ScValueIterator(ScDocument * pDocument,const ScRange & rRange,sal_Bool bSTotal,sal_Bool bTextZero)273 ScValueIterator::ScValueIterator( ScDocument* pDocument, const ScRange& rRange,
274 sal_Bool bSTotal, sal_Bool bTextZero ) :
275 pDoc( pDocument ),
276 nNumFmtIndex(0),
277 nStartCol( rRange.aStart.Col() ),
278 nStartRow( rRange.aStart.Row() ),
279 nStartTab( rRange.aStart.Tab() ),
280 nEndCol( rRange.aEnd.Col() ),
281 nEndRow( rRange.aEnd.Row() ),
282 nEndTab( rRange.aEnd.Tab() ),
283 nNumFmtType( NUMBERFORMAT_UNDEFINED ),
284 bNumValid( sal_False ),
285 bSubTotal(bSTotal),
286 bNextValid( sal_False ),
287 bCalcAsShown( pDocument->GetDocOptions().IsCalcAsShown() ),
288 bTextAsZero( bTextZero )
289 {
290 PutInOrder( nStartCol, nEndCol);
291 PutInOrder( nStartRow, nEndRow);
292 PutInOrder( nStartTab, nEndTab );
293
294 if (!ValidCol(nStartCol)) nStartCol = MAXCOL;
295 if (!ValidCol(nEndCol)) nEndCol = MAXCOL;
296 if (!ValidRow(nStartRow)) nStartRow = MAXROW;
297 if (!ValidRow(nEndRow)) nEndRow = MAXROW;
298 if (!ValidTab(nStartTab)) nStartTab = MAXTAB;
299 if (!ValidTab(nEndTab)) nEndTab = MAXTAB;
300
301 nCol = nStartCol;
302 nRow = nStartRow;
303 nTab = nStartTab;
304
305 nColRow = 0; // wird bei GetFirst initialisiert
306
307 nNumFormat = 0; // werden bei GetNumberFormat initialisiert
308 pAttrArray = 0;
309 nAttrEndRow = 0;
310 }
311
GetThis(double & rValue,sal_uInt16 & rErr)312 sal_Bool ScValueIterator::GetThis(double& rValue, sal_uInt16& rErr)
313 {
314 ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
315 for (;;)
316 {
317 if ( nRow > nEndRow )
318 {
319 nRow = nStartRow;
320 do
321 {
322 nCol++;
323 if ( nCol > nEndCol )
324 {
325 nCol = nStartCol;
326 nTab++;
327 if ( nTab > nEndTab )
328 {
329 // rValue = 0.0; //! do not change caller's value!
330 rErr = 0;
331 return sal_False; // Ende und Aus
332 }
333 }
334 pCol = &(pDoc->pTab[nTab])->aCol[nCol];
335 } while ( pCol->nCount == 0 );
336 pCol->Search( nRow, nColRow );
337 }
338
339 while (( nColRow < pCol->nCount ) && ( pCol->pItems[nColRow].nRow < nRow ))
340 nColRow++;
341
342 if ( nColRow < pCol->nCount && pCol->pItems[nColRow].nRow <= nEndRow )
343 {
344 nRow = pCol->pItems[nColRow].nRow + 1;
345 if ( !bSubTotal || !pDoc->pTab[nTab]->RowFiltered( nRow-1 ) )
346 {
347 ScBaseCell* pCell = pCol->pItems[nColRow].pCell;
348 ++nColRow;
349 switch (pCell->GetCellType())
350 {
351 case CELLTYPE_VALUE:
352 {
353 bNumValid = sal_False;
354 rValue = ((ScValueCell*)pCell)->GetValue();
355 rErr = 0;
356 --nRow;
357 if ( bCalcAsShown )
358 {
359 lcl_IterGetNumberFormat( nNumFormat, pAttrArray,
360 nAttrEndRow, pCol->pAttrArray, nRow, pDoc );
361 rValue = pDoc->RoundValueAsShown( rValue, nNumFormat );
362 }
363 //
364 // wenn in der selben Spalte gleich noch eine Value-Cell folgt, die
365 // auch noch im Block liegt, den Wert jetzt schon holen
366 //
367 if ( nColRow < pCol->nCount &&
368 pCol->pItems[nColRow].nRow <= nEndRow &&
369 pCol->pItems[nColRow].pCell->GetCellType() == CELLTYPE_VALUE &&
370 !bSubTotal )
371 {
372 fNextValue = ((ScValueCell*)pCol->pItems[nColRow].pCell)->GetValue();
373 nNextRow = pCol->pItems[nColRow].nRow;
374 bNextValid = sal_True;
375 if ( bCalcAsShown )
376 {
377 lcl_IterGetNumberFormat( nNumFormat, pAttrArray,
378 nAttrEndRow, pCol->pAttrArray, nNextRow, pDoc );
379 fNextValue = pDoc->RoundValueAsShown( fNextValue, nNumFormat );
380 }
381 }
382
383 return sal_True; // gefunden
384 }
385 // break;
386 case CELLTYPE_FORMULA:
387 {
388 if (!bSubTotal || !((ScFormulaCell*)pCell)->IsSubTotal())
389 {
390 rErr = ((ScFormulaCell*)pCell)->GetErrCode();
391 if ( rErr || ((ScFormulaCell*)pCell)->IsValue() )
392 {
393 rValue = ((ScFormulaCell*)pCell)->GetValue();
394 nRow--;
395 bNumValid = sal_False;
396 return sal_True; // gefunden
397 }
398 else if ( bTextAsZero )
399 {
400 rValue = 0.0;
401 nRow--;
402 bNumValid = sal_False;
403 return sal_True;
404 }
405 }
406 }
407 break;
408 case CELLTYPE_STRING :
409 case CELLTYPE_EDIT :
410 {
411 if ( bTextAsZero )
412 {
413 rErr = 0;
414 rValue = 0.0;
415 nNumFmtType = NUMBERFORMAT_NUMBER;
416 nNumFmtIndex = 0;
417 bNumValid = sal_True;
418 --nRow;
419 return sal_True;
420 }
421 }
422 break;
423 default:
424 {
425 // added to avoid warnings
426 }
427 }
428 }
429 }
430 else
431 nRow = nEndRow + 1; // naechste Spalte
432 }
433 }
434
GetCurNumFmtInfo(short & nType,sal_uLong & nIndex)435 void ScValueIterator::GetCurNumFmtInfo( short& nType, sal_uLong& nIndex )
436 {
437 if (!bNumValid)
438 {
439 const ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
440 nNumFmtIndex = pCol->GetNumberFormat( nRow );
441 if ( (nNumFmtIndex % SV_COUNTRY_LANGUAGE_OFFSET) == 0 )
442 {
443 const ScBaseCell* pCell;
444 SCSIZE nIdx = nColRow - 1;
445 // there might be rearranged something, so be on the safe side
446 if ( nIdx < pCol->nCount && pCol->pItems[nIdx].nRow == nRow )
447 pCell = pCol->pItems[nIdx].pCell;
448 else
449 {
450 if ( pCol->Search( nRow, nIdx ) )
451 pCell = pCol->pItems[nIdx].pCell;
452 else
453 pCell = NULL;
454 }
455 if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA )
456 ((const ScFormulaCell*)pCell)->GetFormatInfo( nNumFmtType, nNumFmtIndex );
457 else
458 nNumFmtType = pDoc->GetFormatTable()->GetType( nNumFmtIndex );
459 }
460 else
461 nNumFmtType = pDoc->GetFormatTable()->GetType( nNumFmtIndex );
462 bNumValid = sal_True;
463 }
464 nType = nNumFmtType;
465 nIndex = nNumFmtIndex;
466 }
467
GetFirst(double & rValue,sal_uInt16 & rErr)468 sal_Bool ScValueIterator::GetFirst(double& rValue, sal_uInt16& rErr)
469 {
470 nCol = nStartCol;
471 nRow = nStartRow;
472 nTab = nStartTab;
473
474 // nColRow = 0;
475 ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
476 pCol->Search( nRow, nColRow );
477
478 nNumFormat = 0; // werden bei GetNumberFormat initialisiert
479 pAttrArray = 0;
480 nAttrEndRow = 0;
481
482 return GetThis(rValue, rErr);
483 }
484
485 /* ist inline:
486 sal_Bool ScValueIterator::GetNext(double& rValue, sal_uInt16& rErr)
487 {
488 ++nRow;
489 return GetThis(rValue, rErr);
490 }
491 */
492
493 // ============================================================================
494
DataAccess(const ScDBQueryDataIterator * pParent)495 ScDBQueryDataIterator::DataAccess::DataAccess(const ScDBQueryDataIterator* pParent) :
496 mpParent(pParent)
497 {
498 }
499
~DataAccess()500 ScDBQueryDataIterator::DataAccess::~DataAccess()
501 {
502 }
503
GetRowByColEntryIndex(ScDocument & rDoc,SCTAB nTab,SCCOL nCol,SCSIZE nColRow)504 SCROW ScDBQueryDataIterator::GetRowByColEntryIndex(ScDocument& rDoc, SCTAB nTab, SCCOL nCol, SCSIZE nColRow)
505 {
506 ScColumn* pCol = &rDoc.pTab[nTab]->aCol[nCol];
507 return pCol->pItems[nColRow].nRow;
508 }
509
GetCellByColEntryIndex(ScDocument & rDoc,SCTAB nTab,SCCOL nCol,SCSIZE nColRow)510 ScBaseCell* ScDBQueryDataIterator::GetCellByColEntryIndex(ScDocument& rDoc, SCTAB nTab, SCCOL nCol, SCSIZE nColRow)
511 {
512 ScColumn* pCol = &rDoc.pTab[nTab]->aCol[nCol];
513 return pCol->pItems[nColRow].pCell;
514 }
515
GetAttrArrayByCol(ScDocument & rDoc,SCTAB nTab,SCCOL nCol)516 ScAttrArray* ScDBQueryDataIterator::GetAttrArrayByCol(ScDocument& rDoc, SCTAB nTab, SCCOL nCol)
517 {
518 ScColumn* pCol = &rDoc.pTab[nTab]->aCol[nCol];
519 return pCol->pAttrArray;
520 }
521
IsQueryValid(ScDocument & rDoc,const ScQueryParam & rParam,SCTAB nTab,SCROW nRow,ScBaseCell * pCell)522 bool ScDBQueryDataIterator::IsQueryValid(ScDocument& rDoc, const ScQueryParam& rParam, SCTAB nTab, SCROW nRow, ScBaseCell* pCell)
523 {
524 return rDoc.pTab[nTab]->ValidQuery(nRow, rParam, NULL, pCell);
525 }
526
SearchColEntryIndex(ScDocument & rDoc,SCTAB nTab,SCROW nRow,SCCOL nCol)527 SCSIZE ScDBQueryDataIterator::SearchColEntryIndex(ScDocument& rDoc, SCTAB nTab, SCROW nRow, SCCOL nCol)
528 {
529 ScColumn* pCol = &rDoc.pTab[nTab]->aCol[nCol];
530 SCSIZE nColRow;
531 pCol->Search(nRow, nColRow);
532 return nColRow;
533 }
534
535 // ----------------------------------------------------------------------------
536
DataAccessInternal(const ScDBQueryDataIterator * pParent,ScDBQueryParamInternal * pParam,ScDocument * pDoc)537 ScDBQueryDataIterator::DataAccessInternal::DataAccessInternal(const ScDBQueryDataIterator* pParent, ScDBQueryParamInternal* pParam, ScDocument* pDoc) :
538 DataAccess(pParent),
539 mpParam(pParam),
540 mpDoc(pDoc),
541 bCalcAsShown( pDoc->GetDocOptions().IsCalcAsShown() )
542 {
543 nCol = mpParam->mnField;
544 nRow = mpParam->nRow1;
545 nTab = mpParam->nTab;
546
547 nColRow = 0; // wird bei GetFirst initialisiert
548 SCSIZE i;
549 SCSIZE nCount = mpParam->GetEntryCount();
550 for (i=0; (i<nCount) && (mpParam->GetEntry(i).bDoQuery); i++)
551 {
552 ScQueryEntry& rEntry = mpParam->GetEntry(i);
553 sal_uInt32 nIndex = 0;
554 rEntry.bQueryByString =
555 !(mpDoc->GetFormatTable()->IsNumberFormat(*rEntry.pStr, nIndex, rEntry.nVal));
556 }
557 nNumFormat = 0; // werden bei GetNumberFormat initialisiert
558 pAttrArray = 0;
559 nAttrEndRow = 0;
560 }
561
~DataAccessInternal()562 ScDBQueryDataIterator::DataAccessInternal::~DataAccessInternal()
563 {
564 }
565
getCurrent(Value & rValue)566 bool ScDBQueryDataIterator::DataAccessInternal::getCurrent(Value& rValue)
567 {
568 SCCOLROW nFirstQueryField = mpParam->GetEntry(0).nField;
569 for ( ;; )
570 {
571 if (nRow > mpParam->nRow2)
572 {
573 // Bottom of the range reached. Bail out.
574 rValue.mnError = 0;
575 return false;
576 }
577
578 SCSIZE nCellCount = mpDoc->GetCellCount(nTab, nCol);
579 SCROW nThisRow = ScDBQueryDataIterator::GetRowByColEntryIndex(*mpDoc, nTab, nCol, nColRow);
580 while ( (nColRow < nCellCount) && (nThisRow < nRow) )
581 nThisRow = ScDBQueryDataIterator::GetRowByColEntryIndex(*mpDoc, nTab, nCol, ++nColRow);
582
583 if ( nColRow < nCellCount && nThisRow <= mpParam->nRow2 )
584 {
585 nRow = nThisRow;
586 ScBaseCell* pCell = NULL;
587 if (nCol == static_cast<SCCOL>(nFirstQueryField))
588 pCell = ScDBQueryDataIterator::GetCellByColEntryIndex(*mpDoc, nTab, nCol, nColRow);
589
590 if (ScDBQueryDataIterator::IsQueryValid(*mpDoc, *mpParam, nTab, nRow, pCell))
591 {
592 // #i109812# get cell here if it wasn't done above
593 if (nCol != static_cast<SCCOL>(nFirstQueryField))
594 pCell = ScDBQueryDataIterator::GetCellByColEntryIndex(*mpDoc, nTab, nCol, nColRow);
595
596 switch (pCell ? pCell->GetCellType() : CELLTYPE_NONE)
597 {
598 case CELLTYPE_VALUE:
599 {
600 rValue.mfValue = ((ScValueCell*)pCell)->GetValue();
601 rValue.mbIsNumber = true;
602 if ( bCalcAsShown )
603 {
604 const ScAttrArray* pNewAttrArray =
605 ScDBQueryDataIterator::GetAttrArrayByCol(*mpDoc, nTab, nCol);
606 lcl_IterGetNumberFormat( nNumFormat, pAttrArray,
607 nAttrEndRow, pNewAttrArray, nRow, mpDoc );
608 rValue.mfValue = mpDoc->RoundValueAsShown( rValue.mfValue, nNumFormat );
609 }
610 nNumFmtType = NUMBERFORMAT_NUMBER;
611 nNumFmtIndex = 0;
612 rValue.mnError = 0;
613 return sal_True; // gefunden
614 }
615 // break;
616 case CELLTYPE_FORMULA:
617 {
618 if (((ScFormulaCell*)pCell)->IsValue())
619 {
620 rValue.mfValue = ((ScFormulaCell*)pCell)->GetValue();
621 rValue.mbIsNumber = true;
622 mpDoc->GetNumberFormatInfo( nNumFmtType,
623 nNumFmtIndex, ScAddress( nCol, nRow, nTab ),
624 pCell );
625 rValue.mnError = ((ScFormulaCell*)pCell)->GetErrCode();
626 return sal_True; // gefunden
627 }
628 else
629 {
630 if (mpParam->mbSkipString)
631 ++nRow;
632 else
633 {
634 rValue.maString = ((ScFormulaCell*)pCell)->GetStringData();
635 rValue.mbIsNumber = false;
636 rValue.mnError = ((ScFormulaCell*)pCell)->GetErrCode();
637 return sal_True;
638 }
639 }
640 }
641 break;
642 case CELLTYPE_STRING:
643 case CELLTYPE_EDIT:
644 if (mpParam->mbSkipString)
645 ++nRow;
646 else
647 {
648 rValue.maString = pCell->GetStringData();
649 rValue.mfValue = 0.0;
650 rValue.mnError = 0;
651 rValue.mbIsNumber = false;
652 return true;
653 }
654 break;
655 default:
656 nRow++;
657 break;
658 }
659 }
660 else
661 nRow++;
662 }
663 else
664 nRow = mpParam->nRow2 + 1; // Naechste Spalte
665 }
666 // statement unreachable
667 // return false;
668 }
669
getFirst(Value & rValue)670 bool ScDBQueryDataIterator::DataAccessInternal::getFirst(Value& rValue)
671 {
672 if (mpParam->bHasHeader)
673 nRow++;
674
675 nColRow = ScDBQueryDataIterator::SearchColEntryIndex(*mpDoc, nTab, nRow, nCol);
676 return getCurrent(rValue);
677 }
678
getNext(Value & rValue)679 bool ScDBQueryDataIterator::DataAccessInternal::getNext(Value& rValue)
680 {
681 ++nRow;
682 return getCurrent(rValue);
683 }
684
685 // ----------------------------------------------------------------------------
686
DataAccessMatrix(const ScDBQueryDataIterator * pParent,ScDBQueryParamMatrix * pParam)687 ScDBQueryDataIterator::DataAccessMatrix::DataAccessMatrix(const ScDBQueryDataIterator* pParent, ScDBQueryParamMatrix* pParam) :
688 DataAccess(pParent),
689 mpParam(pParam)
690 {
691 SCSIZE nC, nR;
692 mpParam->mpMatrix->GetDimensions(nC, nR);
693 mnRows = static_cast<SCROW>(nR);
694 mnCols = static_cast<SCCOL>(nC);
695 }
696
~DataAccessMatrix()697 ScDBQueryDataIterator::DataAccessMatrix::~DataAccessMatrix()
698 {
699 }
700
getCurrent(Value & rValue)701 bool ScDBQueryDataIterator::DataAccessMatrix::getCurrent(Value& rValue)
702 {
703 // Starting from row == mnCurRow, get the first row that satisfies all the
704 // query parameters.
705 for ( ;mnCurRow < mnRows; ++mnCurRow)
706 {
707 const ScMatrix& rMat = *mpParam->mpMatrix;
708 if (rMat.IsEmpty(mpParam->mnField, mnCurRow))
709 // Don't take empty values into account.
710 continue;
711
712 bool bIsStrVal = rMat.IsString(mpParam->mnField, mnCurRow);
713 if (bIsStrVal && mpParam->mbSkipString)
714 continue;
715
716 if (isValidQuery(mnCurRow, rMat))
717 {
718 rValue.maString = rMat.GetString(mpParam->mnField, mnCurRow);
719 rValue.mfValue = rMat.GetDouble(mpParam->mnField, mnCurRow);
720 rValue.mbIsNumber = !bIsStrVal;
721 rValue.mnError = 0;
722 return true;
723 }
724 }
725 return false;
726 }
727
getFirst(Value & rValue)728 bool ScDBQueryDataIterator::DataAccessMatrix::getFirst(Value& rValue)
729 {
730 mnCurRow = mpParam->bHasHeader ? 1 : 0;
731 return getCurrent(rValue);
732 }
733
getNext(Value & rValue)734 bool ScDBQueryDataIterator::DataAccessMatrix::getNext(Value& rValue)
735 {
736 ++mnCurRow;
737 return getCurrent(rValue);
738 }
739
740 namespace {
741
lcl_isQueryByValue(const ScQueryEntry & rEntry,const ScMatrix & rMat,SCSIZE nCol,SCSIZE nRow)742 bool lcl_isQueryByValue(const ScQueryEntry& rEntry, const ScMatrix& rMat, SCSIZE nCol, SCSIZE nRow)
743 {
744 if (rEntry.bQueryByString)
745 return false;
746
747 if (!rMat.IsValueOrEmpty(nCol, nRow))
748 return false;
749
750 return true;
751 }
752
lcl_isQueryByString(const ScQueryEntry & rEntry,const ScMatrix & rMat,SCSIZE nCol,SCSIZE nRow)753 bool lcl_isQueryByString(const ScQueryEntry& rEntry, const ScMatrix& rMat, SCSIZE nCol, SCSIZE nRow)
754 {
755 switch (rEntry.eOp)
756 {
757 case SC_EQUAL:
758 case SC_NOT_EQUAL:
759 case SC_CONTAINS:
760 case SC_DOES_NOT_CONTAIN:
761 case SC_BEGINS_WITH:
762 case SC_ENDS_WITH:
763 case SC_DOES_NOT_BEGIN_WITH:
764 case SC_DOES_NOT_END_WITH:
765 return true;
766 default:
767 ;
768 }
769
770 if (rEntry.bQueryByString && rMat.IsString(nCol, nRow))
771 return true;
772
773 return false;
774 }
775
776 }
777
isValidQuery(SCROW nRow,const ScMatrix & rMat) const778 bool ScDBQueryDataIterator::DataAccessMatrix::isValidQuery(SCROW nRow, const ScMatrix& rMat) const
779 {
780 SCSIZE nEntryCount = mpParam->GetEntryCount();
781 vector<bool> aResults;
782 aResults.reserve(nEntryCount);
783
784 const CollatorWrapper& rCollator =
785 mpParam->bCaseSens ? *ScGlobal::GetCaseCollator() : *ScGlobal::GetCollator();
786
787 for (SCSIZE i = 0; i < nEntryCount; ++i)
788 {
789 const ScQueryEntry& rEntry = mpParam->GetEntry(i);
790 if (!rEntry.bDoQuery)
791 continue;
792
793 switch (rEntry.eOp)
794 {
795 case SC_EQUAL:
796 case SC_LESS:
797 case SC_GREATER:
798 case SC_LESS_EQUAL:
799 case SC_GREATER_EQUAL:
800 case SC_NOT_EQUAL:
801 break;
802 default:
803 // Only the above operators are supported.
804 continue;
805 }
806
807 bool bValid = false;
808
809 SCSIZE nField = static_cast<SCSIZE>(rEntry.nField);
810 if (lcl_isQueryByValue(rEntry, rMat, nField, nRow))
811 {
812 // By value
813 double fMatVal = rMat.GetDouble(nField, nRow);
814 bool bEqual = approxEqual(fMatVal, rEntry.nVal);
815 switch (rEntry.eOp)
816 {
817 case SC_EQUAL:
818 bValid = bEqual;
819 break;
820 case SC_LESS:
821 bValid = (fMatVal < rEntry.nVal) && !bEqual;
822 break;
823 case SC_GREATER:
824 bValid = (fMatVal > rEntry.nVal) && !bEqual;
825 break;
826 case SC_LESS_EQUAL:
827 bValid = (fMatVal < rEntry.nVal) || bEqual;
828 break;
829 case SC_GREATER_EQUAL:
830 bValid = (fMatVal > rEntry.nVal) || bEqual;
831 break;
832 case SC_NOT_EQUAL:
833 bValid = !bEqual;
834 break;
835 default:
836 ;
837 }
838 }
839 else if (lcl_isQueryByString(rEntry, rMat, nField, nRow))
840 {
841 // By string
842 do
843 {
844 if (!rEntry.pStr)
845 break;
846
847 // Equality check first.
848
849 OUString aMatStr = rMat.GetString(nField, nRow);
850 lcl_toUpper(aMatStr);
851 OUString aQueryStr = *rEntry.pStr;
852 lcl_toUpper(aQueryStr);
853 bool bDone = false;
854 switch (rEntry.eOp)
855 {
856 case SC_EQUAL:
857 bValid = aMatStr.equals(aQueryStr);
858 bDone = true;
859 break;
860 case SC_NOT_EQUAL:
861 bValid = !aMatStr.equals(aQueryStr);
862 bDone = true;
863 break;
864 default:
865 ;
866 }
867
868 if (bDone)
869 break;
870
871 // Unequality check using collator.
872
873 sal_Int32 nCompare = rCollator.compareString(aMatStr, aQueryStr);
874 switch (rEntry.eOp)
875 {
876 case SC_LESS :
877 bValid = (nCompare < 0);
878 break;
879 case SC_GREATER :
880 bValid = (nCompare > 0);
881 break;
882 case SC_LESS_EQUAL :
883 bValid = (nCompare <= 0);
884 break;
885 case SC_GREATER_EQUAL :
886 bValid = (nCompare >= 0);
887 break;
888 default:
889 ;
890 }
891 }
892 while (false);
893 }
894 else if (mpParam->bMixedComparison)
895 {
896 // Not used at the moment.
897 }
898
899 if (aResults.empty())
900 // First query entry.
901 aResults.push_back(bValid);
902 else if (rEntry.eConnect == SC_AND)
903 {
904 // For AND op, tuck the result into the last result value.
905 size_t n = aResults.size();
906 aResults[n-1] = aResults[n-1] && bValid;
907 }
908 else
909 // For OR op, store its own result.
910 aResults.push_back(bValid);
911 }
912
913 // Row is valid as long as there is at least one result being true.
914 vector<bool>::const_iterator itr = aResults.begin(), itrEnd = aResults.end();
915 for (; itr != itrEnd; ++itr)
916 if (*itr)
917 return true;
918
919 return false;
920 }
921
922 // ----------------------------------------------------------------------------
923
Value()924 ScDBQueryDataIterator::Value::Value() :
925 mnError(0), mbIsNumber(true)
926 {
927 ::rtl::math::setNan(&mfValue);
928 }
929
930 // ----------------------------------------------------------------------------
931
ScDBQueryDataIterator(ScDocument * pDocument,ScDBQueryParamBase * pParam)932 ScDBQueryDataIterator::ScDBQueryDataIterator(ScDocument* pDocument, ScDBQueryParamBase* pParam) :
933 mpParam (pParam)
934 {
935 switch (mpParam->GetType())
936 {
937 case ScDBQueryParamBase::INTERNAL:
938 {
939 ScDBQueryParamInternal* p = static_cast<ScDBQueryParamInternal*>(pParam);
940 mpData.reset(new DataAccessInternal(this, p, pDocument));
941 }
942 break;
943 case ScDBQueryParamBase::MATRIX:
944 {
945 ScDBQueryParamMatrix* p = static_cast<ScDBQueryParamMatrix*>(pParam);
946 mpData.reset(new DataAccessMatrix(this, p));
947 }
948 }
949 }
950
GetFirst(Value & rValue)951 bool ScDBQueryDataIterator::GetFirst(Value& rValue)
952 {
953 return mpData->getFirst(rValue);
954 }
955
GetNext(Value & rValue)956 bool ScDBQueryDataIterator::GetNext(Value& rValue)
957 {
958 return mpData->getNext(rValue);
959 }
960
961 // ============================================================================
962
ScCellIterator(ScDocument * pDocument,SCCOL nSCol,SCROW nSRow,SCTAB nSTab,SCCOL nECol,SCROW nERow,SCTAB nETab,sal_Bool bSTotal)963 ScCellIterator::ScCellIterator( ScDocument* pDocument,
964 SCCOL nSCol, SCROW nSRow, SCTAB nSTab,
965 SCCOL nECol, SCROW nERow, SCTAB nETab, sal_Bool bSTotal ) :
966 pDoc( pDocument ),
967 nStartCol( nSCol),
968 nStartRow( nSRow),
969 nStartTab( nSTab ),
970 nEndCol( nECol ),
971 nEndRow( nERow),
972 nEndTab( nETab ),
973 bSubTotal(bSTotal)
974
975 {
976 PutInOrder( nStartCol, nEndCol);
977 PutInOrder( nStartRow, nEndRow);
978 PutInOrder( nStartTab, nEndTab );
979
980 if (!ValidCol(nStartCol)) nStartCol = MAXCOL;
981 if (!ValidCol(nEndCol)) nEndCol = MAXCOL;
982 if (!ValidRow(nStartRow)) nStartRow = MAXROW;
983 if (!ValidRow(nEndRow)) nEndRow = MAXROW;
984 if (!ValidTab(nStartTab)) nStartTab = MAXTAB;
985 if (!ValidTab(nEndTab)) nEndTab = MAXTAB;
986
987 while (nEndTab>0 && !pDoc->pTab[nEndTab])
988 --nEndTab; // nur benutzte Tabellen
989 if (nStartTab>nEndTab)
990 nStartTab = nEndTab;
991
992 nCol = nStartCol;
993 nRow = nStartRow;
994 nTab = nStartTab;
995 nColRow = 0; // wird bei GetFirst initialisiert
996
997 if (!pDoc->pTab[nTab])
998 {
999 DBG_ERROR("Tabelle nicht gefunden");
1000 nStartCol = nCol = MAXCOL+1;
1001 nStartRow = nRow = MAXROW+1;
1002 nStartTab = nTab = MAXTAB+1; // -> Abbruch bei GetFirst
1003 }
1004 }
1005
ScCellIterator(ScDocument * pDocument,const ScRange & rRange,sal_Bool bSTotal)1006 ScCellIterator::ScCellIterator
1007 ( ScDocument* pDocument, const ScRange& rRange, sal_Bool bSTotal ) :
1008 pDoc( pDocument ),
1009 nStartCol( rRange.aStart.Col() ),
1010 nStartRow( rRange.aStart.Row() ),
1011 nStartTab( rRange.aStart.Tab() ),
1012 nEndCol( rRange.aEnd.Col() ),
1013 nEndRow( rRange.aEnd.Row() ),
1014 nEndTab( rRange.aEnd.Tab() ),
1015 bSubTotal(bSTotal)
1016
1017 {
1018 PutInOrder( nStartCol, nEndCol);
1019 PutInOrder( nStartRow, nEndRow);
1020 PutInOrder( nStartTab, nEndTab );
1021
1022 if (!ValidCol(nStartCol)) nStartCol = MAXCOL;
1023 if (!ValidCol(nEndCol)) nEndCol = MAXCOL;
1024 if (!ValidRow(nStartRow)) nStartRow = MAXROW;
1025 if (!ValidRow(nEndRow)) nEndRow = MAXROW;
1026 if (!ValidTab(nStartTab)) nStartTab = MAXTAB;
1027 if (!ValidTab(nEndTab)) nEndTab = MAXTAB;
1028
1029 while (nEndTab>0 && !pDoc->pTab[nEndTab])
1030 --nEndTab; // nur benutzte Tabellen
1031 if (nStartTab>nEndTab)
1032 nStartTab = nEndTab;
1033
1034 nCol = nStartCol;
1035 nRow = nStartRow;
1036 nTab = nStartTab;
1037 nColRow = 0; // wird bei GetFirst initialisiert
1038
1039 if (!pDoc->pTab[nTab])
1040 {
1041 DBG_ERROR("Tabelle nicht gefunden");
1042 nStartCol = nCol = MAXCOL+1;
1043 nStartRow = nRow = MAXROW+1;
1044 nStartTab = nTab = MAXTAB+1; // -> Abbruch bei GetFirst
1045 }
1046 }
1047
GetThis()1048 ScBaseCell* ScCellIterator::GetThis()
1049 {
1050 ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
1051 for ( ;; )
1052 {
1053 if ( nRow > nEndRow )
1054 {
1055 nRow = nStartRow;
1056 do
1057 {
1058 nCol++;
1059 if ( nCol > nEndCol )
1060 {
1061 nCol = nStartCol;
1062 nTab++;
1063 if ( nTab > nEndTab )
1064 return NULL; // Ende und Aus
1065 }
1066 pCol = &(pDoc->pTab[nTab])->aCol[nCol];
1067 } while ( pCol->nCount == 0 );
1068 pCol->Search( nRow, nColRow );
1069 }
1070
1071 while ( (nColRow < pCol->nCount) && (pCol->pItems[nColRow].nRow < nRow) )
1072 nColRow++;
1073
1074 if ( nColRow < pCol->nCount && pCol->pItems[nColRow].nRow <= nEndRow )
1075 {
1076 nRow = pCol->pItems[nColRow].nRow;
1077 if ( !bSubTotal || !pDoc->pTab[nTab]->RowFiltered( nRow ) )
1078 {
1079 ScBaseCell* pCell = pCol->pItems[nColRow].pCell;
1080
1081 if ( bSubTotal && pCell->GetCellType() == CELLTYPE_FORMULA
1082 && ((ScFormulaCell*)pCell)->IsSubTotal() )
1083 nRow++; // Sub-Total-Zeilen nicht
1084 else
1085 return pCell; // gefunden
1086 }
1087 else
1088 nRow++;
1089 }
1090 else
1091 nRow = nEndRow + 1; // Naechste Spalte
1092 }
1093 }
1094
GetFirst()1095 ScBaseCell* ScCellIterator::GetFirst()
1096 {
1097 if ( !ValidTab(nTab) )
1098 return NULL;
1099 nCol = nStartCol;
1100 nRow = nStartRow;
1101 nTab = nStartTab;
1102 // nColRow = 0;
1103 ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
1104 pCol->Search( nRow, nColRow );
1105 return GetThis();
1106 }
1107
GetNext()1108 ScBaseCell* ScCellIterator::GetNext()
1109 {
1110 ++nRow;
1111 return GetThis();
1112 }
1113
1114 //-------------------------------------------------------------------------------
1115
ScQueryCellIterator(ScDocument * pDocument,SCTAB nTable,const ScQueryParam & rParam,sal_Bool bMod)1116 ScQueryCellIterator::ScQueryCellIterator(ScDocument* pDocument, SCTAB nTable,
1117 const ScQueryParam& rParam, sal_Bool bMod ) :
1118 aParam (rParam),
1119 pDoc( pDocument ),
1120 nTab( nTable),
1121 nStopOnMismatch( nStopOnMismatchDisabled ),
1122 nTestEqualCondition( nTestEqualConditionDisabled ),
1123 bAdvanceQuery( sal_False ),
1124 bIgnoreMismatchOnLeadingStrings( sal_False )
1125 {
1126 nCol = aParam.nCol1;
1127 nRow = aParam.nRow1;
1128 nColRow = 0; // wird bei GetFirst initialisiert
1129 SCSIZE i;
1130 if (bMod) // sonst schon eingetragen
1131 {
1132 for (i=0; (i<MAXQUERY) && (aParam.GetEntry(i).bDoQuery); i++)
1133 {
1134 ScQueryEntry& rEntry = aParam.GetEntry(i);
1135 sal_uInt32 nIndex = 0;
1136 rEntry.bQueryByString =
1137 !(pDoc->GetFormatTable()->IsNumberFormat(*rEntry.pStr,
1138 nIndex, rEntry.nVal));
1139 }
1140 }
1141 nNumFormat = 0; // werden bei GetNumberFormat initialisiert
1142 pAttrArray = 0;
1143 nAttrEndRow = 0;
1144 }
1145
GetThis()1146 ScBaseCell* ScQueryCellIterator::GetThis()
1147 {
1148 ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
1149 const ScQueryEntry& rEntry = aParam.GetEntry(0);
1150 SCCOLROW nFirstQueryField = rEntry.nField;
1151 bool bAllStringIgnore = bIgnoreMismatchOnLeadingStrings &&
1152 !rEntry.bQueryByString;
1153 bool bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
1154 !aParam.bHasHeader && rEntry.bQueryByString &&
1155 ((aParam.bByRow && nRow == aParam.nRow1) ||
1156 (!aParam.bByRow && nCol == aParam.nCol1));
1157 for ( ;; )
1158 {
1159 if ( nRow > aParam.nRow2 )
1160 {
1161 nRow = aParam.nRow1;
1162 if (aParam.bHasHeader && aParam.bByRow)
1163 nRow++;
1164 do
1165 {
1166 if ( ++nCol > aParam.nCol2 )
1167 return NULL; // Ende und Aus
1168 if ( bAdvanceQuery )
1169 {
1170 AdvanceQueryParamEntryField();
1171 nFirstQueryField = rEntry.nField;
1172 }
1173 pCol = &(pDoc->pTab[nTab])->aCol[nCol];
1174 } while ( pCol->nCount == 0 );
1175 pCol->Search( nRow, nColRow );
1176 bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
1177 !aParam.bHasHeader && rEntry.bQueryByString &&
1178 aParam.bByRow;
1179 }
1180
1181 while ( nColRow < pCol->nCount && pCol->pItems[nColRow].nRow < nRow )
1182 nColRow++;
1183
1184 if ( nColRow < pCol->nCount &&
1185 (nRow = pCol->pItems[nColRow].nRow) <= aParam.nRow2 )
1186 {
1187 ScBaseCell* pCell = pCol->pItems[nColRow].pCell;
1188 if ( pCell->GetCellType() == CELLTYPE_NOTE )
1189 ++nRow;
1190 else if (bAllStringIgnore && pCell->HasStringData())
1191 ++nRow;
1192 else
1193 {
1194 sal_Bool bTestEqualCondition;
1195 if ( (pDoc->pTab[nTab])->ValidQuery( nRow, aParam, NULL,
1196 (nCol == static_cast<SCCOL>(nFirstQueryField) ? pCell : NULL),
1197 (nTestEqualCondition ? &bTestEqualCondition : NULL) ) )
1198 {
1199 if ( nTestEqualCondition && bTestEqualCondition )
1200 nTestEqualCondition |= nTestEqualConditionMatched;
1201 return pCell; // found
1202 }
1203 else if ( nStopOnMismatch )
1204 {
1205 // Yes, even a mismatch may have a fulfilled equal
1206 // condition if regular expressions were involved and
1207 // SC_LESS_EQUAL or SC_GREATER_EQUAL were queried.
1208 if ( nTestEqualCondition && bTestEqualCondition )
1209 {
1210 nTestEqualCondition |= nTestEqualConditionMatched;
1211 nStopOnMismatch |= nStopOnMismatchOccured;
1212 return NULL;
1213 }
1214 bool bStop;
1215 if (bFirstStringIgnore)
1216 {
1217 if (pCell->HasStringData())
1218 {
1219 ++nRow;
1220 bStop = false;
1221 }
1222 else
1223 bStop = true;
1224 }
1225 else
1226 bStop = true;
1227 if (bStop)
1228 {
1229 nStopOnMismatch |= nStopOnMismatchOccured;
1230 return NULL;
1231 }
1232 }
1233 else
1234 nRow++;
1235 }
1236 }
1237 else
1238 nRow = aParam.nRow2 + 1; // Naechste Spalte
1239 bFirstStringIgnore = false;
1240 }
1241 }
1242
GetFirst()1243 ScBaseCell* ScQueryCellIterator::GetFirst()
1244 {
1245 nCol = aParam.nCol1;
1246 nRow = aParam.nRow1;
1247 if (aParam.bHasHeader)
1248 nRow++;
1249 // nColRow = 0;
1250 ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
1251 pCol->Search( nRow, nColRow );
1252 return GetThis();
1253 }
1254
GetNext()1255 ScBaseCell* ScQueryCellIterator::GetNext()
1256 {
1257 ++nRow;
1258 if ( nStopOnMismatch )
1259 nStopOnMismatch = nStopOnMismatchEnabled;
1260 if ( nTestEqualCondition )
1261 nTestEqualCondition = nTestEqualConditionEnabled;
1262 return GetThis();
1263 }
1264
AdvanceQueryParamEntryField()1265 void ScQueryCellIterator::AdvanceQueryParamEntryField()
1266 {
1267 SCSIZE nEntries = aParam.GetEntryCount();
1268 for ( SCSIZE j = 0; j < nEntries; j++ )
1269 {
1270 ScQueryEntry& rEntry = aParam.GetEntry( j );
1271 if ( rEntry.bDoQuery )
1272 {
1273 if ( rEntry.nField < MAXCOL )
1274 rEntry.nField++;
1275 else
1276 {
1277 DBG_ERRORFILE( "AdvanceQueryParamEntryField: ++rEntry.nField > MAXCOL" );
1278 }
1279 }
1280 else
1281 break; // for
1282 }
1283 }
1284
1285
FindEqualOrSortedLastInRange(SCCOL & nFoundCol,SCROW & nFoundRow,sal_Bool bSearchForEqualAfterMismatch,sal_Bool bIgnoreMismatchOnLeadingStringsP)1286 sal_Bool ScQueryCellIterator::FindEqualOrSortedLastInRange( SCCOL& nFoundCol,
1287 SCROW& nFoundRow, sal_Bool bSearchForEqualAfterMismatch,
1288 sal_Bool bIgnoreMismatchOnLeadingStringsP )
1289 {
1290 nFoundCol = MAXCOL+1;
1291 nFoundRow = MAXROW+1;
1292 SetStopOnMismatch( sal_True ); // assume sorted keys
1293 SetTestEqualCondition( sal_True );
1294 bIgnoreMismatchOnLeadingStrings = bIgnoreMismatchOnLeadingStringsP;
1295 bool bRegExp = aParam.bRegExp && aParam.GetEntry(0).bQueryByString;
1296 bool bBinary = !bRegExp && aParam.bByRow && (aParam.GetEntry(0).eOp ==
1297 SC_LESS_EQUAL || aParam.GetEntry(0).eOp == SC_GREATER_EQUAL);
1298 if (bBinary ? (BinarySearch() ? GetThis() : 0) : GetFirst())
1299 {
1300 // First equal entry or last smaller than (greater than) entry.
1301 SCSIZE nColRowSave;
1302 ScBaseCell* pNext = 0;
1303 do
1304 {
1305 nFoundCol = GetCol();
1306 nFoundRow = GetRow();
1307 nColRowSave = nColRow;
1308 } while ( !IsEqualConditionFulfilled() && (pNext = GetNext()) != NULL );
1309 // There may be no pNext but equal condition fulfilled if regular
1310 // expressions are involved. Keep the found entry and proceed.
1311 if (!pNext && !IsEqualConditionFulfilled())
1312 {
1313 // Step back to last in range and adjust position markers for
1314 // GetNumberFormat() or similar.
1315 nCol = nFoundCol;
1316 nRow = nFoundRow;
1317 nColRow = nColRowSave;
1318 }
1319 }
1320 if ( IsEqualConditionFulfilled() )
1321 {
1322 // Position on last equal entry.
1323 SCSIZE nEntries = aParam.GetEntryCount();
1324 for ( SCSIZE j = 0; j < nEntries; j++ )
1325 {
1326 ScQueryEntry& rEntry = aParam.GetEntry( j );
1327 if ( rEntry.bDoQuery )
1328 {
1329 switch ( rEntry.eOp )
1330 {
1331 case SC_LESS_EQUAL :
1332 case SC_GREATER_EQUAL :
1333 rEntry.eOp = SC_EQUAL;
1334 break;
1335 default:
1336 {
1337 // added to avoid warnings
1338 }
1339 }
1340 }
1341 else
1342 break; // for
1343 }
1344 SCSIZE nColRowSave;
1345 bIgnoreMismatchOnLeadingStrings = sal_False;
1346 SetTestEqualCondition( sal_False );
1347 do
1348 {
1349 nFoundCol = GetCol();
1350 nFoundRow = GetRow();
1351 nColRowSave = nColRow;
1352 } while (GetNext());
1353 // Step back conditions same as above
1354 nCol = nFoundCol;
1355 nRow = nFoundRow;
1356 nColRow = nColRowSave;
1357 return sal_True;
1358 }
1359 if ( (bSearchForEqualAfterMismatch || aParam.bRegExp) &&
1360 StoppedOnMismatch() )
1361 {
1362 // Assume found entry to be the last value less than respectively
1363 // greater than the query. But keep on searching for an equal match.
1364 SCSIZE nEntries = aParam.GetEntryCount();
1365 for ( SCSIZE j = 0; j < nEntries; j++ )
1366 {
1367 ScQueryEntry& rEntry = aParam.GetEntry( j );
1368 if ( rEntry.bDoQuery )
1369 {
1370 switch ( rEntry.eOp )
1371 {
1372 case SC_LESS_EQUAL :
1373 case SC_GREATER_EQUAL :
1374 rEntry.eOp = SC_EQUAL;
1375 break;
1376 default:
1377 {
1378 // added to avoid warnings
1379 }
1380 }
1381 }
1382 else
1383 break; // for
1384 }
1385 SetStopOnMismatch( sal_False );
1386 SetTestEqualCondition( sal_False );
1387 if (GetNext())
1388 {
1389 // Last of a consecutive area, avoid searching the entire parameter
1390 // range as it is a real performance bottleneck in case of regular
1391 // expressions.
1392 SCSIZE nColRowSave;
1393 do
1394 {
1395 nFoundCol = GetCol();
1396 nFoundRow = GetRow();
1397 nColRowSave = nColRow;
1398 SetStopOnMismatch( sal_True );
1399 } while (GetNext());
1400 nCol = nFoundCol;
1401 nRow = nFoundRow;
1402 nColRow = nColRowSave;
1403 }
1404 }
1405 return (nFoundCol <= MAXCOL) && (nFoundRow <= MAXROW);
1406 }
1407
1408
BinarySearch()1409 ScBaseCell* ScQueryCellIterator::BinarySearch()
1410 {
1411 nCol = aParam.nCol1;
1412 ScColumn* pCol = &(pDoc->pTab[nTab])->aCol[nCol];
1413 if (!pCol->nCount)
1414 return 0;
1415
1416 ScBaseCell* pCell;
1417 SCSIZE nHi, nLo;
1418 CollatorWrapper* pCollator = (aParam.bCaseSens ? ScGlobal::GetCaseCollator() :
1419 ScGlobal::GetCollator());
1420 SvNumberFormatter& rFormatter = *(pDoc->GetFormatTable());
1421 const ScQueryEntry& rEntry = aParam.GetEntry(0);
1422 bool bLessEqual = rEntry.eOp == SC_LESS_EQUAL;
1423 bool bByString = rEntry.bQueryByString;
1424 bool bAllStringIgnore = bIgnoreMismatchOnLeadingStrings && !bByString;
1425 bool bFirstStringIgnore = bIgnoreMismatchOnLeadingStrings &&
1426 !aParam.bHasHeader && bByString;
1427
1428 nRow = aParam.nRow1;
1429 if (aParam.bHasHeader)
1430 nRow++;
1431 const ColEntry* pItems = pCol->pItems;
1432 if (pCol->Search( nRow, nLo ) && bFirstStringIgnore &&
1433 pItems[nLo].pCell->HasStringData())
1434 {
1435 String aCellStr;
1436 sal_uLong nFormat = pCol->GetNumberFormat( pItems[nLo].nRow);
1437 ScCellFormat::GetInputString( pItems[nLo].pCell, nFormat, aCellStr,
1438 rFormatter);
1439 sal_Int32 nTmp = pCollator->compareString( aCellStr, *rEntry.pStr);
1440 if ((rEntry.eOp == SC_LESS_EQUAL && nTmp > 0) ||
1441 (rEntry.eOp == SC_GREATER_EQUAL && nTmp < 0) ||
1442 (rEntry.eOp == SC_EQUAL && nTmp != 0))
1443 ++nLo;
1444 }
1445 if (!pCol->Search( aParam.nRow2, nHi ) && nHi>0)
1446 --nHi;
1447 while (bAllStringIgnore && nLo <= nHi && nLo < pCol->nCount &&
1448 pItems[nLo].pCell->HasStringData())
1449 ++nLo;
1450
1451 // Bookkeeping values for breaking up the binary search in case the data
1452 // range isn't strictly sorted.
1453 SCSIZE nLastInRange = nLo;
1454 SCSIZE nFirstLastInRange = nLastInRange;
1455 double fLastInRangeValue = bLessEqual ?
1456 -(::std::numeric_limits<double>::max()) :
1457 ::std::numeric_limits<double>::max();
1458 String aLastInRangeString;
1459 if (!bLessEqual)
1460 aLastInRangeString.Assign( sal_Unicode(0xFFFF));
1461 if (nLastInRange < pCol->nCount)
1462 {
1463 pCell = pItems[nLastInRange].pCell;
1464 if (pCell->HasStringData())
1465 {
1466 sal_uLong nFormat = pCol->GetNumberFormat( pItems[nLastInRange].nRow);
1467 ScCellFormat::GetInputString( pCell, nFormat, aLastInRangeString,
1468 rFormatter);
1469 }
1470 else
1471 {
1472 switch ( pCell->GetCellType() )
1473 {
1474 case CELLTYPE_VALUE :
1475 fLastInRangeValue =
1476 static_cast<ScValueCell*>(pCell)->GetValue();
1477 break;
1478 case CELLTYPE_FORMULA :
1479 fLastInRangeValue =
1480 static_cast<ScFormulaCell*>(pCell)->GetValue();
1481 break;
1482 default:
1483 {
1484 // added to avoid warnings
1485 }
1486 }
1487 }
1488 }
1489
1490 sal_Int32 nRes = 0;
1491 bool bFound = false;
1492 bool bDone = false;
1493 while (nLo <= nHi && !bDone)
1494 {
1495 SCSIZE nMid = (nLo+nHi)/2;
1496 SCSIZE i = nMid;
1497 while (i <= nHi && pItems[i].pCell->GetCellType() == CELLTYPE_NOTE)
1498 ++i;
1499 if (i > nHi)
1500 {
1501 if (nMid > 0)
1502 nHi = nMid - 1;
1503 else
1504 bDone = true;
1505 continue; // while
1506 }
1507 sal_Bool bStr = pItems[i].pCell->HasStringData();
1508 nRes = 0;
1509 // compares are content<query:-1, content>query:1
1510 // Cell value comparison similar to ScTable::ValidQuery()
1511 if (!bStr && !bByString)
1512 {
1513 double nCellVal;
1514 pCell = pItems[i].pCell;
1515 switch ( pCell->GetCellType() )
1516 {
1517 case CELLTYPE_VALUE :
1518 nCellVal = static_cast<ScValueCell*>(pCell)->GetValue();
1519 break;
1520 case CELLTYPE_FORMULA :
1521 nCellVal = static_cast<ScFormulaCell*>(pCell)->GetValue();
1522 break;
1523 default:
1524 nCellVal = 0.0;
1525 }
1526 if ((nCellVal < rEntry.nVal) && !::rtl::math::approxEqual(
1527 nCellVal, rEntry.nVal))
1528 {
1529 nRes = -1;
1530 if (bLessEqual)
1531 {
1532 if (fLastInRangeValue < nCellVal)
1533 {
1534 fLastInRangeValue = nCellVal;
1535 nLastInRange = i;
1536 }
1537 else if (fLastInRangeValue > nCellVal)
1538 {
1539 // not strictly sorted, continue with GetThis()
1540 nLastInRange = nFirstLastInRange;
1541 bDone = true;
1542 }
1543 }
1544 }
1545 else if ((nCellVal > rEntry.nVal) && !::rtl::math::approxEqual(
1546 nCellVal, rEntry.nVal))
1547 {
1548 nRes = 1;
1549 if (!bLessEqual)
1550 {
1551 if (fLastInRangeValue > nCellVal)
1552 {
1553 fLastInRangeValue = nCellVal;
1554 nLastInRange = i;
1555 }
1556 else if (fLastInRangeValue < nCellVal)
1557 {
1558 // not strictly sorted, continue with GetThis()
1559 nLastInRange = nFirstLastInRange;
1560 bDone = true;
1561 }
1562 }
1563 }
1564 }
1565 else if (bStr && bByString)
1566 {
1567 String aCellStr;
1568 sal_uLong nFormat = pCol->GetNumberFormat( pItems[i].nRow);
1569 ScCellFormat::GetInputString( pItems[i].pCell, nFormat, aCellStr,
1570 rFormatter);
1571 nRes = pCollator->compareString( aCellStr, *rEntry.pStr);
1572 if (nRes < 0 && bLessEqual)
1573 {
1574 sal_Int32 nTmp = pCollator->compareString( aLastInRangeString,
1575 aCellStr);
1576 if (nTmp < 0)
1577 {
1578 aLastInRangeString = aCellStr;
1579 nLastInRange = i;
1580 }
1581 else if (nTmp > 0)
1582 {
1583 // not strictly sorted, continue with GetThis()
1584 nLastInRange = nFirstLastInRange;
1585 bDone = true;
1586 }
1587 }
1588 else if (nRes > 0 && !bLessEqual)
1589 {
1590 sal_Int32 nTmp = pCollator->compareString( aLastInRangeString,
1591 aCellStr);
1592 if (nTmp > 0)
1593 {
1594 aLastInRangeString = aCellStr;
1595 nLastInRange = i;
1596 }
1597 else if (nTmp < 0)
1598 {
1599 // not strictly sorted, continue with GetThis()
1600 nLastInRange = nFirstLastInRange;
1601 bDone = true;
1602 }
1603 }
1604 }
1605 else if (!bStr && bByString)
1606 {
1607 nRes = -1; // numeric < string
1608 if (bLessEqual)
1609 nLastInRange = i;
1610 }
1611 else // if (bStr && !bByString)
1612 {
1613 nRes = 1; // string > numeric
1614 if (!bLessEqual)
1615 nLastInRange = i;
1616 }
1617 if (nRes < 0)
1618 {
1619 if (bLessEqual)
1620 nLo = nMid + 1;
1621 else // assumed to be SC_GREATER_EQUAL
1622 {
1623 if (nMid > 0)
1624 nHi = nMid - 1;
1625 else
1626 bDone = true;
1627 }
1628 }
1629 else if (nRes > 0)
1630 {
1631 if (bLessEqual)
1632 {
1633 if (nMid > 0)
1634 nHi = nMid - 1;
1635 else
1636 bDone = true;
1637 }
1638 else // assumed to be SC_GREATER_EQUAL
1639 nLo = nMid + 1;
1640 }
1641 else
1642 {
1643 nLo = i;
1644 bDone = bFound = true;
1645 }
1646 }
1647 if (!bFound)
1648 {
1649 // If all hits didn't result in a moving limit there's something
1650 // strange, e.g. data range not properly sorted, or only identical
1651 // values encountered, which doesn't mean there aren't any others in
1652 // between.. leave it to GetThis(). The condition for this would be
1653 // if (nLastInRange == nFirstLastInRange) nLo = nFirstLastInRange;
1654 // Else, in case no exact match was found, we step back for a
1655 // subsequent GetThis() to find the last in range. Effectively this is
1656 // --nLo with nLastInRange == nLo-1. Both conditions combined yield:
1657 nLo = nLastInRange;
1658 }
1659 if (nLo < pCol->nCount && pCol->pItems[nLo].nRow <= aParam.nRow2)
1660 {
1661 nRow = pItems[nLo].nRow;
1662 pCell = pItems[nLo].pCell;
1663 nColRow = nLo;
1664 }
1665 else
1666 {
1667 nRow = aParam.nRow2 + 1;
1668 pCell = 0;
1669 nColRow = pCol->nCount - 1;
1670 }
1671 return pCell;
1672 }
1673
1674
1675 //-------------------------------------------------------------------------------
1676
ScHorizontalCellIterator(ScDocument * pDocument,SCTAB nTable,SCCOL nCol1,SCROW nRow1,SCCOL nCol2,SCROW nRow2)1677 ScHorizontalCellIterator::ScHorizontalCellIterator(ScDocument* pDocument, SCTAB nTable,
1678 SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) :
1679 pDoc( pDocument ),
1680 nTab( nTable ),
1681 nStartCol( nCol1 ),
1682 nEndCol( nCol2 ),
1683 nStartRow( nRow1 ),
1684 nEndRow( nRow2 ),
1685 nCol( nCol1 ),
1686 nRow( nRow1 ),
1687 bMore( sal_True )
1688 {
1689
1690 pNextRows = new SCROW[ nCol2-nCol1+1 ];
1691 pNextIndices = new SCSIZE[ nCol2-nCol1+1 ];
1692
1693 SetTab( nTab );
1694 }
1695
~ScHorizontalCellIterator()1696 ScHorizontalCellIterator::~ScHorizontalCellIterator()
1697 {
1698 delete [] pNextRows;
1699 delete [] pNextIndices;
1700 }
1701
SetTab(SCTAB nTabP)1702 void ScHorizontalCellIterator::SetTab( SCTAB nTabP )
1703 {
1704 nTab = nTabP;
1705 nRow = nStartRow;
1706 nCol = nStartCol;
1707 bMore = sal_True;
1708
1709 for (SCCOL i=nStartCol; i<=nEndCol; i++)
1710 {
1711 ScColumn* pCol = &pDoc->pTab[nTab]->aCol[i];
1712
1713 SCSIZE nIndex;
1714 pCol->Search( nStartRow, nIndex );
1715 if ( nIndex < pCol->nCount )
1716 {
1717 pNextRows[i-nStartCol] = pCol->pItems[nIndex].nRow;
1718 pNextIndices[i-nStartCol] = nIndex;
1719 }
1720 else
1721 {
1722 pNextRows[i-nStartCol] = MAXROWCOUNT; // nichts gefunden
1723 pNextIndices[i-nStartCol] = MAXROWCOUNT;
1724 }
1725 }
1726
1727 if (pNextRows[0] != nStartRow)
1728 Advance();
1729 }
1730
GetNext(SCCOL & rCol,SCROW & rRow)1731 ScBaseCell* ScHorizontalCellIterator::GetNext( SCCOL& rCol, SCROW& rRow )
1732 {
1733 if ( bMore )
1734 {
1735 rCol = nCol;
1736 rRow = nRow;
1737
1738 ScColumn* pCol = &pDoc->pTab[nTab]->aCol[nCol];
1739 SCSIZE nIndex = pNextIndices[nCol-nStartCol];
1740 DBG_ASSERT( nIndex < pCol->nCount, "ScHorizontalCellIterator::GetNext: nIndex out of range" );
1741 ScBaseCell* pCell = pCol->pItems[nIndex].pCell;
1742 if ( ++nIndex < pCol->nCount )
1743 {
1744 pNextRows[nCol-nStartCol] = pCol->pItems[nIndex].nRow;
1745 pNextIndices[nCol-nStartCol] = nIndex;
1746 }
1747 else
1748 {
1749 pNextRows[nCol-nStartCol] = MAXROWCOUNT; // nichts gefunden
1750 pNextIndices[nCol-nStartCol] = MAXROWCOUNT;
1751 }
1752
1753 Advance();
1754 return pCell;
1755 }
1756 else
1757 return NULL;
1758 }
1759
ReturnNext(SCCOL & rCol,SCROW & rRow)1760 sal_Bool ScHorizontalCellIterator::ReturnNext( SCCOL& rCol, SCROW& rRow )
1761 {
1762 rCol = nCol;
1763 rRow = nRow;
1764 return bMore;
1765 }
1766
Advance()1767 void ScHorizontalCellIterator::Advance()
1768 {
1769 sal_Bool bFound = sal_False;
1770 SCCOL i;
1771
1772 for (i=nCol+1; i<=nEndCol && !bFound; i++)
1773 if (pNextRows[i-nStartCol] == nRow)
1774 {
1775 nCol = i;
1776 bFound = sal_True;
1777 }
1778
1779 if (!bFound)
1780 {
1781 SCROW nMinRow = MAXROW+1;
1782 for (i=nStartCol; i<=nEndCol; i++)
1783 if (pNextRows[i-nStartCol] < nMinRow)
1784 {
1785 nCol = i;
1786 nMinRow = pNextRows[i-nStartCol];
1787 }
1788
1789 if (nMinRow <= nEndRow)
1790 {
1791 nRow = nMinRow;
1792 bFound = sal_True;
1793 }
1794 }
1795
1796 if ( !bFound )
1797 bMore = sal_False;
1798 }
1799
1800 //------------------------------------------------------------------------
1801
ScHorizontalValueIterator(ScDocument * pDocument,const ScRange & rRange,bool bSTotal,bool bTextZero)1802 ScHorizontalValueIterator::ScHorizontalValueIterator( ScDocument* pDocument,
1803 const ScRange& rRange, bool bSTotal, bool bTextZero ) :
1804 pDoc( pDocument ),
1805 nNumFmtIndex(0),
1806 nEndTab( rRange.aEnd.Tab() ),
1807 nNumFmtType( NUMBERFORMAT_UNDEFINED ),
1808 bNumValid( false ),
1809 bSubTotal( bSTotal ),
1810 bCalcAsShown( pDocument->GetDocOptions().IsCalcAsShown() ),
1811 bTextAsZero( bTextZero )
1812 {
1813 SCCOL nStartCol = rRange.aStart.Col();
1814 SCROW nStartRow = rRange.aStart.Row();
1815 SCTAB nStartTab = rRange.aStart.Tab();
1816 SCCOL nEndCol = rRange.aEnd.Col();
1817 SCROW nEndRow = rRange.aEnd.Row();
1818 PutInOrder( nStartCol, nEndCol);
1819 PutInOrder( nStartRow, nEndRow);
1820 PutInOrder( nStartTab, nEndTab );
1821
1822 if (!ValidCol(nStartCol)) nStartCol = MAXCOL;
1823 if (!ValidCol(nEndCol)) nEndCol = MAXCOL;
1824 if (!ValidRow(nStartRow)) nStartRow = MAXROW;
1825 if (!ValidRow(nEndRow)) nEndRow = MAXROW;
1826 if (!ValidTab(nStartTab)) nStartTab = MAXTAB;
1827 if (!ValidTab(nEndTab)) nEndTab = MAXTAB;
1828
1829 nCurCol = nStartCol;
1830 nCurRow = nStartRow;
1831 nCurTab = nStartTab;
1832
1833 nNumFormat = 0; // will be initialized in GetNumberFormat()
1834 pAttrArray = 0;
1835 nAttrEndRow = 0;
1836
1837 pCellIter = new ScHorizontalCellIterator( pDoc, nStartTab, nStartCol,
1838 nStartRow, nEndCol, nEndRow );
1839 }
1840
~ScHorizontalValueIterator()1841 ScHorizontalValueIterator::~ScHorizontalValueIterator()
1842 {
1843 delete pCellIter;
1844 }
1845
GetNext(double & rValue,sal_uInt16 & rErr)1846 bool ScHorizontalValueIterator::GetNext( double& rValue, sal_uInt16& rErr )
1847 {
1848 bool bFound = false;
1849 while ( !bFound )
1850 {
1851 ScBaseCell* pCell = pCellIter->GetNext( nCurCol, nCurRow );
1852 while ( !pCell )
1853 {
1854 if ( nCurTab < nEndTab )
1855 {
1856 pCellIter->SetTab( ++nCurTab);
1857 pCell = pCellIter->GetNext( nCurCol, nCurRow );
1858 }
1859 else
1860 return false;
1861 }
1862 if ( !bSubTotal || !pDoc->pTab[nCurTab]->RowFiltered( nCurRow ) )
1863 {
1864 switch (pCell->GetCellType())
1865 {
1866 case CELLTYPE_VALUE:
1867 {
1868 bNumValid = false;
1869 rValue = ((ScValueCell*)pCell)->GetValue();
1870 rErr = 0;
1871 if ( bCalcAsShown )
1872 {
1873 ScColumn* pCol = &pDoc->pTab[nCurTab]->aCol[nCurCol];
1874 lcl_IterGetNumberFormat( nNumFormat, pAttrArray,
1875 nAttrEndRow, pCol->pAttrArray, nCurRow, pDoc );
1876 rValue = pDoc->RoundValueAsShown( rValue, nNumFormat );
1877 }
1878 bFound = true;
1879 }
1880 break;
1881 case CELLTYPE_FORMULA:
1882 {
1883 if (!bSubTotal || !((ScFormulaCell*)pCell)->IsSubTotal())
1884 {
1885 rErr = ((ScFormulaCell*)pCell)->GetErrCode();
1886 if ( rErr || ((ScFormulaCell*)pCell)->IsValue() )
1887 {
1888 rValue = ((ScFormulaCell*)pCell)->GetValue();
1889 bNumValid = false;
1890 bFound = true;
1891 }
1892 else if ( bTextAsZero )
1893 {
1894 rValue = 0.0;
1895 bNumValid = false;
1896 bFound = true;
1897 }
1898 }
1899 }
1900 break;
1901 case CELLTYPE_STRING :
1902 case CELLTYPE_EDIT :
1903 {
1904 if ( bTextAsZero )
1905 {
1906 rErr = 0;
1907 rValue = 0.0;
1908 nNumFmtType = NUMBERFORMAT_NUMBER;
1909 nNumFmtIndex = 0;
1910 bNumValid = true;
1911 bFound = true;
1912 }
1913 }
1914 break;
1915 default:
1916 ; // nothing
1917 }
1918 }
1919 }
1920 return bFound;
1921 }
1922
GetCurNumFmtInfo(short & nType,sal_uLong & nIndex)1923 void ScHorizontalValueIterator::GetCurNumFmtInfo( short& nType, sal_uLong& nIndex )
1924 {
1925 if (!bNumValid)
1926 {
1927 const ScColumn* pCol = &(pDoc->pTab[nCurTab])->aCol[nCurCol];
1928 nNumFmtIndex = pCol->GetNumberFormat( nCurRow );
1929 if ( (nNumFmtIndex % SV_COUNTRY_LANGUAGE_OFFSET) == 0 )
1930 {
1931 const ScBaseCell* pCell;
1932 SCSIZE nCurIndex;
1933 if ( pCol->Search( nCurRow, nCurIndex ) )
1934 pCell = pCol->pItems[nCurIndex].pCell;
1935 else
1936 pCell = NULL;
1937 if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA )
1938 ((const ScFormulaCell*)pCell)->GetFormatInfo( nNumFmtType, nNumFmtIndex );
1939 else
1940 nNumFmtType = pDoc->GetFormatTable()->GetType( nNumFmtIndex );
1941 }
1942 else
1943 nNumFmtType = pDoc->GetFormatTable()->GetType( nNumFmtIndex );
1944 bNumValid = true;
1945 }
1946 nType = nNumFmtType;
1947 nIndex = nNumFmtIndex;
1948 }
1949
1950 //-------------------------------------------------------------------------------
1951
ScHorizontalAttrIterator(ScDocument * pDocument,SCTAB nTable,SCCOL nCol1,SCROW nRow1,SCCOL nCol2,SCROW nRow2)1952 ScHorizontalAttrIterator::ScHorizontalAttrIterator( ScDocument* pDocument, SCTAB nTable,
1953 SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) :
1954 pDoc( pDocument ),
1955 nTab( nTable ),
1956 nStartCol( nCol1 ),
1957 nStartRow( nRow1 ),
1958 nEndCol( nCol2 ),
1959 nEndRow( nRow2 )
1960 {
1961 DBG_ASSERT( pDoc->pTab[nTab], "Tabelle nicht da" );
1962
1963 SCCOL i;
1964
1965 nRow = nStartRow;
1966 nCol = nStartCol;
1967 bRowEmpty = sal_False;
1968
1969 pIndices = new SCSIZE[nEndCol-nStartCol+1];
1970 pNextEnd = new SCROW[nEndCol-nStartCol+1];
1971 ppPatterns = new const ScPatternAttr*[nEndCol-nStartCol+1];
1972
1973 SCROW nSkipTo = MAXROW;
1974 sal_Bool bEmpty = sal_True;
1975 for (i=nStartCol; i<=nEndCol; i++)
1976 {
1977 SCCOL nPos = i - nStartCol;
1978 ScAttrArray* pArray = pDoc->pTab[nTab]->aCol[i].pAttrArray;
1979 DBG_ASSERT( pArray, "pArray == 0" );
1980
1981 SCSIZE nIndex;
1982 pArray->Search( nStartRow, nIndex );
1983
1984 const ScPatternAttr* pPattern = pArray->pData[nIndex].pPattern;
1985 SCROW nThisEnd = pArray->pData[nIndex].nRow;
1986 if ( IsDefaultItem( pPattern ) )
1987 {
1988 pPattern = NULL;
1989 if ( nThisEnd < nSkipTo )
1990 nSkipTo = nThisEnd; // nSkipTo kann gleich hier gesetzt werden
1991 }
1992 else
1993 bEmpty = sal_False; // Attribute gefunden
1994
1995 pIndices[nPos] = nIndex;
1996 pNextEnd[nPos] = nThisEnd;
1997 ppPatterns[nPos] = pPattern;
1998 }
1999
2000 if (bEmpty)
2001 nRow = nSkipTo; // bis zum naechsten Bereichsende ueberspringen
2002 bRowEmpty = bEmpty;
2003 }
2004
~ScHorizontalAttrIterator()2005 ScHorizontalAttrIterator::~ScHorizontalAttrIterator()
2006 {
2007 delete[] (ScPatternAttr**)ppPatterns;
2008 delete[] pNextEnd;
2009 delete[] pIndices;
2010 }
2011
GetNext(SCCOL & rCol1,SCCOL & rCol2,SCROW & rRow)2012 const ScPatternAttr* ScHorizontalAttrIterator::GetNext( SCCOL& rCol1, SCCOL& rCol2, SCROW& rRow )
2013 {
2014 for (;;)
2015 {
2016 if (!bRowEmpty)
2017 {
2018 // in dieser Zeile suchen
2019
2020 while ( nCol <= nEndCol && !ppPatterns[nCol-nStartCol] )
2021 ++nCol;
2022
2023 if ( nCol <= nEndCol )
2024 {
2025 const ScPatternAttr* pPat = ppPatterns[nCol-nStartCol];
2026 rRow = nRow;
2027 rCol1 = nCol;
2028 while ( nCol < nEndCol && ppPatterns[nCol+1-nStartCol] == pPat )
2029 ++nCol;
2030 rCol2 = nCol;
2031 ++nCol; // hochzaehlen fuer naechsten Aufruf
2032 return pPat; // gefunden
2033 }
2034 }
2035
2036 // naechste Zeile
2037
2038 ++nRow;
2039 if ( nRow > nEndRow ) // schon am Ende?
2040 return NULL; // nichts gefunden
2041
2042 sal_Bool bEmpty = sal_True;
2043 SCCOL i;
2044
2045 for ( i = nStartCol; i <= nEndCol; i++)
2046 {
2047 SCCOL nPos = i-nStartCol;
2048 if ( pNextEnd[nPos] < nRow )
2049 {
2050 ScAttrArray* pArray = pDoc->pTab[nTab]->aCol[i].pAttrArray;
2051
2052 SCSIZE nIndex = ++pIndices[nPos];
2053 if ( nIndex < pArray->nCount )
2054 {
2055 const ScPatternAttr* pPattern = pArray->pData[nIndex].pPattern;
2056 SCROW nThisEnd = pArray->pData[nIndex].nRow;
2057 if ( IsDefaultItem( pPattern ) )
2058 pPattern = NULL;
2059 else
2060 bEmpty = sal_False; // Attribute gefunden
2061
2062 pNextEnd[nPos] = nThisEnd;
2063 ppPatterns[nPos] = pPattern;
2064
2065 DBG_ASSERT( pNextEnd[nPos] >= nRow, "Reihenfolge durcheinander" );
2066 }
2067 else
2068 {
2069 DBG_ERROR("AttrArray reicht nicht bis MAXROW");
2070 pNextEnd[nPos] = MAXROW;
2071 ppPatterns[nPos] = NULL;
2072 }
2073 }
2074 else if ( ppPatterns[nPos] )
2075 bEmpty = sal_False; // Bereich noch nicht zuende
2076 }
2077
2078 if (bEmpty)
2079 {
2080 SCCOL nCount = nEndCol-nStartCol+1;
2081 SCROW nSkipTo = pNextEnd[0]; // naechstes Bereichsende suchen
2082 for (i=1; i<nCount; i++)
2083 if ( pNextEnd[i] < nSkipTo )
2084 nSkipTo = pNextEnd[i];
2085 nRow = nSkipTo; // leere Zeilen ueberspringen
2086 }
2087 bRowEmpty = bEmpty;
2088 nCol = nStartCol; // wieder links anfangen
2089 }
2090
2091 // return NULL;
2092 }
2093
2094 //-------------------------------------------------------------------------------
2095
IsGreater(SCCOL nCol1,SCROW nRow1,SCCOL nCol2,SCROW nRow2)2096 inline sal_Bool IsGreater( SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
2097 {
2098 return ( nRow1 > nRow2 ) || ( nRow1 == nRow2 && nCol1 > nCol2 );
2099 }
2100
ScUsedAreaIterator(ScDocument * pDocument,SCTAB nTable,SCCOL nCol1,SCROW nRow1,SCCOL nCol2,SCROW nRow2)2101 ScUsedAreaIterator::ScUsedAreaIterator( ScDocument* pDocument, SCTAB nTable,
2102 SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 ) :
2103 aCellIter( pDocument, nTable, nCol1, nRow1, nCol2, nRow2 ),
2104 aAttrIter( pDocument, nTable, nCol1, nRow1, nCol2, nRow2 ),
2105 nNextCol( nCol1 ),
2106 nNextRow( nRow1 )
2107 {
2108 pCell = aCellIter.GetNext( nCellCol, nCellRow );
2109 pPattern = aAttrIter.GetNext( nAttrCol1, nAttrCol2, nAttrRow );
2110 }
2111
~ScUsedAreaIterator()2112 ScUsedAreaIterator::~ScUsedAreaIterator()
2113 {
2114 }
2115
GetNext()2116 sal_Bool ScUsedAreaIterator::GetNext()
2117 {
2118 // Iteratoren weiterzaehlen
2119
2120 if ( pCell && IsGreater( nNextCol, nNextRow, nCellCol, nCellRow ) )
2121 pCell = aCellIter.GetNext( nCellCol, nCellRow );
2122
2123 while ( pCell && pCell->IsBlank() )
2124 pCell = aCellIter.GetNext( nCellCol, nCellRow );
2125
2126 if ( pPattern && IsGreater( nNextCol, nNextRow, nAttrCol2, nAttrRow ) )
2127 pPattern = aAttrIter.GetNext( nAttrCol1, nAttrCol2, nAttrRow );
2128
2129 if ( pPattern && nAttrRow == nNextRow && nAttrCol1 < nNextCol )
2130 nAttrCol1 = nNextCol;
2131
2132 // naechsten Abschnitt heraussuchen
2133
2134 sal_Bool bFound = sal_True;
2135 sal_Bool bUseCell = sal_False;
2136
2137 if ( pCell && pPattern )
2138 {
2139 if ( IsGreater( nCellCol, nCellRow, nAttrCol1, nAttrRow ) ) // vorne nur Attribute ?
2140 {
2141 pFoundCell = NULL;
2142 pFoundPattern = pPattern;
2143 nFoundRow = nAttrRow;
2144 nFoundStartCol = nAttrCol1;
2145 if ( nCellRow == nAttrRow && nCellCol <= nAttrCol2 ) // auch Zelle im Bereich ?
2146 nFoundEndCol = nCellCol - 1; // nur bis vor der Zelle
2147 else
2148 nFoundEndCol = nAttrCol2; // alles
2149 }
2150 else
2151 {
2152 bUseCell = sal_True;
2153 if ( nAttrRow == nCellRow && nAttrCol1 == nCellCol ) // Attribute auf der Zelle ?
2154 pFoundPattern = pPattern;
2155 else
2156 pFoundPattern = NULL;
2157 }
2158 }
2159 else if ( pCell ) // nur Zelle -> direkt uebernehmen
2160 {
2161 pFoundPattern = NULL;
2162 bUseCell = sal_True; // Position von Zelle
2163 }
2164 else if ( pPattern ) // nur Attribute -> direkt uebernehmen
2165 {
2166 pFoundCell = NULL;
2167 pFoundPattern = pPattern;
2168 nFoundRow = nAttrRow;
2169 nFoundStartCol = nAttrCol1;
2170 nFoundEndCol = nAttrCol2;
2171 }
2172 else // gar nichts
2173 bFound = sal_False;
2174
2175 if ( bUseCell ) // Position von Zelle
2176 {
2177 pFoundCell = pCell;
2178 nFoundRow = nCellRow;
2179 nFoundStartCol = nFoundEndCol = nCellCol;
2180 }
2181
2182 if (bFound)
2183 {
2184 nNextRow = nFoundRow;
2185 nNextCol = nFoundEndCol + 1;
2186 }
2187
2188 return bFound;
2189 }
2190
2191 //-------------------------------------------------------------------------------
2192
ScDocAttrIterator(ScDocument * pDocument,SCTAB nTable,SCCOL nCol1,SCROW nRow1,SCCOL nCol2,SCROW nRow2)2193 ScDocAttrIterator::ScDocAttrIterator(ScDocument* pDocument, SCTAB nTable,
2194 SCCOL nCol1, SCROW nRow1,
2195 SCCOL nCol2, SCROW nRow2) :
2196 pDoc( pDocument ),
2197 nTab( nTable ),
2198 nEndCol( nCol2 ),
2199 nStartRow( nRow1 ),
2200 nEndRow( nRow2 ),
2201 nCol( nCol1 )
2202 {
2203 if ( ValidTab(nTab) && pDoc->pTab[nTab] )
2204 pColIter = pDoc->pTab[nTab]->aCol[nCol].CreateAttrIterator( nStartRow, nEndRow );
2205 else
2206 pColIter = NULL;
2207 }
2208
~ScDocAttrIterator()2209 ScDocAttrIterator::~ScDocAttrIterator()
2210 {
2211 delete pColIter;
2212 }
2213
GetNext(SCCOL & rCol,SCROW & rRow1,SCROW & rRow2)2214 const ScPatternAttr* ScDocAttrIterator::GetNext( SCCOL& rCol, SCROW& rRow1, SCROW& rRow2 )
2215 {
2216 while ( pColIter )
2217 {
2218 const ScPatternAttr* pPattern = pColIter->Next( rRow1, rRow2 );
2219 if ( pPattern )
2220 {
2221 rCol = nCol;
2222 return pPattern;
2223 }
2224
2225 delete pColIter;
2226 ++nCol;
2227 if ( nCol <= nEndCol )
2228 pColIter = pDoc->pTab[nTab]->aCol[nCol].CreateAttrIterator( nStartRow, nEndRow );
2229 else
2230 pColIter = NULL;
2231 }
2232 return NULL; // is nix mehr
2233 }
2234
2235 //-------------------------------------------------------------------------------
2236
ScAttrRectIterator(ScDocument * pDocument,SCTAB nTable,SCCOL nCol1,SCROW nRow1,SCCOL nCol2,SCROW nRow2)2237 ScAttrRectIterator::ScAttrRectIterator(ScDocument* pDocument, SCTAB nTable,
2238 SCCOL nCol1, SCROW nRow1,
2239 SCCOL nCol2, SCROW nRow2) :
2240 pDoc( pDocument ),
2241 nTab( nTable ),
2242 nEndCol( nCol2 ),
2243 nStartRow( nRow1 ),
2244 nEndRow( nRow2 ),
2245 nIterStartCol( nCol1 ),
2246 nIterEndCol( nCol1 )
2247 {
2248 if ( ValidTab(nTab) && pDoc->pTab[nTab] )
2249 {
2250 pColIter = pDoc->pTab[nTab]->aCol[nIterStartCol].CreateAttrIterator( nStartRow, nEndRow );
2251 while ( nIterEndCol < nEndCol &&
2252 pDoc->pTab[nTab]->aCol[nIterEndCol].IsAllAttrEqual(
2253 pDoc->pTab[nTab]->aCol[nIterEndCol+1], nStartRow, nEndRow ) )
2254 ++nIterEndCol;
2255 }
2256 else
2257 pColIter = NULL;
2258 }
2259
~ScAttrRectIterator()2260 ScAttrRectIterator::~ScAttrRectIterator()
2261 {
2262 delete pColIter;
2263 }
2264
DataChanged()2265 void ScAttrRectIterator::DataChanged()
2266 {
2267 if (pColIter)
2268 {
2269 SCROW nNextRow = pColIter->GetNextRow();
2270 delete pColIter;
2271 pColIter = pDoc->pTab[nTab]->aCol[nIterStartCol].CreateAttrIterator( nNextRow, nEndRow );
2272 }
2273 }
2274
GetNext(SCCOL & rCol1,SCCOL & rCol2,SCROW & rRow1,SCROW & rRow2)2275 const ScPatternAttr* ScAttrRectIterator::GetNext( SCCOL& rCol1, SCCOL& rCol2,
2276 SCROW& rRow1, SCROW& rRow2 )
2277 {
2278 while ( pColIter )
2279 {
2280 const ScPatternAttr* pPattern = pColIter->Next( rRow1, rRow2 );
2281 if ( pPattern )
2282 {
2283 rCol1 = nIterStartCol;
2284 rCol2 = nIterEndCol;
2285 return pPattern;
2286 }
2287
2288 delete pColIter;
2289 nIterStartCol = nIterEndCol+1;
2290 if ( nIterStartCol <= nEndCol )
2291 {
2292 nIterEndCol = nIterStartCol;
2293 pColIter = pDoc->pTab[nTab]->aCol[nIterStartCol].CreateAttrIterator( nStartRow, nEndRow );
2294 while ( nIterEndCol < nEndCol &&
2295 pDoc->pTab[nTab]->aCol[nIterEndCol].IsAllAttrEqual(
2296 pDoc->pTab[nTab]->aCol[nIterEndCol+1], nStartRow, nEndRow ) )
2297 ++nIterEndCol;
2298 }
2299 else
2300 pColIter = NULL;
2301 }
2302 return NULL; // is nix mehr
2303 }
2304
2305 // ============================================================================
2306
2307 SCROW ScRowBreakIterator::NOT_FOUND = -1;
2308
ScRowBreakIterator(set<SCROW> & rBreaks)2309 ScRowBreakIterator::ScRowBreakIterator(set<SCROW>& rBreaks) :
2310 mrBreaks(rBreaks),
2311 maItr(rBreaks.begin()), maEnd(rBreaks.end())
2312 {
2313 }
2314
first()2315 SCROW ScRowBreakIterator::first()
2316 {
2317 maItr = mrBreaks.begin();
2318 return maItr == maEnd ? NOT_FOUND : *maItr;
2319 }
2320
next()2321 SCROW ScRowBreakIterator::next()
2322 {
2323 ++maItr;
2324 return maItr == maEnd ? NOT_FOUND : *maItr;
2325 }
2326