Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <rtl/math.hxx>
21 : #include <comphelper/random.hxx>
22 : #include <unotools/textsearch.hxx>
23 : #include <svl/zforlist.hxx>
24 : #include <svl/zformat.hxx>
25 : #include <unotools/charclass.hxx>
26 : #include <unotools/collatorwrapper.hxx>
27 : #include <com/sun/star/i18n/CollatorOptions.hpp>
28 : #include <stdlib.h>
29 : #include <unotools/transliterationwrapper.hxx>
30 :
31 : #include "table.hxx"
32 : #include "scitems.hxx"
33 : #include "attrib.hxx"
34 : #include "formulacell.hxx"
35 : #include "document.hxx"
36 : #include "globstr.hrc"
37 : #include "global.hxx"
38 : #include "stlpool.hxx"
39 : #include "compiler.hxx"
40 : #include "patattr.hxx"
41 : #include "subtotal.hxx"
42 : #include "docoptio.hxx"
43 : #include "markdata.hxx"
44 : #include "rangelst.hxx"
45 : #include "attarray.hxx"
46 : #include "userlist.hxx"
47 : #include "progress.hxx"
48 : #include "cellform.hxx"
49 : #include "postit.hxx"
50 : #include "queryparam.hxx"
51 : #include "queryentry.hxx"
52 : #include "segmenttree.hxx"
53 : #include "subtotalparam.hxx"
54 : #include "docpool.hxx"
55 : #include "cellvalue.hxx"
56 : #include "tokenarray.hxx"
57 : #include "mtvcellfunc.hxx"
58 : #include "columnspanset.hxx"
59 : #include <fstalgorithm.hxx>
60 : #include <listenercontext.hxx>
61 : #include <sharedformula.hxx>
62 : #include <refhint.hxx>
63 : #include <listenerquery.hxx>
64 : #include <bcaslot.hxx>
65 :
66 : #include <svl/sharedstringpool.hxx>
67 :
68 : #include <vector>
69 : #include <boost/checked_delete.hpp>
70 : #include <boost/scoped_ptr.hpp>
71 : #include <boost/scoped_array.hpp>
72 : #include <boost/unordered_set.hpp>
73 : #include <boost/noncopyable.hpp>
74 : #include <boost/ptr_container/ptr_vector.hpp>
75 : #include <mdds/flat_segment_tree.hpp>
76 :
77 : using namespace ::com::sun::star;
78 :
79 : namespace naturalsort {
80 :
81 : using namespace ::com::sun::star::i18n;
82 :
83 : /** Splits a given string into three parts: the prefix, number string, and
84 : the suffix.
85 :
86 : @param sWhole
87 : Original string to be split into pieces
88 :
89 : @param sPrefix
90 : Prefix string that consists of the part before the first number token
91 :
92 : @param sSuffix
93 : String after the last number token. This may still contain number strings.
94 :
95 : @param fNum
96 : Number converted from the middle number string
97 :
98 : @return Returns TRUE if a numeral element is found in a given string, or
99 : FALSE if no numeral element is found.
100 : */
101 0 : bool SplitString( const OUString &sWhole,
102 : OUString &sPrefix, OUString &sSuffix, double &fNum )
103 : {
104 0 : i18n::LocaleDataItem aLocaleItem = ScGlobal::pLocaleData->getLocaleItem();
105 :
106 : // Get prefix element
107 0 : OUString sEmpty, sUser = "-";
108 : ParseResult aPRPre = ScGlobal::pCharClass->parsePredefinedToken(
109 : KParseType::IDENTNAME, sWhole, 0,
110 0 : KParseTokens::ANY_LETTER, sUser, KParseTokens::ANY_LETTER, sUser );
111 0 : sPrefix = sWhole.copy( 0, aPRPre.EndPos );
112 :
113 : // Return FALSE if no numeral element is found
114 0 : if ( aPRPre.EndPos == sWhole.getLength() )
115 0 : return false;
116 :
117 : // Get numeral element
118 0 : sUser = aLocaleItem.decimalSeparator;
119 : ParseResult aPRNum = ScGlobal::pCharClass->parsePredefinedToken(
120 : KParseType::ANY_NUMBER, sWhole, aPRPre.EndPos,
121 0 : KParseTokens::ANY_NUMBER, sEmpty, KParseTokens::ANY_NUMBER, sUser );
122 :
123 0 : if ( aPRNum.EndPos == aPRPre.EndPos )
124 0 : return false;
125 :
126 0 : fNum = aPRNum.Value;
127 0 : sSuffix = sWhole.copy( aPRNum.EndPos );
128 :
129 0 : return true;
130 : }
131 :
132 : /** Naturally compares two given strings.
133 :
134 : This is the main function that should be called externally. It returns
135 : either 1, 0, or -1 depending on the comparison result of given two strings.
136 :
137 : @param sInput1
138 : Input string 1
139 :
140 : @param sInput2
141 : Input string 2
142 :
143 : @param bCaseSens
144 : Boolean value for case sensitivity
145 :
146 : @param pData
147 : Pointer to user defined sort list
148 :
149 : @param pCW
150 : Pointer to collator wrapper for normal string comparison
151 :
152 : @return Returnes 1 if sInput1 is greater, 0 if sInput1 == sInput2, and -1 if
153 : sInput2 is greater.
154 : */
155 0 : short Compare( const OUString &sInput1, const OUString &sInput2,
156 : const bool bCaseSens, const ScUserListData* pData, const CollatorWrapper *pCW )
157 : {
158 0 : OUString sStr1( sInput1 ), sStr2( sInput2 ), sPre1, sSuf1, sPre2, sSuf2;
159 :
160 : do
161 : {
162 : double nNum1, nNum2;
163 0 : bool bNumFound1 = SplitString( sStr1, sPre1, sSuf1, nNum1 );
164 0 : bool bNumFound2 = SplitString( sStr2, sPre2, sSuf2, nNum2 );
165 :
166 : short nPreRes; // Prefix comparison result
167 0 : if ( pData )
168 : {
169 0 : if ( bCaseSens )
170 : {
171 0 : if ( !bNumFound1 || !bNumFound2 )
172 0 : return static_cast<short>(pData->Compare( sStr1, sStr2 ));
173 : else
174 0 : nPreRes = pData->Compare( sPre1, sPre2 );
175 : }
176 : else
177 : {
178 0 : if ( !bNumFound1 || !bNumFound2 )
179 0 : return static_cast<short>(pData->ICompare( sStr1, sStr2 ));
180 : else
181 0 : nPreRes = pData->ICompare( sPre1, sPre2 );
182 : }
183 : }
184 : else
185 : {
186 0 : if ( !bNumFound1 || !bNumFound2 )
187 0 : return static_cast<short>(pCW->compareString( sStr1, sStr2 ));
188 : else
189 0 : nPreRes = static_cast<short>(pCW->compareString( sPre1, sPre2 ));
190 : }
191 :
192 : // Prefix strings differ. Return immediately.
193 0 : if ( nPreRes != 0 ) return nPreRes;
194 :
195 0 : if ( nNum1 != nNum2 )
196 : {
197 0 : if ( nNum1 < nNum2 ) return -1;
198 0 : return static_cast<short>( nNum1 > nNum2 );
199 : }
200 :
201 : // The prefix and the first numerical elements are equal, but the suffix
202 : // strings may still differ. Stay in the loop.
203 :
204 0 : sStr1 = sSuf1;
205 0 : sStr2 = sSuf2;
206 :
207 : } while (true);
208 :
209 0 : return 0;
210 : }
211 :
212 : }
213 :
214 : // STATIC DATA -----------------------------------------------------------
215 :
216 556 : struct ScSortInfo
217 : {
218 : ScRefCellValue maCell;
219 : SCCOLROW nOrg;
220 556 : DECL_FIXEDMEMPOOL_NEWDEL( ScSortInfo );
221 : };
222 76 : IMPL_FIXEDMEMPOOL_NEWDEL( ScSortInfo )
223 :
224 : // END OF STATIC DATA -----------------------------------------------------
225 :
226 : class ScSortInfoArray : boost::noncopyable
227 : {
228 : public:
229 :
230 22628 : struct Cell
231 : {
232 : ScRefCellValue maCell;
233 : const sc::CellTextAttr* mpAttr;
234 : const SvtBroadcaster* mpBroadcaster;
235 : const ScPostIt* mpNote;
236 : const ScPatternAttr* mpPattern;
237 :
238 388 : Cell() : mpAttr(NULL), mpBroadcaster(NULL), mpNote(NULL), mpPattern(NULL) {}
239 : };
240 :
241 388 : struct Row
242 : {
243 : std::vector<Cell> maCells;
244 :
245 : bool mbHidden:1;
246 : bool mbFiltered:1;
247 :
248 388 : Row( size_t nColSize ) : maCells(nColSize, Cell()), mbHidden(false), mbFiltered(false) {}
249 : };
250 :
251 : typedef std::vector<Row*> RowsType;
252 :
253 : private:
254 : boost::scoped_ptr<RowsType> mpRows; /// row-wise data table for sort by row operation.
255 :
256 : ScSortInfo*** pppInfo;
257 : SCSIZE nCount;
258 : SCCOLROW nStart;
259 : SCCOLROW mnLastIndex; /// index of last non-empty cell position.
260 : sal_uInt16 nUsedSorts;
261 :
262 : std::vector<SCCOLROW> maOrderIndices;
263 : bool mbKeepQuery;
264 : bool mbUpdateRefs;
265 :
266 : public:
267 88 : ScSortInfoArray( sal_uInt16 nSorts, SCCOLROW nInd1, SCCOLROW nInd2 ) :
268 : pppInfo(NULL),
269 88 : nCount( nInd2 - nInd1 + 1 ), nStart( nInd1 ),
270 : mnLastIndex(nInd2),
271 : nUsedSorts(nSorts),
272 : mbKeepQuery(false),
273 176 : mbUpdateRefs(false)
274 : {
275 88 : if (nUsedSorts)
276 : {
277 54 : pppInfo = new ScSortInfo**[nUsedSorts];
278 108 : for ( sal_uInt16 nSort = 0; nSort < nUsedSorts; nSort++ )
279 : {
280 54 : ScSortInfo** ppInfo = new ScSortInfo* [nCount];
281 332 : for ( SCSIZE j = 0; j < nCount; j++ )
282 278 : ppInfo[j] = new ScSortInfo;
283 54 : pppInfo[nSort] = ppInfo;
284 : }
285 : }
286 :
287 548 : for (size_t i = 0; i < nCount; ++i)
288 460 : maOrderIndices.push_back(i+nStart);
289 88 : }
290 :
291 88 : ~ScSortInfoArray()
292 88 : {
293 88 : if (pppInfo)
294 : {
295 108 : for ( sal_uInt16 nSort = 0; nSort < nUsedSorts; nSort++ )
296 : {
297 54 : ScSortInfo** ppInfo = pppInfo[nSort];
298 332 : for ( SCSIZE j = 0; j < nCount; j++ )
299 278 : delete ppInfo[j];
300 54 : delete [] ppInfo;
301 : }
302 54 : delete[] pppInfo;
303 : }
304 :
305 88 : if (mpRows)
306 74 : std::for_each(mpRows->begin(), mpRows->end(), boost::checked_deleter<Row>());
307 88 : }
308 :
309 88 : void SetKeepQuery( bool b ) { mbKeepQuery = b; }
310 :
311 462 : bool IsKeepQuery() const { return mbKeepQuery; }
312 :
313 88 : void SetUpdateRefs( bool b ) { mbUpdateRefs = b; }
314 :
315 596 : bool IsUpdateRefs() const { return mbUpdateRefs; }
316 :
317 : /**
318 : * Call this only during normal sorting, not from reordering.
319 : */
320 0 : ScSortInfo** GetFirstArray() const
321 : {
322 : OSL_ASSERT(pppInfo);
323 0 : return pppInfo[0];
324 : }
325 :
326 : /**
327 : * Call this only during normal sorting, not from reordering.
328 : */
329 2610 : ScSortInfo* Get( sal_uInt16 nSort, SCCOLROW nInd )
330 : {
331 : OSL_ASSERT(pppInfo);
332 2610 : return (pppInfo[nSort])[ nInd - nStart ];
333 : }
334 :
335 : /**
336 : * Call this only during normal sorting, not from reordering.
337 : */
338 176 : void Swap( SCCOLROW nInd1, SCCOLROW nInd2 )
339 : {
340 : OSL_ASSERT(pppInfo);
341 176 : SCSIZE n1 = static_cast<SCSIZE>(nInd1 - nStart);
342 176 : SCSIZE n2 = static_cast<SCSIZE>(nInd2 - nStart);
343 352 : for ( sal_uInt16 nSort = 0; nSort < nUsedSorts; nSort++ )
344 : {
345 176 : ScSortInfo** ppInfo = pppInfo[nSort];
346 176 : ScSortInfo* pTmp = ppInfo[n1];
347 176 : ppInfo[n1] = ppInfo[n2];
348 176 : ppInfo[n2] = pTmp;
349 : }
350 :
351 176 : std::swap(maOrderIndices[n1], maOrderIndices[n2]);
352 :
353 176 : if (mpRows)
354 : {
355 : // Swap rows in data table.
356 162 : RowsType& rRows = *mpRows;
357 162 : std::swap(rRows[n1], rRows[n2]);
358 : }
359 176 : }
360 :
361 8 : void SetOrderIndices( const std::vector<SCCOLROW>& rIndices )
362 : {
363 8 : maOrderIndices = rIndices;
364 8 : }
365 :
366 : /**
367 : * @param rIndices indices are actual row positions on the sheet, not an
368 : * offset from the top row.
369 : */
370 26 : void ReorderByRow( const std::vector<SCCOLROW>& rIndices )
371 : {
372 26 : if (!mpRows)
373 26 : return;
374 :
375 26 : RowsType& rRows = *mpRows;
376 :
377 26 : std::vector<SCCOLROW> aOrderIndices2;
378 26 : aOrderIndices2.reserve(rIndices.size());
379 :
380 52 : RowsType aRows2;
381 26 : aRows2.reserve(rRows.size());
382 :
383 26 : std::vector<SCCOLROW>::const_iterator it = rIndices.begin(), itEnd = rIndices.end();
384 164 : for (; it != itEnd; ++it)
385 : {
386 138 : size_t nPos = *it - nStart; // switch to an offset to top row.
387 138 : aRows2.push_back(rRows[nPos]);
388 138 : aOrderIndices2.push_back(maOrderIndices[nPos]);
389 : }
390 :
391 26 : rRows.swap(aRows2);
392 52 : maOrderIndices.swap(aOrderIndices2);
393 : }
394 :
395 232 : sal_uInt16 GetUsedSorts() const { return nUsedSorts; }
396 :
397 88 : SCCOLROW GetStart() const { return nStart; }
398 88 : SCCOLROW GetLast() const { return mnLastIndex; }
399 :
400 144 : const std::vector<SCCOLROW>& GetOrderIndices() const { return maOrderIndices; }
401 :
402 74 : RowsType& InitDataRows( size_t nRowSize, size_t nColSize )
403 : {
404 74 : mpRows.reset(new RowsType);
405 74 : mpRows->reserve(nRowSize);
406 462 : for (size_t i = 0; i < nRowSize; ++i)
407 388 : mpRows->push_back(new Row(nColSize));
408 :
409 74 : return *mpRows;
410 : }
411 :
412 74 : RowsType* GetDataRows()
413 : {
414 74 : return mpRows.get();
415 : }
416 : };
417 :
418 : namespace {
419 :
420 74 : void initDataRows(
421 : ScSortInfoArray& rArray, ScTable& rTab, ScColumn* pCols,
422 : SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2,
423 : bool bPattern, bool bHiddenFiltered )
424 : {
425 : // Fill row-wise data table.
426 74 : ScSortInfoArray::RowsType& rRows = rArray.InitDataRows(nRow2-nRow1+1, nCol2-nCol1+1);
427 :
428 2288 : for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
429 : {
430 2214 : ScColumn& rCol = pCols[nCol];
431 :
432 : // Skip reordering of cell formats if the whole span is on the same pattern entry.
433 2214 : bool bUniformPattern = rCol.GetPatternCount(nRow1, nRow2) < 2u;
434 :
435 2214 : sc::ColumnBlockConstPosition aBlockPos;
436 2214 : rCol.InitBlockPosition(aBlockPos);
437 13334 : for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
438 : {
439 11120 : ScSortInfoArray::Row& rRow = *rRows[nRow-nRow1];
440 11120 : ScSortInfoArray::Cell& rCell = rRow.maCells[nCol-nCol1];
441 :
442 11120 : rCell.maCell = rCol.GetCellValue(aBlockPos, nRow);
443 11120 : rCell.mpAttr = rCol.GetCellTextAttr(aBlockPos, nRow);
444 11120 : rCell.mpBroadcaster = rCol.GetBroadcaster(aBlockPos, nRow);
445 11120 : rCell.mpNote = rCol.GetCellNote(aBlockPos, nRow);
446 :
447 11120 : if (!bUniformPattern && bPattern)
448 6 : rCell.mpPattern = rCol.GetPattern(nRow);
449 : }
450 : }
451 :
452 74 : if (bHiddenFiltered)
453 : {
454 0 : for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
455 : {
456 0 : ScSortInfoArray::Row& rRow = *rRows[nRow-nRow1];
457 0 : rRow.mbHidden = rTab.RowHidden(nRow);
458 0 : rRow.mbFiltered = rTab.RowFiltered(nRow);
459 : }
460 : }
461 74 : }
462 :
463 : }
464 :
465 34 : ScSortInfoArray* ScTable::CreateSortInfoArray( const sc::ReorderParam& rParam )
466 : {
467 34 : ScSortInfoArray* pArray = NULL;
468 :
469 34 : if (rParam.mbByRow)
470 : {
471 : // Create a sort info array with just the data table.
472 26 : SCROW nRow1 = rParam.maSortRange.aStart.Row();
473 26 : SCROW nRow2 = rParam.maSortRange.aEnd.Row();
474 26 : SCCOL nCol1 = rParam.maSortRange.aStart.Col();
475 26 : SCCOL nCol2 = rParam.maSortRange.aEnd.Col();
476 :
477 26 : pArray = new ScSortInfoArray(0, nRow1, nRow2);
478 26 : pArray->SetKeepQuery(rParam.mbHiddenFiltered);
479 26 : pArray->SetUpdateRefs(rParam.mbUpdateRefs);
480 :
481 : initDataRows(
482 : *pArray, *this, aCol, nCol1, nRow1, nCol2, nRow2,
483 26 : rParam.mbPattern, rParam.mbHiddenFiltered);
484 : }
485 : else
486 : {
487 8 : SCCOLROW nCol1 = rParam.maSortRange.aStart.Col();
488 8 : SCCOLROW nCol2 = rParam.maSortRange.aEnd.Col();
489 :
490 8 : pArray = new ScSortInfoArray(0, nCol1, nCol2);
491 8 : pArray->SetKeepQuery(rParam.mbHiddenFiltered);
492 8 : pArray->SetUpdateRefs(rParam.mbUpdateRefs);
493 : }
494 :
495 34 : return pArray;
496 : }
497 :
498 54 : ScSortInfoArray* ScTable::CreateSortInfoArray(
499 : const ScSortParam& rSortParam, SCCOLROW nInd1, SCCOLROW nInd2,
500 : bool bKeepQuery, bool bUpdateRefs )
501 : {
502 54 : sal_uInt16 nUsedSorts = 1;
503 108 : while ( nUsedSorts < rSortParam.GetSortKeyCount() && rSortParam.maKeyState[nUsedSorts].bDoSort )
504 0 : nUsedSorts++;
505 54 : ScSortInfoArray* pArray = new ScSortInfoArray( nUsedSorts, nInd1, nInd2 );
506 54 : pArray->SetKeepQuery(bKeepQuery);
507 54 : pArray->SetUpdateRefs(bUpdateRefs);
508 :
509 54 : if ( rSortParam.bByRow )
510 : {
511 96 : for ( sal_uInt16 nSort = 0; nSort < nUsedSorts; nSort++ )
512 : {
513 48 : SCCOL nCol = static_cast<SCCOL>(rSortParam.maKeyState[nSort].nField);
514 48 : ScColumn* pCol = &aCol[nCol];
515 48 : sc::ColumnBlockConstPosition aBlockPos;
516 48 : pCol->InitBlockPosition(aBlockPos);
517 298 : for ( SCROW nRow = nInd1; nRow <= nInd2; nRow++ )
518 : {
519 250 : ScSortInfo* pInfo = pArray->Get( nSort, nRow );
520 250 : pInfo->maCell = pCol->GetCellValue(aBlockPos, nRow);
521 250 : pInfo->nOrg = nRow;
522 : }
523 : }
524 :
525 : initDataRows(
526 : *pArray, *this, aCol, rSortParam.nCol1, nInd1, rSortParam.nCol2, nInd2,
527 48 : rSortParam.bIncludePattern, bKeepQuery);
528 : }
529 : else
530 : {
531 12 : for ( sal_uInt16 nSort = 0; nSort < nUsedSorts; nSort++ )
532 : {
533 6 : SCROW nRow = rSortParam.maKeyState[nSort].nField;
534 68 : for ( SCCOL nCol = static_cast<SCCOL>(nInd1);
535 34 : nCol <= static_cast<SCCOL>(nInd2); nCol++ )
536 : {
537 28 : ScSortInfo* pInfo = pArray->Get( nSort, nCol );
538 28 : pInfo->maCell = GetCellValue(nCol, nRow);
539 28 : pInfo->nOrg = nCol;
540 : }
541 : }
542 : }
543 54 : return pArray;
544 : }
545 :
546 : namespace {
547 :
548 2214 : struct SortedColumn : boost::noncopyable
549 : {
550 : typedef mdds::flat_segment_tree<SCROW, const ScPatternAttr*> PatRangeType;
551 :
552 : sc::CellStoreType maCells;
553 : sc::CellTextAttrStoreType maCellTextAttrs;
554 : sc::BroadcasterStoreType maBroadcasters;
555 : sc::CellNoteStoreType maCellNotes;
556 :
557 : PatRangeType maPatterns;
558 : PatRangeType::const_iterator miPatternPos;
559 :
560 2214 : SortedColumn( size_t nTopEmptyRows ) :
561 : maCells(nTopEmptyRows),
562 : maCellTextAttrs(nTopEmptyRows),
563 : maBroadcasters(nTopEmptyRows),
564 : maCellNotes(nTopEmptyRows),
565 : maPatterns(0, MAXROWCOUNT, NULL),
566 2214 : miPatternPos(maPatterns.begin()) {}
567 :
568 6 : void setPattern( SCROW nRow, const ScPatternAttr* pPat )
569 : {
570 6 : miPatternPos = maPatterns.insert(miPatternPos, nRow, nRow+1, pPat).first;
571 6 : }
572 : };
573 :
574 74 : struct SortedRowFlags
575 : {
576 : typedef mdds::flat_segment_tree<SCROW,bool> FlagsType;
577 :
578 : FlagsType maRowsHidden;
579 : FlagsType maRowsFiltered;
580 : FlagsType::const_iterator miPosHidden;
581 : FlagsType::const_iterator miPosFiltered;
582 :
583 74 : SortedRowFlags() :
584 : maRowsHidden(0, MAXROWCOUNT, false),
585 : maRowsFiltered(0, MAXROWCOUNT, false),
586 : miPosHidden(maRowsHidden.begin()),
587 74 : miPosFiltered(maRowsFiltered.begin()) {}
588 :
589 0 : void setRowHidden( SCROW nRow, bool b )
590 : {
591 0 : miPosHidden = maRowsHidden.insert(miPosHidden, nRow, nRow+1, b).first;
592 0 : }
593 :
594 0 : void setRowFiltered( SCROW nRow, bool b )
595 : {
596 0 : miPosFiltered = maRowsFiltered.insert(miPosFiltered, nRow, nRow+1, b).first;
597 0 : }
598 : };
599 :
600 : struct PatternSpan
601 : {
602 : SCROW mnRow1;
603 : SCROW mnRow2;
604 : const ScPatternAttr* mpPattern;
605 :
606 6 : PatternSpan( SCROW nRow1, SCROW nRow2, const ScPatternAttr* pPat ) :
607 6 : mnRow1(nRow1), mnRow2(nRow2), mpPattern(pPat) {}
608 : };
609 :
610 : }
611 :
612 58 : bool ScTable::IsSortCollatorGlobal() const
613 : {
614 58 : return pSortCollator == ScGlobal::GetCollator() ||
615 58 : pSortCollator == ScGlobal::GetCaseCollator();
616 : }
617 :
618 58 : void ScTable::InitSortCollator( const ScSortParam& rPar )
619 : {
620 58 : if ( !rPar.aCollatorLocale.Language.isEmpty() )
621 : {
622 0 : if ( !pSortCollator || IsSortCollatorGlobal() )
623 0 : pSortCollator = new CollatorWrapper( comphelper::getProcessComponentContext() );
624 : pSortCollator->loadCollatorAlgorithm( rPar.aCollatorAlgorithm,
625 0 : rPar.aCollatorLocale, (rPar.bCaseSens ? 0 : SC_COLLATOR_IGNORES) );
626 : }
627 : else
628 : { // SYSTEM
629 58 : DestroySortCollator();
630 : pSortCollator = (rPar.bCaseSens ? ScGlobal::GetCaseCollator() :
631 58 : ScGlobal::GetCollator());
632 : }
633 58 : }
634 :
635 4434 : void ScTable::DestroySortCollator()
636 : {
637 4434 : if ( pSortCollator )
638 : {
639 58 : if ( !IsSortCollatorGlobal() )
640 0 : delete pSortCollator;
641 58 : pSortCollator = NULL;
642 : }
643 4434 : }
644 :
645 : namespace {
646 :
647 : template<typename _Hint, typename _ReorderMap, typename _Index>
648 400 : class ReorderNotifier : std::unary_function<SvtListener*, void>
649 : {
650 : _Hint maHint;
651 : public:
652 80 : ReorderNotifier( const _ReorderMap& rMap, SCTAB nTab, _Index nPos1, _Index nPos2 ) :
653 80 : maHint(rMap, nTab, nPos1, nPos2) {}
654 :
655 242 : void operator() ( SvtListener* p )
656 : {
657 242 : p->Notify(maHint);
658 242 : }
659 : };
660 :
661 : typedef ReorderNotifier<sc::RefColReorderHint, sc::ColRowReorderMapType, SCCOL> ColReorderNotifier;
662 : typedef ReorderNotifier<sc::RefRowReorderHint, sc::ColRowReorderMapType, SCROW> RowReorderNotifier;
663 :
664 : class FormulaGroupPosCollector : std::unary_function<SvtListener*, void>
665 : {
666 : sc::RefQueryFormulaGroup& mrQuery;
667 :
668 : public:
669 66 : FormulaGroupPosCollector( sc::RefQueryFormulaGroup& rQuery ) : mrQuery(rQuery) {}
670 :
671 236 : void operator() ( SvtListener* p )
672 : {
673 236 : p->Query(mrQuery);
674 236 : }
675 : };
676 :
677 : }
678 :
679 14 : void ScTable::SortReorderByColumn(
680 : ScSortInfoArray* pArray, SCROW nRow1, SCROW nRow2, bool bPattern, ScProgress* pProgress )
681 : {
682 14 : SCCOLROW nStart = pArray->GetStart();
683 14 : SCCOLROW nLast = pArray->GetLast();
684 :
685 14 : std::vector<SCCOLROW> aIndices = pArray->GetOrderIndices();
686 14 : size_t nCount = aIndices.size();
687 :
688 : // Cut formula grouping at row and reference boundaries before the reordering.
689 14 : ScRange aSortRange(nStart, nRow1, nTab, nLast, nRow2, nTab);
690 86 : for (SCCOL nCol = nStart; nCol <= nLast; ++nCol)
691 72 : aCol[nCol].SplitFormulaGroupByRelativeRef(aSortRange);
692 :
693 : // table to keep track of column index to position in the index table.
694 28 : std::vector<SCCOLROW> aPosTable(nCount);
695 86 : for (size_t i = 0; i < nCount; ++i)
696 72 : aPosTable[aIndices[i]-nStart] = i;
697 :
698 14 : SCCOLROW nDest = nStart;
699 86 : for (size_t i = 0; i < nCount; ++i, ++nDest)
700 : {
701 72 : SCCOLROW nSrc = aIndices[i];
702 72 : if (nDest != nSrc)
703 : {
704 34 : aCol[nDest].Swap(aCol[nSrc], nRow1, nRow2, bPattern);
705 :
706 : // Update the position of the index that was originally equal to nDest.
707 34 : size_t nPos = aPosTable[nDest-nStart];
708 34 : aIndices[nPos] = nSrc;
709 34 : aPosTable[nSrc-nStart] = nPos;
710 : }
711 :
712 72 : if (pProgress)
713 28 : pProgress->SetStateOnPercent(i);
714 : }
715 :
716 : // Reset formula cell positions which became out-of-sync after column reordering.
717 86 : for (SCCOL nCol = nStart; nCol <= nLast; ++nCol)
718 72 : aCol[nCol].ResetFormulaCellPositions(nRow1, nRow2);
719 :
720 : // Set up column reorder map (for later broadcasting of reference updates).
721 28 : sc::ColRowReorderMapType aColMap;
722 14 : const std::vector<SCCOLROW>& rOldIndices = pArray->GetOrderIndices();
723 86 : for (size_t i = 0, n = rOldIndices.size(); i < n; ++i)
724 : {
725 72 : SCCOL nNew = i + nStart;
726 72 : SCCOL nOld = rOldIndices[i];
727 72 : aColMap.insert(sc::ColRowReorderMapType::value_type(nOld, nNew));
728 : }
729 :
730 : // Collect all listeners within sorted range ahead of time.
731 28 : std::vector<SvtListener*> aListeners;
732 :
733 : // Get all area listeners that listen on one column within the range and
734 : // end their listening.
735 14 : ScRange aMoveRange( nStart, nRow1, nTab, nLast, nRow2, nTab);
736 : std::vector<sc::AreaListener> aAreaListeners = pDocument->GetBASM()->GetAllListeners(
737 28 : aMoveRange, sc::OneColumnInsideArea);
738 : {
739 14 : std::vector<sc::AreaListener>::iterator it = aAreaListeners.begin(), itEnd = aAreaListeners.end();
740 14 : for (; it != itEnd; ++it)
741 : {
742 0 : pDocument->EndListeningArea(it->maArea, it->mpListener);
743 0 : aListeners.push_back( it->mpListener);
744 : }
745 : }
746 :
747 14 : if (pArray->IsUpdateRefs())
748 : {
749 86 : for (SCCOL nCol = nStart; nCol <= nLast; ++nCol)
750 72 : aCol[nCol].CollectListeners(aListeners, nRow1, nRow2);
751 :
752 : // Remove any duplicate listener entries and notify all listeners
753 : // afterward. We must ensure that we notify each unique listener only
754 : // once.
755 14 : std::sort(aListeners.begin(), aListeners.end());
756 14 : aListeners.erase(std::unique(aListeners.begin(), aListeners.end()), aListeners.end());
757 14 : ColReorderNotifier aFunc(aColMap, nTab, nRow1, nRow2);
758 14 : std::for_each(aListeners.begin(), aListeners.end(), aFunc);
759 : }
760 :
761 : // Re-start area listeners on the reordered columns.
762 : {
763 14 : std::vector<sc::AreaListener>::iterator it = aAreaListeners.begin(), itEnd = aAreaListeners.end();
764 14 : for (; it != itEnd; ++it)
765 : {
766 0 : ScRange aNewRange = it->maArea;
767 0 : sc::ColRowReorderMapType::const_iterator itCol = aColMap.find( aNewRange.aStart.Col());
768 0 : if (itCol != aColMap.end())
769 : {
770 0 : aNewRange.aStart.SetCol( itCol->second);
771 0 : aNewRange.aEnd.SetCol( itCol->second);
772 : }
773 0 : pDocument->StartListeningArea(aNewRange, it->mpListener);
774 : }
775 : }
776 :
777 : // Re-join formulas at row boundaries now that all the references have
778 : // been adjusted for column reordering.
779 86 : for (SCCOL nCol = nStart; nCol <= nLast; ++nCol)
780 : {
781 72 : sc::CellStoreType& rCells = aCol[nCol].maCells;
782 72 : sc::CellStoreType::position_type aPos = rCells.position(nRow1);
783 72 : sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
784 72 : if (nRow2 < MAXROW)
785 : {
786 42 : aPos = rCells.position(aPos.first, nRow2+1);
787 42 : sc::SharedFormulaUtil::joinFormulaCellAbove(aPos);
788 : }
789 14 : }
790 14 : }
791 :
792 74 : void ScTable::SortReorderByRow(
793 : ScSortInfoArray* pArray, SCCOL nCol1, SCCOL nCol2, ScProgress* pProgress )
794 : {
795 74 : if (nCol2 < nCol1)
796 74 : return;
797 :
798 74 : SCROW nRow1 = pArray->GetStart();
799 74 : SCROW nRow2 = pArray->GetLast();
800 74 : ScSortInfoArray::RowsType* pRows = pArray->GetDataRows();
801 : assert(pRows); // In sort-by-row mode we must have data rows already populated.
802 :
803 74 : if (!pArray->IsUpdateRefs())
804 : {
805 : // When the update ref mode is disabled, we need to detach all formula
806 : // cells in the sorted range before reordering, and re-start them
807 : // afterward.
808 8 : sc::EndListeningContext aCxt(*pDocument);
809 8 : DetachFormulaCells(aCxt, nCol1, nRow1, nCol2, nRow2);
810 : }
811 :
812 : // Split formula groups at the sort range boundaries (if applicable).
813 74 : std::vector<SCROW> aRowBounds;
814 74 : aRowBounds.reserve(2);
815 74 : aRowBounds.push_back(nRow1);
816 74 : aRowBounds.push_back(nRow2+1);
817 2288 : for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
818 2214 : SplitFormulaGroups(nCol, aRowBounds);
819 :
820 : // Cells in the data rows only reference values in the document. Make
821 : // a copy before updating the document.
822 :
823 74 : size_t nColCount = nCol2 - nCol1 + 1;
824 148 : boost::ptr_vector<SortedColumn> aSortedCols; // storage for copied cells.
825 148 : SortedRowFlags aRowFlags;
826 74 : aSortedCols.reserve(nColCount);
827 2288 : for (size_t i = 0; i < nColCount; ++i)
828 : {
829 : // In the sorted column container, element positions and row
830 : // positions must match, else formula cells may mis-behave during
831 : // grouping.
832 2214 : aSortedCols.push_back(new SortedColumn(nRow1));
833 : }
834 :
835 462 : for (size_t i = 0; i < pRows->size(); ++i)
836 : {
837 388 : ScSortInfoArray::Row* pRow = (*pRows)[i];
838 11508 : for (size_t j = 0; j < pRow->maCells.size(); ++j)
839 : {
840 11120 : ScAddress aCellPos(nCol1 + j, nRow1 + i, nTab);
841 :
842 11120 : ScSortInfoArray::Cell& rCell = pRow->maCells[j];
843 :
844 11120 : sc::CellStoreType& rCellStore = aSortedCols.at(j).maCells;
845 11120 : switch (rCell.maCell.meType)
846 : {
847 : case CELLTYPE_STRING:
848 : assert(rCell.mpAttr);
849 68 : rCellStore.push_back(*rCell.maCell.mpString);
850 68 : break;
851 : case CELLTYPE_VALUE:
852 : assert(rCell.mpAttr);
853 388 : rCellStore.push_back(rCell.maCell.mfValue);
854 388 : break;
855 : case CELLTYPE_EDIT:
856 : assert(rCell.mpAttr);
857 4 : rCellStore.push_back(rCell.maCell.mpEditText->Clone());
858 4 : break;
859 : case CELLTYPE_FORMULA:
860 : {
861 : assert(rCell.mpAttr);
862 360 : ScAddress aOldPos = rCell.maCell.mpFormula->aPos;
863 :
864 360 : ScFormulaCell* pNew = rCell.maCell.mpFormula->Clone( aCellPos, SC_CLONECELL_DEFAULT);
865 360 : if (pArray->IsUpdateRefs())
866 : {
867 342 : pNew->CopyAllBroadcasters(*rCell.maCell.mpFormula);
868 342 : pNew->GetCode()->AdjustReferenceOnMovedOrigin(aOldPos, aCellPos);
869 : }
870 :
871 360 : rCellStore.push_back(pNew);
872 : }
873 360 : break;
874 : default:
875 : assert(!rCell.mpAttr);
876 10300 : rCellStore.push_back_empty();
877 : }
878 :
879 11120 : sc::CellTextAttrStoreType& rAttrStore = aSortedCols.at(j).maCellTextAttrs;
880 11120 : if (rCell.mpAttr)
881 820 : rAttrStore.push_back(*rCell.mpAttr);
882 : else
883 10300 : rAttrStore.push_back_empty();
884 :
885 : // At this point each broadcaster instance is managed by 2
886 : // containers. We will release those in the original storage
887 : // below before transferring them to the document.
888 11120 : sc::BroadcasterStoreType& rBCStore = aSortedCols.at(j).maBroadcasters;
889 11120 : if (rCell.mpBroadcaster)
890 : // A const pointer would be implicitly converted to a bool type.
891 242 : rBCStore.push_back(const_cast<SvtBroadcaster*>(rCell.mpBroadcaster));
892 : else
893 10878 : rBCStore.push_back_empty();
894 :
895 : // The same with cell note instances ...
896 11120 : sc::CellNoteStoreType& rNoteStore = aSortedCols.at(j).maCellNotes;
897 11120 : if (rCell.mpNote)
898 2 : rNoteStore.push_back(const_cast<ScPostIt*>(rCell.mpNote));
899 : else
900 11118 : rNoteStore.push_back_empty();
901 :
902 11120 : if (rCell.mpPattern)
903 6 : aSortedCols.at(j).setPattern(aCellPos.Row(), rCell.mpPattern);
904 : }
905 :
906 388 : if (pArray->IsKeepQuery())
907 : {
908 : // Hidden and filtered flags are first converted to segments.
909 0 : SCROW nRow = nRow1 + i;
910 0 : aRowFlags.setRowHidden(nRow, pRow->mbHidden);
911 0 : aRowFlags.setRowFiltered(nRow, pRow->mbFiltered);
912 : }
913 :
914 388 : if (pProgress)
915 194 : pProgress->SetStateOnPercent(i);
916 : }
917 :
918 2288 : for (size_t i = 0, n = aSortedCols.size(); i < n; ++i)
919 : {
920 2214 : SCCOL nThisCol = i + nCol1;
921 :
922 : {
923 2214 : sc::CellStoreType& rDest = aCol[nThisCol].maCells;
924 2214 : sc::CellStoreType& rSrc = aSortedCols[i].maCells;
925 2214 : rSrc.transfer(nRow1, nRow2, rDest, nRow1);
926 : }
927 :
928 : {
929 2214 : sc::CellTextAttrStoreType& rDest = aCol[nThisCol].maCellTextAttrs;
930 2214 : sc::CellTextAttrStoreType& rSrc = aSortedCols[i].maCellTextAttrs;
931 2214 : rSrc.transfer(nRow1, nRow2, rDest, nRow1);
932 : }
933 :
934 : {
935 2214 : sc::BroadcasterStoreType& rSrc = aSortedCols[i].maBroadcasters;
936 2214 : sc::BroadcasterStoreType& rDest = aCol[nThisCol].maBroadcasters;
937 :
938 : // Release current broadcasters first, to prevent them from getting deleted.
939 2214 : rDest.release_range(nRow1, nRow2);
940 :
941 : // Transfer sorted broadcaster segment to the document.
942 2214 : rSrc.transfer(nRow1, nRow2, rDest, nRow1);
943 : }
944 :
945 : {
946 2214 : sc::CellNoteStoreType& rSrc = aSortedCols[i].maCellNotes;
947 2214 : sc::CellNoteStoreType& rDest = aCol[nThisCol].maCellNotes;
948 :
949 : // Do the same as broadcaster storage transfer (to prevent double deletion).
950 2214 : rDest.release_range(nRow1, nRow2);
951 2214 : rSrc.transfer(nRow1, nRow2, rDest, nRow1);
952 2214 : aCol[nThisCol].UpdateNoteCaptions(nRow1, nRow2);
953 : }
954 :
955 : {
956 : // Get all row spans where the pattern is not NULL.
957 : std::vector<PatternSpan> aSpans =
958 : sc::toSpanArrayWithValue<SCROW,const ScPatternAttr*,PatternSpan>(
959 2214 : aSortedCols[i].maPatterns);
960 :
961 2214 : std::vector<PatternSpan>::iterator it = aSpans.begin(), itEnd = aSpans.end();
962 2220 : for (; it != itEnd; ++it)
963 : {
964 : assert(it->mpPattern); // should never be NULL.
965 6 : pDocument->GetPool()->Put(*it->mpPattern);
966 : }
967 :
968 2220 : for (it = aSpans.begin(); it != itEnd; ++it)
969 : {
970 6 : aCol[nThisCol].SetPatternArea(it->mnRow1, it->mnRow2, *it->mpPattern, true);
971 6 : pDocument->GetPool()->Remove(*it->mpPattern);
972 2214 : }
973 : }
974 :
975 2214 : aCol[nThisCol].CellStorageModified();
976 : }
977 :
978 74 : if (pArray->IsKeepQuery())
979 : {
980 0 : aRowFlags.maRowsHidden.build_tree();
981 0 : aRowFlags.maRowsFiltered.build_tree();
982 :
983 : // Remove all flags in the range first.
984 0 : SetRowHidden(nRow1, nRow2, false);
985 0 : SetRowFiltered(nRow1, nRow2, false);
986 :
987 : std::vector<sc::RowSpan> aSpans =
988 0 : sc::toSpanArray<SCROW,sc::RowSpan>(aRowFlags.maRowsHidden, nRow1);
989 :
990 0 : std::vector<sc::RowSpan>::const_iterator it = aSpans.begin(), itEnd = aSpans.end();
991 0 : for (; it != itEnd; ++it)
992 0 : SetRowHidden(it->mnRow1, it->mnRow2, true);
993 :
994 0 : aSpans = sc::toSpanArray<SCROW,sc::RowSpan>(aRowFlags.maRowsFiltered, nRow1);
995 :
996 0 : it = aSpans.begin(), itEnd = aSpans.end();
997 0 : for (; it != itEnd; ++it)
998 0 : SetRowFiltered(it->mnRow1, it->mnRow2, true);
999 : }
1000 :
1001 : // Set up row reorder map (for later broadcasting of reference updates).
1002 74 : sc::ColRowReorderMapType aRowMap;
1003 74 : const std::vector<SCCOLROW>& rOldIndices = pArray->GetOrderIndices();
1004 462 : for (size_t i = 0, n = rOldIndices.size(); i < n; ++i)
1005 : {
1006 388 : SCROW nNew = i + nRow1;
1007 388 : SCROW nOld = rOldIndices[i];
1008 388 : aRowMap.insert(sc::ColRowReorderMapType::value_type(nOld, nNew));
1009 : }
1010 :
1011 : // Collect all listeners within sorted range ahead of time.
1012 148 : std::vector<SvtListener*> aListeners;
1013 :
1014 : // Get all area listeners that listen on one row within the range and end
1015 : // their listening.
1016 74 : ScRange aMoveRange( nCol1, nRow1, nTab, nCol2, nRow2, nTab);
1017 : std::vector<sc::AreaListener> aAreaListeners = pDocument->GetBASM()->GetAllListeners(
1018 148 : aMoveRange, sc::OneRowInsideArea);
1019 : {
1020 74 : std::vector<sc::AreaListener>::iterator it = aAreaListeners.begin(), itEnd = aAreaListeners.end();
1021 114 : for (; it != itEnd; ++it)
1022 : {
1023 40 : pDocument->EndListeningArea(it->maArea, it->mpListener);
1024 40 : aListeners.push_back( it->mpListener);
1025 : }
1026 : }
1027 :
1028 74 : if (pArray->IsUpdateRefs())
1029 : {
1030 : // Collect listeners of cell broadcasters.
1031 2260 : for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
1032 2194 : aCol[nCol].CollectListeners(aListeners, nRow1, nRow2);
1033 :
1034 : // Remove any duplicate listener entries. We must ensure that we notify
1035 : // each unique listener only once.
1036 66 : std::sort(aListeners.begin(), aListeners.end());
1037 66 : aListeners.erase(std::unique(aListeners.begin(), aListeners.end()), aListeners.end());
1038 :
1039 : // Collect positions of all shared formula cells outside the sorted range,
1040 : // and make them unshared before notifying them.
1041 66 : sc::RefQueryFormulaGroup aFormulaGroupPos;
1042 66 : aFormulaGroupPos.setSkipRange(ScRange(nCol1, nRow1, nTab, nCol2, nRow2, nTab));
1043 :
1044 66 : std::for_each(aListeners.begin(), aListeners.end(), FormulaGroupPosCollector(aFormulaGroupPos));
1045 66 : const sc::RefQueryFormulaGroup::TabsType& rGroupTabs = aFormulaGroupPos.getAllPositions();
1046 66 : sc::RefQueryFormulaGroup::TabsType::const_iterator itGroupTab = rGroupTabs.begin(), itGroupTabEnd = rGroupTabs.end();
1047 76 : for (; itGroupTab != itGroupTabEnd; ++itGroupTab)
1048 : {
1049 10 : const sc::RefQueryFormulaGroup::ColsType& rCols = itGroupTab->second;
1050 10 : sc::RefQueryFormulaGroup::ColsType::const_iterator itCol = rCols.begin(), itColEnd = rCols.end();
1051 20 : for (; itCol != itColEnd; ++itCol)
1052 : {
1053 10 : const sc::RefQueryFormulaGroup::ColType& rCol = itCol->second;
1054 10 : std::vector<SCROW> aBounds(rCol);
1055 10 : pDocument->UnshareFormulaCells(itGroupTab->first, itCol->first, aBounds);
1056 10 : }
1057 : }
1058 :
1059 : // Notify the listeners.
1060 132 : RowReorderNotifier aFunc(aRowMap, nTab, nCol1, nCol2);
1061 66 : std::for_each(aListeners.begin(), aListeners.end(), aFunc);
1062 :
1063 : // Re-group formulas in affected columns.
1064 76 : for (itGroupTab = rGroupTabs.begin(); itGroupTab != itGroupTabEnd; ++itGroupTab)
1065 : {
1066 10 : const sc::RefQueryFormulaGroup::ColsType& rCols = itGroupTab->second;
1067 10 : sc::RefQueryFormulaGroup::ColsType::const_iterator itCol = rCols.begin(), itColEnd = rCols.end();
1068 20 : for (; itCol != itColEnd; ++itCol)
1069 10 : pDocument->RegroupFormulaCells(itGroupTab->first, itCol->first);
1070 66 : }
1071 : }
1072 :
1073 : // Re-start area listeners on the reordered rows.
1074 : {
1075 74 : std::vector<sc::AreaListener>::iterator it = aAreaListeners.begin(), itEnd = aAreaListeners.end();
1076 114 : for (; it != itEnd; ++it)
1077 : {
1078 40 : ScRange aNewRange = it->maArea;
1079 40 : sc::ColRowReorderMapType::const_iterator itRow = aRowMap.find( aNewRange.aStart.Row());
1080 40 : if (itRow != aRowMap.end())
1081 : {
1082 40 : aNewRange.aStart.SetRow( itRow->second);
1083 40 : aNewRange.aEnd.SetRow( itRow->second);
1084 : }
1085 40 : pDocument->StartListeningArea(aNewRange, it->mpListener);
1086 : }
1087 : }
1088 :
1089 : // Re-group columns in the sorted range too.
1090 2288 : for (SCCOL i = nCol1; i <= nCol2; ++i)
1091 2214 : aCol[i].RegroupFormulaCells();
1092 :
1093 74 : if (!pArray->IsUpdateRefs())
1094 : {
1095 8 : sc::StartListeningContext aCxt(*pDocument);
1096 8 : AttachFormulaCells(aCxt, nCol1, nRow1, nCol2, nRow2);
1097 148 : }
1098 : }
1099 :
1100 1010 : short ScTable::CompareCell(
1101 : sal_uInt16 nSort,
1102 : ScRefCellValue& rCell1, SCCOL nCell1Col, SCROW nCell1Row,
1103 : ScRefCellValue& rCell2, SCCOL nCell2Col, SCROW nCell2Row ) const
1104 : {
1105 1010 : short nRes = 0;
1106 :
1107 1010 : CellType eType1 = rCell1.meType, eType2 = rCell2.meType;
1108 :
1109 1010 : if (!rCell1.isEmpty())
1110 : {
1111 998 : if (!rCell2.isEmpty())
1112 : {
1113 994 : bool bStr1 = ( eType1 != CELLTYPE_VALUE );
1114 994 : if (eType1 == CELLTYPE_FORMULA && rCell1.mpFormula->IsValue())
1115 218 : bStr1 = false;
1116 994 : bool bStr2 = ( eType2 != CELLTYPE_VALUE );
1117 994 : if (eType2 == CELLTYPE_FORMULA && rCell2.mpFormula->IsValue())
1118 216 : bStr2 = false;
1119 :
1120 994 : if ( bStr1 && bStr2 ) // nur Strings untereinander als String vergleichen!
1121 : {
1122 98 : OUString aStr1;
1123 196 : OUString aStr2;
1124 98 : if (eType1 == CELLTYPE_STRING)
1125 62 : aStr1 = rCell1.mpString->getString();
1126 : else
1127 36 : GetString(nCell1Col, nCell1Row, aStr1);
1128 98 : if (eType2 == CELLTYPE_STRING)
1129 62 : aStr2 = rCell2.mpString->getString();
1130 : else
1131 36 : GetString(nCell2Col, nCell2Row, aStr2);
1132 :
1133 98 : bool bUserDef = aSortParam.bUserDef; // custom sort order
1134 98 : bool bNaturalSort = aSortParam.bNaturalSort; // natural sort
1135 98 : bool bCaseSens = aSortParam.bCaseSens; // case sensitivity
1136 :
1137 98 : if (bUserDef)
1138 : {
1139 0 : ScUserList* pList = ScGlobal::GetUserList();
1140 0 : const ScUserListData* pData = (*pList)[aSortParam.nUserIndex];
1141 :
1142 0 : if (pData)
1143 : {
1144 0 : if ( bNaturalSort )
1145 0 : nRes = naturalsort::Compare( aStr1, aStr2, bCaseSens, pData, pSortCollator );
1146 : else
1147 : {
1148 0 : if ( bCaseSens )
1149 0 : nRes = sal::static_int_cast<short>( pData->Compare(aStr1, aStr2) );
1150 : else
1151 0 : nRes = sal::static_int_cast<short>( pData->ICompare(aStr1, aStr2) );
1152 : }
1153 : }
1154 : else
1155 0 : bUserDef = false;
1156 :
1157 : }
1158 98 : if (!bUserDef)
1159 : {
1160 98 : if ( bNaturalSort )
1161 0 : nRes = naturalsort::Compare( aStr1, aStr2, bCaseSens, NULL, pSortCollator );
1162 : else
1163 98 : nRes = static_cast<short>( pSortCollator->compareString( aStr1, aStr2 ) );
1164 98 : }
1165 : }
1166 896 : else if ( bStr1 ) // String <-> Zahl
1167 22 : nRes = 1; // Zahl vorne
1168 874 : else if ( bStr2 ) // Zahl <-> String
1169 30 : nRes = -1; // Zahl vorne
1170 : else // Zahlen untereinander
1171 : {
1172 844 : double nVal1 = rCell1.getValue();
1173 844 : double nVal2 = rCell2.getValue();
1174 844 : if (nVal1 < nVal2)
1175 372 : nRes = -1;
1176 472 : else if (nVal1 > nVal2)
1177 276 : nRes = 1;
1178 : }
1179 994 : if ( !aSortParam.maKeyState[nSort].bAscending )
1180 176 : nRes = -nRes;
1181 : }
1182 : else
1183 4 : nRes = -1;
1184 : }
1185 : else
1186 : {
1187 12 : if (!rCell2.isEmpty())
1188 6 : nRes = 1;
1189 : else
1190 6 : nRes = 0; // beide leer
1191 : }
1192 1010 : return nRes;
1193 : }
1194 :
1195 934 : short ScTable::Compare( ScSortInfoArray* pArray, SCCOLROW nIndex1, SCCOLROW nIndex2 ) const
1196 : {
1197 : short nRes;
1198 934 : sal_uInt16 nSort = 0;
1199 934 : do
1200 : {
1201 934 : ScSortInfo* pInfo1 = pArray->Get( nSort, nIndex1 );
1202 934 : ScSortInfo* pInfo2 = pArray->Get( nSort, nIndex2 );
1203 934 : if ( aSortParam.bByRow )
1204 : nRes = CompareCell( nSort,
1205 850 : pInfo1->maCell, static_cast<SCCOL>(aSortParam.maKeyState[nSort].nField), pInfo1->nOrg,
1206 1700 : pInfo2->maCell, static_cast<SCCOL>(aSortParam.maKeyState[nSort].nField), pInfo2->nOrg );
1207 : else
1208 : nRes = CompareCell( nSort,
1209 84 : pInfo1->maCell, static_cast<SCCOL>(pInfo1->nOrg), aSortParam.maKeyState[nSort].nField,
1210 168 : pInfo2->maCell, static_cast<SCCOL>(pInfo2->nOrg), aSortParam.maKeyState[nSort].nField );
1211 934 : } while ( nRes == 0 && ++nSort < pArray->GetUsedSorts() );
1212 934 : if( nRes == 0 )
1213 : {
1214 232 : ScSortInfo* pInfo1 = pArray->Get( 0, nIndex1 );
1215 232 : ScSortInfo* pInfo2 = pArray->Get( 0, nIndex2 );
1216 232 : if( pInfo1->nOrg < pInfo2->nOrg )
1217 0 : nRes = -1;
1218 232 : else if( pInfo1->nOrg > pInfo2->nOrg )
1219 2 : nRes = 1;
1220 : }
1221 934 : return nRes;
1222 : }
1223 :
1224 258 : void ScTable::QuickSort( ScSortInfoArray* pArray, SCsCOLROW nLo, SCsCOLROW nHi )
1225 : {
1226 258 : if ((nHi - nLo) == 1)
1227 : {
1228 108 : if (Compare(pArray, nLo, nHi) > 0)
1229 52 : pArray->Swap( nLo, nHi );
1230 : }
1231 : else
1232 : {
1233 150 : SCsCOLROW ni = nLo;
1234 150 : SCsCOLROW nj = nHi;
1235 222 : do
1236 : {
1237 464 : while ((ni <= nHi) && (Compare(pArray, ni, nLo)) < 0)
1238 20 : ni++;
1239 806 : while ((nj >= nLo) && (Compare(pArray, nLo, nj)) < 0)
1240 362 : nj--;
1241 222 : if (ni <= nj)
1242 : {
1243 172 : if (ni != nj)
1244 124 : pArray->Swap( ni, nj );
1245 172 : ni++;
1246 172 : nj--;
1247 : }
1248 : } while (ni < nj);
1249 150 : if ((nj - nLo) < (nHi - ni))
1250 : {
1251 120 : if (nLo < nj)
1252 24 : QuickSort(pArray, nLo, nj);
1253 120 : if (ni < nHi)
1254 120 : QuickSort(pArray, ni, nHi);
1255 : }
1256 : else
1257 : {
1258 30 : if (ni < nHi)
1259 30 : QuickSort(pArray, ni, nHi);
1260 30 : if (nLo < nj)
1261 30 : QuickSort(pArray, nLo, nj);
1262 : }
1263 : }
1264 258 : }
1265 :
1266 76 : short ScTable::Compare(SCCOLROW nIndex1, SCCOLROW nIndex2) const
1267 : {
1268 : short nRes;
1269 76 : sal_uInt16 nSort = 0;
1270 76 : const sal_uInt32 nMaxSorts = aSortParam.GetSortKeyCount();
1271 76 : if (aSortParam.bByRow)
1272 : {
1273 66 : do
1274 : {
1275 66 : SCCOL nCol = static_cast<SCCOL>(aSortParam.maKeyState[nSort].nField);
1276 66 : ScRefCellValue aCell1 = aCol[nCol].GetCellValue(nIndex1);
1277 132 : ScRefCellValue aCell2 = aCol[nCol].GetCellValue(nIndex2);
1278 132 : nRes = CompareCell(nSort, aCell1, nCol, nIndex1, aCell2, nCol, nIndex2);
1279 66 : } while ( nRes == 0 && ++nSort < nMaxSorts && aSortParam.maKeyState[nSort].bDoSort );
1280 : }
1281 : else
1282 : {
1283 10 : do
1284 : {
1285 10 : SCROW nRow = aSortParam.maKeyState[nSort].nField;
1286 10 : ScRefCellValue aCell1 = aCol[nIndex1].GetCellValue(nRow);
1287 20 : ScRefCellValue aCell2 = aCol[nIndex2].GetCellValue(nRow);
1288 : nRes = CompareCell( nSort, aCell1, static_cast<SCCOL>(nIndex1),
1289 20 : nRow, aCell2, static_cast<SCCOL>(nIndex2), nRow );
1290 10 : } while ( nRes == 0 && ++nSort < nMaxSorts && aSortParam.maKeyState[nSort].bDoSort );
1291 : }
1292 76 : return nRes;
1293 : }
1294 :
1295 58 : bool ScTable::IsSorted( SCCOLROW nStart, SCCOLROW nEnd ) const // ueber aSortParam
1296 : {
1297 80 : for (SCCOLROW i=nStart; i<nEnd; i++)
1298 : {
1299 76 : if (Compare( i, i+1 ) > 0)
1300 54 : return false;
1301 : }
1302 4 : return true;
1303 : }
1304 :
1305 0 : void ScTable::DecoladeRow( ScSortInfoArray* pArray, SCROW nRow1, SCROW nRow2 )
1306 : {
1307 : SCROW nRow;
1308 0 : int nMax = nRow2 - nRow1;
1309 0 : for (SCROW i = nRow1; (i + 4) <= nRow2; i += 4)
1310 : {
1311 0 : nRow = comphelper::rng::uniform_int_distribution(0, nMax-1);
1312 0 : pArray->Swap(i, nRow1 + nRow);
1313 : }
1314 0 : }
1315 :
1316 58 : void ScTable::Sort(
1317 : const ScSortParam& rSortParam, bool bKeepQuery, bool bUpdateRefs,
1318 : ScProgress* pProgress, sc::ReorderParam* pUndo )
1319 : {
1320 58 : aSortParam = rSortParam;
1321 58 : InitSortCollator( rSortParam );
1322 58 : bGlobalKeepQuery = bKeepQuery;
1323 :
1324 58 : if (pUndo)
1325 : {
1326 : // Copy over the basic sort parameters.
1327 46 : pUndo->mbByRow = rSortParam.bByRow;
1328 46 : pUndo->mbPattern = rSortParam.bIncludePattern;
1329 46 : pUndo->mbHiddenFiltered = bKeepQuery;
1330 46 : pUndo->mbUpdateRefs = bUpdateRefs;
1331 : }
1332 :
1333 58 : if (rSortParam.bByRow)
1334 : {
1335 52 : SCROW nLastRow = 0;
1336 2220 : for (SCCOL nCol = aSortParam.nCol1; nCol <= aSortParam.nCol2; nCol++)
1337 2168 : nLastRow = std::max(nLastRow, aCol[nCol].GetLastDataPos());
1338 52 : nLastRow = std::min(nLastRow, aSortParam.nRow2);
1339 : SCROW nRow1 = (rSortParam.bHasHeader ?
1340 52 : aSortParam.nRow1 + 1 : aSortParam.nRow1);
1341 52 : if (!IsSorted(nRow1, nLastRow))
1342 : {
1343 48 : if(pProgress)
1344 36 : pProgress->SetState( 0, nLastRow-nRow1 );
1345 :
1346 48 : boost::scoped_ptr<ScSortInfoArray> pArray(CreateSortInfoArray(aSortParam, nRow1, nLastRow, bKeepQuery, bUpdateRefs));
1347 :
1348 48 : if ( nLastRow - nRow1 > 255 )
1349 0 : DecoladeRow(pArray.get(), nRow1, nLastRow);
1350 :
1351 48 : QuickSort(pArray.get(), nRow1, nLastRow);
1352 48 : SortReorderByRow(pArray.get(), aSortParam.nCol1, aSortParam.nCol2, pProgress);
1353 :
1354 48 : if (pUndo)
1355 : {
1356 36 : pUndo->maSortRange = ScRange(rSortParam.nCol1, nRow1, nTab, rSortParam.nCol2, nLastRow, nTab);
1357 36 : pUndo->maOrderIndices = pArray->GetOrderIndices();
1358 48 : }
1359 : }
1360 : }
1361 : else
1362 : {
1363 : SCCOL nLastCol;
1364 12 : for (nLastCol = aSortParam.nCol2;
1365 6 : (nLastCol > aSortParam.nCol1) && aCol[nLastCol].IsEmptyBlock(aSortParam.nRow1, aSortParam.nRow2); nLastCol--)
1366 : {
1367 : }
1368 : SCCOL nCol1 = (rSortParam.bHasHeader ?
1369 6 : aSortParam.nCol1 + 1 : aSortParam.nCol1);
1370 6 : if (!IsSorted(nCol1, nLastCol))
1371 : {
1372 6 : if(pProgress)
1373 6 : pProgress->SetState( 0, nLastCol-nCol1 );
1374 :
1375 6 : boost::scoped_ptr<ScSortInfoArray> pArray(CreateSortInfoArray(aSortParam, nCol1, nLastCol, bKeepQuery, bUpdateRefs));
1376 :
1377 6 : QuickSort(pArray.get(), nCol1, nLastCol);
1378 6 : SortReorderByColumn(pArray.get(), aSortParam.nRow1, aSortParam.nRow2, aSortParam.bIncludePattern, pProgress);
1379 :
1380 6 : if (pUndo)
1381 : {
1382 6 : pUndo->maSortRange = ScRange(nCol1, aSortParam.nRow1, nTab, nLastCol, aSortParam.nRow2, nTab);
1383 6 : pUndo->maOrderIndices = pArray->GetOrderIndices();
1384 6 : }
1385 : }
1386 : }
1387 58 : DestroySortCollator();
1388 58 : }
1389 :
1390 34 : void ScTable::Reorder( const sc::ReorderParam& rParam, ScProgress* pProgress )
1391 : {
1392 34 : if (rParam.maOrderIndices.empty())
1393 0 : return;
1394 :
1395 34 : boost::scoped_ptr<ScSortInfoArray> pArray(CreateSortInfoArray(rParam));
1396 34 : if (!pArray)
1397 0 : return;
1398 :
1399 34 : if (rParam.mbByRow)
1400 : {
1401 : // Re-play sorting from the known sort indices.
1402 26 : pArray->ReorderByRow(rParam.maOrderIndices);
1403 :
1404 : SortReorderByRow(
1405 26 : pArray.get(), rParam.maSortRange.aStart.Col(), rParam.maSortRange.aEnd.Col(), pProgress);
1406 : }
1407 : else
1408 : {
1409 : // Ordering by column is much simpler. Just set the order indices and we are done.
1410 8 : pArray->SetOrderIndices(rParam.maOrderIndices);
1411 : SortReorderByColumn(
1412 : pArray.get(), rParam.maSortRange.aStart.Row(), rParam.maSortRange.aEnd.Row(),
1413 8 : rParam.mbPattern, pProgress);
1414 34 : }
1415 : }
1416 :
1417 : namespace {
1418 :
1419 : class SubTotalRowFinder
1420 : {
1421 : const ScTable& mrTab;
1422 : const ScSubTotalParam& mrParam;
1423 :
1424 : public:
1425 16 : SubTotalRowFinder(const ScTable& rTab, const ScSubTotalParam& rParam) :
1426 16 : mrTab(rTab), mrParam(rParam) {}
1427 :
1428 4 : bool operator() (size_t nRow, const ScFormulaCell* pCell)
1429 : {
1430 4 : if (!pCell->IsSubTotal())
1431 0 : return false;
1432 :
1433 4 : SCCOL nStartCol = mrParam.nCol1;
1434 4 : SCCOL nEndCol = mrParam.nCol2;
1435 :
1436 4100 : for (SCCOL i = 0; i <= MAXCOL; ++i)
1437 : {
1438 4096 : if (nStartCol <= i && i <= nEndCol)
1439 16 : continue;
1440 :
1441 4080 : if (mrTab.HasData(i, nRow))
1442 0 : return true;
1443 : }
1444 :
1445 4 : return false;
1446 : }
1447 : };
1448 :
1449 : }
1450 :
1451 4 : bool ScTable::TestRemoveSubTotals( const ScSubTotalParam& rParam )
1452 : {
1453 4 : SCCOL nStartCol = rParam.nCol1;
1454 4 : SCROW nStartRow = rParam.nRow1 + 1; // Header
1455 4 : SCCOL nEndCol = rParam.nCol2;
1456 4 : SCROW nEndRow = rParam.nRow2;
1457 :
1458 20 : for (SCCOL nCol = nStartCol; nCol <= nEndCol; ++nCol)
1459 : {
1460 16 : const sc::CellStoreType& rCells = aCol[nCol].maCells;
1461 16 : SubTotalRowFinder aFunc(*this, rParam);
1462 : std::pair<sc::CellStoreType::const_iterator,size_t> aPos =
1463 16 : sc::FindFormula(rCells, nStartRow, nEndRow, aFunc);
1464 16 : if (aPos.first != rCells.end())
1465 0 : return true;
1466 : }
1467 4 : return false;
1468 : }
1469 :
1470 : namespace {
1471 :
1472 8 : class RemoveSubTotalsHandler
1473 : {
1474 : std::vector<SCROW> maRemoved;
1475 : public:
1476 :
1477 4 : void operator() (size_t nRow, const ScFormulaCell* p)
1478 : {
1479 4 : if (p->IsSubTotal())
1480 4 : maRemoved.push_back(nRow);
1481 4 : }
1482 :
1483 4 : void getRows(std::vector<SCROW>& rRows)
1484 : {
1485 : // Sort and remove duplicates.
1486 4 : std::sort(maRemoved.begin(), maRemoved.end());
1487 4 : std::vector<SCROW>::iterator it = std::unique(maRemoved.begin(), maRemoved.end());
1488 4 : maRemoved.erase(it, maRemoved.end());
1489 :
1490 4 : maRemoved.swap(rRows);
1491 4 : }
1492 : };
1493 :
1494 : }
1495 :
1496 4 : void ScTable::RemoveSubTotals( ScSubTotalParam& rParam )
1497 : {
1498 4 : SCCOL nStartCol = rParam.nCol1;
1499 4 : SCROW nStartRow = rParam.nRow1 + 1; // Header
1500 4 : SCCOL nEndCol = rParam.nCol2;
1501 4 : SCROW nEndRow = rParam.nRow2; // wird veraendert
1502 :
1503 4 : RemoveSubTotalsHandler aFunc;
1504 20 : for (SCCOL nCol = nStartCol; nCol <= nEndCol; ++nCol)
1505 : {
1506 16 : const sc::CellStoreType& rCells = aCol[nCol].maCells;
1507 16 : sc::ParseFormula(rCells.begin(), rCells, nStartRow, nEndRow, aFunc);
1508 : }
1509 :
1510 8 : std::vector<SCROW> aRows;
1511 4 : aFunc.getRows(aRows);
1512 :
1513 4 : std::vector<SCROW>::reverse_iterator it = aRows.rbegin(), itEnd = aRows.rend();
1514 8 : for (; it != itEnd; ++it)
1515 : {
1516 4 : SCROW nRow = *it;
1517 4 : RemoveRowBreak(nRow+1, false, true);
1518 4 : pDocument->DeleteRow(0, nTab, MAXCOL, nTab, nRow, 1);
1519 : }
1520 :
1521 8 : rParam.nRow2 -= aRows.size();
1522 4 : }
1523 :
1524 : // harte Zahlenformate loeschen (fuer Ergebnisformeln)
1525 :
1526 0 : static void lcl_RemoveNumberFormat( ScTable* pTab, SCCOL nCol, SCROW nRow )
1527 : {
1528 0 : const ScPatternAttr* pPattern = pTab->GetPattern( nCol, nRow );
1529 0 : if ( pPattern->GetItemSet().GetItemState( ATTR_VALUE_FORMAT, false )
1530 : == SfxItemState::SET )
1531 : {
1532 0 : ScPatternAttr aNewPattern( *pPattern );
1533 0 : SfxItemSet& rSet = aNewPattern.GetItemSet();
1534 0 : rSet.ClearItem( ATTR_VALUE_FORMAT );
1535 0 : rSet.ClearItem( ATTR_LANGUAGE_FORMAT );
1536 0 : pTab->SetPattern( nCol, nRow, aNewPattern, true );
1537 : }
1538 0 : }
1539 :
1540 : // at least MSC needs this at linkage level to be able to use it in a template
1541 : typedef struct lcl_ScTable_DoSubTotals_RowEntry
1542 : {
1543 : sal_uInt16 nGroupNo;
1544 : SCROW nSubStartRow;
1545 : SCROW nDestRow;
1546 : SCROW nFuncStart;
1547 : SCROW nFuncEnd;
1548 : } RowEntry;
1549 :
1550 : // neue Zwischenergebnisse
1551 : // rParam.nRow2 wird veraendert !
1552 :
1553 2 : bool ScTable::DoSubTotals( ScSubTotalParam& rParam )
1554 : {
1555 2 : SCCOL nStartCol = rParam.nCol1;
1556 2 : SCROW nStartRow = rParam.nRow1 + 1; // Header
1557 2 : SCCOL nEndCol = rParam.nCol2;
1558 2 : SCROW nEndRow = rParam.nRow2; // wird veraendert
1559 : sal_uInt16 i;
1560 :
1561 : // Leerzeilen am Ende weglassen,
1562 : // damit alle Ueberlaeufe (MAXROW) bei InsertRow gefunden werden (#35180#)
1563 : // Wenn sortiert wurde, sind alle Leerzeilen am Ende.
1564 2 : SCSIZE nEmpty = GetEmptyLinesInBlock( nStartCol, nStartRow, nEndCol, nEndRow, DIR_BOTTOM );
1565 2 : nEndRow -= nEmpty;
1566 :
1567 2 : sal_uInt16 nLevelCount = 0; // Anzahl Gruppierungen
1568 2 : bool bDoThis = true;
1569 6 : for (i=0; i<MAXSUBTOTAL && bDoThis; i++)
1570 4 : if (rParam.bGroupActive[i])
1571 2 : nLevelCount = i+1;
1572 : else
1573 2 : bDoThis = false;
1574 :
1575 2 : if (nLevelCount==0) // nichts tun
1576 0 : return true;
1577 :
1578 2 : SCCOL* nGroupCol = rParam.nField; // Spalten nach denen
1579 : // gruppiert wird
1580 :
1581 : // Durch (leer) als eigene Kategorie muss immer auf
1582 : // Teilergebniszeilen aus den anderen Spalten getestet werden
1583 : // (frueher nur, wenn eine Spalte mehrfach vorkam)
1584 2 : bool bTestPrevSub = ( nLevelCount > 1 );
1585 :
1586 2 : OUString aSubString;
1587 4 : OUString aOutString;
1588 :
1589 2 : bool bIgnoreCase = !rParam.bCaseSens;
1590 :
1591 : OUString *pCompString[MAXSUBTOTAL]; // Pointer wegen Compiler-Problemen
1592 8 : for (i=0; i<MAXSUBTOTAL; i++)
1593 6 : pCompString[i] = new OUString;
1594 :
1595 : //! sortieren?
1596 :
1597 2 : ScStyleSheet* pStyle = (ScStyleSheet*) pDocument->GetStyleSheetPool()->Find(
1598 2 : ScGlobal::GetRscString(STR_STYLENAME_RESULT), SFX_STYLE_FAMILY_PARA );
1599 :
1600 2 : bool bSpaceLeft = true; // Erfolg beim Einfuegen?
1601 :
1602 : // For performance reasons collect formula entries so their
1603 : // references don't have to be tested for updates each time a new row is
1604 : // inserted
1605 : RowEntry aRowEntry;
1606 4 : ::std::vector< RowEntry > aRowVector;
1607 :
1608 6 : for (sal_uInt16 nLevel=0; nLevel<=nLevelCount && bSpaceLeft; nLevel++) // incl. Gesamtergebnis
1609 : {
1610 4 : bool bTotal = ( nLevel == nLevelCount );
1611 4 : aRowEntry.nGroupNo = bTotal ? 0 : (nLevelCount-nLevel-1);
1612 :
1613 : // how many results per level
1614 4 : SCCOL nResCount = rParam.nSubTotals[aRowEntry.nGroupNo];
1615 : // result functions
1616 4 : ScSubTotalFunc* eResFunc = rParam.pFunctions[aRowEntry.nGroupNo];
1617 :
1618 4 : if (nResCount > 0) // sonst nur sortieren
1619 : {
1620 8 : for (i=0; i<=aRowEntry.nGroupNo; i++)
1621 : {
1622 4 : GetString( nGroupCol[i], nStartRow, aSubString );
1623 4 : if ( bIgnoreCase )
1624 4 : *pCompString[i] = ScGlobal::pCharClass->uppercase( aSubString );
1625 : else
1626 0 : *pCompString[i] = aSubString;
1627 : } // aSubString bleibt auf dem letzten stehen
1628 :
1629 4 : bool bBlockVis = false; // Gruppe eingeblendet?
1630 4 : aRowEntry.nSubStartRow = nStartRow;
1631 18 : for (SCROW nRow=nStartRow; nRow<=nEndRow+1 && bSpaceLeft; nRow++)
1632 : {
1633 : bool bChanged;
1634 14 : if (nRow>nEndRow)
1635 4 : bChanged = true;
1636 : else
1637 : {
1638 10 : bChanged = false;
1639 10 : if (!bTotal)
1640 : {
1641 4 : OUString aString;
1642 8 : for (i=0; i<=aRowEntry.nGroupNo && !bChanged; i++)
1643 : {
1644 4 : GetString( nGroupCol[i], nRow, aString );
1645 4 : if (bIgnoreCase)
1646 4 : aString = ScGlobal::pCharClass->uppercase(aString);
1647 : // wenn sortiert, ist "leer" eine eigene Gruppe
1648 : // sonst sind leere Zellen unten erlaubt
1649 8 : bChanged = ( ( !aString.isEmpty() || rParam.bDoSort ) &&
1650 8 : aString != *pCompString[i] );
1651 : }
1652 4 : if ( bChanged && bTestPrevSub )
1653 : {
1654 : // No group change on rows that will contain subtotal formulas
1655 0 : for ( ::std::vector< RowEntry >::const_iterator
1656 0 : iEntry( aRowVector.begin());
1657 0 : iEntry != aRowVector.end(); ++iEntry)
1658 : {
1659 0 : if ( iEntry->nDestRow == nRow )
1660 : {
1661 0 : bChanged = false;
1662 0 : break;
1663 : }
1664 : }
1665 4 : }
1666 : }
1667 : }
1668 14 : if ( bChanged )
1669 : {
1670 4 : aRowEntry.nDestRow = nRow;
1671 4 : aRowEntry.nFuncStart = aRowEntry.nSubStartRow;
1672 4 : aRowEntry.nFuncEnd = nRow-1;
1673 :
1674 : bSpaceLeft = pDocument->InsertRow( 0, nTab, MAXCOL, nTab,
1675 4 : aRowEntry.nDestRow, 1 );
1676 4 : DBShowRow( aRowEntry.nDestRow, bBlockVis );
1677 4 : bBlockVis = false;
1678 4 : if ( rParam.bPagebreak && nRow < MAXROW &&
1679 0 : aRowEntry.nSubStartRow != nStartRow && nLevel == 0)
1680 0 : SetRowBreak(aRowEntry.nSubStartRow, false, true);
1681 :
1682 4 : if (bSpaceLeft)
1683 : {
1684 18 : for ( ::std::vector< RowEntry >::iterator iMove(
1685 4 : aRowVector.begin() );
1686 12 : iMove != aRowVector.end(); ++iMove)
1687 : {
1688 2 : if ( aRowEntry.nDestRow <= iMove->nSubStartRow )
1689 0 : ++iMove->nSubStartRow;
1690 2 : if ( aRowEntry.nDestRow <= iMove->nDestRow )
1691 0 : ++iMove->nDestRow;
1692 2 : if ( aRowEntry.nDestRow <= iMove->nFuncStart )
1693 0 : ++iMove->nFuncStart;
1694 2 : if ( aRowEntry.nDestRow <= iMove->nFuncEnd )
1695 0 : ++iMove->nFuncEnd;
1696 : }
1697 : // collect formula positions
1698 4 : aRowVector.push_back( aRowEntry );
1699 :
1700 4 : if (bTotal) // "Gesamtergebnis"
1701 2 : aOutString = ScGlobal::GetRscString( STR_TABLE_GESAMTERGEBNIS );
1702 : else
1703 : { // " Ergebnis"
1704 2 : aOutString = aSubString;
1705 2 : if (aOutString.isEmpty())
1706 0 : aOutString = ScGlobal::GetRscString( STR_EMPTYDATA );
1707 2 : aOutString += " ";
1708 2 : sal_uInt16 nStrId = STR_TABLE_ERGEBNIS;
1709 2 : if ( nResCount == 1 )
1710 2 : switch ( eResFunc[0] )
1711 : {
1712 0 : case SUBTOTAL_FUNC_AVE: nStrId = STR_FUN_TEXT_AVG; break;
1713 : case SUBTOTAL_FUNC_CNT:
1714 0 : case SUBTOTAL_FUNC_CNT2: nStrId = STR_FUN_TEXT_COUNT; break;
1715 0 : case SUBTOTAL_FUNC_MAX: nStrId = STR_FUN_TEXT_MAX; break;
1716 0 : case SUBTOTAL_FUNC_MIN: nStrId = STR_FUN_TEXT_MIN; break;
1717 0 : case SUBTOTAL_FUNC_PROD: nStrId = STR_FUN_TEXT_PRODUCT; break;
1718 : case SUBTOTAL_FUNC_STD:
1719 0 : case SUBTOTAL_FUNC_STDP: nStrId = STR_FUN_TEXT_STDDEV; break;
1720 2 : case SUBTOTAL_FUNC_SUM: nStrId = STR_FUN_TEXT_SUM; break;
1721 : case SUBTOTAL_FUNC_VAR:
1722 0 : case SUBTOTAL_FUNC_VARP: nStrId = STR_FUN_TEXT_VAR; break;
1723 : default:
1724 : {
1725 : // added to avoid warnings
1726 : }
1727 : }
1728 2 : aOutString += ScGlobal::GetRscString( nStrId );
1729 : }
1730 4 : SetString( nGroupCol[aRowEntry.nGroupNo], aRowEntry.nDestRow, nTab, aOutString );
1731 4 : ApplyStyle( nGroupCol[aRowEntry.nGroupNo], aRowEntry.nDestRow, *pStyle );
1732 :
1733 4 : ++nRow;
1734 4 : ++nEndRow;
1735 4 : aRowEntry.nSubStartRow = nRow;
1736 8 : for (i=0; i<=aRowEntry.nGroupNo; i++)
1737 : {
1738 4 : GetString( nGroupCol[i], nRow, aSubString );
1739 4 : if ( bIgnoreCase )
1740 4 : *pCompString[i] = ScGlobal::pCharClass->uppercase( aSubString );
1741 : else
1742 0 : *pCompString[i] = aSubString;
1743 : }
1744 : }
1745 : }
1746 14 : bBlockVis = !RowFiltered(nRow);
1747 : }
1748 : }
1749 : }
1750 :
1751 : // now insert the formulas
1752 : ScComplexRefData aRef;
1753 2 : aRef.InitFlags();
1754 2 : aRef.Ref1.SetAbsTab(nTab);
1755 2 : aRef.Ref2.SetAbsTab(nTab);
1756 18 : for ( ::std::vector< RowEntry >::const_iterator iEntry( aRowVector.begin());
1757 12 : iEntry != aRowVector.end(); ++iEntry)
1758 : {
1759 4 : SCCOL nResCount = rParam.nSubTotals[iEntry->nGroupNo];
1760 4 : SCCOL* nResCols = rParam.pSubTotals[iEntry->nGroupNo];
1761 4 : ScSubTotalFunc* eResFunc = rParam.pFunctions[iEntry->nGroupNo];
1762 8 : for ( SCCOL nResult=0; nResult < nResCount; ++nResult )
1763 : {
1764 4 : aRef.Ref1.SetAbsCol(nResCols[nResult]);
1765 4 : aRef.Ref1.SetAbsRow(iEntry->nFuncStart);
1766 4 : aRef.Ref2.SetAbsCol(nResCols[nResult]);
1767 4 : aRef.Ref2.SetAbsRow(iEntry->nFuncEnd);
1768 :
1769 4 : ScTokenArray aArr;
1770 4 : aArr.AddOpCode( ocSubTotal );
1771 4 : aArr.AddOpCode( ocOpen );
1772 4 : aArr.AddDouble( (double) eResFunc[nResult] );
1773 4 : aArr.AddOpCode( ocSep );
1774 4 : aArr.AddDoubleReference( aRef );
1775 4 : aArr.AddOpCode( ocClose );
1776 4 : aArr.AddOpCode( ocStop );
1777 : ScFormulaCell* pCell = new ScFormulaCell(
1778 4 : pDocument, ScAddress(nResCols[nResult], iEntry->nDestRow, nTab), aArr);
1779 :
1780 4 : SetFormulaCell(nResCols[nResult], iEntry->nDestRow, pCell);
1781 :
1782 4 : if ( nResCols[nResult] != nGroupCol[iEntry->nGroupNo] )
1783 : {
1784 0 : ApplyStyle( nResCols[nResult], iEntry->nDestRow, *pStyle );
1785 :
1786 : // Zahlformat loeschen
1787 0 : lcl_RemoveNumberFormat( this, nResCols[nResult], iEntry->nDestRow );
1788 : }
1789 4 : }
1790 :
1791 : }
1792 :
1793 : //! je nach Einstellung Zwischensummen-Zeilen nach oben verschieben ?
1794 :
1795 : //! Outlines direkt erzeugen?
1796 :
1797 2 : if (bSpaceLeft)
1798 2 : DoAutoOutline( nStartCol, nStartRow, nEndCol, nEndRow );
1799 :
1800 8 : for (i=0; i<MAXSUBTOTAL; i++)
1801 6 : delete pCompString[i];
1802 :
1803 2 : rParam.nRow2 = nEndRow; // neues Ende
1804 4 : return bSpaceLeft;
1805 : }
1806 :
1807 0 : void ScTable::MarkSubTotalCells(
1808 : sc::ColumnSpanSet& rSet, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, bool bVal ) const
1809 : {
1810 0 : if (!ValidCol(nCol1) || !ValidCol(nCol2))
1811 0 : return;
1812 :
1813 : // Pick up all subtotal formula cells.
1814 0 : for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
1815 0 : aCol[nCol].MarkSubTotalCells(rSet, nRow1, nRow2, bVal);
1816 :
1817 : // Pick up all filtered rows.
1818 : ScFlatBoolRowSegments::RangeData aFilteredSpan;
1819 0 : SCROW nRow = nRow1;
1820 0 : while (nRow <= nRow2)
1821 : {
1822 0 : if (!mpFilteredRows->getRangeData(nRow, aFilteredSpan))
1823 : // Failed for whatever reason.
1824 0 : return;
1825 :
1826 0 : if (aFilteredSpan.mbValue)
1827 : {
1828 : // Filtered span found.
1829 0 : for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
1830 0 : rSet.set(nTab, nCol, nRow, aFilteredSpan.mnRow2, bVal);
1831 : }
1832 :
1833 0 : nRow = aFilteredSpan.mnRow2 + 1;
1834 : }
1835 : }
1836 :
1837 : namespace {
1838 :
1839 : class QueryEvaluator
1840 : {
1841 : ScDocument& mrDoc;
1842 : svl::SharedStringPool& mrStrPool;
1843 : const ScTable& mrTab;
1844 : const ScQueryParam& mrParam;
1845 : const bool* mpTestEqualCondition;
1846 : utl::TransliterationWrapper* mpTransliteration;
1847 : CollatorWrapper* mpCollator;
1848 : const bool mbMatchWholeCell;
1849 :
1850 1402 : bool isPartialTextMatchOp(const ScQueryEntry& rEntry) const
1851 : {
1852 1402 : switch (rEntry.eOp)
1853 : {
1854 : // these operators can only be used with textural comparisons.
1855 : case SC_CONTAINS:
1856 : case SC_DOES_NOT_CONTAIN:
1857 : case SC_BEGINS_WITH:
1858 : case SC_ENDS_WITH:
1859 : case SC_DOES_NOT_BEGIN_WITH:
1860 : case SC_DOES_NOT_END_WITH:
1861 0 : return true;
1862 : default:
1863 : ;
1864 : }
1865 1402 : return false;
1866 : }
1867 :
1868 962 : bool isTextMatchOp(const ScQueryEntry& rEntry) const
1869 : {
1870 962 : if (isPartialTextMatchOp(rEntry))
1871 0 : return true;
1872 :
1873 962 : switch (rEntry.eOp)
1874 : {
1875 : // these operators can be used for either textural or value comparison.
1876 : case SC_EQUAL:
1877 : case SC_NOT_EQUAL:
1878 644 : return true;
1879 : default:
1880 : ;
1881 : }
1882 318 : return false;
1883 : }
1884 :
1885 440 : bool isRealRegExp(const ScQueryEntry& rEntry) const
1886 : {
1887 440 : if (!mrParam.bRegExp)
1888 392 : return false;
1889 :
1890 48 : return isTextMatchOp(rEntry);
1891 : }
1892 :
1893 440 : bool isTestRegExp(const ScQueryEntry& rEntry) const
1894 : {
1895 440 : if (!mpTestEqualCondition)
1896 346 : return false;
1897 :
1898 94 : if (!mrParam.bRegExp)
1899 94 : return false;
1900 :
1901 0 : return (rEntry.eOp == SC_LESS_EQUAL || rEntry.eOp == SC_GREATER_EQUAL);
1902 : }
1903 :
1904 : public:
1905 1494 : QueryEvaluator(ScDocument& rDoc, const ScTable& rTab, const ScQueryParam& rParam,
1906 : const bool* pTestEqualCondition) :
1907 : mrDoc(rDoc),
1908 1494 : mrStrPool(rDoc.GetSharedStringPool()),
1909 : mrTab(rTab),
1910 : mrParam(rParam),
1911 : mpTestEqualCondition(pTestEqualCondition),
1912 2988 : mbMatchWholeCell(rDoc.GetDocOptions().IsMatchWholeCell())
1913 : {
1914 1494 : if (rParam.bCaseSens)
1915 : {
1916 0 : mpTransliteration = ScGlobal::GetCaseTransliteration();
1917 0 : mpCollator = ScGlobal::GetCaseCollator();
1918 : }
1919 : else
1920 : {
1921 1494 : mpTransliteration = ScGlobal::GetpTransliteration();
1922 1494 : mpCollator = ScGlobal::GetCollator();
1923 : }
1924 1494 : }
1925 :
1926 1680 : bool isQueryByValue(
1927 : const ScQueryEntry::Item& rItem, SCCOL nCol, SCROW nRow, ScRefCellValue& rCell)
1928 : {
1929 1680 : if (rItem.meType == ScQueryEntry::ByString)
1930 496 : return false;
1931 :
1932 1184 : if (!rCell.isEmpty())
1933 : {
1934 1180 : if (rCell.meType == CELLTYPE_FORMULA && rCell.mpFormula->GetErrCode())
1935 : // Error values are compared as string.
1936 0 : return false;
1937 :
1938 1180 : return rCell.hasNumeric();
1939 : }
1940 :
1941 4 : return mrTab.HasValueData(nCol, nRow);
1942 : }
1943 :
1944 522 : bool isQueryByString(
1945 : const ScQueryEntry& rEntry, const ScQueryEntry::Item& rItem,
1946 : SCCOL nCol, SCROW nRow, ScRefCellValue& rCell)
1947 : {
1948 522 : if (isTextMatchOp(rEntry))
1949 322 : return true;
1950 :
1951 200 : if (rItem.meType != ScQueryEntry::ByString)
1952 14 : return false;
1953 :
1954 186 : if (!rCell.isEmpty())
1955 182 : return rCell.hasString();
1956 :
1957 4 : return mrTab.HasStringData(nCol, nRow);
1958 : }
1959 :
1960 1158 : std::pair<bool,bool> compareByValue(
1961 : const ScRefCellValue& rCell, SCCOL nCol, SCROW nRow,
1962 : const ScQueryEntry& rEntry, const ScQueryEntry::Item& rItem)
1963 : {
1964 1158 : bool bOk = false;
1965 1158 : bool bTestEqual = false;
1966 : double nCellVal;
1967 1158 : if (!rCell.isEmpty())
1968 : {
1969 1158 : switch (rCell.meType)
1970 : {
1971 : case CELLTYPE_VALUE :
1972 1158 : nCellVal = rCell.mfValue;
1973 1158 : break;
1974 : case CELLTYPE_FORMULA :
1975 0 : nCellVal = rCell.mpFormula->GetValue();
1976 0 : break;
1977 : default:
1978 0 : nCellVal = 0.0;
1979 : }
1980 :
1981 : }
1982 : else
1983 0 : nCellVal = mrTab.GetValue(nCol, nRow);
1984 :
1985 : /* NOTE: lcl_PrepareQuery() prepares a filter query such that if a
1986 : * date+time format was queried rEntry.bQueryByDate is not set. In
1987 : * case other queries wanted to use this mechanism they should do
1988 : * the same, in other words only if rEntry.nVal is an integer value
1989 : * rEntry.bQueryByDate should be true and the time fraction be
1990 : * stripped here. */
1991 1158 : if (rItem.meType == ScQueryEntry::ByDate)
1992 : {
1993 0 : sal_uInt32 nNumFmt = mrTab.GetNumberFormat(nCol, nRow);
1994 0 : const SvNumberformat* pEntry = mrDoc.GetFormatTable()->GetEntry(nNumFmt);
1995 0 : if (pEntry)
1996 : {
1997 0 : short nNumFmtType = pEntry->GetType();
1998 : /* NOTE: Omitting the check for absence of
1999 : * NUMBERFORMAT_TIME would include also date+time formatted
2000 : * values of the same day. That may be desired in some
2001 : * cases, querying all time values of a day, but confusing
2002 : * in other cases. A user can always setup a standard
2003 : * filter query for x >= date AND x < date+1 */
2004 0 : if ((nNumFmtType & NUMBERFORMAT_DATE) && !(nNumFmtType & NUMBERFORMAT_TIME))
2005 : {
2006 : // The format is of date type. Strip off the time
2007 : // element.
2008 0 : nCellVal = ::rtl::math::approxFloor(nCellVal);
2009 : }
2010 : }
2011 : }
2012 :
2013 1158 : switch (rEntry.eOp)
2014 : {
2015 : case SC_EQUAL :
2016 478 : bOk = ::rtl::math::approxEqual(nCellVal, rItem.mfVal);
2017 478 : break;
2018 : case SC_LESS :
2019 24 : bOk = (nCellVal < rItem.mfVal) && !::rtl::math::approxEqual(nCellVal, rItem.mfVal);
2020 24 : break;
2021 : case SC_GREATER :
2022 98 : bOk = (nCellVal > rItem.mfVal) && !::rtl::math::approxEqual(nCellVal, rItem.mfVal);
2023 98 : break;
2024 : case SC_LESS_EQUAL :
2025 258 : bOk = (nCellVal < rItem.mfVal) || ::rtl::math::approxEqual(nCellVal, rItem.mfVal);
2026 258 : if ( bOk && mpTestEqualCondition )
2027 200 : bTestEqual = ::rtl::math::approxEqual(nCellVal, rItem.mfVal);
2028 258 : break;
2029 : case SC_GREATER_EQUAL :
2030 300 : bOk = (nCellVal > rItem.mfVal) || ::rtl::math::approxEqual( nCellVal, rItem.mfVal);
2031 300 : if ( bOk && mpTestEqualCondition )
2032 170 : bTestEqual = ::rtl::math::approxEqual(nCellVal, rItem.mfVal);
2033 300 : break;
2034 : case SC_NOT_EQUAL :
2035 0 : bOk = !::rtl::math::approxEqual(nCellVal, rItem.mfVal);
2036 0 : break;
2037 : default:
2038 : {
2039 : // added to avoid warnings
2040 : }
2041 : }
2042 :
2043 1158 : return std::pair<bool,bool>(bOk, bTestEqual);
2044 : }
2045 :
2046 440 : std::pair<bool,bool> compareByString(
2047 : ScRefCellValue& rCell, SCROW nRow, const ScQueryEntry& rEntry, const ScQueryEntry::Item& rItem)
2048 : {
2049 440 : bool bOk = false;
2050 440 : bool bTestEqual = false;
2051 440 : bool bMatchWholeCell = mbMatchWholeCell;
2052 440 : svl::SharedString aCellStr;
2053 440 : if (isPartialTextMatchOp(rEntry))
2054 : // may have to do partial textural comparison.
2055 0 : bMatchWholeCell = false;
2056 :
2057 440 : if (!rCell.isEmpty())
2058 : {
2059 438 : if (rCell.meType == CELLTYPE_FORMULA && rCell.mpFormula->GetErrCode())
2060 : {
2061 : // Error cell is evaluated as string (for now).
2062 0 : aCellStr = mrStrPool.intern(ScGlobal::GetErrorString(rCell.mpFormula->GetErrCode()));
2063 : }
2064 438 : else if (rCell.meType == CELLTYPE_STRING)
2065 382 : aCellStr = *rCell.mpString;
2066 : else
2067 : {
2068 56 : sal_uLong nFormat = mrTab.GetNumberFormat( static_cast<SCCOL>(rEntry.nField), nRow );
2069 56 : OUString aStr;
2070 56 : ScCellFormat::GetInputString(rCell, nFormat, aStr, *mrDoc.GetFormatTable(), &mrDoc);
2071 56 : aCellStr = mrStrPool.intern(aStr);
2072 : }
2073 : }
2074 : else
2075 : {
2076 2 : OUString aStr;
2077 2 : mrTab.GetInputString(static_cast<SCCOL>(rEntry.nField), nRow, aStr);
2078 2 : aCellStr = mrStrPool.intern(aStr);
2079 : }
2080 :
2081 440 : bool bRealRegExp = isRealRegExp(rEntry);
2082 440 : bool bTestRegExp = isTestRegExp(rEntry);
2083 :
2084 440 : if ( bRealRegExp || bTestRegExp )
2085 : {
2086 48 : sal_Int32 nStart = 0;
2087 48 : sal_Int32 nEnd = aCellStr.getLength();
2088 :
2089 : // from 614 on, nEnd is behind the found text
2090 48 : bool bMatch = false;
2091 48 : if ( rEntry.eOp == SC_ENDS_WITH || rEntry.eOp == SC_DOES_NOT_END_WITH )
2092 : {
2093 0 : nEnd = 0;
2094 0 : nStart = aCellStr.getLength();
2095 : bMatch = rEntry.GetSearchTextPtr( mrParam.bCaseSens )
2096 0 : ->SearchBackward(aCellStr.getString(), &nStart, &nEnd);
2097 : }
2098 : else
2099 : {
2100 : bMatch = rEntry.GetSearchTextPtr( mrParam.bCaseSens )
2101 48 : ->SearchForward(aCellStr.getString(), &nStart, &nEnd);
2102 : }
2103 62 : if ( bMatch && bMatchWholeCell
2104 62 : && (nStart != 0 || nEnd != aCellStr.getLength()) )
2105 0 : bMatch = false; // RegExp must match entire cell string
2106 48 : if ( bRealRegExp )
2107 48 : switch (rEntry.eOp)
2108 : {
2109 : case SC_EQUAL:
2110 : case SC_CONTAINS:
2111 40 : bOk = bMatch;
2112 40 : break;
2113 : case SC_NOT_EQUAL:
2114 : case SC_DOES_NOT_CONTAIN:
2115 8 : bOk = !bMatch;
2116 8 : break;
2117 : case SC_BEGINS_WITH:
2118 0 : bOk = ( bMatch && (nStart == 0) );
2119 0 : break;
2120 : case SC_DOES_NOT_BEGIN_WITH:
2121 0 : bOk = !( bMatch && (nStart == 0) );
2122 0 : break;
2123 : case SC_ENDS_WITH:
2124 0 : bOk = ( bMatch && (nEnd == aCellStr.getLength()) );
2125 0 : break;
2126 : case SC_DOES_NOT_END_WITH:
2127 0 : bOk = !( bMatch && (nEnd == aCellStr.getLength()) );
2128 0 : break;
2129 : default:
2130 : {
2131 : // added to avoid warnings
2132 : }
2133 : }
2134 : else
2135 0 : bTestEqual = bMatch;
2136 : }
2137 440 : if ( !bRealRegExp )
2138 : {
2139 : // Simple string matching i.e. no regexp match.
2140 392 : if (isTextMatchOp(rEntry))
2141 : {
2142 274 : if (rItem.meType != ScQueryEntry::ByString && rItem.maString.isEmpty())
2143 : {
2144 : // #i18374# When used from functions (match, countif, sumif, vlookup, hlookup, lookup),
2145 : // the query value is assigned directly, and the string is empty. In that case,
2146 : // don't find any string (isEqual would find empty string results in formula cells).
2147 12 : bOk = false;
2148 12 : if ( rEntry.eOp == SC_NOT_EQUAL )
2149 0 : bOk = !bOk;
2150 : }
2151 262 : else if ( bMatchWholeCell )
2152 : {
2153 : // Fast string equality check by comparing string identifiers.
2154 262 : if (mrParam.bCaseSens)
2155 0 : bOk = aCellStr.getData() == rItem.maString.getData();
2156 : else
2157 262 : bOk = aCellStr.getDataIgnoreCase() == rItem.maString.getDataIgnoreCase();
2158 :
2159 262 : if ( rEntry.eOp == SC_NOT_EQUAL )
2160 0 : bOk = !bOk;
2161 : }
2162 : else
2163 : {
2164 0 : OUString aQueryStr = rItem.maString.getString();
2165 : OUString aCell( mpTransliteration->transliterate(
2166 : aCellStr.getString(), ScGlobal::eLnge, 0, aCellStr.getLength(),
2167 0 : NULL ) );
2168 : OUString aQuer( mpTransliteration->transliterate(
2169 : aQueryStr, ScGlobal::eLnge, 0, aQueryStr.getLength(),
2170 0 : NULL ) );
2171 0 : sal_Int32 nIndex = (rEntry.eOp == SC_ENDS_WITH
2172 0 : || rEntry.eOp == SC_DOES_NOT_END_WITH) ? (aCell.getLength()-aQuer.getLength()) : 0;
2173 0 : sal_Int32 nStrPos = aCell.indexOf( aQuer, nIndex );
2174 0 : switch (rEntry.eOp)
2175 : {
2176 : case SC_EQUAL:
2177 : case SC_CONTAINS:
2178 0 : bOk = ( nStrPos != -1 );
2179 0 : break;
2180 : case SC_NOT_EQUAL:
2181 : case SC_DOES_NOT_CONTAIN:
2182 0 : bOk = ( nStrPos == -1 );
2183 0 : break;
2184 : case SC_BEGINS_WITH:
2185 0 : bOk = ( nStrPos == 0 );
2186 0 : break;
2187 : case SC_DOES_NOT_BEGIN_WITH:
2188 0 : bOk = ( nStrPos != 0 );
2189 0 : break;
2190 : case SC_ENDS_WITH:
2191 0 : bOk = ( nStrPos + aQuer.getLength() == aCell.getLength() );
2192 0 : break;
2193 : case SC_DOES_NOT_END_WITH:
2194 0 : bOk = ( nStrPos + aQuer.getLength() != aCell.getLength() );
2195 0 : break;
2196 : default:
2197 : {
2198 : // added to avoid warnings
2199 : }
2200 0 : }
2201 : }
2202 : }
2203 : else
2204 : { // use collator here because data was probably sorted
2205 : sal_Int32 nCompare = mpCollator->compareString(
2206 118 : aCellStr.getString(), rItem.maString.getString());
2207 118 : switch (rEntry.eOp)
2208 : {
2209 : case SC_LESS :
2210 6 : bOk = (nCompare < 0);
2211 6 : break;
2212 : case SC_GREATER :
2213 0 : bOk = (nCompare > 0);
2214 0 : break;
2215 : case SC_LESS_EQUAL :
2216 56 : bOk = (nCompare <= 0);
2217 56 : if ( bOk && mpTestEqualCondition && !bTestEqual )
2218 42 : bTestEqual = (nCompare == 0);
2219 56 : break;
2220 : case SC_GREATER_EQUAL :
2221 56 : bOk = (nCompare >= 0);
2222 56 : if ( bOk && mpTestEqualCondition && !bTestEqual )
2223 26 : bTestEqual = (nCompare == 0);
2224 56 : break;
2225 : default:
2226 : {
2227 : // added to avoid warnings
2228 : }
2229 : }
2230 : }
2231 : }
2232 :
2233 440 : return std::pair<bool,bool>(bOk, bTestEqual);
2234 : }
2235 :
2236 : // To be called only if both isQueryByValue() and isQueryByString()
2237 : // returned false and range lookup is wanted! In range lookup comparison
2238 : // numbers are less than strings. Nothing else is compared.
2239 56 : std::pair<bool,bool> compareByRangeLookup(
2240 : const ScRefCellValue& rCell, SCCOL nCol, SCROW nRow,
2241 : const ScQueryEntry& rEntry, const ScQueryEntry::Item& rItem)
2242 : {
2243 56 : bool bTestEqual = false;
2244 :
2245 56 : if (rItem.meType == ScQueryEntry::ByString && rEntry.eOp != SC_LESS && rEntry.eOp != SC_LESS_EQUAL)
2246 2 : return std::pair<bool,bool>(false, bTestEqual);
2247 :
2248 54 : if (rItem.meType != ScQueryEntry::ByString && rEntry.eOp != SC_GREATER && rEntry.eOp != SC_GREATER_EQUAL)
2249 0 : return std::pair<bool,bool>(false, bTestEqual);
2250 :
2251 54 : if (!rCell.isEmpty())
2252 : {
2253 54 : if (rItem.meType == ScQueryEntry::ByString)
2254 : {
2255 54 : if (rCell.meType == CELLTYPE_FORMULA && rCell.mpFormula->GetErrCode())
2256 : // Error values are compared as string.
2257 0 : return std::pair<bool,bool>(false, bTestEqual);
2258 :
2259 54 : return std::pair<bool,bool>(rCell.hasNumeric(), bTestEqual);
2260 : }
2261 :
2262 0 : return std::pair<bool,bool>(!rCell.hasNumeric(), bTestEqual);
2263 : }
2264 :
2265 0 : if (rItem.meType == ScQueryEntry::ByString)
2266 0 : return std::pair<bool,bool>(mrTab.HasValueData(nCol, nRow), bTestEqual);
2267 :
2268 0 : return std::pair<bool,bool>(!mrTab.HasValueData(nCol, nRow), bTestEqual);
2269 : }
2270 : };
2271 :
2272 : }
2273 :
2274 1532 : bool ScTable::ValidQuery(
2275 : SCROW nRow, const ScQueryParam& rParam, ScRefCellValue* pCell, bool* pbTestEqualCondition)
2276 : {
2277 1532 : if (!rParam.GetEntry(0).bDoQuery)
2278 38 : return true;
2279 :
2280 1494 : SCSIZE nEntryCount = rParam.GetEntryCount();
2281 :
2282 : typedef std::pair<bool,bool> ResultType;
2283 1494 : static std::vector<ResultType> aResults;
2284 1494 : if (aResults.size() < nEntryCount)
2285 14 : aResults.resize(nEntryCount);
2286 :
2287 1494 : long nPos = -1;
2288 1494 : QueryEvaluator aEval(*pDocument, *this, rParam, pbTestEqualCondition);
2289 1494 : ScQueryParam::const_iterator it, itBeg = rParam.begin(), itEnd = rParam.end();
2290 3198 : for (it = itBeg; it != itEnd && it->bDoQuery; ++it)
2291 : {
2292 1704 : const ScQueryEntry& rEntry = *it;
2293 1704 : SCCOL nCol = static_cast<SCCOL>(rEntry.nField);
2294 :
2295 : // we can only handle one single direct query
2296 1704 : ScRefCellValue aCell;
2297 1704 : if (pCell && it == itBeg)
2298 1166 : aCell = *pCell;
2299 : else
2300 538 : aCell = GetCellValue(nCol, nRow);
2301 :
2302 1704 : std::pair<bool,bool> aRes(false, false);
2303 :
2304 1704 : const ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems();
2305 1704 : if (rItems.size() == 1 && rItems.front().meType == ScQueryEntry::ByEmpty)
2306 : {
2307 44 : if (rEntry.IsQueryByEmpty())
2308 22 : aRes.first = !aCol[rEntry.nField].HasDataAt(nRow);
2309 : else
2310 : {
2311 : OSL_ASSERT(rEntry.IsQueryByNonEmpty());
2312 22 : aRes.first = aCol[rEntry.nField].HasDataAt(nRow);
2313 : }
2314 : }
2315 : else
2316 : {
2317 1660 : ScQueryEntry::QueryItemsType::const_iterator itr = rItems.begin(), itrEnd = rItems.end();
2318 :
2319 3322 : for (; itr != itrEnd; ++itr)
2320 : {
2321 1680 : if (aEval.isQueryByValue(*itr, nCol, nRow, aCell))
2322 : {
2323 : std::pair<bool,bool> aThisRes =
2324 1158 : aEval.compareByValue(aCell, nCol, nRow, rEntry, *itr);
2325 1158 : aRes.first |= aThisRes.first;
2326 1158 : aRes.second |= aThisRes.second;
2327 : }
2328 522 : else if (aEval.isQueryByString(rEntry, *itr, nCol, nRow, aCell))
2329 : {
2330 : std::pair<bool,bool> aThisRes =
2331 440 : aEval.compareByString(aCell, nRow, rEntry, *itr);
2332 440 : aRes.first |= aThisRes.first;
2333 440 : aRes.second |= aThisRes.second;
2334 : }
2335 82 : else if (rParam.mbRangeLookup)
2336 : {
2337 : std::pair<bool,bool> aThisRes =
2338 56 : aEval.compareByRangeLookup(aCell, nCol, nRow, rEntry, *itr);
2339 56 : aRes.first |= aThisRes.first;
2340 56 : aRes.second |= aThisRes.second;
2341 : }
2342 :
2343 1680 : if (aRes.first && aRes.second)
2344 18 : break;
2345 : }
2346 : }
2347 :
2348 1704 : if (nPos == -1)
2349 : {
2350 1494 : nPos++;
2351 1494 : aResults[nPos] = aRes;
2352 : }
2353 : else
2354 : {
2355 210 : if (rEntry.eConnect == SC_AND)
2356 : {
2357 76 : aResults[nPos].first = aResults[nPos].first && aRes.first;
2358 76 : aResults[nPos].second = aResults[nPos].second && aRes.second;
2359 : }
2360 : else
2361 : {
2362 134 : nPos++;
2363 134 : aResults[nPos] = aRes;
2364 : }
2365 : }
2366 1704 : }
2367 :
2368 1628 : for ( long j=1; j <= nPos; j++ )
2369 : {
2370 134 : aResults[0].first = aResults[0].first || aResults[j].first;
2371 134 : aResults[0].second = aResults[0].second || aResults[j].second;
2372 : }
2373 :
2374 1494 : bool bRet = aResults[0].first;
2375 1494 : if ( pbTestEqualCondition )
2376 614 : *pbTestEqualCondition = aResults[0].second;
2377 :
2378 1494 : return bRet;
2379 : }
2380 :
2381 0 : void ScTable::TopTenQuery( ScQueryParam& rParam )
2382 : {
2383 0 : bool bSortCollatorInitialized = false;
2384 0 : SCSIZE nEntryCount = rParam.GetEntryCount();
2385 0 : SCROW nRow1 = (rParam.bHasHeader ? rParam.nRow1 + 1 : rParam.nRow1);
2386 0 : SCSIZE nCount = static_cast<SCSIZE>(rParam.nRow2 - nRow1 + 1);
2387 0 : for ( SCSIZE i=0; (i<nEntryCount) && (rParam.GetEntry(i).bDoQuery); i++ )
2388 : {
2389 0 : ScQueryEntry& rEntry = rParam.GetEntry(i);
2390 0 : ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
2391 :
2392 0 : switch ( rEntry.eOp )
2393 : {
2394 : case SC_TOPVAL:
2395 : case SC_BOTVAL:
2396 : case SC_TOPPERC:
2397 : case SC_BOTPERC:
2398 : {
2399 0 : ScSortParam aLocalSortParam( rParam, static_cast<SCCOL>(rEntry.nField) );
2400 0 : aSortParam = aLocalSortParam; // used in CreateSortInfoArray, Compare
2401 0 : if ( !bSortCollatorInitialized )
2402 : {
2403 0 : bSortCollatorInitialized = true;
2404 0 : InitSortCollator( aLocalSortParam );
2405 : }
2406 0 : boost::scoped_ptr<ScSortInfoArray> pArray(CreateSortInfoArray(aSortParam, nRow1, rParam.nRow2, bGlobalKeepQuery, false));
2407 0 : DecoladeRow( pArray.get(), nRow1, rParam.nRow2 );
2408 0 : QuickSort( pArray.get(), nRow1, rParam.nRow2 );
2409 0 : ScSortInfo** ppInfo = pArray->GetFirstArray();
2410 0 : SCSIZE nValidCount = nCount;
2411 : // keine Note-/Leerzellen zaehlen, sind ans Ende sortiert
2412 0 : while (nValidCount > 0 && ppInfo[nValidCount-1]->maCell.isEmpty())
2413 0 : nValidCount--;
2414 : // keine Strings zaehlen, sind zwischen Value und Leer
2415 0 : while (nValidCount > 0 && ppInfo[nValidCount-1]->maCell.hasString())
2416 0 : nValidCount--;
2417 0 : if ( nValidCount > 0 )
2418 : {
2419 0 : if ( rItem.meType == ScQueryEntry::ByString )
2420 : { // dat wird nix
2421 0 : rItem.meType = ScQueryEntry::ByValue;
2422 0 : rItem.mfVal = 10; // 10 bzw. 10%
2423 : }
2424 0 : SCSIZE nVal = (rItem.mfVal >= 1 ? static_cast<SCSIZE>(rItem.mfVal) : 1);
2425 0 : SCSIZE nOffset = 0;
2426 0 : switch ( rEntry.eOp )
2427 : {
2428 : case SC_TOPVAL:
2429 : {
2430 0 : rEntry.eOp = SC_GREATER_EQUAL;
2431 0 : if ( nVal > nValidCount )
2432 0 : nVal = nValidCount;
2433 0 : nOffset = nValidCount - nVal; // 1 <= nVal <= nValidCount
2434 : }
2435 0 : break;
2436 : case SC_BOTVAL:
2437 : {
2438 0 : rEntry.eOp = SC_LESS_EQUAL;
2439 0 : if ( nVal > nValidCount )
2440 0 : nVal = nValidCount;
2441 0 : nOffset = nVal - 1; // 1 <= nVal <= nValidCount
2442 : }
2443 0 : break;
2444 : case SC_TOPPERC:
2445 : {
2446 0 : rEntry.eOp = SC_GREATER_EQUAL;
2447 0 : if ( nVal > 100 )
2448 0 : nVal = 100;
2449 0 : nOffset = nValidCount - (nValidCount * nVal / 100);
2450 0 : if ( nOffset >= nValidCount )
2451 0 : nOffset = nValidCount - 1;
2452 : }
2453 0 : break;
2454 : case SC_BOTPERC:
2455 : {
2456 0 : rEntry.eOp = SC_LESS_EQUAL;
2457 0 : if ( nVal > 100 )
2458 0 : nVal = 100;
2459 0 : nOffset = (nValidCount * nVal / 100);
2460 0 : if ( nOffset >= nValidCount )
2461 0 : nOffset = nValidCount - 1;
2462 : }
2463 0 : break;
2464 : default:
2465 : {
2466 : // added to avoid warnings
2467 : }
2468 : }
2469 0 : ScRefCellValue aCell = ppInfo[nOffset]->maCell;
2470 0 : if (aCell.hasNumeric())
2471 0 : rItem.mfVal = aCell.getValue();
2472 : else
2473 : {
2474 : OSL_FAIL( "TopTenQuery: pCell no ValueData" );
2475 0 : rEntry.eOp = SC_GREATER_EQUAL;
2476 0 : rItem.mfVal = 0;
2477 0 : }
2478 : }
2479 : else
2480 : {
2481 0 : rEntry.eOp = SC_GREATER_EQUAL;
2482 0 : rItem.meType = ScQueryEntry::ByValue;
2483 0 : rItem.mfVal = 0;
2484 0 : }
2485 : }
2486 0 : break;
2487 : default:
2488 : {
2489 : // added to avoid warnings
2490 : }
2491 : }
2492 : }
2493 0 : if ( bSortCollatorInitialized )
2494 0 : DestroySortCollator();
2495 0 : }
2496 :
2497 : namespace {
2498 :
2499 : class PrepareQueryItem : public std::unary_function<ScQueryEntry::Item, void>
2500 : {
2501 : const ScDocument& mrDoc;
2502 : public:
2503 32 : PrepareQueryItem(const ScDocument& rDoc) : mrDoc(rDoc) {}
2504 :
2505 36 : void operator() (ScQueryEntry::Item& rItem)
2506 : {
2507 36 : if (rItem.meType != ScQueryEntry::ByString && rItem.meType != ScQueryEntry::ByDate)
2508 54 : return;
2509 :
2510 18 : sal_uInt32 nIndex = 0;
2511 : bool bNumber = mrDoc.GetFormatTable()->
2512 18 : IsNumberFormat(rItem.maString.getString(), nIndex, rItem.mfVal);
2513 :
2514 : // Advanced Filter creates only ByString queries that need to be
2515 : // converted to ByValue if appropriate. rItem.mfVal now holds the value
2516 : // if bNumber==true.
2517 :
2518 18 : if (rItem.meType == ScQueryEntry::ByString)
2519 : {
2520 18 : if (bNumber)
2521 6 : rItem.meType = ScQueryEntry::ByValue;
2522 18 : return;
2523 : }
2524 :
2525 : // Double-check if the query by date is really appropriate.
2526 :
2527 0 : if (bNumber && ((nIndex % SV_COUNTRY_LANGUAGE_OFFSET) != 0))
2528 : {
2529 0 : const SvNumberformat* pEntry = mrDoc.GetFormatTable()->GetEntry(nIndex);
2530 0 : if (pEntry)
2531 : {
2532 0 : short nNumFmtType = pEntry->GetType();
2533 0 : if (!((nNumFmtType & NUMBERFORMAT_DATE) && !(nNumFmtType & NUMBERFORMAT_TIME)))
2534 0 : rItem.meType = ScQueryEntry::ByValue; // not a date only
2535 : }
2536 : else
2537 0 : rItem.meType = ScQueryEntry::ByValue; // what the ... not a date
2538 : }
2539 : else
2540 0 : rItem.meType = ScQueryEntry::ByValue; // not a date
2541 : }
2542 : };
2543 :
2544 36 : void lcl_PrepareQuery( const ScDocument* pDoc, ScTable* pTab, ScQueryParam& rParam )
2545 : {
2546 36 : bool bTopTen = false;
2547 36 : SCSIZE nEntryCount = rParam.GetEntryCount();
2548 :
2549 324 : for ( SCSIZE i = 0; i < nEntryCount; ++i )
2550 : {
2551 288 : ScQueryEntry& rEntry = rParam.GetEntry(i);
2552 288 : if (!rEntry.bDoQuery)
2553 256 : continue;
2554 :
2555 32 : ScQueryEntry::QueryItemsType& rItems = rEntry.GetQueryItems();
2556 32 : std::for_each(rItems.begin(), rItems.end(), PrepareQueryItem(*pDoc));
2557 :
2558 32 : if ( !bTopTen )
2559 : {
2560 32 : switch ( rEntry.eOp )
2561 : {
2562 : case SC_TOPVAL:
2563 : case SC_BOTVAL:
2564 : case SC_TOPPERC:
2565 : case SC_BOTPERC:
2566 : {
2567 0 : bTopTen = true;
2568 : }
2569 0 : break;
2570 : default:
2571 : {
2572 : }
2573 : }
2574 : }
2575 : }
2576 :
2577 36 : if ( bTopTen )
2578 : {
2579 0 : pTab->TopTenQuery( rParam );
2580 : }
2581 36 : }
2582 :
2583 : }
2584 :
2585 36 : SCSIZE ScTable::Query(ScQueryParam& rParamOrg, bool bKeepSub)
2586 : {
2587 36 : ScQueryParam aParam( rParamOrg );
2588 : typedef boost::unordered_set<OUString, OUStringHash> StrSetType;
2589 72 : StrSetType aStrSet;
2590 :
2591 36 : bool bStarted = false;
2592 36 : bool bOldResult = true;
2593 36 : SCROW nOldStart = 0;
2594 36 : SCROW nOldEnd = 0;
2595 :
2596 36 : SCSIZE nCount = 0;
2597 36 : SCROW nOutRow = 0;
2598 36 : SCROW nHeader = aParam.bHasHeader ? 1 : 0;
2599 :
2600 36 : lcl_PrepareQuery(pDocument, this, aParam);
2601 :
2602 36 : if (!aParam.bInplace)
2603 : {
2604 0 : nOutRow = aParam.nDestRow + nHeader;
2605 0 : if (nHeader > 0)
2606 : CopyData( aParam.nCol1, aParam.nRow1, aParam.nCol2, aParam.nRow1,
2607 0 : aParam.nDestCol, aParam.nDestRow, aParam.nDestTab );
2608 : }
2609 :
2610 36 : SCROW nRealRow2 = aParam.nRow2;
2611 208 : for (SCROW j = aParam.nRow1 + nHeader; j <= nRealRow2; ++j)
2612 : {
2613 : bool bResult; // Filterergebnis
2614 172 : bool bValid = ValidQuery(j, aParam);
2615 172 : if (!bValid && bKeepSub) // Subtotals stehenlassen
2616 : {
2617 48 : for (SCCOL nCol=aParam.nCol1; nCol<=aParam.nCol2 && !bValid; nCol++)
2618 : {
2619 36 : ScRefCellValue aCell = GetCellValue(nCol, j);
2620 36 : if (aCell.meType != CELLTYPE_FORMULA)
2621 36 : continue;
2622 :
2623 0 : if (!aCell.mpFormula->IsSubTotal())
2624 0 : continue;
2625 :
2626 0 : if (RefVisible(aCell.mpFormula))
2627 0 : bValid = true;
2628 0 : }
2629 : }
2630 172 : if (bValid)
2631 : {
2632 104 : if (aParam.bDuplicate)
2633 104 : bResult = true;
2634 : else
2635 : {
2636 0 : OUString aStr;
2637 0 : for (SCCOL k=aParam.nCol1; k <= aParam.nCol2; k++)
2638 : {
2639 0 : OUString aCellStr;
2640 0 : GetString(k, j, aCellStr);
2641 0 : OUStringBuffer aBuf(aStr);
2642 0 : aBuf.append(aCellStr);
2643 0 : aBuf.append(static_cast<sal_Unicode>(1));
2644 0 : aStr = aBuf.makeStringAndClear();
2645 0 : }
2646 :
2647 0 : std::pair<StrSetType::iterator, bool> r = aStrSet.insert(aStr);
2648 0 : bool bIsUnique = r.second; // unique if inserted.
2649 0 : bResult = bIsUnique;
2650 : }
2651 : }
2652 : else
2653 68 : bResult = false;
2654 :
2655 172 : if (aParam.bInplace)
2656 : {
2657 172 : if (bResult == bOldResult && bStarted)
2658 80 : nOldEnd = j;
2659 : else
2660 : {
2661 92 : if (bStarted)
2662 56 : DBShowRows(nOldStart,nOldEnd, bOldResult);
2663 92 : nOldStart = nOldEnd = j;
2664 92 : bOldResult = bResult;
2665 : }
2666 172 : bStarted = true;
2667 : }
2668 : else
2669 : {
2670 0 : if (bResult)
2671 : {
2672 0 : CopyData( aParam.nCol1,j, aParam.nCol2,j, aParam.nDestCol,nOutRow,aParam.nDestTab );
2673 0 : ++nOutRow;
2674 : }
2675 : }
2676 172 : if (bResult)
2677 104 : ++nCount;
2678 : }
2679 :
2680 36 : if (aParam.bInplace && bStarted)
2681 36 : DBShowRows(nOldStart,nOldEnd, bOldResult);
2682 :
2683 36 : if (aParam.bInplace)
2684 36 : SetDrawPageSize();
2685 :
2686 72 : return nCount;
2687 : }
2688 :
2689 2 : bool ScTable::CreateExcelQuery(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam& rQueryParam)
2690 : {
2691 2 : bool bValid = true;
2692 2 : boost::scoped_array<SCCOL> pFields(new SCCOL[nCol2-nCol1+1]);
2693 4 : OUString aCellStr;
2694 2 : SCCOL nCol = nCol1;
2695 : OSL_ENSURE( rQueryParam.nTab != SCTAB_MAX, "rQueryParam.nTab no value, not bad but no good" );
2696 2 : SCTAB nDBTab = (rQueryParam.nTab == SCTAB_MAX ? nTab : rQueryParam.nTab);
2697 2 : SCROW nDBRow1 = rQueryParam.nRow1;
2698 2 : SCCOL nDBCol2 = rQueryParam.nCol2;
2699 : // Erste Zeile muessen Spaltenkoepfe sein
2700 12 : while (bValid && (nCol <= nCol2))
2701 : {
2702 8 : OUString aQueryStr;
2703 8 : GetUpperCellString(nCol, nRow1, aQueryStr);
2704 8 : bool bFound = false;
2705 8 : SCCOL i = rQueryParam.nCol1;
2706 24 : while (!bFound && (i <= nDBCol2))
2707 : {
2708 8 : if ( nTab == nDBTab )
2709 8 : GetUpperCellString(i, nDBRow1, aCellStr);
2710 : else
2711 0 : pDocument->GetUpperCellString(i, nDBRow1, nDBTab, aCellStr);
2712 8 : bFound = (aCellStr == aQueryStr);
2713 8 : if (!bFound) i++;
2714 : }
2715 8 : if (bFound)
2716 8 : pFields[nCol - nCol1] = i;
2717 : else
2718 0 : bValid = false;
2719 8 : nCol++;
2720 8 : }
2721 2 : if (bValid)
2722 : {
2723 2 : sal_uLong nVisible = 0;
2724 10 : for ( nCol=nCol1; nCol<=nCol2; nCol++ )
2725 8 : nVisible += aCol[nCol].VisibleCount( nRow1+1, nRow2 );
2726 :
2727 2 : if ( nVisible > SCSIZE_MAX / sizeof(void*) )
2728 : {
2729 : OSL_FAIL("too many filter criteria");
2730 0 : nVisible = 0;
2731 : }
2732 :
2733 2 : SCSIZE nNewEntries = nVisible;
2734 2 : rQueryParam.Resize( nNewEntries );
2735 :
2736 2 : SCSIZE nIndex = 0;
2737 2 : SCROW nRow = nRow1 + 1;
2738 2 : svl::SharedStringPool& rPool = pDocument->GetSharedStringPool();
2739 12 : while (nRow <= nRow2)
2740 : {
2741 8 : nCol = nCol1;
2742 48 : while (nCol <= nCol2)
2743 : {
2744 32 : GetInputString( nCol, nRow, aCellStr );
2745 32 : if (!aCellStr.isEmpty())
2746 : {
2747 0 : if (nIndex < nNewEntries)
2748 : {
2749 0 : rQueryParam.GetEntry(nIndex).nField = pFields[nCol - nCol1];
2750 0 : rQueryParam.FillInExcelSyntax(rPool, aCellStr, nIndex);
2751 0 : nIndex++;
2752 0 : if (nIndex < nNewEntries)
2753 0 : rQueryParam.GetEntry(nIndex).eConnect = SC_AND;
2754 : }
2755 : else
2756 0 : bValid = false;
2757 : }
2758 32 : nCol++;
2759 : }
2760 8 : nRow++;
2761 8 : if (nIndex < nNewEntries)
2762 0 : rQueryParam.GetEntry(nIndex).eConnect = SC_OR;
2763 : }
2764 : }
2765 4 : return bValid;
2766 : }
2767 :
2768 2 : bool ScTable::CreateStarQuery(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam& rQueryParam)
2769 : {
2770 : // A valid StarQuery must be at least 4 columns wide. To be precise it
2771 : // should be exactly 4 columns ...
2772 : // Additionally, if this wasn't checked, a formula pointing to a valid 1-3
2773 : // column Excel style query range immediately left to itself would result
2774 : // in a circular reference when the field name or operator or value (first
2775 : // to third query range column) is obtained (#i58354#). Furthermore, if the
2776 : // range wasn't sufficiently specified data changes wouldn't flag formula
2777 : // cells for recalculation.
2778 2 : if (nCol2 - nCol1 < 3)
2779 0 : return false;
2780 :
2781 : bool bValid;
2782 : bool bFound;
2783 2 : OUString aCellStr;
2784 2 : SCSIZE nIndex = 0;
2785 2 : SCROW nRow = nRow1;
2786 : OSL_ENSURE( rQueryParam.nTab != SCTAB_MAX, "rQueryParam.nTab no value, not bad but no good" );
2787 2 : SCTAB nDBTab = (rQueryParam.nTab == SCTAB_MAX ? nTab : rQueryParam.nTab);
2788 2 : SCROW nDBRow1 = rQueryParam.nRow1;
2789 2 : SCCOL nDBCol2 = rQueryParam.nCol2;
2790 :
2791 2 : SCSIZE nNewEntries = static_cast<SCSIZE>(nRow2-nRow1+1);
2792 2 : rQueryParam.Resize( nNewEntries );
2793 2 : svl::SharedStringPool& rPool = pDocument->GetSharedStringPool();
2794 :
2795 4 : do
2796 : {
2797 4 : ScQueryEntry& rEntry = rQueryParam.GetEntry(nIndex);
2798 :
2799 4 : bValid = false;
2800 : // Erste Spalte UND/ODER
2801 4 : if (nIndex > 0)
2802 : {
2803 2 : GetUpperCellString(nCol1, nRow, aCellStr);
2804 2 : if ( aCellStr == ScGlobal::GetRscString(STR_TABLE_UND) )
2805 : {
2806 0 : rEntry.eConnect = SC_AND;
2807 0 : bValid = true;
2808 : }
2809 2 : else if ( aCellStr == ScGlobal::GetRscString(STR_TABLE_ODER) )
2810 : {
2811 0 : rEntry.eConnect = SC_OR;
2812 0 : bValid = true;
2813 : }
2814 : }
2815 : // Zweite Spalte FeldName
2816 4 : if ((nIndex < 1) || bValid)
2817 : {
2818 2 : bFound = false;
2819 2 : GetUpperCellString(nCol1 + 1, nRow, aCellStr);
2820 4 : for (SCCOL i=rQueryParam.nCol1; (i <= nDBCol2) && (!bFound); i++)
2821 : {
2822 2 : OUString aFieldStr;
2823 2 : if ( nTab == nDBTab )
2824 2 : GetUpperCellString(i, nDBRow1, aFieldStr);
2825 : else
2826 0 : pDocument->GetUpperCellString(i, nDBRow1, nDBTab, aFieldStr);
2827 2 : bFound = (aCellStr == aFieldStr);
2828 2 : if (bFound)
2829 : {
2830 2 : rEntry.nField = i;
2831 2 : bValid = true;
2832 : }
2833 : else
2834 0 : bValid = false;
2835 2 : }
2836 : }
2837 : // Dritte Spalte Operator =<>...
2838 4 : if (bValid)
2839 : {
2840 2 : bFound = false;
2841 2 : GetUpperCellString(nCol1 + 2, nRow, aCellStr);
2842 2 : if (aCellStr.startsWith("<"))
2843 : {
2844 0 : if (aCellStr[1] == '>')
2845 0 : rEntry.eOp = SC_NOT_EQUAL;
2846 0 : else if (aCellStr[1] == '=')
2847 0 : rEntry.eOp = SC_LESS_EQUAL;
2848 : else
2849 0 : rEntry.eOp = SC_LESS;
2850 : }
2851 2 : else if (aCellStr.startsWith(">"))
2852 : {
2853 0 : if (aCellStr[1] == '=')
2854 0 : rEntry.eOp = SC_GREATER_EQUAL;
2855 : else
2856 0 : rEntry.eOp = SC_GREATER;
2857 : }
2858 2 : else if (aCellStr.startsWith("="))
2859 0 : rEntry.eOp = SC_EQUAL;
2860 :
2861 : }
2862 : // Vierte Spalte Wert
2863 4 : if (bValid)
2864 : {
2865 2 : OUString aStr;
2866 2 : GetString(nCol1 + 3, nRow, aStr);
2867 2 : rEntry.GetQueryItem().maString = rPool.intern(aStr);
2868 2 : rEntry.bDoQuery = true;
2869 : }
2870 4 : nIndex++;
2871 4 : nRow++;
2872 : }
2873 2 : while (bValid && (nRow <= nRow2) /* && (nIndex < MAXQUERY) */ );
2874 2 : return bValid;
2875 : }
2876 :
2877 2 : bool ScTable::CreateQueryParam(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam& rQueryParam)
2878 : {
2879 : SCSIZE i, nCount;
2880 2 : PutInOrder(nCol1, nCol2);
2881 2 : PutInOrder(nRow1, nRow2);
2882 :
2883 2 : nCount = rQueryParam.GetEntryCount();
2884 18 : for (i=0; i < nCount; i++)
2885 16 : rQueryParam.GetEntry(i).Clear();
2886 :
2887 : // Standard QueryTabelle
2888 2 : bool bValid = CreateStarQuery(nCol1, nRow1, nCol2, nRow2, rQueryParam);
2889 : // Excel QueryTabelle
2890 2 : if (!bValid)
2891 2 : bValid = CreateExcelQuery(nCol1, nRow1, nCol2, nRow2, rQueryParam);
2892 :
2893 2 : nCount = rQueryParam.GetEntryCount();
2894 2 : if (bValid)
2895 : {
2896 : // bQueryByString muss gesetzt sein
2897 18 : for (i=0; i < nCount; i++)
2898 16 : rQueryParam.GetEntry(i).GetQueryItem().meType = ScQueryEntry::ByString;
2899 : }
2900 : else
2901 : {
2902 : // nix
2903 0 : for (i=0; i < nCount; i++)
2904 0 : rQueryParam.GetEntry(i).Clear();
2905 : }
2906 2 : return bValid;
2907 : }
2908 :
2909 18 : bool ScTable::HasColHeader( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW /* nEndRow */ ) const
2910 : {
2911 36 : for (SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++)
2912 : {
2913 32 : CellType eType = GetCellType( nCol, nStartRow );
2914 32 : if (eType != CELLTYPE_STRING && eType != CELLTYPE_EDIT)
2915 14 : return false;
2916 : }
2917 4 : return true;
2918 : }
2919 :
2920 0 : bool ScTable::HasRowHeader( SCCOL nStartCol, SCROW nStartRow, SCCOL /* nEndCol */, SCROW nEndRow ) const
2921 : {
2922 0 : for (SCROW nRow=nStartRow; nRow<=nEndRow; nRow++)
2923 : {
2924 0 : CellType eType = GetCellType( nStartCol, nRow );
2925 0 : if (eType != CELLTYPE_STRING && eType != CELLTYPE_EDIT)
2926 0 : return false;
2927 : }
2928 0 : return true;
2929 : }
2930 :
2931 0 : void ScTable::GetFilterEntries(SCCOL nCol, SCROW nRow1, SCROW nRow2, std::vector<ScTypedStrData>& rStrings, bool& rHasDates)
2932 : {
2933 0 : sc::ColumnBlockConstPosition aBlockPos;
2934 0 : aCol[nCol].InitBlockPosition(aBlockPos);
2935 0 : aCol[nCol].GetFilterEntries(aBlockPos, nRow1, nRow2, rStrings, rHasDates);
2936 0 : }
2937 :
2938 0 : void ScTable::GetFilteredFilterEntries(
2939 : SCCOL nCol, SCROW nRow1, SCROW nRow2, const ScQueryParam& rParam, std::vector<ScTypedStrData>& rStrings, bool& rHasDates)
2940 : {
2941 0 : sc::ColumnBlockConstPosition aBlockPos;
2942 0 : aCol[nCol].InitBlockPosition(aBlockPos);
2943 :
2944 : // remove the entry for this column from the query parameter
2945 0 : ScQueryParam aParam( rParam );
2946 0 : aParam.RemoveEntryByField(nCol);
2947 :
2948 0 : lcl_PrepareQuery(pDocument, this, aParam);
2949 0 : bool bHasDates = false;
2950 0 : for ( SCROW j = nRow1; j <= nRow2; ++j )
2951 : {
2952 0 : if (ValidQuery(j, aParam))
2953 : {
2954 0 : bool bThisHasDates = false;
2955 0 : aCol[nCol].GetFilterEntries(aBlockPos, j, j, rStrings, bThisHasDates);
2956 0 : bHasDates |= bThisHasDates;
2957 : }
2958 : }
2959 :
2960 0 : rHasDates = bHasDates;
2961 0 : }
2962 :
2963 4 : bool ScTable::GetDataEntries(SCCOL nCol, SCROW nRow, std::set<ScTypedStrData>& rStrings, bool bLimit)
2964 : {
2965 4 : return aCol[nCol].GetDataEntries( nRow, rStrings, bLimit );
2966 : }
2967 :
2968 74 : sal_uLong ScTable::GetCellCount() const
2969 : {
2970 74 : sal_uLong nCellCount = 0;
2971 :
2972 75850 : for ( SCCOL nCol=0; nCol<=MAXCOL; nCol++ )
2973 75776 : nCellCount += aCol[nCol].GetCellCount();
2974 :
2975 74 : return nCellCount;
2976 : }
2977 :
2978 2766 : sal_uLong ScTable::GetWeightedCount() const
2979 : {
2980 2766 : sal_uLong nCellCount = 0;
2981 :
2982 2835150 : for ( SCCOL nCol=0; nCol<=MAXCOL; nCol++ )
2983 2832384 : if ( aCol[nCol].GetCellCount() ) // GetCellCount ist inline
2984 13372 : nCellCount += aCol[nCol].GetWeightedCount();
2985 :
2986 2766 : return nCellCount;
2987 : }
2988 :
2989 0 : sal_uLong ScTable::GetCodeCount() const
2990 : {
2991 0 : sal_uLong nCodeCount = 0;
2992 :
2993 0 : for ( SCCOL nCol=0; nCol<=MAXCOL; nCol++ )
2994 0 : if ( aCol[nCol].GetCellCount() ) // GetCellCount ist inline
2995 0 : nCodeCount += aCol[nCol].GetCodeCount();
2996 :
2997 0 : return nCodeCount;
2998 : }
2999 :
3000 0 : sal_Int32 ScTable::GetMaxStringLen( SCCOL nCol, SCROW nRowStart,
3001 : SCROW nRowEnd, rtl_TextEncoding eCharSet ) const
3002 : {
3003 0 : if ( ValidCol(nCol) )
3004 0 : return aCol[nCol].GetMaxStringLen( nRowStart, nRowEnd, eCharSet );
3005 : else
3006 0 : return 0;
3007 : }
3008 :
3009 0 : sal_Int32 ScTable::GetMaxNumberStringLen(
3010 : sal_uInt16& nPrecision, SCCOL nCol, SCROW nRowStart, SCROW nRowEnd ) const
3011 : {
3012 0 : if ( ValidCol(nCol) )
3013 0 : return aCol[nCol].GetMaxNumberStringLen( nPrecision, nRowStart, nRowEnd );
3014 : else
3015 0 : return 0;
3016 : }
3017 :
3018 428 : void ScTable::UpdateSelectionFunction( ScFunctionData& rData, const ScMarkData& rMark )
3019 : {
3020 428 : ScRangeList aRanges = rMark.GetMarkedRanges();
3021 438700 : for (SCCOL nCol = 0; nCol <= MAXCOL && !rData.bError; ++nCol)
3022 : {
3023 438272 : if (pColFlags && ColHidden(nCol))
3024 0 : continue;
3025 :
3026 438272 : aCol[nCol].UpdateSelectionFunction(aRanges, rData, *mpHiddenRows);
3027 428 : }
3028 656 : }
3029 :
3030 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|