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

Generated by: LCOV version 1.10