LCOV - code coverage report
Current view: top level - sc/source/core/data - table3.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 1195 1597 74.8 %
Date: 2015-06-13 12:38:46 Functions: 114 130 87.7 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11