Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : :
30 : : #include <rtl/math.hxx>
31 : : #include <unotools/textsearch.hxx>
32 : : #include <svl/zforlist.hxx>
33 : : #include <svl/zformat.hxx>
34 : : #include <unotools/charclass.hxx>
35 : : #include <unotools/collatorwrapper.hxx>
36 : : #include <com/sun/star/i18n/CollatorOptions.hpp>
37 : : #include <stdlib.h>
38 : : #include <unotools/transliterationwrapper.hxx>
39 : :
40 : : #include "table.hxx"
41 : : #include "scitems.hxx"
42 : : #include "attrib.hxx"
43 : : #include "cell.hxx"
44 : : #include "document.hxx"
45 : : #include "globstr.hrc"
46 : : #include "global.hxx"
47 : : #include "stlpool.hxx"
48 : : #include "compiler.hxx"
49 : : #include "patattr.hxx"
50 : : #include "subtotal.hxx"
51 : : #include "docoptio.hxx"
52 : : #include "markdata.hxx"
53 : : #include "rangelst.hxx"
54 : : #include "attarray.hxx"
55 : : #include "userlist.hxx"
56 : : #include "progress.hxx"
57 : : #include "cellform.hxx"
58 : : #include "postit.hxx"
59 : : #include "queryparam.hxx"
60 : : #include "queryentry.hxx"
61 : : #include "segmenttree.hxx"
62 : : #include "subtotalparam.hxx"
63 : : #include "docpool.hxx"
64 : :
65 : : #include <vector>
66 : : #include <boost/unordered_set.hpp>
67 : :
68 : : using namespace ::com::sun::star;
69 : :
70 : : namespace naturalsort {
71 : :
72 : : using namespace ::com::sun::star::i18n;
73 : :
74 : : /** Splits a given string into three parts: the prefix, number string, and
75 : : the suffix.
76 : :
77 : : @param sWhole
78 : : Original string to be split into pieces
79 : :
80 : : @param sPrefix
81 : : Prefix string that consists of the part before the first number token
82 : :
83 : : @param sSuffix
84 : : String after the last number token. This may still contain number strings.
85 : :
86 : : @param fNum
87 : : Number converted from the middle number string
88 : :
89 : : @return Returns TRUE if a numeral element is found in a given string, or
90 : : FALSE if no numeral element is found.
91 : : */
92 : 0 : bool SplitString( const rtl::OUString &sWhole,
93 : : rtl::OUString &sPrefix, rtl::OUString &sSuffix, double &fNum )
94 : : {
95 [ # # ]: 0 : i18n::LocaleDataItem aLocaleItem = ScGlobal::pLocaleData->getLocaleItem();
96 : :
97 : : // Get prefix element
98 [ # # ]: 0 : rtl::OUString sEmpty, sUser = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM( "-" ));
99 : : ParseResult aPRPre = ScGlobal::pCharClass->parsePredefinedToken(
100 : : KParseType::IDENTNAME, sWhole, 0,
101 [ # # ][ # # ]: 0 : KParseTokens::ANY_LETTER, sUser, KParseTokens::ANY_LETTER, sUser );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
102 : 0 : sPrefix = sWhole.copy( 0, aPRPre.EndPos );
103 : :
104 : : // Return FALSE if no numeral element is found
105 [ # # ]: 0 : if ( aPRPre.EndPos == sWhole.getLength() )
106 : 0 : return false;
107 : :
108 : : // Get numeral element
109 : 0 : sUser = aLocaleItem.decimalSeparator;
110 : : ParseResult aPRNum = ScGlobal::pCharClass->parsePredefinedToken(
111 : : KParseType::ANY_NUMBER, sWhole, aPRPre.EndPos,
112 [ # # ][ # # ]: 0 : KParseTokens::ANY_NUMBER, sEmpty, KParseTokens::ANY_NUMBER, sUser );
[ # # ][ # # ]
[ # # ][ # # ]
[ # # ]
113 : :
114 [ # # ]: 0 : if ( aPRNum.EndPos == aPRPre.EndPos )
115 : 0 : return false;
116 : :
117 : 0 : fNum = aPRNum.Value;
118 : 0 : sSuffix = sWhole.copy( aPRNum.EndPos );
119 : :
120 : 0 : return true;
121 : : }
122 : :
123 : : /** Naturally compares two given strings.
124 : :
125 : : This is the main function that should be called externally. It returns
126 : : either 1, 0, or -1 depending on the comparison result of given two strings.
127 : :
128 : : @param sInput1
129 : : Input string 1
130 : :
131 : : @param sInput2
132 : : Input string 2
133 : :
134 : : @param bCaseSens
135 : : Boolean value for case sensitivity
136 : :
137 : : @param pData
138 : : Pointer to user defined sort list
139 : :
140 : : @param pCW
141 : : Pointer to collator wrapper for normal string comparison
142 : :
143 : : @return Returnes 1 if sInput1 is greater, 0 if sInput1 == sInput2, and -1 if
144 : : sInput2 is greater.
145 : : */
146 : 0 : short Compare( const String &sInput1, const String &sInput2,
147 : : const bool bCaseSens, const ScUserListData* pData, const CollatorWrapper *pCW )
148 : : {
149 [ # # ][ # # ]: 0 : rtl::OUString sStr1( sInput1 ), sStr2( sInput2 ), sPre1, sSuf1, sPre2, sSuf2;
150 : :
151 : 0 : do
152 : : {
153 : : double nNum1, nNum2;
154 [ # # ]: 0 : bool bNumFound1 = SplitString( sStr1, sPre1, sSuf1, nNum1 );
155 [ # # ]: 0 : bool bNumFound2 = SplitString( sStr2, sPre2, sSuf2, nNum2 );
156 : :
157 : : short nPreRes; // Prefix comparison result
158 [ # # ]: 0 : if ( pData )
159 : : {
160 [ # # ]: 0 : if ( bCaseSens )
161 : : {
162 [ # # ][ # # ]: 0 : if ( !bNumFound1 || !bNumFound2 )
163 [ # # ]: 0 : return static_cast<short>(pData->Compare( sStr1, sStr2 ));
164 : : else
165 [ # # ]: 0 : nPreRes = pData->Compare( sPre1, sPre2 );
166 : : }
167 : : else
168 : : {
169 [ # # ][ # # ]: 0 : if ( !bNumFound1 || !bNumFound2 )
170 [ # # ]: 0 : return static_cast<short>(pData->ICompare( sStr1, sStr2 ));
171 : : else
172 [ # # ]: 0 : nPreRes = pData->ICompare( sPre1, sPre2 );
173 : : }
174 : : }
175 : : else
176 : : {
177 [ # # ][ # # ]: 0 : if ( !bNumFound1 || !bNumFound2 )
178 [ # # ]: 0 : return static_cast<short>(pCW->compareString( sStr1, sStr2 ));
179 : : else
180 [ # # ]: 0 : nPreRes = static_cast<short>(pCW->compareString( sPre1, sPre2 ));
181 : : }
182 : :
183 : : // Prefix strings differ. Return immediately.
184 [ # # ]: 0 : if ( nPreRes != 0 ) return nPreRes;
185 : :
186 [ # # ]: 0 : if ( nNum1 != nNum2 )
187 : : {
188 [ # # ]: 0 : if ( nNum1 < nNum2 ) return -1;
189 : 0 : return static_cast<short>( nNum1 > nNum2 );
190 : : }
191 : :
192 : : // The prefix and the first numerical elements are equal, but the suffix
193 : : // strings may still differ. Stay in the loop.
194 : :
195 : 0 : sStr1 = sSuf1;
196 : 0 : sStr2 = sSuf2;
197 : :
198 : : } while (true);
199 : :
200 : 0 : return 0;
201 : : }
202 : :
203 : : }
204 : :
205 : : // STATIC DATA -----------------------------------------------------------
206 : :
207 : : struct ScSortInfo
208 : : {
209 : : ScBaseCell* pCell;
210 : : SCCOLROW nOrg;
211 [ + - ][ + - ]: 64 : DECL_FIXEDMEMPOOL_NEWDEL( ScSortInfo );
212 : : };
213 : 51 : IMPL_FIXEDMEMPOOL_NEWDEL( ScSortInfo )
214 : :
215 : : // END OF STATIC DATA -----------------------------------------------------
216 : :
217 : :
218 : : class ScSortInfoArray
219 : : {
220 : : private:
221 : : ScSortInfo*** pppInfo;
222 : : SCSIZE nCount;
223 : : SCCOLROW nStart;
224 : : sal_uInt16 nUsedSorts;
225 : :
226 : : public:
227 : 8 : ScSortInfoArray( sal_uInt16 nSorts, SCCOLROW nInd1, SCCOLROW nInd2 ) :
228 : 8 : pppInfo( new ScSortInfo**[nSorts]),
229 : : nCount( nInd2 - nInd1 + 1 ), nStart( nInd1 ),
230 : 8 : nUsedSorts( nSorts )
231 : : {
232 [ + + ]: 16 : for ( sal_uInt16 nSort = 0; nSort < nUsedSorts; nSort++ )
233 : : {
234 : 8 : ScSortInfo** ppInfo = new ScSortInfo* [nCount];
235 [ + + ]: 40 : for ( SCSIZE j = 0; j < nCount; j++ )
236 : 32 : ppInfo[j] = new ScSortInfo;
237 : 8 : pppInfo[nSort] = ppInfo;
238 : : }
239 : 8 : }
240 : 8 : ~ScSortInfoArray()
241 : : {
242 [ + + ]: 16 : for ( sal_uInt16 nSort = 0; nSort < nUsedSorts; nSort++ )
243 : : {
244 : 8 : ScSortInfo** ppInfo = pppInfo[nSort];
245 [ + + ]: 40 : for ( SCSIZE j = 0; j < nCount; j++ )
246 : 32 : delete ppInfo[j];
247 [ + - ]: 8 : delete [] ppInfo;
248 : : }
249 [ + - ]: 8 : delete[] pppInfo;
250 : 8 : }
251 : 228 : ScSortInfo* Get( sal_uInt16 nSort, SCCOLROW nInd )
252 : 228 : { return (pppInfo[nSort])[ nInd - nStart ]; }
253 : 18 : void Swap( SCCOLROW nInd1, SCCOLROW nInd2 )
254 : : {
255 : 18 : SCSIZE n1 = static_cast<SCSIZE>(nInd1 - nStart);
256 : 18 : SCSIZE n2 = static_cast<SCSIZE>(nInd2 - nStart);
257 [ + + ]: 36 : for ( sal_uInt16 nSort = 0; nSort < nUsedSorts; nSort++ )
258 : : {
259 : 18 : ScSortInfo** ppInfo = pppInfo[nSort];
260 : 18 : ScSortInfo* pTmp = ppInfo[n1];
261 : 18 : ppInfo[n1] = ppInfo[n2];
262 : 18 : ppInfo[n2] = pTmp;
263 : : }
264 : 18 : }
265 : 22 : sal_uInt16 GetUsedSorts() const { return nUsedSorts; }
266 : 8 : ScSortInfo** GetFirstArray() const { return pppInfo[0]; }
267 : 8 : SCCOLROW GetStart() const { return nStart; }
268 : 8 : SCSIZE GetCount() const { return nCount; }
269 : : };
270 : :
271 : 8 : ScSortInfoArray* ScTable::CreateSortInfoArray( SCCOLROW nInd1, SCCOLROW nInd2 )
272 : : {
273 : 8 : sal_uInt16 nUsedSorts = 1;
274 [ + - ][ - + ]: 8 : while ( nUsedSorts < aSortParam.GetSortKeyCount() && aSortParam.maKeyState[nUsedSorts].bDoSort )
[ - + ]
275 : 0 : nUsedSorts++;
276 [ + - ]: 8 : ScSortInfoArray* pArray = new ScSortInfoArray( nUsedSorts, nInd1, nInd2 );
277 [ + - ]: 8 : if ( aSortParam.bByRow )
278 : : {
279 [ + + ]: 16 : for ( sal_uInt16 nSort = 0; nSort < nUsedSorts; nSort++ )
280 : : {
281 : 8 : SCCOL nCol = static_cast<SCCOL>(aSortParam.maKeyState[nSort].nField);
282 : 8 : ScColumn* pCol = &aCol[nCol];
283 [ + + ]: 40 : for ( SCROW nRow = nInd1; nRow <= nInd2; nRow++ )
284 : : {
285 : : //2do: FillSortInfo an ScColumn und Array abklappern statt Search in GetCell
286 : 32 : ScSortInfo* pInfo = pArray->Get( nSort, nRow );
287 : 32 : pInfo->pCell = pCol->GetCell( nRow );
288 : 32 : pInfo->nOrg = nRow;
289 : : }
290 : : }
291 : : }
292 : : else
293 : : {
294 [ # # ]: 0 : for ( sal_uInt16 nSort = 0; nSort < nUsedSorts; nSort++ )
295 : : {
296 : 0 : SCROW nRow = aSortParam.maKeyState[nSort].nField;
297 [ # # ]: 0 : for ( SCCOL nCol = static_cast<SCCOL>(nInd1);
298 : : nCol <= static_cast<SCCOL>(nInd2); nCol++ )
299 : : {
300 : 0 : ScSortInfo* pInfo = pArray->Get( nSort, nCol );
301 : 0 : pInfo->pCell = GetCell( nCol, nRow );
302 : 0 : pInfo->nOrg = nCol;
303 : : }
304 : : }
305 : : }
306 : 8 : return pArray;
307 : : }
308 : :
309 : :
310 : 10 : bool ScTable::IsSortCollatorGlobal() const
311 : : {
312 : 10 : return pSortCollator == ScGlobal::GetCollator() ||
313 [ # # ][ - + ]: 10 : pSortCollator == ScGlobal::GetCaseCollator();
314 : : }
315 : :
316 : :
317 : 10 : void ScTable::InitSortCollator( const ScSortParam& rPar )
318 : : {
319 [ - + ]: 10 : if ( !rPar.aCollatorLocale.Language.isEmpty() )
320 : : {
321 [ # # ][ # # ]: 0 : if ( !pSortCollator || IsSortCollatorGlobal() )
[ # # ]
322 [ # # ][ # # ]: 0 : pSortCollator = new CollatorWrapper( pDocument->GetServiceManager() );
323 : : pSortCollator->loadCollatorAlgorithm( rPar.aCollatorAlgorithm,
324 [ # # ]: 0 : rPar.aCollatorLocale, (rPar.bCaseSens ? 0 : SC_COLLATOR_IGNORES) );
325 : : }
326 : : else
327 : : { // SYSTEM
328 : 10 : DestroySortCollator();
329 : : pSortCollator = (rPar.bCaseSens ? ScGlobal::GetCaseCollator() :
330 [ - + ]: 10 : ScGlobal::GetCollator());
331 : : }
332 : 10 : }
333 : :
334 : :
335 : 1766 : void ScTable::DestroySortCollator()
336 : : {
337 [ + + ]: 1766 : if ( pSortCollator )
338 : : {
339 [ - + ]: 10 : if ( !IsSortCollatorGlobal() )
340 [ # # ]: 0 : delete pSortCollator;
341 : 10 : pSortCollator = NULL;
342 : : }
343 : 1766 : }
344 : :
345 : :
346 : 8 : void ScTable::SortReorder( ScSortInfoArray* pArray, ScProgress& rProgress )
347 : : {
348 : 8 : bool bByRow = aSortParam.bByRow;
349 : 8 : SCSIZE nCount = pArray->GetCount();
350 : 8 : SCCOLROW nStart = pArray->GetStart();
351 : 8 : ScSortInfo** ppInfo = pArray->GetFirstArray();
352 [ + - ]: 8 : ::std::vector<ScSortInfo*> aTable(nCount);
353 : : SCSIZE nPos;
354 [ + + ]: 40 : for ( nPos = 0; nPos < nCount; nPos++ )
355 : 32 : aTable[ppInfo[nPos]->nOrg - nStart] = ppInfo[nPos];
356 : :
357 : 8 : SCCOLROW nDest = nStart;
358 [ + + ]: 40 : for ( nPos = 0; nPos < nCount; nPos++, nDest++ )
359 : : {
360 : 32 : SCCOLROW nOrg = ppInfo[nPos]->nOrg;
361 [ + + ]: 32 : if ( nDest != nOrg )
362 : : {
363 [ + - ]: 18 : if ( bByRow )
364 [ + - ]: 18 : SwapRow( nDest, nOrg );
365 : : else
366 [ # # ]: 0 : SwapCol( static_cast<SCCOL>(nDest), static_cast<SCCOL>(nOrg) );
367 : : // neue Position des weggeswapten eintragen
368 : 18 : ScSortInfo* p = ppInfo[nPos];
369 : 18 : p->nOrg = nDest;
370 : 18 : ::std::swap(p, aTable[nDest-nStart]);
371 : 18 : p->nOrg = nOrg;
372 : 18 : ::std::swap(p, aTable[nOrg-nStart]);
373 : : OSL_ENSURE( p == ppInfo[nPos], "SortReorder: nOrg MisMatch" );
374 : : }
375 [ + - ]: 32 : rProgress.SetStateOnPercent( nPos );
376 : 8 : }
377 : 8 : }
378 : :
379 : 89 : short ScTable::CompareCell( sal_uInt16 nSort,
380 : : ScBaseCell* pCell1, SCCOL nCell1Col, SCROW nCell1Row,
381 : : ScBaseCell* pCell2, SCCOL nCell2Col, SCROW nCell2Row ) const
382 : : {
383 : 89 : short nRes = 0;
384 : :
385 : 89 : CellType eType1 = CELLTYPE_NONE, eType2 = CELLTYPE_NONE;
386 [ + - ]: 89 : if (pCell1)
387 : : {
388 : 89 : eType1 = pCell1->GetCellType();
389 : : }
390 [ + + ]: 89 : if (pCell2)
391 : : {
392 : 88 : eType2 = pCell2->GetCellType();
393 : : }
394 : :
395 [ + - ]: 89 : if (pCell1)
396 : : {
397 [ + + ]: 89 : if (pCell2)
398 : : {
399 : 88 : bool bStr1 = ( eType1 != CELLTYPE_VALUE );
400 [ - + ][ # # ]: 88 : if ( eType1 == CELLTYPE_FORMULA && ((ScFormulaCell*)pCell1)->IsValue() )
[ # # ][ - + ]
401 : 0 : bStr1 = false;
402 : 88 : bool bStr2 = ( eType2 != CELLTYPE_VALUE );
403 [ - + ][ # # ]: 88 : if ( eType2 == CELLTYPE_FORMULA && ((ScFormulaCell*)pCell2)->IsValue() )
[ # # ][ - + ]
404 : 0 : bStr2 = false;
405 : :
406 [ + + ][ + + ]: 88 : if ( bStr1 && bStr2 ) // nur Strings untereinander als String vergleichen!
407 : : {
408 : 8 : rtl::OUString aStr1;
409 : 8 : rtl::OUString aStr2;
410 [ + - ]: 8 : if (eType1 == CELLTYPE_STRING)
411 : 8 : aStr1 = ((ScStringCell*)pCell1)->GetString();
412 : : else
413 [ # # ]: 0 : GetString(nCell1Col, nCell1Row, aStr1);
414 [ + - ]: 8 : if (eType2 == CELLTYPE_STRING)
415 : 8 : aStr2 = ((ScStringCell*)pCell2)->GetString();
416 : : else
417 [ # # ]: 0 : GetString(nCell2Col, nCell2Row, aStr2);
418 : :
419 : 8 : bool bUserDef = aSortParam.bUserDef; // custom sort order
420 : 8 : bool bNaturalSort = aSortParam.bNaturalSort; // natural sort
421 : 8 : bool bCaseSens = aSortParam.bCaseSens; // case sensitivity
422 : :
423 [ - + ]: 8 : if (bUserDef)
424 : : {
425 [ # # ]: 0 : ScUserList* pList = ScGlobal::GetUserList();
426 [ # # ]: 0 : const ScUserListData* pData = (*pList)[aSortParam.nUserIndex];
427 : :
428 [ # # ]: 0 : if (pData)
429 : : {
430 [ # # ]: 0 : if ( bNaturalSort )
431 [ # # ][ # # ]: 0 : nRes = naturalsort::Compare( aStr1, aStr2, bCaseSens, pData, pSortCollator );
[ # # ][ # # ]
[ # # ]
432 : : else
433 : : {
434 [ # # ]: 0 : if ( bCaseSens )
435 [ # # ]: 0 : nRes = sal::static_int_cast<short>( pData->Compare(aStr1, aStr2) );
436 : : else
437 [ # # ]: 0 : nRes = sal::static_int_cast<short>( pData->ICompare(aStr1, aStr2) );
438 : : }
439 : : }
440 : : else
441 : 0 : bUserDef = false;
442 : :
443 : : }
444 [ + - ]: 8 : if (!bUserDef)
445 : : {
446 [ - + ]: 8 : if ( bNaturalSort )
447 [ # # ][ # # ]: 0 : nRes = naturalsort::Compare( aStr1, aStr2, bCaseSens, NULL, pSortCollator );
[ # # ][ # # ]
[ # # ]
448 : : else
449 [ + - ]: 8 : nRes = static_cast<short>( pSortCollator->compareString( aStr1, aStr2 ) );
450 : 8 : }
451 : : }
452 [ + + ]: 80 : else if ( bStr1 ) // String <-> Zahl
453 : 16 : nRes = 1; // Zahl vorne
454 [ + + ]: 64 : else if ( bStr2 ) // Zahl <-> String
455 : 18 : nRes = -1; // Zahl vorne
456 : : else // Zahlen untereinander
457 : : {
458 : : double nVal1;
459 : : double nVal2;
460 [ + - ]: 46 : if (eType1 == CELLTYPE_VALUE)
461 : 46 : nVal1 = ((ScValueCell*)pCell1)->GetValue();
462 [ # # ]: 0 : else if (eType1 == CELLTYPE_FORMULA)
463 [ # # ]: 0 : nVal1 = ((ScFormulaCell*)pCell1)->GetValue();
464 : : else
465 : 0 : nVal1 = 0;
466 [ + - ]: 46 : if (eType2 == CELLTYPE_VALUE)
467 : 46 : nVal2 = ((ScValueCell*)pCell2)->GetValue();
468 [ # # ]: 0 : else if (eType2 == CELLTYPE_FORMULA)
469 [ # # ]: 0 : nVal2 = ((ScFormulaCell*)pCell2)->GetValue();
470 : : else
471 : 0 : nVal2 = 0;
472 [ + + ]: 46 : if (nVal1 < nVal2)
473 : 14 : nRes = -1;
474 [ + + ]: 32 : else if (nVal1 > nVal2)
475 : 16 : nRes = 1;
476 : : }
477 [ + + ]: 88 : if ( !aSortParam.maKeyState[nSort].bAscending )
478 : 44 : nRes = -nRes;
479 : : }
480 : : else
481 : 1 : nRes = -1;
482 : : }
483 : : else
484 : : {
485 [ # # ]: 0 : if ( pCell2 )
486 : 0 : nRes = 1;
487 : : else
488 : 0 : nRes = 0; // beide leer
489 : : }
490 : 89 : return nRes;
491 : : }
492 : :
493 : 76 : short ScTable::Compare( ScSortInfoArray* pArray, SCCOLROW nIndex1, SCCOLROW nIndex2 ) const
494 : : {
495 : : short nRes;
496 : 76 : sal_uInt16 nSort = 0;
497 [ + + - + ]: 98 : do
[ - + ]
498 : : {
499 : 76 : ScSortInfo* pInfo1 = pArray->Get( nSort, nIndex1 );
500 : 76 : ScSortInfo* pInfo2 = pArray->Get( nSort, nIndex2 );
501 [ + - ]: 76 : if ( aSortParam.bByRow )
502 : : nRes = CompareCell( nSort,
503 : 76 : pInfo1->pCell, static_cast<SCCOL>(aSortParam.maKeyState[nSort].nField), pInfo1->nOrg,
504 : 152 : pInfo2->pCell, static_cast<SCCOL>(aSortParam.maKeyState[nSort].nField), pInfo2->nOrg );
505 : : else
506 : : nRes = CompareCell( nSort,
507 : 0 : pInfo1->pCell, static_cast<SCCOL>(pInfo1->nOrg), aSortParam.maKeyState[nSort].nField,
508 : 0 : pInfo2->pCell, static_cast<SCCOL>(pInfo2->nOrg), aSortParam.maKeyState[nSort].nField );
509 : 22 : } while ( nRes == 0 && ++nSort < pArray->GetUsedSorts() );
510 [ + + ]: 76 : if( nRes == 0 )
511 : : {
512 : 22 : ScSortInfo* pInfo1 = pArray->Get( 0, nIndex1 );
513 : 22 : ScSortInfo* pInfo2 = pArray->Get( 0, nIndex2 );
514 [ - + ]: 22 : if( pInfo1->nOrg < pInfo2->nOrg )
515 : 0 : nRes = -1;
516 [ - + ]: 22 : else if( pInfo1->nOrg > pInfo2->nOrg )
517 : 0 : nRes = 1;
518 : : }
519 : 76 : return nRes;
520 : : }
521 : :
522 : 28 : void ScTable::QuickSort( ScSortInfoArray* pArray, SCsCOLROW nLo, SCsCOLROW nHi )
523 : : {
524 [ + + ]: 28 : if ((nHi - nLo) == 1)
525 : : {
526 [ + + ]: 12 : if (Compare(pArray, nLo, nHi) > 0)
527 : 2 : pArray->Swap( nLo, nHi );
528 : : }
529 : : else
530 : : {
531 : 16 : SCsCOLROW ni = nLo;
532 : 16 : SCsCOLROW nj = nHi;
533 [ + + ]: 22 : do
534 : : {
535 [ + - ][ - + ]: 22 : while ((ni <= nHi) && (Compare(pArray, ni, nLo)) < 0)
[ - + ]
536 : 0 : ni++;
537 [ + - ][ + + ]: 42 : while ((nj >= nLo) && (Compare(pArray, nLo, nj)) < 0)
[ + + ]
538 : 20 : nj--;
539 [ + + ]: 22 : if (ni <= nj)
540 : : {
541 [ + - ]: 16 : if (ni != nj)
542 : 16 : pArray->Swap( ni, nj );
543 : 16 : ni++;
544 : 16 : nj--;
545 : : }
546 : : } while (ni < nj);
547 [ + + ]: 16 : if ((nj - nLo) < (nHi - ni))
548 : : {
549 [ + + ]: 14 : if (nLo < nj)
550 : 2 : QuickSort(pArray, nLo, nj);
551 [ + - ]: 14 : if (ni < nHi)
552 : 14 : QuickSort(pArray, ni, nHi);
553 : : }
554 : : else
555 : : {
556 [ + - ]: 2 : if (ni < nHi)
557 : 2 : QuickSort(pArray, ni, nHi);
558 [ + - ]: 2 : if (nLo < nj)
559 : 2 : QuickSort(pArray, nLo, nj);
560 : : }
561 : : }
562 : 28 : }
563 : :
564 : 0 : void ScTable::SwapCol(SCCOL nCol1, SCCOL nCol2)
565 : : {
566 [ # # ]: 0 : for (SCROW nRow = aSortParam.nRow1; nRow <= aSortParam.nRow2; nRow++)
567 : : {
568 [ # # ]: 0 : aCol[nCol1].SwapCell(nRow, aCol[nCol2]);
569 [ # # ]: 0 : if (aSortParam.bIncludePattern)
570 : : {
571 [ # # ]: 0 : const ScPatternAttr* pPat1 = GetPattern(nCol1, nRow);
572 [ # # ]: 0 : const ScPatternAttr* pPat2 = GetPattern(nCol2, nRow);
573 [ # # ]: 0 : if (pPat1 != pPat2)
574 : : {
575 [ # # ][ # # ]: 0 : pDocument->GetPool()->Put(*pPat1);
576 [ # # ]: 0 : SetPattern(nCol1, nRow, *pPat2, true);
577 [ # # ]: 0 : SetPattern(nCol2, nRow, *pPat1, true);
578 [ # # ][ # # ]: 0 : pDocument->GetPool()->Remove(*pPat1);
579 : : }
580 : : }
581 : : }
582 : :
583 [ # # ]: 0 : ScNotes aNoteMap(pDocument);
584 [ # # ]: 0 : ScNotes::iterator itr = maNotes.begin();
585 [ # # ][ # # ]: 0 : while(itr != maNotes.end())
[ # # ]
586 : : {
587 [ # # ]: 0 : SCCOL nCol = itr->first.first;
588 [ # # ]: 0 : SCROW nRow = itr->first.second;
589 [ # # ]: 0 : ScPostIt* pPostIt = itr->second;
590 [ # # ]: 0 : ++itr;
591 : :
592 [ # # ]: 0 : if (nCol == nCol1)
593 : : {
594 [ # # ]: 0 : aNoteMap.insert(nCol, nRow, pPostIt);
595 [ # # ]: 0 : maNotes.ReleaseNote(nCol2, nRow);
596 : : }
597 [ # # ]: 0 : else if (nCol == nCol2)
598 : : {
599 [ # # ]: 0 : aNoteMap.insert(nCol, nRow, pPostIt);
600 [ # # ]: 0 : maNotes.ReleaseNote(nCol1, nRow);
601 : :
602 : : }
603 : : }
604 : :
605 [ # # ]: 0 : itr = aNoteMap.begin();
606 [ # # ][ # # ]: 0 : while(itr != aNoteMap.end())
[ # # ]
607 : : {
608 : : //we can here assume that there is no note in the target location
609 [ # # ]: 0 : SCCOL nCol = itr->first.first;
610 [ # # ]: 0 : SCROW nRow = itr->first.second;
611 [ # # ]: 0 : ScPostIt* pPostIt = itr->second;
612 : :
613 [ # # ]: 0 : maNotes.insert(nCol, nRow, pPostIt);
614 [ # # ]: 0 : aNoteMap.ReleaseNote(nCol, nRow);
615 [ # # ]: 0 : }
616 : 0 : }
617 : :
618 : 18 : void ScTable::SwapRow(SCROW nRow1, SCROW nRow2)
619 : : {
620 [ + + ]: 90 : for (SCCOL nCol = aSortParam.nCol1; nCol <= aSortParam.nCol2; nCol++)
621 : : {
622 [ + - ]: 72 : aCol[nCol].SwapRow(nRow1, nRow2);
623 [ + - ]: 72 : if (aSortParam.bIncludePattern)
624 : : {
625 [ + - ]: 72 : const ScPatternAttr* pPat1 = GetPattern(nCol, nRow1);
626 [ + - ]: 72 : const ScPatternAttr* pPat2 = GetPattern(nCol, nRow2);
627 [ - + ]: 72 : if (pPat1 != pPat2)
628 : : {
629 [ # # ][ # # ]: 0 : pDocument->GetPool()->Put(*pPat1);
630 [ # # ]: 0 : SetPattern(nCol, nRow1, *pPat2, true);
631 [ # # ]: 0 : SetPattern(nCol, nRow2, *pPat1, true);
632 [ # # ][ # # ]: 0 : pDocument->GetPool()->Remove(*pPat1);
633 : : }
634 : : }
635 : : }
636 [ - + ]: 18 : if (bGlobalKeepQuery)
637 : : {
638 [ # # ]: 0 : bool bRow1Hidden = RowHidden(nRow1);
639 [ # # ]: 0 : bool bRow2Hidden = RowHidden(nRow2);
640 [ # # ]: 0 : SetRowHidden(nRow1, nRow1, bRow2Hidden);
641 [ # # ]: 0 : SetRowHidden(nRow2, nRow2, bRow1Hidden);
642 : :
643 [ # # ]: 0 : bool bRow1Filtered = RowFiltered(nRow1);
644 [ # # ]: 0 : bool bRow2Filtered = RowFiltered(nRow2);
645 [ # # ]: 0 : SetRowFiltered(nRow1, nRow1, bRow2Filtered);
646 [ # # ]: 0 : SetRowFiltered(nRow2, nRow2, bRow1Filtered);
647 : : }
648 : :
649 [ + - ]: 18 : ScNotes aNoteMap(pDocument);
650 [ + - ]: 18 : ScNotes::iterator itr = maNotes.begin();
651 [ + - ][ + - ]: 18 : while(itr != maNotes.end())
[ - + ]
652 : : {
653 [ # # ]: 0 : SCCOL nCol = itr->first.first;
654 [ # # ]: 0 : SCROW nRow = itr->first.second;
655 [ # # ]: 0 : ScPostIt* pPostIt = itr->second;
656 [ # # ]: 0 : ++itr;
657 : :
658 [ # # ]: 0 : if (nRow == nRow1)
659 : : {
660 [ # # ]: 0 : aNoteMap.insert(nCol, nRow, pPostIt);
661 [ # # ]: 0 : maNotes.ReleaseNote(nCol, nRow2);
662 : : }
663 [ # # ]: 0 : else if (nRow == nRow2)
664 : : {
665 [ # # ]: 0 : aNoteMap.insert(nCol, nRow, pPostIt);
666 [ # # ]: 0 : maNotes.ReleaseNote(nCol, nRow1);
667 : :
668 : : }
669 : : }
670 : :
671 [ + - ]: 18 : itr = aNoteMap.begin();
672 [ + - ][ + - ]: 18 : while(itr != aNoteMap.end())
[ - + ]
673 : : {
674 : : //we can here assume that there is no note in the target location
675 [ # # ]: 0 : SCCOL nCol = itr->first.first;
676 [ # # ]: 0 : SCROW nRow = itr->first.second;
677 [ # # ]: 0 : ScPostIt* pPostIt = itr->second;
678 : :
679 [ # # ]: 0 : maNotes.insert(nCol, nRow, pPostIt);
680 [ # # ]: 0 : aNoteMap.ReleaseNote(nCol, nRow);
681 [ + - ]: 18 : }
682 : 18 : }
683 : :
684 : 13 : short ScTable::Compare(SCCOLROW nIndex1, SCCOLROW nIndex2) const
685 : : {
686 : : short nRes;
687 : 13 : sal_uInt16 nSort = 0;
688 : 13 : const sal_uInt32 nMaxSorts = aSortParam.GetSortKeyCount();
689 [ + - ]: 13 : if (aSortParam.bByRow)
690 : : {
691 [ - + # # ]: 13 : do
[ - + ][ + + ]
692 : : {
693 : 13 : SCCOL nCol = static_cast<SCCOL>(aSortParam.maKeyState[nSort].nField);
694 : 13 : ScBaseCell* pCell1 = aCol[nCol].GetCell( nIndex1 );
695 : 13 : ScBaseCell* pCell2 = aCol[nCol].GetCell( nIndex2 );
696 : 13 : nRes = CompareCell( nSort, pCell1, nCol, nIndex1, pCell2, nCol, nIndex2 );
697 : 0 : } while ( nRes == 0 && ++nSort < nMaxSorts && aSortParam.maKeyState[nSort].bDoSort );
698 : : }
699 : : else
700 : : {
701 [ # # # # ]: 0 : do
[ # # ][ # # ]
702 : : {
703 : 0 : SCROW nRow = aSortParam.maKeyState[nSort].nField;
704 : 0 : ScBaseCell* pCell1 = aCol[nIndex1].GetCell( nRow );
705 : 0 : ScBaseCell* pCell2 = aCol[nIndex2].GetCell( nRow );
706 : : nRes = CompareCell( nSort, pCell1, static_cast<SCCOL>(nIndex1),
707 : 0 : nRow, pCell2, static_cast<SCCOL>(nIndex2), nRow );
708 : 0 : } while ( nRes == 0 && ++nSort < nMaxSorts && aSortParam.maKeyState[nSort].bDoSort );
709 : : }
710 : 13 : return nRes;
711 : : }
712 : :
713 : 10 : bool ScTable::IsSorted( SCCOLROW nStart, SCCOLROW nEnd ) const // ueber aSortParam
714 : : {
715 [ + + ]: 15 : for (SCCOLROW i=nStart; i<nEnd; i++)
716 : : {
717 [ + + ]: 13 : if (Compare( i, i+1 ) > 0)
718 : 8 : return false;
719 : : }
720 : 10 : return true;
721 : : }
722 : :
723 : 0 : void ScTable::DecoladeRow( ScSortInfoArray* pArray, SCROW nRow1, SCROW nRow2 )
724 : : {
725 : : SCROW nRow;
726 : 0 : SCROW nMax = nRow2 - nRow1;
727 [ # # ]: 0 : for (SCROW i = nRow1; (i + 4) <= nRow2; i += 4)
728 : : {
729 : 0 : nRow = rand() % nMax;
730 : 0 : pArray->Swap(i, nRow1 + nRow);
731 : : }
732 : 0 : }
733 : :
734 : 10 : void ScTable::Sort(const ScSortParam& rSortParam, bool bKeepQuery)
735 : : {
736 : 10 : aSortParam = rSortParam;
737 : 10 : InitSortCollator( rSortParam );
738 : 10 : bGlobalKeepQuery = bKeepQuery;
739 [ + - ]: 10 : if (rSortParam.bByRow)
740 : : {
741 : 10 : SCROW nLastRow = 0;
742 [ + + ]: 50 : for (SCCOL nCol = aSortParam.nCol1; nCol <= aSortParam.nCol2; nCol++)
743 : 40 : nLastRow = Max(nLastRow, aCol[nCol].GetLastDataPos());
744 : 10 : nLastRow = Min(nLastRow, aSortParam.nRow2);
745 : : SCROW nRow1 = (rSortParam.bHasHeader ?
746 [ + + ]: 10 : aSortParam.nRow1 + 1 : aSortParam.nRow1);
747 [ + + ]: 10 : if (!IsSorted(nRow1, nLastRow))
748 : : {
749 : : ScProgress aProgress( pDocument->GetDocumentShell(),
750 [ + - ][ + - ]: 8 : ScGlobal::GetRscString(STR_PROGRESS_SORTING), nLastRow - nRow1 );
751 [ + - ]: 8 : ScSortInfoArray* pArray = CreateSortInfoArray( nRow1, nLastRow );
752 [ - + ]: 8 : if ( nLastRow - nRow1 > 255 )
753 : 0 : DecoladeRow( pArray, nRow1, nLastRow );
754 [ + - ]: 8 : QuickSort( pArray, nRow1, nLastRow );
755 [ + - ]: 8 : SortReorder( pArray, aProgress );
756 [ + - ][ + - ]: 8 : delete pArray;
757 : : // #i59745# update position of caption objects of cell notes
758 [ + - ][ + - ]: 8 : ScNoteUtil::UpdateCaptionPositions( *pDocument, ScRange( aSortParam.nCol1, nRow1, nTab, aSortParam.nCol2, nLastRow, nTab ) );
759 : : }
760 : : }
761 : : else
762 : : {
763 : : SCCOL nLastCol;
764 [ # # # # ]: 0 : for (nLastCol = aSortParam.nCol2;
[ # # ]
765 : 0 : (nLastCol > aSortParam.nCol1) && aCol[nLastCol].IsEmptyBlock(aSortParam.nRow1, aSortParam.nRow2); nLastCol--)
766 : : {
767 : : }
768 : : SCCOL nCol1 = (rSortParam.bHasHeader ?
769 [ # # ]: 0 : aSortParam.nCol1 + 1 : aSortParam.nCol1);
770 [ # # ]: 0 : if (!IsSorted(nCol1, nLastCol))
771 : : {
772 : : ScProgress aProgress( pDocument->GetDocumentShell(),
773 [ # # ][ # # ]: 0 : ScGlobal::GetRscString(STR_PROGRESS_SORTING), nLastCol - nCol1 );
774 [ # # ]: 0 : ScSortInfoArray* pArray = CreateSortInfoArray( nCol1, nLastCol );
775 [ # # ]: 0 : QuickSort( pArray, nCol1, nLastCol );
776 [ # # ]: 0 : SortReorder( pArray, aProgress );
777 [ # # ][ # # ]: 0 : delete pArray;
778 : : // #i59745# update position of caption objects of cell notes
779 [ # # ][ # # ]: 0 : ScNoteUtil::UpdateCaptionPositions( *pDocument, ScRange( nCol1, aSortParam.nRow1, nTab, nLastCol, aSortParam.nRow2, nTab ) );
780 : : }
781 : : }
782 : 10 : DestroySortCollator();
783 : 10 : }
784 : :
785 : :
786 : : // Testen, ob beim Loeschen von Zwischenergebnissen andere Daten mit geloescht werden
787 : : // (fuer Hinweis-Box)
788 : :
789 : 4 : bool ScTable::TestRemoveSubTotals( const ScSubTotalParam& rParam )
790 : : {
791 : 4 : SCCOL nStartCol = rParam.nCol1;
792 : 4 : SCROW nStartRow = rParam.nRow1 + 1; // Header
793 : 4 : SCCOL nEndCol = rParam.nCol2;
794 : 4 : SCROW nEndRow = rParam.nRow2;
795 : :
796 : : SCCOL nCol;
797 : : SCROW nRow;
798 : : ScBaseCell* pCell;
799 : :
800 : 4 : bool bWillDelete = false;
801 [ + + ][ + - ]: 20 : for ( nCol=nStartCol; nCol<=nEndCol && !bWillDelete; nCol++ )
[ + + ]
802 : : {
803 [ + - ]: 16 : ScColumnIterator aIter( &aCol[nCol],nStartRow,nEndRow );
804 [ + - ][ + + ]: 39 : while ( aIter.Next( nRow, pCell ) && !bWillDelete )
[ + - ][ + + ]
805 : : {
806 [ + + ]: 23 : if ( pCell->GetCellType() == CELLTYPE_FORMULA )
807 [ + - ][ + - ]: 3 : if (((ScFormulaCell*)pCell)->IsSubTotal())
808 : : {
809 [ + + ]: 3075 : for (SCCOL nTestCol=0; nTestCol<=MAXCOL; nTestCol++)
810 [ + - ][ + + ]: 3072 : if (nTestCol<nStartCol || nTestCol>nEndCol)
811 [ + - ][ - + ]: 3060 : if (aCol[nTestCol].HasDataAt(nRow))
812 : 0 : bWillDelete = true;
813 : : }
814 : : }
815 [ + - ]: 16 : }
816 : 4 : return bWillDelete;
817 : : }
818 : :
819 : : // alte Ergebnisse loeschen
820 : : // rParam.nRow2 wird veraendert !
821 : :
822 : 4 : void ScTable::RemoveSubTotals( ScSubTotalParam& rParam )
823 : : {
824 : 4 : SCCOL nStartCol = rParam.nCol1;
825 : 4 : SCROW nStartRow = rParam.nRow1 + 1; // Header
826 : 4 : SCCOL nEndCol = rParam.nCol2;
827 : 4 : SCROW nEndRow = rParam.nRow2; // wird veraendert
828 : :
829 : : SCCOL nCol;
830 : : SCROW nRow;
831 : : ScBaseCell* pCell;
832 : :
833 [ + + ]: 20 : for ( nCol=nStartCol; nCol<=nEndCol; nCol++ )
834 : : {
835 [ + - ]: 16 : ScColumnIterator aIter( &aCol[nCol],nStartRow,nEndRow );
836 [ + - ][ + + ]: 39 : while ( aIter.Next( nRow, pCell ) )
837 : : {
838 [ + + ]: 23 : if ( pCell->GetCellType() == CELLTYPE_FORMULA )
839 [ + - ][ + - ]: 3 : if (((ScFormulaCell*)pCell)->IsSubTotal())
840 : : {
841 [ + - ]: 3 : RemoveRowBreak(nRow+1, false, true);
842 [ + - ]: 3 : pDocument->DeleteRow( 0,nTab, MAXCOL,nTab, nRow, 1 );
843 : 3 : --nEndRow;
844 [ + - ][ + - ]: 3 : aIter = ScColumnIterator( &aCol[nCol],nRow,nEndRow );
845 : : }
846 : : }
847 [ + - ]: 16 : }
848 : :
849 : 4 : rParam.nRow2 = nEndRow; // neues Ende
850 : 4 : }
851 : :
852 : : // harte Zahlenformate loeschen (fuer Ergebnisformeln)
853 : :
854 : 0 : void lcl_RemoveNumberFormat( ScTable* pTab, SCCOL nCol, SCROW nRow )
855 : : {
856 : 0 : const ScPatternAttr* pPattern = pTab->GetPattern( nCol, nRow );
857 [ # # ]: 0 : if ( pPattern->GetItemSet().GetItemState( ATTR_VALUE_FORMAT, false )
858 : : == SFX_ITEM_SET )
859 : : {
860 [ # # ]: 0 : ScPatternAttr aNewPattern( *pPattern );
861 : 0 : SfxItemSet& rSet = aNewPattern.GetItemSet();
862 [ # # ]: 0 : rSet.ClearItem( ATTR_VALUE_FORMAT );
863 [ # # ]: 0 : rSet.ClearItem( ATTR_LANGUAGE_FORMAT );
864 [ # # ][ # # ]: 0 : pTab->SetPattern( nCol, nRow, aNewPattern, true );
865 : : }
866 : 0 : }
867 : :
868 : :
869 : : // at least MSC needs this at linkage level to be able to use it in a template
870 : : typedef struct lcl_ScTable_DoSubTotals_RowEntry
871 : : {
872 : : sal_uInt16 nGroupNo;
873 : : SCROW nSubStartRow;
874 : : SCROW nDestRow;
875 : : SCROW nFuncStart;
876 : : SCROW nFuncEnd;
877 : : } RowEntry;
878 : :
879 : : // neue Zwischenergebnisse
880 : : // rParam.nRow2 wird veraendert !
881 : :
882 : 2 : bool ScTable::DoSubTotals( ScSubTotalParam& rParam )
883 : : {
884 : 2 : SCCOL nStartCol = rParam.nCol1;
885 : 2 : SCROW nStartRow = rParam.nRow1 + 1; // Header
886 : 2 : SCCOL nEndCol = rParam.nCol2;
887 : 2 : SCROW nEndRow = rParam.nRow2; // wird veraendert
888 : : sal_uInt16 i;
889 : :
890 : : // Leerzeilen am Ende weglassen,
891 : : // damit alle Ueberlaeufe (MAXROW) bei InsertRow gefunden werden (#35180#)
892 : : // Wenn sortiert wurde, sind alle Leerzeilen am Ende.
893 [ + - ]: 2 : SCSIZE nEmpty = GetEmptyLinesInBlock( nStartCol, nStartRow, nEndCol, nEndRow, DIR_BOTTOM );
894 : 2 : nEndRow -= nEmpty;
895 : :
896 : 2 : sal_uInt16 nLevelCount = 0; // Anzahl Gruppierungen
897 : 2 : bool bDoThis = true;
898 [ + - ][ + + ]: 6 : for (i=0; i<MAXSUBTOTAL && bDoThis; i++)
[ + + ]
899 [ + + ]: 4 : if (rParam.bGroupActive[i])
900 : 2 : nLevelCount = i+1;
901 : : else
902 : 2 : bDoThis = false;
903 : :
904 [ - + ]: 2 : if (nLevelCount==0) // nichts tun
905 : 0 : return true;
906 : :
907 : 2 : SCCOL* nGroupCol = rParam.nField; // Spalten nach denen
908 : : // gruppiert wird
909 : :
910 : : // Durch (leer) als eigene Kategorie muss immer auf
911 : : // Teilergebniszeilen aus den anderen Spalten getestet werden
912 : : // (frueher nur, wenn eine Spalte mehrfach vorkam)
913 : 2 : bool bTestPrevSub = ( nLevelCount > 1 );
914 : :
915 : 2 : rtl::OUString aSubString;
916 [ + - ]: 2 : String aOutString;
917 : :
918 : 2 : bool bIgnoreCase = !rParam.bCaseSens;
919 : :
920 : : String *pCompString[MAXSUBTOTAL]; // Pointer wegen Compiler-Problemen
921 [ + + ]: 8 : for (i=0; i<MAXSUBTOTAL; i++)
922 [ + - ][ + - ]: 6 : pCompString[i] = new String;
923 : :
924 : : //! sortieren?
925 : :
926 [ + - ]: 2 : ScStyleSheet* pStyle = (ScStyleSheet*) pDocument->GetStyleSheetPool()->Find(
927 [ + - ][ + - ]: 2 : ScGlobal::GetRscString(STR_STYLENAME_RESULT), SFX_STYLE_FAMILY_PARA );
928 : :
929 : 2 : bool bSpaceLeft = true; // Erfolg beim Einfuegen?
930 : :
931 : : // For performance reasons collect formula entries so their
932 : : // references don't have to be tested for updates each time a new row is
933 : : // inserted
934 : : RowEntry aRowEntry;
935 [ + - ]: 2 : ::std::vector< RowEntry > aRowVector;
936 : :
937 [ + + ][ + - ]: 6 : for (sal_uInt16 nLevel=0; nLevel<=nLevelCount && bSpaceLeft; nLevel++) // incl. Gesamtergebnis
[ + + ]
938 : : {
939 : 4 : bool bTotal = ( nLevel == nLevelCount );
940 [ + + ]: 4 : aRowEntry.nGroupNo = bTotal ? 0 : (nLevelCount-nLevel-1);
941 : :
942 : : // how many results per level
943 : 4 : SCCOL nResCount = rParam.nSubTotals[aRowEntry.nGroupNo];
944 : : // result functions
945 : 4 : ScSubTotalFunc* eResFunc = rParam.pFunctions[aRowEntry.nGroupNo];
946 : :
947 [ + - ]: 4 : if (nResCount > 0) // sonst nur sortieren
948 : : {
949 [ + + ]: 8 : for (i=0; i<=aRowEntry.nGroupNo; i++)
950 : : {
951 [ + - ]: 4 : GetString( nGroupCol[i], nStartRow, aSubString );
952 [ + - ]: 4 : if ( bIgnoreCase )
953 [ + - ][ + - ]: 4 : *pCompString[i] = ScGlobal::pCharClass->uppercase( aSubString );
954 : : else
955 [ # # ]: 0 : *pCompString[i] = aSubString;
956 : : } // aSubString bleibt auf dem letzten stehen
957 : :
958 : 4 : bool bBlockVis = false; // Gruppe eingeblendet?
959 : 4 : aRowEntry.nSubStartRow = nStartRow;
960 [ + + ][ + - ]: 21 : for (SCROW nRow=nStartRow; nRow<=nEndRow+1 && bSpaceLeft; nRow++)
[ + + ]
961 : : {
962 : : bool bChanged;
963 [ + + ]: 17 : if (nRow>nEndRow)
964 : 4 : bChanged = true;
965 : : else
966 : : {
967 : 13 : bChanged = false;
968 [ + + ]: 13 : if (!bTotal)
969 : : {
970 : 5 : rtl::OUString aString;
971 [ + + ][ + - ]: 10 : for (i=0; i<=aRowEntry.nGroupNo && !bChanged; i++)
[ + + ]
972 : : {
973 [ + - ]: 5 : GetString( nGroupCol[i], nRow, aString );
974 [ + - ]: 5 : if (bIgnoreCase)
975 [ + - ]: 5 : aString = ScGlobal::pCharClass->uppercase(aString);
976 : : // wenn sortiert, ist "leer" eine eigene Gruppe
977 : : // sonst sind leere Zellen unten erlaubt
978 : 5 : bChanged = ( ( !aString.isEmpty() || rParam.bDoSort ) &&
979 [ + - ][ + - ]: 5 : aString != rtl::OUString(*pCompString[i]) );
[ + + ][ + - ]
[ # # ][ + + ]
980 : : }
981 [ + + ][ - + ]: 5 : if ( bChanged && bTestPrevSub )
982 : : {
983 : : // No group change on rows that will contain subtotal formulas
984 [ # # ][ # # ]: 0 : for ( ::std::vector< RowEntry >::const_iterator
985 [ # # ]: 0 : iEntry( aRowVector.begin());
986 : 0 : iEntry != aRowVector.end(); ++iEntry)
987 : : {
988 [ # # ]: 0 : if ( iEntry->nDestRow == nRow )
989 : : {
990 : 0 : bChanged = false;
991 : 0 : break;
992 : : }
993 : : }
994 : 5 : }
995 : : }
996 : : }
997 [ + + ]: 17 : if ( bChanged )
998 : : {
999 : 5 : aRowEntry.nDestRow = nRow;
1000 : 5 : aRowEntry.nFuncStart = aRowEntry.nSubStartRow;
1001 : 5 : aRowEntry.nFuncEnd = nRow-1;
1002 : :
1003 : : bSpaceLeft = pDocument->InsertRow( 0, nTab, MAXCOL, nTab,
1004 [ + - ]: 5 : aRowEntry.nDestRow, 1 );
1005 [ + - ]: 5 : DBShowRow( aRowEntry.nDestRow, bBlockVis );
1006 : 5 : bBlockVis = false;
1007 [ - + ][ # # ]: 5 : if ( rParam.bPagebreak && nRow < MAXROW &&
[ # # ][ # # ]
1008 : : aRowEntry.nSubStartRow != nStartRow && nLevel == 0)
1009 [ # # ]: 0 : SetRowBreak(aRowEntry.nSubStartRow, false, true);
1010 : :
1011 [ + - ]: 5 : if (bSpaceLeft)
1012 : : {
1013 [ + - ][ + + ]: 18 : for ( ::std::vector< RowEntry >::iterator iMove(
1014 : 5 : aRowVector.begin() );
1015 : 9 : iMove != aRowVector.end(); ++iMove)
1016 : : {
1017 [ - + ]: 4 : if ( aRowEntry.nDestRow <= iMove->nSubStartRow )
1018 : 0 : ++iMove->nSubStartRow;
1019 [ - + ]: 4 : if ( aRowEntry.nDestRow <= iMove->nDestRow )
1020 : 0 : ++iMove->nDestRow;
1021 [ - + ]: 4 : if ( aRowEntry.nDestRow <= iMove->nFuncStart )
1022 : 0 : ++iMove->nFuncStart;
1023 [ - + ]: 4 : if ( aRowEntry.nDestRow <= iMove->nFuncEnd )
1024 : 0 : ++iMove->nFuncEnd;
1025 : : }
1026 : : // collect formula positions
1027 [ + - ]: 5 : aRowVector.push_back( aRowEntry );
1028 : :
1029 [ + + ]: 5 : if (bTotal) // "Gesamtergebnis"
1030 [ + - ][ + - ]: 2 : aOutString = ScGlobal::GetRscString( STR_TABLE_GESAMTERGEBNIS );
1031 : : else
1032 : : { // " Ergebnis"
1033 [ + - ]: 3 : aOutString = aSubString;
1034 [ + + ]: 3 : if (!aOutString.Len())
1035 [ + - ][ + - ]: 1 : aOutString = ScGlobal::GetRscString( STR_EMPTYDATA );
1036 [ + - ]: 3 : aOutString += ' ';
1037 : 3 : sal_uInt16 nStrId = STR_TABLE_ERGEBNIS;
1038 [ + - ]: 3 : if ( nResCount == 1 )
1039 [ - - - - : 3 : switch ( eResFunc[0] )
- - + -
- ]
1040 : : {
1041 : 0 : case SUBTOTAL_FUNC_AVE: nStrId = STR_FUN_TEXT_AVG; break;
1042 : : case SUBTOTAL_FUNC_CNT:
1043 : 0 : case SUBTOTAL_FUNC_CNT2: nStrId = STR_FUN_TEXT_COUNT; break;
1044 : 0 : case SUBTOTAL_FUNC_MAX: nStrId = STR_FUN_TEXT_MAX; break;
1045 : 0 : case SUBTOTAL_FUNC_MIN: nStrId = STR_FUN_TEXT_MIN; break;
1046 : 0 : case SUBTOTAL_FUNC_PROD: nStrId = STR_FUN_TEXT_PRODUCT; break;
1047 : : case SUBTOTAL_FUNC_STD:
1048 : 0 : case SUBTOTAL_FUNC_STDP: nStrId = STR_FUN_TEXT_STDDEV; break;
1049 : 3 : case SUBTOTAL_FUNC_SUM: nStrId = STR_FUN_TEXT_SUM; break;
1050 : : case SUBTOTAL_FUNC_VAR:
1051 : 3 : case SUBTOTAL_FUNC_VARP: nStrId = STR_FUN_TEXT_VAR; break;
1052 : : default:
1053 : : {
1054 : : // added to avoid warnings
1055 : : }
1056 : : }
1057 [ + - ][ + - ]: 3 : aOutString += ScGlobal::GetRscString( nStrId );
1058 : : }
1059 [ + - ]: 5 : SetString( nGroupCol[aRowEntry.nGroupNo], aRowEntry.nDestRow, nTab, aOutString );
1060 [ + - ]: 5 : ApplyStyle( nGroupCol[aRowEntry.nGroupNo], aRowEntry.nDestRow, *pStyle );
1061 : :
1062 : 5 : ++nRow;
1063 : 5 : ++nEndRow;
1064 : 5 : aRowEntry.nSubStartRow = nRow;
1065 [ + + ]: 10 : for (i=0; i<=aRowEntry.nGroupNo; i++)
1066 : : {
1067 [ + - ]: 5 : GetString( nGroupCol[i], nRow, aSubString );
1068 [ + - ]: 5 : if ( bIgnoreCase )
1069 [ + - ][ + - ]: 5 : *pCompString[i] = ScGlobal::pCharClass->uppercase( aSubString );
1070 : : else
1071 [ # # ]: 0 : *pCompString[i] = aSubString;
1072 : : }
1073 : : }
1074 : : }
1075 [ + - ]: 17 : bBlockVis = !RowFiltered(nRow);
1076 : : }
1077 : : }
1078 : : }
1079 : :
1080 : : // now insert the formulas
1081 : : ScComplexRefData aRef;
1082 : 2 : aRef.InitFlags();
1083 : 2 : aRef.Ref1.nTab = nTab;
1084 : 2 : aRef.Ref2.nTab = nTab;
1085 [ + - ][ + + ]: 14 : for ( ::std::vector< RowEntry >::const_iterator iEntry( aRowVector.begin());
[ + - ]
1086 : 7 : iEntry != aRowVector.end(); ++iEntry)
1087 : : {
1088 : 5 : SCCOL nResCount = rParam.nSubTotals[iEntry->nGroupNo];
1089 : 5 : SCCOL* nResCols = rParam.pSubTotals[iEntry->nGroupNo];
1090 : 5 : ScSubTotalFunc* eResFunc = rParam.pFunctions[iEntry->nGroupNo];
1091 [ + + ]: 10 : for ( SCCOL nResult=0; nResult < nResCount; ++nResult )
1092 : : {
1093 : 5 : aRef.Ref1.nCol = nResCols[nResult];
1094 : 5 : aRef.Ref1.nRow = iEntry->nFuncStart;
1095 : 5 : aRef.Ref2.nCol = nResCols[nResult];
1096 : 5 : aRef.Ref2.nRow = iEntry->nFuncEnd;
1097 : :
1098 [ + - ]: 5 : ScTokenArray aArr;
1099 [ + - ]: 5 : aArr.AddOpCode( ocSubTotal );
1100 [ + - ]: 5 : aArr.AddOpCode( ocOpen );
1101 [ + - ]: 5 : aArr.AddDouble( (double) eResFunc[nResult] );
1102 [ + - ]: 5 : aArr.AddOpCode( ocSep );
1103 [ + - ]: 5 : aArr.AddDoubleReference( aRef );
1104 [ + - ]: 5 : aArr.AddOpCode( ocClose );
1105 [ + - ]: 5 : aArr.AddOpCode( ocStop );
1106 : : ScBaseCell* pCell = new ScFormulaCell( pDocument, ScAddress(
1107 [ + - ][ + - ]: 5 : nResCols[nResult], iEntry->nDestRow, nTab), &aArr );
[ + - ]
1108 [ + - ]: 5 : PutCell( nResCols[nResult], iEntry->nDestRow, pCell );
1109 : :
1110 [ - + ]: 5 : if ( nResCols[nResult] != nGroupCol[iEntry->nGroupNo] )
1111 : : {
1112 [ # # ]: 0 : ApplyStyle( nResCols[nResult], iEntry->nDestRow, *pStyle );
1113 : :
1114 : : // Zahlformat loeschen
1115 [ # # ]: 0 : lcl_RemoveNumberFormat( this, nResCols[nResult], iEntry->nDestRow );
1116 : : }
1117 [ + - ]: 5 : }
1118 : :
1119 : : }
1120 : :
1121 : : //! je nach Einstellung Zwischensummen-Zeilen nach oben verschieben ?
1122 : :
1123 : : //! Outlines direkt erzeugen?
1124 : :
1125 [ + - ]: 2 : if (bSpaceLeft)
1126 [ + - ]: 2 : DoAutoOutline( nStartCol, nStartRow, nEndCol, nEndRow );
1127 : :
1128 [ + + ]: 8 : for (i=0; i<MAXSUBTOTAL; i++)
1129 [ + - ][ + - ]: 6 : delete pCompString[i];
1130 : :
1131 : 2 : rParam.nRow2 = nEndRow; // neues Ende
1132 [ + - ]: 2 : return bSpaceLeft;
1133 : : }
1134 : :
1135 : : namespace {
1136 : :
1137 : : class QueryEvaluator
1138 : : {
1139 : : const ScDocument& mrDoc;
1140 : : const ScTable& mrTab;
1141 : : const ScQueryParam& mrParam;
1142 : : const bool* mpTestEqualCondition;
1143 : : utl::TransliterationWrapper* mpTransliteration;
1144 : : CollatorWrapper* mpCollator;
1145 : : const bool mbMatchWholeCell;
1146 : :
1147 : 573 : bool isPartialTextMatchOp(const ScQueryEntry& rEntry) const
1148 : : {
1149 [ - + ]: 573 : switch (rEntry.eOp)
1150 : : {
1151 : : // these operators can only be used with textural comparisons.
1152 : : case SC_CONTAINS:
1153 : : case SC_DOES_NOT_CONTAIN:
1154 : : case SC_BEGINS_WITH:
1155 : : case SC_ENDS_WITH:
1156 : : case SC_DOES_NOT_BEGIN_WITH:
1157 : : case SC_DOES_NOT_END_WITH:
1158 : 0 : return true;
1159 : : default:
1160 : : ;
1161 : : }
1162 : 573 : return false;
1163 : : }
1164 : :
1165 : 402 : bool isTextMatchOp(const ScQueryEntry& rEntry) const
1166 : : {
1167 [ - + ]: 402 : if (isPartialTextMatchOp(rEntry))
1168 : 0 : return true;
1169 : :
1170 [ + + ]: 402 : switch (rEntry.eOp)
1171 : : {
1172 : : // these operators can be used for either textural or value comparison.
1173 : : case SC_EQUAL:
1174 : : case SC_NOT_EQUAL:
1175 : 204 : return true;
1176 : : default:
1177 : : ;
1178 : : }
1179 : 402 : return false;
1180 : : }
1181 : :
1182 : 171 : bool isRealRegExp(const ScQueryEntry& rEntry) const
1183 : : {
1184 [ + - ]: 171 : if (!mrParam.bRegExp)
1185 : 171 : return false;
1186 : :
1187 : 171 : return isTextMatchOp(rEntry);
1188 : : }
1189 : :
1190 : 171 : bool isTestRegExp(const ScQueryEntry& rEntry) const
1191 : : {
1192 [ + + ]: 171 : if (!mpTestEqualCondition)
1193 : 108 : return false;
1194 : :
1195 [ + - ]: 63 : if (!mrParam.bRegExp)
1196 : 63 : return false;
1197 : :
1198 [ # # ][ # # ]: 171 : return (rEntry.eOp == SC_LESS_EQUAL || rEntry.eOp == SC_GREATER_EQUAL);
1199 : : }
1200 : :
1201 : : public:
1202 : 1033 : QueryEvaluator(const ScDocument& rDoc, const ScTable& rTab, const ScQueryParam& rParam,
1203 : : const bool* pTestEqualCondition) :
1204 : : mrDoc(rDoc),
1205 : : mrTab(rTab),
1206 : : mrParam(rParam),
1207 : : mpTestEqualCondition(pTestEqualCondition),
1208 : 1033 : mbMatchWholeCell(rDoc.GetDocOptions().IsMatchWholeCell())
1209 : : {
1210 [ - + ]: 1033 : if (rParam.bCaseSens)
1211 : : {
1212 : 0 : mpTransliteration = ScGlobal::GetCaseTransliteration();
1213 : 0 : mpCollator = ScGlobal::GetCaseCollator();
1214 : : }
1215 : : else
1216 : : {
1217 : 1033 : mpTransliteration = ScGlobal::GetpTransliteration();
1218 : 1033 : mpCollator = ScGlobal::GetCollator();
1219 : : }
1220 : 1033 : }
1221 : :
1222 : 1110 : bool isQueryByValue(
1223 : : const ScQueryEntry::Item& rItem, SCCOL nCol, SCROW nRow, const ScBaseCell* pCell)
1224 : : {
1225 [ + + ]: 1110 : if (rItem.meType == ScQueryEntry::ByString)
1226 : 135 : return false;
1227 : :
1228 [ + + ]: 975 : if (pCell)
1229 : : {
1230 [ - + ]: 972 : if (pCell->GetErrorCode())
1231 : : // Error values are compared as string.
1232 : 0 : return false;
1233 : :
1234 : 972 : return pCell->HasValueData();
1235 : : }
1236 : :
1237 : 1110 : return mrTab.HasValueData(nCol, nRow);
1238 : : }
1239 : :
1240 : 231 : bool isQueryByString(
1241 : : const ScQueryEntry& rEntry, const ScQueryEntry::Item& rItem,
1242 : : SCCOL nCol, SCROW nRow, const ScBaseCell* pCell)
1243 : : {
1244 [ + + ]: 231 : if (isTextMatchOp(rEntry))
1245 : 102 : return true;
1246 : :
1247 [ + + ]: 129 : if (rItem.meType != ScQueryEntry::ByString)
1248 : 48 : return false;
1249 : :
1250 [ + + ]: 81 : if (pCell)
1251 : 78 : return pCell->HasStringData();
1252 : :
1253 : 231 : return mrTab.HasStringData(nCol, nRow);
1254 : : }
1255 : :
1256 : 879 : std::pair<bool,bool> compareByValue(
1257 : : const ScBaseCell* pCell, SCCOL nCol, SCROW nRow,
1258 : : const ScQueryEntry& rEntry, const ScQueryEntry::Item& rItem)
1259 : : {
1260 : 879 : bool bOk = false;
1261 : 879 : bool bTestEqual = false;
1262 : : double nCellVal;
1263 [ + - ]: 879 : if ( pCell )
1264 : : {
1265 [ + + - ]: 879 : switch ( pCell->GetCellType() )
1266 : : {
1267 : : case CELLTYPE_VALUE :
1268 : 849 : nCellVal = ((ScValueCell*)pCell)->GetValue();
1269 : 849 : break;
1270 : : case CELLTYPE_FORMULA :
1271 [ + - ][ + - ]: 30 : nCellVal = ((ScFormulaCell*)pCell)->GetValue();
1272 : 30 : break;
1273 : : default:
1274 : 879 : nCellVal = 0.0;
1275 : : }
1276 : :
1277 : : }
1278 : : else
1279 [ # # ]: 0 : nCellVal = mrTab.GetValue(nCol, nRow);
1280 : :
1281 : : /* NOTE: lcl_PrepareQuery() prepares a filter query such that if a
1282 : : * date+time format was queried rEntry.bQueryByDate is not set. In
1283 : : * case other queries wanted to use this mechanism they should do
1284 : : * the same, in other words only if rEntry.nVal is an integer value
1285 : : * rEntry.bQueryByDate should be true and the time fraction be
1286 : : * stripped here. */
1287 [ - + ]: 879 : if (rItem.meType == ScQueryEntry::ByDate)
1288 : : {
1289 [ # # ]: 0 : sal_uInt32 nNumFmt = mrTab.GetNumberFormat(nCol, nRow);
1290 [ # # ][ # # ]: 0 : const SvNumberformat* pEntry = mrDoc.GetFormatTable()->GetEntry(nNumFmt);
1291 [ # # ]: 0 : if (pEntry)
1292 : : {
1293 : 0 : short nNumFmtType = pEntry->GetType();
1294 : : /* NOTE: Omitting the check for absence of
1295 : : * NUMBERFORMAT_TIME would include also date+time formatted
1296 : : * values of the same day. That may be desired in some
1297 : : * cases, querying all time values of a day, but confusing
1298 : : * in other cases. A user can always setup a standard
1299 : : * filter query for x >= date AND x < date+1 */
1300 [ # # ][ # # ]: 0 : if ((nNumFmtType & NUMBERFORMAT_DATE) && !(nNumFmtType & NUMBERFORMAT_TIME))
1301 : : {
1302 : : // The format is of date type. Strip off the time
1303 : : // element.
1304 : 0 : nCellVal = ::rtl::math::approxFloor(nCellVal);
1305 : : }
1306 : : }
1307 : : }
1308 : :
1309 [ + + + + : 879 : switch (rEntry.eOp)
+ - - ]
1310 : : {
1311 : : case SC_EQUAL :
1312 : 339 : bOk = ::rtl::math::approxEqual(nCellVal, rItem.mfVal);
1313 : 339 : break;
1314 : : case SC_LESS :
1315 [ + + ][ + - ]: 45 : bOk = (nCellVal < rItem.mfVal) && !::rtl::math::approxEqual(nCellVal, rItem.mfVal);
1316 : 45 : break;
1317 : : case SC_GREATER :
1318 [ + + ][ + - ]: 162 : bOk = (nCellVal > rItem.mfVal) && !::rtl::math::approxEqual(nCellVal, rItem.mfVal);
1319 : 162 : break;
1320 : : case SC_LESS_EQUAL :
1321 [ + + ][ - + ]: 105 : bOk = (nCellVal < rItem.mfVal) || ::rtl::math::approxEqual(nCellVal, rItem.mfVal);
1322 [ + + ][ + - ]: 105 : if ( bOk && mpTestEqualCondition )
1323 : 60 : bTestEqual = ::rtl::math::approxEqual(nCellVal, rItem.mfVal);
1324 : 105 : break;
1325 : : case SC_GREATER_EQUAL :
1326 [ + + ][ + + ]: 228 : bOk = (nCellVal > rItem.mfVal) || ::rtl::math::approxEqual( nCellVal, rItem.mfVal);
1327 [ + + ][ + + ]: 228 : if ( bOk && mpTestEqualCondition )
1328 : 33 : bTestEqual = ::rtl::math::approxEqual(nCellVal, rItem.mfVal);
1329 : 228 : break;
1330 : : case SC_NOT_EQUAL :
1331 : 0 : bOk = !::rtl::math::approxEqual(nCellVal, rItem.mfVal);
1332 : 0 : break;
1333 : : default:
1334 : : {
1335 : : // added to avoid warnings
1336 : : }
1337 : : }
1338 : :
1339 [ + - ]: 879 : return std::pair<bool,bool>(bOk, bTestEqual);
1340 : : }
1341 : :
1342 : 171 : std::pair<bool,bool> compareByString(
1343 : : ScBaseCell* pCell, SCROW nRow, const ScQueryEntry& rEntry, const ScQueryEntry::Item& rItem)
1344 : : {
1345 : 171 : bool bOk = false;
1346 : 171 : bool bTestEqual = false;
1347 : 171 : bool bMatchWholeCell = mbMatchWholeCell;
1348 : 171 : rtl::OUString aCellStr;
1349 [ - + ]: 171 : if (isPartialTextMatchOp(rEntry))
1350 : : // may have to do partial textural comparison.
1351 : 0 : bMatchWholeCell = false;
1352 : :
1353 [ + - ]: 171 : if ( pCell )
1354 : : {
1355 [ + + ][ + - ]: 171 : if (pCell->GetCellType() == CELLTYPE_FORMULA && pCell->GetErrorCode())
[ - + ][ - + ]
1356 : : {
1357 : : // Error cell is evaluated as string (for now).
1358 [ # # ][ # # ]: 0 : aCellStr = ScGlobal::GetErrorString(pCell->GetErrorCode());
[ # # ][ # # ]
1359 : : }
1360 [ + - ]: 171 : else if (pCell->GetCellType() != CELLTYPE_NOTE)
1361 : : {
1362 [ + - ]: 171 : sal_uLong nFormat = mrTab.GetNumberFormat( static_cast<SCCOL>(rEntry.nField), nRow );
1363 [ + - ][ + - ]: 171 : ScCellFormat::GetInputString(pCell, nFormat, aCellStr, *mrDoc.GetFormatTable());
1364 : : }
1365 : : }
1366 : : else
1367 [ # # ]: 0 : mrTab.GetInputString( static_cast<SCCOL>(rEntry.nField), nRow, aCellStr );
1368 : :
1369 : 171 : bool bRealRegExp = isRealRegExp(rEntry);
1370 : 171 : bool bTestRegExp = isTestRegExp(rEntry);
1371 : :
1372 [ - + ][ + - ]: 171 : if ( bRealRegExp || bTestRegExp )
1373 : : {
1374 : 0 : xub_StrLen nStart = 0;
1375 : 0 : xub_StrLen nEnd = aCellStr.getLength();
1376 : :
1377 : : // from 614 on, nEnd is behind the found text
1378 : 0 : bool bMatch = false;
1379 [ # # ][ # # ]: 0 : if ( rEntry.eOp == SC_ENDS_WITH || rEntry.eOp == SC_DOES_NOT_END_WITH )
1380 : : {
1381 : 0 : nEnd = 0;
1382 : 0 : nStart = aCellStr.getLength();
1383 : : bMatch = (bool) rEntry.GetSearchTextPtr( mrParam.bCaseSens )
1384 [ # # ][ # # ]: 0 : ->SearchBkwrd( aCellStr, &nStart, &nEnd );
[ # # ][ # # ]
1385 : : }
1386 : : else
1387 : : {
1388 : : bMatch = (bool) rEntry.GetSearchTextPtr( mrParam.bCaseSens )
1389 [ # # ][ # # ]: 0 : ->SearchFrwrd( aCellStr, &nStart, &nEnd );
[ # # ][ # # ]
1390 : : }
1391 [ # # ][ # # ]: 0 : if ( bMatch && bMatchWholeCell
[ # # # # ]
[ # # ]
1392 : 0 : && (nStart != 0 || nEnd != aCellStr.getLength()) )
1393 : 0 : bMatch = false; // RegExp must match entire cell string
1394 [ # # ]: 0 : if ( bRealRegExp )
1395 [ # # # # : 0 : switch (rEntry.eOp)
# # # ]
1396 : : {
1397 : : case SC_EQUAL:
1398 : : case SC_CONTAINS:
1399 : 0 : bOk = bMatch;
1400 : 0 : break;
1401 : : case SC_NOT_EQUAL:
1402 : : case SC_DOES_NOT_CONTAIN:
1403 : 0 : bOk = !bMatch;
1404 : 0 : break;
1405 : : case SC_BEGINS_WITH:
1406 [ # # ][ # # ]: 0 : bOk = ( bMatch && (nStart == 0) );
1407 : 0 : break;
1408 : : case SC_DOES_NOT_BEGIN_WITH:
1409 [ # # ][ # # ]: 0 : bOk = !( bMatch && (nStart == 0) );
1410 : 0 : break;
1411 : : case SC_ENDS_WITH:
1412 [ # # ][ # # ]: 0 : bOk = ( bMatch && (nEnd == aCellStr.getLength()) );
1413 : 0 : break;
1414 : : case SC_DOES_NOT_END_WITH:
1415 [ # # ][ # # ]: 0 : bOk = !( bMatch && (nEnd == aCellStr.getLength()) );
1416 : 0 : break;
1417 : : default:
1418 : : {
1419 : : // added to avoid warnings
1420 : : }
1421 : : }
1422 : : else
1423 : 0 : bTestEqual = bMatch;
1424 : : }
1425 [ + - ]: 171 : if ( !bRealRegExp )
1426 : : {
1427 : : // Simple string matching i.e. no regexp match.
1428 [ + + ]: 171 : if (isTextMatchOp(rEntry))
1429 : : {
1430 [ + + ][ + - ]: 102 : if (rItem.meType != ScQueryEntry::ByString && rItem.maString.isEmpty())
[ + + ]
1431 : : {
1432 : : // #i18374# When used from functions (match, countif, sumif, vlookup, hlookup, lookup),
1433 : : // the query value is assigned directly, and the string is empty. In that case,
1434 : : // don't find any string (isEqual would find empty string results in formula cells).
1435 : 48 : bOk = false;
1436 [ - + ]: 48 : if ( rEntry.eOp == SC_NOT_EQUAL )
1437 : 0 : bOk = !bOk;
1438 : : }
1439 [ + - ]: 54 : else if ( bMatchWholeCell )
1440 : : {
1441 [ + - ][ + - ]: 54 : bOk = mpTransliteration->isEqual(aCellStr, rItem.maString);
[ + - ][ + - ]
[ + - ]
1442 [ - + ]: 54 : if ( rEntry.eOp == SC_NOT_EQUAL )
1443 : 0 : bOk = !bOk;
1444 : : }
1445 : : else
1446 : : {
1447 : 0 : const rtl::OUString& rQueryStr = rItem.maString;
1448 : : String aCell( mpTransliteration->transliterate(
1449 : 0 : aCellStr, ScGlobal::eLnge, 0, aCellStr.getLength(),
1450 [ # # ][ # # ]: 0 : NULL ) );
[ # # ]
1451 : : String aQuer( mpTransliteration->transliterate(
1452 : 0 : rQueryStr, ScGlobal::eLnge, 0, rQueryStr.getLength(),
1453 [ # # ][ # # ]: 0 : NULL ) );
[ # # ]
1454 : : xub_StrLen nIndex = (rEntry.eOp == SC_ENDS_WITH
1455 [ # # ][ # # ]: 0 : || rEntry.eOp == SC_DOES_NOT_END_WITH)? (aCell.Len()-aQuer.Len()):0;
1456 [ # # ]: 0 : xub_StrLen nStrPos = aCell.Search( aQuer, nIndex );
1457 [ # # # # : 0 : switch (rEntry.eOp)
# # # ]
1458 : : {
1459 : : case SC_EQUAL:
1460 : : case SC_CONTAINS:
1461 : 0 : bOk = ( nStrPos != STRING_NOTFOUND );
1462 : 0 : break;
1463 : : case SC_NOT_EQUAL:
1464 : : case SC_DOES_NOT_CONTAIN:
1465 : 0 : bOk = ( nStrPos == STRING_NOTFOUND );
1466 : 0 : break;
1467 : : case SC_BEGINS_WITH:
1468 : 0 : bOk = ( nStrPos == 0 );
1469 : 0 : break;
1470 : : case SC_DOES_NOT_BEGIN_WITH:
1471 : 0 : bOk = ( nStrPos != 0 );
1472 : 0 : break;
1473 : : case SC_ENDS_WITH:
1474 : 0 : bOk = ( nStrPos + aQuer.Len() == aCell.Len() );
1475 : 0 : break;
1476 : : case SC_DOES_NOT_END_WITH:
1477 : 0 : bOk = ( nStrPos + aQuer.Len() != aCell.Len() );
1478 : 0 : break;
1479 : : default:
1480 : : {
1481 : : // added to avoid warnings
1482 : : }
1483 [ # # ][ # # ]: 0 : }
1484 : : }
1485 : : }
1486 : : else
1487 : : { // use collator here because data was probably sorted
1488 : : sal_Int32 nCompare = mpCollator->compareString(
1489 [ + - ]: 69 : aCellStr, rItem.maString);
1490 [ + - + + : 69 : switch (rEntry.eOp)
- ]
1491 : : {
1492 : : case SC_LESS :
1493 : 6 : bOk = (nCompare < 0);
1494 : 6 : break;
1495 : : case SC_GREATER :
1496 : 0 : bOk = (nCompare > 0);
1497 : 0 : break;
1498 : : case SC_LESS_EQUAL :
1499 : 45 : bOk = (nCompare <= 0);
1500 [ + + ][ + - ]: 45 : if ( bOk && mpTestEqualCondition && !bTestEqual )
[ + - ]
1501 : 30 : bTestEqual = (nCompare == 0);
1502 : 45 : break;
1503 : : case SC_GREATER_EQUAL :
1504 : 18 : bOk = (nCompare >= 0);
1505 [ + + ][ + - ]: 18 : if ( bOk && mpTestEqualCondition && !bTestEqual )
[ + - ]
1506 : 9 : bTestEqual = (nCompare == 0);
1507 : 171 : break;
1508 : : default:
1509 : : {
1510 : : // added to avoid warnings
1511 : : }
1512 : : }
1513 : : }
1514 : : }
1515 : :
1516 [ + - ]: 171 : return std::pair<bool,bool>(bOk, bTestEqual);
1517 : : }
1518 : : };
1519 : :
1520 : : }
1521 : :
1522 : 1045 : bool ScTable::ValidQuery(
1523 : : SCROW nRow, const ScQueryParam& rParam, ScBaseCell* pCell,
1524 : : bool* pbTestEqualCondition)
1525 : : {
1526 [ + - ][ + + ]: 1045 : if (!rParam.GetEntry(0).bDoQuery)
1527 : 12 : return true;
1528 : :
1529 [ + - ]: 1033 : SCSIZE nEntryCount = rParam.GetEntryCount();
1530 : :
1531 : : typedef std::pair<bool,bool> ResultType;
1532 [ + + ][ + - ]: 1033 : static std::vector<ResultType> aResults;
[ + - ][ # # ]
1533 [ + + ]: 1033 : if (aResults.size() < nEntryCount)
1534 [ + - ]: 9 : aResults.resize(nEntryCount);
1535 : :
1536 : 1033 : long nPos = -1;
1537 [ + - ]: 1033 : QueryEvaluator aEval(*pDocument, *this, rParam, pbTestEqualCondition);
1538 [ + - ][ + - ]: 1033 : ScQueryParam::const_iterator it, itBeg = rParam.begin(), itEnd = rParam.end();
[ + - ]
1539 [ + - ][ + - ]: 2147 : for (it = itBeg; it != itEnd && it->bDoQuery; ++it)
[ + - ][ + - ]
[ + + ][ + + ]
1540 : : {
1541 [ + - ]: 1114 : const ScQueryEntry& rEntry = *it;
1542 : 1114 : SCCOL nCol = static_cast<SCCOL>(rEntry.nField);
1543 : :
1544 : : // we can only handle one single direct query
1545 [ + + ][ + - ]: 1114 : if (!pCell || it != itBeg)
[ + + ][ + + ]
1546 [ + - ]: 136 : pCell = GetCell(nCol, nRow);
1547 : :
1548 : 1114 : std::pair<bool,bool> aRes(false, false);
1549 : :
1550 [ + - ]: 1114 : const ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems();
1551 [ + + ][ + - ]: 1114 : if (rItems.size() == 1 && rItems.front().meType == ScQueryEntry::ByEmpty)
[ + + ][ + + ]
1552 : : {
1553 [ + - ][ + + ]: 24 : if (rEntry.IsQueryByEmpty())
1554 [ + - ]: 12 : aRes.first = !aCol[rEntry.nField].HasDataAt(nRow);
1555 : : else
1556 : : {
1557 : : OSL_ASSERT(rEntry.IsQueryByNonEmpty());
1558 [ + - ]: 12 : aRes.first = aCol[rEntry.nField].HasDataAt(nRow);
1559 : : }
1560 : : }
1561 : : else
1562 : : {
1563 : 1090 : ScQueryEntry::QueryItemsType::const_iterator itr = rItems.begin(), itrEnd = rItems.end();
1564 : :
1565 [ + - ][ + - ]: 2200 : for (; itr != itrEnd; ++itr)
[ + + ]
1566 : : {
1567 [ + - ][ + - ]: 1110 : if (aEval.isQueryByValue(*itr, nCol, nRow, pCell))
[ + + ]
1568 : : {
1569 : : std::pair<bool,bool> aThisRes =
1570 [ + - ][ + - ]: 879 : aEval.compareByValue(pCell, nCol, nRow, rEntry, *itr);
1571 : 879 : aRes.first |= aThisRes.first;
1572 : 879 : aRes.second |= aThisRes.second;
1573 : : }
1574 [ + - ][ + - ]: 231 : else if (aEval.isQueryByString(rEntry, *itr, nCol, nRow, pCell))
[ + + ]
1575 : : {
1576 : : std::pair<bool,bool> aThisRes =
1577 [ + - ][ + - ]: 171 : aEval.compareByString(pCell, nRow, rEntry, *itr);
1578 : 171 : aRes.first |= aThisRes.first;
1579 : 171 : aRes.second |= aThisRes.second;
1580 : : }
1581 : :
1582 [ + + ][ - + ]: 1110 : if (aRes.first && aRes.second)
1583 : 0 : break;
1584 : : }
1585 : : }
1586 : :
1587 [ + + ]: 1114 : if (nPos == -1)
1588 : : {
1589 : 1033 : nPos++;
1590 [ + - ][ + - ]: 1033 : aResults[nPos] = aRes;
1591 : : }
1592 : : else
1593 : : {
1594 [ + - ]: 81 : if (rEntry.eConnect == SC_AND)
1595 : : {
1596 [ + - ][ + - ]: 81 : aResults[nPos].first = aResults[nPos].first && aRes.first;
[ + + ][ + + ]
1597 [ + - ][ + - ]: 81 : aResults[nPos].second = aResults[nPos].second && aRes.second;
[ - + ][ # # ]
1598 : : }
1599 : : else
1600 : : {
1601 : 0 : nPos++;
1602 [ # # ][ # # ]: 0 : aResults[nPos] = aRes;
1603 : : }
1604 : : }
1605 : : }
1606 : :
1607 [ - + ]: 1033 : for ( long j=1; j <= nPos; j++ )
1608 : : {
1609 [ # # ][ # # ]: 0 : aResults[0].first = aResults[0].first || aResults[j].first;
[ # # ][ # # ]
[ # # ]
1610 [ # # ][ # # ]: 0 : aResults[0].second = aResults[0].second || aResults[j].second;
[ # # ][ # # ]
[ # # ]
1611 : : }
1612 : :
1613 [ + - ]: 1033 : bool bRet = aResults[0].first;
1614 [ + + ]: 1033 : if ( pbTestEqualCondition )
1615 [ + - ]: 237 : *pbTestEqualCondition = aResults[0].second;
1616 : :
1617 : 1045 : return bRet;
1618 : : }
1619 : :
1620 : 0 : void ScTable::TopTenQuery( ScQueryParam& rParam )
1621 : : {
1622 : 0 : bool bSortCollatorInitialized = false;
1623 : 0 : SCSIZE nEntryCount = rParam.GetEntryCount();
1624 [ # # ]: 0 : SCROW nRow1 = (rParam.bHasHeader ? rParam.nRow1 + 1 : rParam.nRow1);
1625 : 0 : SCSIZE nCount = static_cast<SCSIZE>(rParam.nRow2 - nRow1 + 1);
1626 [ # # ][ # # ]: 0 : for ( SCSIZE i=0; (i<nEntryCount) && (rParam.GetEntry(i).bDoQuery); i++ )
[ # # ]
1627 : : {
1628 : 0 : ScQueryEntry& rEntry = rParam.GetEntry(i);
1629 : 0 : ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
1630 : :
1631 [ # # ]: 0 : switch ( rEntry.eOp )
1632 : : {
1633 : : case SC_TOPVAL:
1634 : : case SC_BOTVAL:
1635 : : case SC_TOPPERC:
1636 : : case SC_BOTPERC:
1637 : : {
1638 [ # # ]: 0 : ScSortParam aLocalSortParam( rParam, static_cast<SCCOL>(rEntry.nField) );
1639 [ # # ]: 0 : aSortParam = aLocalSortParam; // used in CreateSortInfoArray, Compare
1640 [ # # ]: 0 : if ( !bSortCollatorInitialized )
1641 : : {
1642 : 0 : bSortCollatorInitialized = true;
1643 [ # # ]: 0 : InitSortCollator( aLocalSortParam );
1644 : : }
1645 [ # # ]: 0 : ScSortInfoArray* pArray = CreateSortInfoArray( nRow1, rParam.nRow2 );
1646 : 0 : DecoladeRow( pArray, nRow1, rParam.nRow2 );
1647 [ # # ]: 0 : QuickSort( pArray, nRow1, rParam.nRow2 );
1648 : 0 : ScSortInfo** ppInfo = pArray->GetFirstArray();
1649 : 0 : SCSIZE nValidCount = nCount;
1650 : : // keine Note-/Leerzellen zaehlen, sind ans Ende sortiert
1651 [ # # ]: 0 : while ( nValidCount > 0 && ( ppInfo[nValidCount-1]->pCell == NULL ||
[ # # # # ]
[ # # ]
1652 : 0 : ppInfo[nValidCount-1]->pCell->GetCellType() == CELLTYPE_NOTE ) )
1653 : 0 : nValidCount--;
1654 : : // keine Strings zaehlen, sind zwischen Value und Leer
1655 [ # # ][ # # ]: 0 : while ( nValidCount > 0
[ # # ]
1656 [ # # ]: 0 : && ppInfo[nValidCount-1]->pCell->HasStringData() )
1657 : 0 : nValidCount--;
1658 [ # # ]: 0 : if ( nValidCount > 0 )
1659 : : {
1660 [ # # ]: 0 : if ( rItem.meType == ScQueryEntry::ByString )
1661 : : { // dat wird nix
1662 : 0 : rItem.meType = ScQueryEntry::ByValue;
1663 : 0 : rItem.mfVal = 10; // 10 bzw. 10%
1664 : : }
1665 [ # # ]: 0 : SCSIZE nVal = (rItem.mfVal >= 1 ? static_cast<SCSIZE>(rItem.mfVal) : 1);
1666 : 0 : SCSIZE nOffset = 0;
1667 [ # # # # : 0 : switch ( rEntry.eOp )
# ]
1668 : : {
1669 : : case SC_TOPVAL:
1670 : : {
1671 : 0 : rEntry.eOp = SC_GREATER_EQUAL;
1672 [ # # ]: 0 : if ( nVal > nValidCount )
1673 : 0 : nVal = nValidCount;
1674 : 0 : nOffset = nValidCount - nVal; // 1 <= nVal <= nValidCount
1675 : : }
1676 : 0 : break;
1677 : : case SC_BOTVAL:
1678 : : {
1679 : 0 : rEntry.eOp = SC_LESS_EQUAL;
1680 [ # # ]: 0 : if ( nVal > nValidCount )
1681 : 0 : nVal = nValidCount;
1682 : 0 : nOffset = nVal - 1; // 1 <= nVal <= nValidCount
1683 : : }
1684 : 0 : break;
1685 : : case SC_TOPPERC:
1686 : : {
1687 : 0 : rEntry.eOp = SC_GREATER_EQUAL;
1688 [ # # ]: 0 : if ( nVal > 100 )
1689 : 0 : nVal = 100;
1690 : 0 : nOffset = nValidCount - (nValidCount * nVal / 100);
1691 [ # # ]: 0 : if ( nOffset >= nValidCount )
1692 : 0 : nOffset = nValidCount - 1;
1693 : : }
1694 : 0 : break;
1695 : : case SC_BOTPERC:
1696 : : {
1697 : 0 : rEntry.eOp = SC_LESS_EQUAL;
1698 [ # # ]: 0 : if ( nVal > 100 )
1699 : 0 : nVal = 100;
1700 : 0 : nOffset = (nValidCount * nVal / 100);
1701 [ # # ]: 0 : if ( nOffset >= nValidCount )
1702 : 0 : nOffset = nValidCount - 1;
1703 : : }
1704 : 0 : break;
1705 : : default:
1706 : : {
1707 : : // added to avoid warnings
1708 : : }
1709 : : }
1710 : 0 : ScBaseCell* pCell = ppInfo[nOffset]->pCell;
1711 [ # # ][ # # ]: 0 : if ( pCell->HasValueData() )
1712 : : {
1713 [ # # ]: 0 : if ( pCell->GetCellType() == CELLTYPE_VALUE )
1714 : 0 : rItem.mfVal = ((ScValueCell*)pCell)->GetValue();
1715 : : else
1716 [ # # ][ # # ]: 0 : rItem.mfVal = ((ScFormulaCell*)pCell)->GetValue();
1717 : : }
1718 : : else
1719 : : {
1720 : : OSL_FAIL( "TopTenQuery: pCell kein ValueData" );
1721 : 0 : rEntry.eOp = SC_GREATER_EQUAL;
1722 : 0 : rItem.mfVal = 0;
1723 : : }
1724 : : }
1725 : : else
1726 : : {
1727 : 0 : rEntry.eOp = SC_GREATER_EQUAL;
1728 : 0 : rItem.meType = ScQueryEntry::ByValue;
1729 : 0 : rItem.mfVal = 0;
1730 : : }
1731 [ # # ][ # # ]: 0 : delete pArray;
[ # # ]
1732 : : }
1733 : 0 : break;
1734 : : default:
1735 : : {
1736 : : // added to avoid warnings
1737 : : }
1738 : : }
1739 : : }
1740 [ # # ]: 0 : if ( bSortCollatorInitialized )
1741 : 0 : DestroySortCollator();
1742 : 0 : }
1743 : :
1744 : : namespace {
1745 : :
1746 : : class PrepareQueryItem : public std::unary_function<ScQueryEntry::Item, void>
1747 : : {
1748 : : const ScDocument& mrDoc;
1749 : : public:
1750 : 15 : PrepareQueryItem(const ScDocument& rDoc) : mrDoc(rDoc) {}
1751 : :
1752 : 19 : void operator() (ScQueryEntry::Item& rItem)
1753 : : {
1754 [ + + ][ - + ]: 19 : if (rItem.meType != ScQueryEntry::ByString && rItem.meType != ScQueryEntry::ByDate)
1755 : : return;
1756 : :
1757 : 8 : sal_uInt32 nIndex = 0;
1758 : : bool bNumber = mrDoc.GetFormatTable()->
1759 [ + - ][ + - ]: 8 : IsNumberFormat(rItem.maString, nIndex, rItem.mfVal);
[ + - ][ + - ]
1760 : :
1761 : : // Advanced Filter creates only ByString queries that need to be
1762 : : // converted to ByValue if appropriate. rItem.mfVal now holds the value
1763 : : // if bNumber==true.
1764 : :
1765 [ + - ]: 8 : if (rItem.meType == ScQueryEntry::ByString)
1766 : : {
1767 [ + + ]: 8 : if (bNumber)
1768 : 6 : rItem.meType = ScQueryEntry::ByValue;
1769 : : return;
1770 : : }
1771 : :
1772 : : // Double-check if the query by date is really appropriate.
1773 : :
1774 [ # # ][ # # ]: 0 : if (bNumber && ((nIndex % SV_COUNTRY_LANGUAGE_OFFSET) != 0))
1775 : : {
1776 [ # # ][ # # ]: 0 : const SvNumberformat* pEntry = mrDoc.GetFormatTable()->GetEntry(nIndex);
1777 [ # # ]: 0 : if (pEntry)
1778 : : {
1779 : 0 : short nNumFmtType = pEntry->GetType();
1780 [ # # ][ # # ]: 0 : if (!((nNumFmtType & NUMBERFORMAT_DATE) && !(nNumFmtType & NUMBERFORMAT_TIME)))
1781 : 0 : rItem.meType = ScQueryEntry::ByValue; // not a date only
1782 : : }
1783 : : else
1784 : 0 : rItem.meType = ScQueryEntry::ByValue; // what the ... not a date
1785 : : }
1786 : : else
1787 : 19 : rItem.meType = ScQueryEntry::ByValue; // not a date
1788 : : }
1789 : : };
1790 : :
1791 : 16 : void lcl_PrepareQuery( const ScDocument* pDoc, ScTable* pTab, ScQueryParam& rParam )
1792 : : {
1793 : 16 : bool bTopTen = false;
1794 : 16 : SCSIZE nEntryCount = rParam.GetEntryCount();
1795 : :
1796 [ + + ]: 144 : for ( SCSIZE i = 0; i < nEntryCount; ++i )
1797 : : {
1798 : 128 : ScQueryEntry& rEntry = rParam.GetEntry(i);
1799 [ + + ]: 128 : if (!rEntry.bDoQuery)
1800 : 113 : continue;
1801 : :
1802 : 15 : ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems();
1803 [ + - ]: 15 : std::for_each(rItems.begin(), rItems.end(), PrepareQueryItem(*pDoc));
1804 : :
1805 [ + - ]: 15 : if ( !bTopTen )
1806 : : {
1807 [ - + ]: 15 : switch ( rEntry.eOp )
1808 : : {
1809 : : case SC_TOPVAL:
1810 : : case SC_BOTVAL:
1811 : : case SC_TOPPERC:
1812 : : case SC_BOTPERC:
1813 : : {
1814 : 0 : bTopTen = true;
1815 : : }
1816 : 15 : break;
1817 : : default:
1818 : : {
1819 : : }
1820 : : }
1821 : : }
1822 : : }
1823 : :
1824 [ - + ]: 16 : if ( bTopTen )
1825 : : {
1826 : 0 : pTab->TopTenQuery( rParam );
1827 : : }
1828 : 16 : }
1829 : :
1830 : : }
1831 : :
1832 : 16 : SCSIZE ScTable::Query(ScQueryParam& rParamOrg, bool bKeepSub)
1833 : : {
1834 [ + - ]: 16 : ScQueryParam aParam( rParamOrg );
1835 : : typedef boost::unordered_set<rtl::OUString, rtl::OUStringHash> StrSetType;
1836 [ + - ]: 16 : StrSetType aStrSet;
1837 : :
1838 : 16 : bool bStarted = false;
1839 : 16 : bool bOldResult = true;
1840 : 16 : SCROW nOldStart = 0;
1841 : 16 : SCROW nOldEnd = 0;
1842 : :
1843 : 16 : SCSIZE nCount = 0;
1844 : 16 : SCROW nOutRow = 0;
1845 [ + + ]: 16 : SCROW nHeader = aParam.bHasHeader ? 1 : 0;
1846 : :
1847 [ + - ]: 16 : lcl_PrepareQuery(pDocument, this, aParam);
1848 : :
1849 [ - + ]: 16 : if (!aParam.bInplace)
1850 : : {
1851 : 0 : nOutRow = aParam.nDestRow + nHeader;
1852 [ # # ]: 0 : if (nHeader > 0)
1853 : : CopyData( aParam.nCol1, aParam.nRow1, aParam.nCol2, aParam.nRow1,
1854 [ # # ]: 0 : aParam.nDestCol, aParam.nDestRow, aParam.nDestTab );
1855 : : }
1856 : :
1857 : :
1858 [ + - ]: 16 : if (aParam.bInplace)
1859 [ + - ]: 16 : InitializeNoteCaptions();
1860 : :
1861 : 16 : SCROW nRealRow2 = aParam.nRow2;
1862 [ + + ]: 83 : for (SCROW j = aParam.nRow1 + nHeader; j <= nRealRow2; ++j)
1863 : : {
1864 : : bool bResult; // Filterergebnis
1865 [ + - ]: 67 : bool bValid = ValidQuery(j, aParam);
1866 [ + + ][ + + ]: 67 : if (!bValid && bKeepSub) // Subtotals stehenlassen
1867 : : {
1868 [ + + ][ + - ]: 72 : for (SCCOL nCol=aParam.nCol1; nCol<=aParam.nCol2 && !bValid; nCol++)
[ + + ]
1869 : : {
1870 : : ScBaseCell* pCell;
1871 [ + - ]: 54 : pCell = GetCell( nCol, j );
1872 [ + + ]: 54 : if ( pCell )
1873 [ - + ]: 48 : if ( pCell->GetCellType() == CELLTYPE_FORMULA )
1874 [ # # ][ # # ]: 0 : if (((ScFormulaCell*)pCell)->IsSubTotal())
1875 [ # # ][ # # ]: 0 : if (RefVisible((ScFormulaCell*)pCell))
[ # # ]
1876 : 0 : bValid = true;
1877 : : }
1878 : : }
1879 [ + + ]: 67 : if (bValid)
1880 : : {
1881 [ + - ]: 34 : if (aParam.bDuplicate)
1882 : 34 : bResult = true;
1883 : : else
1884 : : {
1885 : 0 : rtl::OUString aStr;
1886 [ # # ]: 0 : for (SCCOL k=aParam.nCol1; k <= aParam.nCol2; k++)
1887 : : {
1888 : 0 : rtl::OUString aCellStr;
1889 [ # # ]: 0 : GetString(k, j, aCellStr);
1890 [ # # ]: 0 : rtl::OUStringBuffer aBuf(aStr);
1891 [ # # ]: 0 : aBuf.append(aCellStr);
1892 [ # # ]: 0 : aBuf.append(static_cast<sal_Unicode>(1));
1893 [ # # ]: 0 : aStr = aBuf.makeStringAndClear();
1894 : 0 : }
1895 : :
1896 [ # # ]: 0 : std::pair<StrSetType::iterator, bool> r = aStrSet.insert(aStr);
1897 : 0 : bool bIsUnique = r.second; // unique if inserted.
1898 : 0 : bResult = bIsUnique;
1899 : : }
1900 : : }
1901 : : else
1902 : 33 : bResult = false;
1903 : :
1904 [ + - ]: 67 : if (aParam.bInplace)
1905 : : {
1906 [ + + ][ + + ]: 67 : if (bResult == bOldResult && bStarted)
1907 : 27 : nOldEnd = j;
1908 : : else
1909 : : {
1910 [ + + ]: 40 : if (bStarted)
1911 [ + - ]: 24 : DBShowRows(nOldStart,nOldEnd, bOldResult);
1912 : 40 : nOldStart = nOldEnd = j;
1913 : 40 : bOldResult = bResult;
1914 : : }
1915 : 67 : bStarted = true;
1916 : : }
1917 : : else
1918 : : {
1919 [ # # ]: 0 : if (bResult)
1920 : : {
1921 [ # # ]: 0 : CopyData( aParam.nCol1,j, aParam.nCol2,j, aParam.nDestCol,nOutRow,aParam.nDestTab );
1922 : 0 : ++nOutRow;
1923 : : }
1924 : : }
1925 [ + + ]: 67 : if (bResult)
1926 : 34 : ++nCount;
1927 : : }
1928 : :
1929 [ + - ][ + - ]: 16 : if (aParam.bInplace && bStarted)
1930 [ + - ]: 16 : DBShowRows(nOldStart,nOldEnd, bOldResult);
1931 : :
1932 [ + - ]: 16 : if (aParam.bInplace)
1933 [ + - ]: 16 : SetDrawPageSize();
1934 : :
1935 [ + - ][ + - ]: 16 : return nCount;
1936 : : }
1937 : :
1938 : 2 : bool ScTable::CreateExcelQuery(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam& rQueryParam)
1939 : : {
1940 : 2 : bool bValid = true;
1941 [ + - ]: 2 : SCCOL* pFields = new SCCOL[nCol2-nCol1+1];
1942 : 2 : rtl::OUString aCellStr;
1943 : 2 : SCCOL nCol = nCol1;
1944 : : OSL_ENSURE( rQueryParam.nTab != SCTAB_MAX, "rQueryParam.nTab no value, not bad but no good" );
1945 [ - + ]: 2 : SCTAB nDBTab = (rQueryParam.nTab == SCTAB_MAX ? nTab : rQueryParam.nTab);
1946 : 2 : SCROW nDBRow1 = rQueryParam.nRow1;
1947 : 2 : SCCOL nDBCol2 = rQueryParam.nCol2;
1948 : : // Erste Zeile muessen Spaltenkoepfe sein
1949 [ + - ][ + + ]: 10 : while (bValid && (nCol <= nCol2))
[ + + ]
1950 : : {
1951 : 8 : rtl::OUString aQueryStr;
1952 [ + - ]: 8 : GetUpperCellString(nCol, nRow1, aQueryStr);
1953 : 8 : bool bFound = false;
1954 : 8 : SCCOL i = rQueryParam.nCol1;
1955 [ + + ][ + - ]: 16 : while (!bFound && (i <= nDBCol2))
[ + + ]
1956 : : {
1957 [ + - ]: 8 : if ( nTab == nDBTab )
1958 [ + - ]: 8 : GetUpperCellString(i, nDBRow1, aCellStr);
1959 : : else
1960 [ # # ]: 0 : pDocument->GetUpperCellString(i, nDBRow1, nDBTab, aCellStr);
1961 : 8 : bFound = (aCellStr == aQueryStr);
1962 [ - + ]: 8 : if (!bFound) i++;
1963 : : }
1964 [ + - ]: 8 : if (bFound)
1965 : 8 : pFields[nCol - nCol1] = i;
1966 : : else
1967 : 0 : bValid = false;
1968 : 8 : nCol++;
1969 : 8 : }
1970 [ + - ]: 2 : if (bValid)
1971 : : {
1972 : 2 : sal_uLong nVisible = 0;
1973 [ + + ]: 10 : for ( nCol=nCol1; nCol<=nCol2; nCol++ )
1974 [ + - ]: 8 : nVisible += aCol[nCol].VisibleCount( nRow1+1, nRow2 );
1975 : :
1976 [ - + ]: 2 : if ( nVisible > SCSIZE_MAX / sizeof(void*) )
1977 : : {
1978 : : OSL_FAIL("zu viele Filterkritierien");
1979 : 0 : nVisible = 0;
1980 : : }
1981 : :
1982 : 2 : SCSIZE nNewEntries = nVisible;
1983 [ + - ]: 2 : rQueryParam.Resize( nNewEntries );
1984 : :
1985 : 2 : SCSIZE nIndex = 0;
1986 : 2 : SCROW nRow = nRow1 + 1;
1987 [ + + ]: 9 : while (nRow <= nRow2)
1988 : : {
1989 : 7 : nCol = nCol1;
1990 [ + + ]: 35 : while (nCol <= nCol2)
1991 : : {
1992 [ + - ]: 28 : GetInputString( nCol, nRow, aCellStr );
1993 [ + - ]: 28 : aCellStr = ScGlobal::pCharClass->uppercase(aCellStr);
1994 [ + + ]: 28 : if (!aCellStr.isEmpty())
1995 : : {
1996 [ + - ]: 3 : if (nIndex < nNewEntries)
1997 : : {
1998 [ + - ]: 3 : rQueryParam.GetEntry(nIndex).nField = pFields[nCol - nCol1];
1999 [ + - ]: 3 : rQueryParam.FillInExcelSyntax(aCellStr, nIndex);
2000 : 3 : nIndex++;
2001 [ + + ]: 3 : if (nIndex < nNewEntries)
2002 [ + - ]: 2 : rQueryParam.GetEntry(nIndex).eConnect = SC_AND;
2003 : : }
2004 : : else
2005 : 0 : bValid = false;
2006 : : }
2007 : 28 : nCol++;
2008 : : }
2009 : 7 : nRow++;
2010 [ + + ]: 7 : if (nIndex < nNewEntries)
2011 [ + - ]: 2 : rQueryParam.GetEntry(nIndex).eConnect = SC_OR;
2012 : : }
2013 : : }
2014 [ + - ]: 2 : delete [] pFields;
2015 : 2 : return bValid;
2016 : : }
2017 : :
2018 : 2 : bool ScTable::CreateStarQuery(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam& rQueryParam)
2019 : : {
2020 : : // A valid StarQuery must be at least 4 columns wide. To be precise it
2021 : : // should be exactly 4 columns ...
2022 : : // Additionally, if this wasn't checked, a formula pointing to a valid 1-3
2023 : : // column Excel style query range immediately left to itself would result
2024 : : // in a circular reference when the field name or operator or value (first
2025 : : // to third query range column) is obtained (#i58354#). Furthermore, if the
2026 : : // range wasn't sufficiently specified data changes wouldn't flag formula
2027 : : // cells for recalculation.
2028 [ - + ]: 2 : if (nCol2 - nCol1 < 3)
2029 : 0 : return false;
2030 : :
2031 : : bool bValid;
2032 : : bool bFound;
2033 : 2 : rtl::OUString aCellStr;
2034 : 2 : SCSIZE nIndex = 0;
2035 : 2 : SCROW nRow = nRow1;
2036 : : OSL_ENSURE( rQueryParam.nTab != SCTAB_MAX, "rQueryParam.nTab no value, not bad but no good" );
2037 [ - + ]: 2 : SCTAB nDBTab = (rQueryParam.nTab == SCTAB_MAX ? nTab : rQueryParam.nTab);
2038 : 2 : SCROW nDBRow1 = rQueryParam.nRow1;
2039 : 2 : SCCOL nDBCol2 = rQueryParam.nCol2;
2040 : :
2041 : 2 : SCSIZE nNewEntries = static_cast<SCSIZE>(nRow2-nRow1+1);
2042 [ + - ]: 2 : rQueryParam.Resize( nNewEntries );
2043 : :
2044 [ + + ][ + - ]: 4 : do
[ + + ]
2045 : : {
2046 [ + - ]: 4 : ScQueryEntry& rEntry = rQueryParam.GetEntry(nIndex);
2047 : :
2048 : 4 : bValid = false;
2049 : : // Erste Spalte UND/ODER
2050 [ + + ]: 4 : if (nIndex > 0)
2051 : : {
2052 [ + - ]: 2 : GetUpperCellString(nCol1, nRow, aCellStr);
2053 [ + - ][ + - ]: 2 : if ( aCellStr == rtl::OUString(ScGlobal::GetRscString(STR_TABLE_UND)) )
[ - + ]
2054 : : {
2055 : 0 : rEntry.eConnect = SC_AND;
2056 : 0 : bValid = true;
2057 : : }
2058 [ + - ][ + - ]: 2 : else if ( aCellStr == rtl::OUString(ScGlobal::GetRscString(STR_TABLE_ODER)) )
[ - + ]
2059 : : {
2060 : 0 : rEntry.eConnect = SC_OR;
2061 : 0 : bValid = true;
2062 : : }
2063 : : }
2064 : : // Zweite Spalte FeldName
2065 [ + + ][ - + ]: 4 : if ((nIndex < 1) || bValid)
2066 : : {
2067 : 2 : bFound = false;
2068 [ + - ]: 2 : GetUpperCellString(nCol1 + 1, nRow, aCellStr);
2069 [ + - ][ + + ]: 4 : for (SCCOL i=rQueryParam.nCol1; (i <= nDBCol2) && (!bFound); i++)
[ + + ]
2070 : : {
2071 : 2 : rtl::OUString aFieldStr;
2072 [ + - ]: 2 : if ( nTab == nDBTab )
2073 [ + - ]: 2 : GetUpperCellString(i, nDBRow1, aFieldStr);
2074 : : else
2075 [ # # ]: 0 : pDocument->GetUpperCellString(i, nDBRow1, nDBTab, aFieldStr);
2076 : 2 : bFound = (aCellStr == aFieldStr);
2077 [ + - ]: 2 : if (bFound)
2078 : : {
2079 : 2 : rEntry.nField = i;
2080 : 2 : bValid = true;
2081 : : }
2082 : : else
2083 : 0 : bValid = false;
2084 : 2 : }
2085 : : }
2086 : : // Dritte Spalte Operator =<>...
2087 [ + + ]: 4 : if (bValid)
2088 : : {
2089 : 2 : bFound = false;
2090 [ + - ]: 2 : GetUpperCellString(nCol1 + 2, nRow, aCellStr);
2091 [ - + ]: 2 : if (aCellStr[0] == '<')
2092 : : {
2093 [ # # ]: 0 : if (aCellStr[1] == '>')
2094 : 0 : rEntry.eOp = SC_NOT_EQUAL;
2095 [ # # ]: 0 : else if (aCellStr[1] == '=')
2096 : 0 : rEntry.eOp = SC_LESS_EQUAL;
2097 : : else
2098 : 0 : rEntry.eOp = SC_LESS;
2099 : : }
2100 [ - + ]: 2 : else if (aCellStr[0] == '>')
2101 : : {
2102 [ # # ]: 0 : if (aCellStr[1] == '=')
2103 : 0 : rEntry.eOp = SC_GREATER_EQUAL;
2104 : : else
2105 : 0 : rEntry.eOp = SC_GREATER;
2106 : : }
2107 [ - + ]: 2 : else if (aCellStr[0] == '=')
2108 : 0 : rEntry.eOp = SC_EQUAL;
2109 : :
2110 : : }
2111 : : // Vierte Spalte Wert
2112 [ + + ]: 4 : if (bValid)
2113 : : {
2114 : 2 : rtl::OUString aStr;
2115 [ + - ]: 2 : GetString(nCol1 + 3, nRow, aStr);
2116 [ + - ]: 2 : rEntry.GetQueryItem().maString = aStr;
2117 : 2 : rEntry.bDoQuery = true;
2118 : : }
2119 : 4 : nIndex++;
2120 : 4 : nRow++;
2121 : : }
2122 : : while (bValid && (nRow <= nRow2) /* && (nIndex < MAXQUERY) */ );
2123 : 2 : return bValid;
2124 : : }
2125 : :
2126 : 2 : bool ScTable::CreateQueryParam(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam& rQueryParam)
2127 : : {
2128 : : SCSIZE i, nCount;
2129 : 2 : PutInOrder(nCol1, nCol2);
2130 : 2 : PutInOrder(nRow1, nRow2);
2131 : :
2132 : 2 : nCount = rQueryParam.GetEntryCount();
2133 [ + + ]: 18 : for (i=0; i < nCount; i++)
2134 : 16 : rQueryParam.GetEntry(i).Clear();
2135 : :
2136 : : // Standard QueryTabelle
2137 : 2 : bool bValid = CreateStarQuery(nCol1, nRow1, nCol2, nRow2, rQueryParam);
2138 : : // Excel QueryTabelle
2139 [ + - ]: 2 : if (!bValid)
2140 : 2 : bValid = CreateExcelQuery(nCol1, nRow1, nCol2, nRow2, rQueryParam);
2141 : :
2142 : 2 : nCount = rQueryParam.GetEntryCount();
2143 [ + - ]: 2 : if (bValid)
2144 : : {
2145 : : // bQueryByString muss gesetzt sein
2146 [ + + ]: 18 : for (i=0; i < nCount; i++)
2147 : 16 : rQueryParam.GetEntry(i).GetQueryItem().meType = ScQueryEntry::ByString;
2148 : : }
2149 : : else
2150 : : {
2151 : : // nix
2152 [ # # ]: 0 : for (i=0; i < nCount; i++)
2153 : 0 : rQueryParam.GetEntry(i).Clear();
2154 : : }
2155 : 2 : return bValid;
2156 : : }
2157 : :
2158 : 14 : bool ScTable::HasColHeader( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW /* nEndRow */ ) const
2159 : : {
2160 [ + + ]: 27 : for (SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++)
2161 : : {
2162 : 25 : CellType eType = GetCellType( nCol, nStartRow );
2163 [ + - ][ + + ]: 25 : if (eType != CELLTYPE_STRING && eType != CELLTYPE_EDIT)
2164 : 12 : return false;
2165 : : }
2166 : 14 : return true;
2167 : : }
2168 : :
2169 : 0 : bool ScTable::HasRowHeader( SCCOL nStartCol, SCROW nStartRow, SCCOL /* nEndCol */, SCROW nEndRow ) const
2170 : : {
2171 [ # # ]: 0 : for (SCROW nRow=nStartRow; nRow<=nEndRow; nRow++)
2172 : : {
2173 : 0 : CellType eType = GetCellType( nStartCol, nRow );
2174 [ # # ][ # # ]: 0 : if (eType != CELLTYPE_STRING && eType != CELLTYPE_EDIT)
2175 : 0 : return false;
2176 : : }
2177 : 0 : return true;
2178 : : }
2179 : :
2180 : 0 : void ScTable::GetFilterEntries(SCCOL nCol, SCROW nRow1, SCROW nRow2, std::vector<ScTypedStrData>& rStrings, bool& rHasDates)
2181 : : {
2182 : 0 : aCol[nCol].GetFilterEntries( nRow1, nRow2, rStrings, rHasDates );
2183 : 0 : }
2184 : :
2185 : 0 : void ScTable::GetFilteredFilterEntries(
2186 : : SCCOL nCol, SCROW nRow1, SCROW nRow2, const ScQueryParam& rParam, std::vector<ScTypedStrData>& rStrings, bool& rHasDates)
2187 : : {
2188 : : // remove the entry for this column from the query parameter
2189 [ # # ]: 0 : ScQueryParam aParam( rParam );
2190 [ # # ]: 0 : aParam.RemoveEntryByField(nCol);
2191 : :
2192 [ # # ]: 0 : lcl_PrepareQuery(pDocument, this, aParam);
2193 : 0 : bool bHasDates = false;
2194 [ # # ]: 0 : for ( SCROW j = nRow1; j <= nRow2; ++j )
2195 : : {
2196 [ # # ][ # # ]: 0 : if (ValidQuery(j, aParam))
2197 : : {
2198 : 0 : bool bThisHasDates = false;
2199 [ # # ]: 0 : aCol[nCol].GetFilterEntries( j, j, rStrings, bThisHasDates );
2200 : 0 : bHasDates |= bThisHasDates;
2201 : : }
2202 : : }
2203 : :
2204 [ # # ]: 0 : rHasDates = bHasDates;
2205 : 0 : }
2206 : :
2207 : 0 : bool ScTable::GetDataEntries(SCCOL nCol, SCROW nRow, std::set<ScTypedStrData>& rStrings, bool bLimit)
2208 : : {
2209 : 0 : return aCol[nCol].GetDataEntries( nRow, rStrings, bLimit );
2210 : : }
2211 : :
2212 : 72 : SCSIZE ScTable::GetCellCount(SCCOL nCol) const
2213 : : {
2214 : 72 : return aCol[nCol].GetCellCount();
2215 : : }
2216 : :
2217 : 18 : sal_uLong ScTable::GetCellCount() const
2218 : : {
2219 : 18 : sal_uLong nCellCount = 0;
2220 : :
2221 [ + + ]: 18450 : for ( SCCOL nCol=0; nCol<=MAXCOL; nCol++ )
2222 : 18432 : nCellCount += aCol[nCol].GetCellCount();
2223 : :
2224 : 18 : return nCellCount;
2225 : : }
2226 : :
2227 : 1836 : sal_uLong ScTable::GetWeightedCount() const
2228 : : {
2229 : 1836 : sal_uLong nCellCount = 0;
2230 : :
2231 [ + + ]: 1881900 : for ( SCCOL nCol=0; nCol<=MAXCOL; nCol++ )
2232 [ + + ]: 1880064 : if ( aCol[nCol].GetCellCount() ) // GetCellCount ist inline
2233 : 2922 : nCellCount += aCol[nCol].GetWeightedCount();
2234 : :
2235 : 1836 : return nCellCount;
2236 : : }
2237 : :
2238 : 0 : sal_uLong ScTable::GetCodeCount() const
2239 : : {
2240 : 0 : sal_uLong nCodeCount = 0;
2241 : :
2242 [ # # ]: 0 : for ( SCCOL nCol=0; nCol<=MAXCOL; nCol++ )
2243 [ # # ]: 0 : if ( aCol[nCol].GetCellCount() ) // GetCellCount ist inline
2244 : 0 : nCodeCount += aCol[nCol].GetCodeCount();
2245 : :
2246 : 0 : return nCodeCount;
2247 : : }
2248 : :
2249 : 0 : sal_Int32 ScTable::GetMaxStringLen( SCCOL nCol, SCROW nRowStart,
2250 : : SCROW nRowEnd, CharSet eCharSet ) const
2251 : : {
2252 [ # # ]: 0 : if ( ValidCol(nCol) )
2253 : 0 : return aCol[nCol].GetMaxStringLen( nRowStart, nRowEnd, eCharSet );
2254 : : else
2255 : 0 : return 0;
2256 : : }
2257 : :
2258 : 0 : xub_StrLen ScTable::GetMaxNumberStringLen(
2259 : : sal_uInt16& nPrecision, SCCOL nCol, SCROW nRowStart, SCROW nRowEnd ) const
2260 : : {
2261 [ # # ]: 0 : if ( ValidCol(nCol) )
2262 : 0 : return aCol[nCol].GetMaxNumberStringLen( nPrecision, nRowStart, nRowEnd );
2263 : : else
2264 : 0 : return 0;
2265 : : }
2266 : :
2267 : 225 : void ScTable::UpdateSelectionFunction( ScFunctionData& rData,
2268 : : SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
2269 : : const ScMarkData& rMark )
2270 : : {
2271 : : // Cursor neben einer Markierung nicht beruecksichtigen:
2272 : : //! nur noch MarkData uebergeben, Cursorposition ggf. hineinselektieren!!!
2273 [ + + ][ + + ]: 225 : bool bSingle = ( rMark.IsMarked() || !rMark.IsMultiMarked() );
2274 : :
2275 : : // Mehrfachselektion:
2276 : :
2277 : : SCCOL nCol;
2278 [ + + ]: 225 : if ( rMark.IsMultiMarked() )
2279 [ + + ][ + - ]: 2050 : for (nCol=0; nCol<=MAXCOL && !rData.bError; nCol++)
[ + + ]
2280 [ + - ][ + - ]: 2048 : if ( !pColFlags || !ColHidden(nCol) )
[ + - ]
2281 : 2048 : aCol[nCol].UpdateSelectionFunction( rMark, rData, *mpHiddenRows,
2282 : : bSingle && ( nCol >= nStartCol && nCol <= nEndCol ),
2283 [ - + ][ # # ]: 4096 : nStartRow, nEndRow );
[ # # ]
2284 : :
2285 : : // Einfachselektion (oder Cursor) nur wenn nicht negativ (und s.o.):
2286 : :
2287 [ + + ][ + - ]: 225 : if ( bSingle && !rMark.IsMarkNegative() )
[ + + ]
2288 [ + + ][ + - ]: 458 : for (nCol=nStartCol; nCol<=nEndCol && !rData.bError; nCol++)
[ + + ]
2289 [ + - ][ + - ]: 235 : if ( !pColFlags || !ColHidden(nCol) )
[ + - ]
2290 : 235 : aCol[nCol].UpdateAreaFunction( rData, *mpHiddenRows, nStartRow, nEndRow );
2291 : 225 : }
2292 : :
2293 : 0 : void ScTable::FindConditionalFormat( sal_uLong nKey, ScRangeList& rList ) const
2294 : : {
2295 : 0 : SCROW nStartRow = 0, nEndRow = 0;
2296 [ # # ]: 0 : for (SCCOL nCol=0; nCol<=MAXCOL; nCol++)
2297 : : {
2298 [ # # ]: 0 : ScAttrIterator* pIter = aCol[nCol].CreateAttrIterator( 0, MAXROW );
2299 [ # # ]: 0 : const ScPatternAttr* pPattern = pIter->Next( nStartRow, nEndRow );
2300 [ # # ]: 0 : while (pPattern)
2301 : : {
2302 [ # # ][ # # ]: 0 : if (((SfxUInt32Item&)pPattern->GetItem(ATTR_CONDITIONAL)).GetValue() == nKey)
2303 [ # # ]: 0 : rList.Join( ScRange(nCol,nStartRow,nTab, nCol,nEndRow,nTab) );
2304 [ # # ]: 0 : pPattern = pIter->Next( nStartRow, nEndRow );
2305 : : }
2306 : 0 : delete pIter;
2307 : : }
2308 : 0 : }
2309 : :
2310 : 66294 : void ScTable::IncRecalcLevel()
2311 : : {
2312 : 66294 : ++nRecalcLvl;
2313 : 66294 : }
2314 : :
2315 : 66294 : void ScTable::DecRecalcLevel(bool bUpdateNoteCaptionPos)
2316 : : {
2317 [ + + ]: 66294 : if (!--nRecalcLvl)
2318 : 66250 : SetDrawPageSize(true, bUpdateNoteCaptionPos);
2319 [ + - ][ + - ]: 66447 : }
2320 : :
2321 : :
2322 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|