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

Generated by: LCOV version 1.10