2000-09-18 23:16:46 +00:00
|
|
|
/*************************************************************************
|
|
|
|
*
|
2005-09-08 17:30:49 +00:00
|
|
|
* OpenOffice.org - a multi-platform office productivity suite
|
2000-09-18 23:16:46 +00:00
|
|
|
*
|
2005-09-08 17:30:49 +00:00
|
|
|
* $RCSfile: table3.cxx,v $
|
2000-09-18 23:16:46 +00:00
|
|
|
*
|
2007-02-27 11:09:41 +00:00
|
|
|
* $Revision: 1.27 $
|
2000-09-18 23:16:46 +00:00
|
|
|
*
|
2007-02-27 11:09:41 +00:00
|
|
|
* last change: $Author: vg $ $Date: 2007-02-27 12:09:41 $
|
2000-09-18 23:16:46 +00:00
|
|
|
*
|
2005-09-08 17:30:49 +00:00
|
|
|
* The Contents of this file are made available subject to
|
|
|
|
* the terms of GNU Lesser General Public License Version 2.1.
|
2000-09-18 23:16:46 +00:00
|
|
|
*
|
|
|
|
*
|
2005-09-08 17:30:49 +00:00
|
|
|
* GNU Lesser General Public License Version 2.1
|
|
|
|
* =============================================
|
|
|
|
* Copyright 2005 by Sun Microsystems, Inc.
|
|
|
|
* 901 San Antonio Road, Palo Alto, CA 94303, USA
|
2000-09-18 23:16:46 +00:00
|
|
|
*
|
2005-09-08 17:30:49 +00:00
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License version 2.1, as published by the Free Software Foundation.
|
2000-09-18 23:16:46 +00:00
|
|
|
*
|
2005-09-08 17:30:49 +00:00
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
2000-09-18 23:16:46 +00:00
|
|
|
*
|
2005-09-08 17:30:49 +00:00
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
|
|
|
* MA 02111-1307 USA
|
2000-09-18 23:16:46 +00:00
|
|
|
*
|
|
|
|
************************************************************************/
|
|
|
|
|
2006-07-21 10:09:37 +00:00
|
|
|
// MARKER(update_precomp.py): autogen include statement, do not remove
|
|
|
|
#include "precompiled_sc.hxx"
|
|
|
|
|
2000-09-18 23:16:46 +00:00
|
|
|
|
|
|
|
|
|
|
|
// INCLUDE ---------------------------------------------------------------
|
|
|
|
|
2003-03-26 17:07:02 +00:00
|
|
|
#include <rtl/math.hxx>
|
2000-11-20 09:31:47 +00:00
|
|
|
#include <unotools/textsearch.hxx>
|
2000-09-18 23:16:46 +00:00
|
|
|
#include <svtools/zforlist.hxx>
|
|
|
|
#include <unotools/charclass.hxx>
|
2001-03-14 14:57:39 +00:00
|
|
|
#include <unotools/collatorwrapper.hxx>
|
|
|
|
#include <com/sun/star/i18n/CollatorOptions.hpp>
|
2000-09-18 23:16:46 +00:00
|
|
|
#include <stdlib.h>
|
2001-07-11 14:22:13 +00:00
|
|
|
#ifndef _UNOTOOLS_TRANSLITERATIONWRAPPER_HXX
|
|
|
|
#include <unotools/transliterationwrapper.hxx>
|
|
|
|
#endif
|
2000-09-18 23:16:46 +00:00
|
|
|
|
|
|
|
#include "table.hxx"
|
|
|
|
#include "scitems.hxx"
|
|
|
|
#include "collect.hxx"
|
|
|
|
#include "attrib.hxx"
|
|
|
|
#include "cell.hxx"
|
|
|
|
#include "document.hxx"
|
|
|
|
#include "globstr.hrc"
|
|
|
|
#include "global.hxx"
|
|
|
|
#include "stlpool.hxx"
|
|
|
|
#include "compiler.hxx"
|
|
|
|
#include "patattr.hxx"
|
|
|
|
#include "subtotal.hxx"
|
|
|
|
#include "docoptio.hxx"
|
|
|
|
#include "markdata.hxx"
|
|
|
|
#include "rangelst.hxx"
|
|
|
|
#include "attarray.hxx"
|
|
|
|
#include "userlist.hxx"
|
|
|
|
#include "progress.hxx"
|
2001-06-21 11:08:38 +00:00
|
|
|
#include "cellform.hxx"
|
2000-09-18 23:16:46 +00:00
|
|
|
|
2002-11-27 20:40:50 +00:00
|
|
|
#include <vector>
|
|
|
|
|
2000-09-18 23:16:46 +00:00
|
|
|
// STATIC DATA -----------------------------------------------------------
|
|
|
|
|
|
|
|
const USHORT nMaxSorts = 3; // maximale Anzahl Sortierkriterien in aSortParam
|
|
|
|
|
|
|
|
struct ScSortInfo
|
|
|
|
{
|
|
|
|
ScBaseCell* pCell;
|
2004-06-04 09:28:40 +00:00
|
|
|
SCCOLROW nOrg;
|
2000-09-18 23:16:46 +00:00
|
|
|
DECL_FIXEDMEMPOOL_NEWDEL( ScSortInfo );
|
|
|
|
};
|
|
|
|
const USHORT nMemPoolSortInfo = (0x8000 - 64) / sizeof(ScSortInfo);
|
2007-02-27 11:09:41 +00:00
|
|
|
IMPL_FIXEDMEMPOOL_NEWDEL( ScSortInfo, nMemPoolSortInfo, nMemPoolSortInfo )
|
2000-09-18 23:16:46 +00:00
|
|
|
|
|
|
|
// END OF STATIC DATA -----------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
class ScSortInfoArray
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
ScSortInfo** pppInfo[nMaxSorts];
|
2004-06-04 09:28:40 +00:00
|
|
|
SCSIZE nCount;
|
|
|
|
SCCOLROW nStart;
|
2000-09-18 23:16:46 +00:00
|
|
|
USHORT nUsedSorts;
|
|
|
|
|
|
|
|
public:
|
2004-06-04 09:28:40 +00:00
|
|
|
ScSortInfoArray( USHORT nSorts, SCCOLROW nInd1, SCCOLROW nInd2 ) :
|
2000-09-18 23:16:46 +00:00
|
|
|
nCount( nInd2 - nInd1 + 1 ), nStart( nInd1 ),
|
|
|
|
nUsedSorts( Min( nSorts, nMaxSorts ) )
|
|
|
|
{
|
|
|
|
for ( USHORT nSort = 0; nSort < nUsedSorts; nSort++ )
|
|
|
|
{
|
|
|
|
ScSortInfo** ppInfo = new ScSortInfo* [nCount];
|
2004-06-04 09:28:40 +00:00
|
|
|
for ( SCSIZE j = 0; j < nCount; j++ )
|
2000-09-18 23:16:46 +00:00
|
|
|
ppInfo[j] = new ScSortInfo;
|
|
|
|
pppInfo[nSort] = ppInfo;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
~ScSortInfoArray()
|
|
|
|
{
|
|
|
|
for ( USHORT nSort = 0; nSort < nUsedSorts; nSort++ )
|
|
|
|
{
|
|
|
|
ScSortInfo** ppInfo = pppInfo[nSort];
|
2004-06-04 09:28:40 +00:00
|
|
|
for ( SCSIZE j = 0; j < nCount; j++ )
|
2000-09-18 23:16:46 +00:00
|
|
|
delete ppInfo[j];
|
|
|
|
delete [] ppInfo;
|
|
|
|
}
|
|
|
|
}
|
2004-06-04 09:28:40 +00:00
|
|
|
ScSortInfo* Get( USHORT nSort, SCCOLROW nInd )
|
2000-09-18 23:16:46 +00:00
|
|
|
{ return (pppInfo[nSort])[ nInd - nStart ]; }
|
2004-06-04 09:28:40 +00:00
|
|
|
void Swap( SCCOLROW nInd1, SCCOLROW nInd2 )
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
2004-06-04 09:28:40 +00:00
|
|
|
SCSIZE n1 = static_cast<SCSIZE>(nInd1 - nStart);
|
|
|
|
SCSIZE n2 = static_cast<SCSIZE>(nInd2 - nStart);
|
2000-09-18 23:16:46 +00:00
|
|
|
for ( USHORT nSort = 0; nSort < nUsedSorts; nSort++ )
|
|
|
|
{
|
|
|
|
ScSortInfo** ppInfo = pppInfo[nSort];
|
|
|
|
ScSortInfo* pTmp = ppInfo[n1];
|
|
|
|
ppInfo[n1] = ppInfo[n2];
|
|
|
|
ppInfo[n2] = pTmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
USHORT GetUsedSorts() { return nUsedSorts; }
|
|
|
|
ScSortInfo** GetFirstArray() { return pppInfo[0]; }
|
2004-06-04 09:28:40 +00:00
|
|
|
SCCOLROW GetStart() { return nStart; }
|
|
|
|
SCSIZE GetCount() { return nCount; }
|
2000-09-18 23:16:46 +00:00
|
|
|
};
|
|
|
|
|
2004-06-04 09:28:40 +00:00
|
|
|
ScSortInfoArray* ScTable::CreateSortInfoArray( SCCOLROW nInd1, SCCOLROW nInd2 )
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
|
|
|
USHORT nUsedSorts = 1;
|
|
|
|
while ( nUsedSorts < nMaxSorts && aSortParam.bDoSort[nUsedSorts] )
|
|
|
|
nUsedSorts++;
|
|
|
|
ScSortInfoArray* pArray = new ScSortInfoArray( nUsedSorts, nInd1, nInd2 );
|
|
|
|
if ( aSortParam.bByRow )
|
|
|
|
{
|
|
|
|
for ( USHORT nSort = 0; nSort < nUsedSorts; nSort++ )
|
|
|
|
{
|
2004-06-04 09:28:40 +00:00
|
|
|
SCCOL nCol = static_cast<SCCOL>(aSortParam.nField[nSort]);
|
2000-09-18 23:16:46 +00:00
|
|
|
ScColumn* pCol = &aCol[nCol];
|
2004-06-04 09:28:40 +00:00
|
|
|
for ( SCROW nRow = nInd1; nRow <= nInd2; nRow++ )
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
|
|
|
//2do: FillSortInfo an ScColumn und Array abklappern statt Search in GetCell
|
|
|
|
ScSortInfo* pInfo = pArray->Get( nSort, nRow );
|
|
|
|
pInfo->pCell = pCol->GetCell( nRow );
|
|
|
|
pInfo->nOrg = nRow;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
for ( USHORT nSort = 0; nSort < nUsedSorts; nSort++ )
|
|
|
|
{
|
2004-06-04 09:28:40 +00:00
|
|
|
SCROW nRow = aSortParam.nField[nSort];
|
|
|
|
for ( SCCOL nCol = static_cast<SCCOL>(nInd1);
|
|
|
|
nCol <= static_cast<SCCOL>(nInd2); nCol++ )
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
|
|
|
ScSortInfo* pInfo = pArray->Get( nSort, nCol );
|
|
|
|
pInfo->pCell = GetCell( nCol, nRow );
|
|
|
|
pInfo->nOrg = nCol;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return pArray;
|
|
|
|
}
|
|
|
|
|
2001-03-14 14:57:39 +00:00
|
|
|
|
|
|
|
BOOL ScTable::IsSortCollatorGlobal() const
|
|
|
|
{
|
|
|
|
return pSortCollator == ScGlobal::pCollator ||
|
|
|
|
pSortCollator == ScGlobal::pCaseCollator;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ScTable::InitSortCollator( const ScSortParam& rPar )
|
|
|
|
{
|
|
|
|
if ( rPar.aCollatorLocale.Language.getLength() )
|
|
|
|
{
|
|
|
|
if ( !pSortCollator || IsSortCollatorGlobal() )
|
|
|
|
pSortCollator = new CollatorWrapper( pDocument->GetServiceManager() );
|
|
|
|
pSortCollator->loadCollatorAlgorithm( rPar.aCollatorAlgorithm,
|
|
|
|
rPar.aCollatorLocale, (rPar.bCaseSens ? 0 : SC_COLLATOR_IGNORES) );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{ // SYSTEM
|
|
|
|
DestroySortCollator();
|
|
|
|
pSortCollator = (rPar.bCaseSens ? ScGlobal::pCaseCollator :
|
|
|
|
ScGlobal::pCollator);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void ScTable::DestroySortCollator()
|
|
|
|
{
|
|
|
|
if ( pSortCollator )
|
|
|
|
{
|
|
|
|
if ( !IsSortCollatorGlobal() )
|
|
|
|
delete pSortCollator;
|
|
|
|
pSortCollator = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-09-18 23:16:46 +00:00
|
|
|
void ScTable::SortReorder( ScSortInfoArray* pArray, ScProgress& rProgress )
|
|
|
|
{
|
|
|
|
BOOL bByRow = aSortParam.bByRow;
|
2004-06-04 09:28:40 +00:00
|
|
|
SCSIZE nCount = pArray->GetCount();
|
2000-09-18 23:16:46 +00:00
|
|
|
ScSortInfo** ppInfo = pArray->GetFirstArray();
|
2004-06-04 09:28:40 +00:00
|
|
|
// hngngn.. Win16 legacy? Table has ULONG count but can only be initialized using USHORT :-/
|
|
|
|
// FIXME: use std::vector instead, would be better anyway (type safe)
|
|
|
|
USHORT nArghl = (nCount > USHRT_MAX ? USHRT_MAX : static_cast<USHORT>(nCount));
|
|
|
|
Table aTable( nArghl );
|
|
|
|
SCSIZE nPos;
|
2000-09-18 23:16:46 +00:00
|
|
|
for ( nPos = 0; nPos < nCount; nPos++ )
|
|
|
|
{
|
|
|
|
aTable.Insert( ppInfo[nPos]->nOrg, (void*) ppInfo[nPos] );
|
|
|
|
}
|
2004-06-04 09:28:40 +00:00
|
|
|
SCCOLROW nDest = pArray->GetStart();
|
2000-09-18 23:16:46 +00:00
|
|
|
for ( nPos = 0; nPos < nCount; nPos++, nDest++ )
|
|
|
|
{
|
2004-06-04 09:28:40 +00:00
|
|
|
SCCOLROW nOrg = ppInfo[nPos]->nOrg;
|
2000-09-18 23:16:46 +00:00
|
|
|
if ( nDest != nOrg )
|
|
|
|
{
|
|
|
|
if ( bByRow )
|
|
|
|
SwapRow( nDest, nOrg );
|
|
|
|
else
|
2004-06-04 09:28:40 +00:00
|
|
|
SwapCol( static_cast<SCCOL>(nDest), static_cast<SCCOL>(nOrg) );
|
2000-09-18 23:16:46 +00:00
|
|
|
// neue Position des weggeswapten eintragen
|
|
|
|
ScSortInfo* p = ppInfo[nPos];
|
|
|
|
p->nOrg = nDest;
|
|
|
|
p = (ScSortInfo*) aTable.Replace( nDest, (void*) p );
|
|
|
|
p->nOrg = nOrg;
|
|
|
|
p = (ScSortInfo*) aTable.Replace( nOrg, (void*) p );
|
|
|
|
DBG_ASSERT( p == ppInfo[nPos], "SortReorder: nOrg MisMatch" );
|
|
|
|
}
|
|
|
|
rProgress.SetStateOnPercent( nPos );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
short ScTable::CompareCell( USHORT nSort,
|
2004-06-04 09:28:40 +00:00
|
|
|
ScBaseCell* pCell1, SCCOL nCell1Col, SCROW nCell1Row,
|
|
|
|
ScBaseCell* pCell2, SCCOL nCell2Col, SCROW nCell2Row )
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
|
|
|
short nRes = 0;
|
|
|
|
|
2007-02-27 11:09:41 +00:00
|
|
|
CellType eType1 = CELLTYPE_NONE, eType2 = CELLTYPE_NONE;
|
2000-09-18 23:16:46 +00:00
|
|
|
if (pCell1)
|
|
|
|
{
|
|
|
|
eType1 = pCell1->GetCellType();
|
|
|
|
if (eType1 == CELLTYPE_NOTE)
|
|
|
|
pCell1 = NULL;
|
|
|
|
}
|
|
|
|
if (pCell2)
|
|
|
|
{
|
|
|
|
eType2 = pCell2->GetCellType();
|
|
|
|
if (eType2 == CELLTYPE_NOTE)
|
|
|
|
pCell2 = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pCell1)
|
|
|
|
{
|
|
|
|
if (pCell2)
|
|
|
|
{
|
|
|
|
BOOL bStr1 = ( eType1 != CELLTYPE_VALUE );
|
|
|
|
if ( eType1 == CELLTYPE_FORMULA && ((ScFormulaCell*)pCell1)->IsValue() )
|
|
|
|
bStr1 = FALSE;
|
|
|
|
BOOL bStr2 = ( eType2 != CELLTYPE_VALUE );
|
|
|
|
if ( eType2 == CELLTYPE_FORMULA && ((ScFormulaCell*)pCell2)->IsValue() )
|
|
|
|
bStr2 = FALSE;
|
|
|
|
|
|
|
|
if ( bStr1 && bStr2 ) // nur Strings untereinander als String vergleichen!
|
|
|
|
{
|
|
|
|
String aStr1;
|
|
|
|
String aStr2;
|
|
|
|
if (eType1 == CELLTYPE_STRING)
|
|
|
|
((ScStringCell*)pCell1)->GetString(aStr1);
|
|
|
|
else
|
|
|
|
GetString(nCell1Col, nCell1Row, aStr1);
|
|
|
|
if (eType2 == CELLTYPE_STRING)
|
|
|
|
((ScStringCell*)pCell2)->GetString(aStr2);
|
|
|
|
else
|
|
|
|
GetString(nCell2Col, nCell2Row, aStr2);
|
|
|
|
BOOL bUserDef = aSortParam.bUserDef;
|
|
|
|
if (bUserDef)
|
|
|
|
{
|
|
|
|
ScUserListData* pData =
|
|
|
|
(ScUserListData*)(ScGlobal::GetUserList()->At(
|
|
|
|
aSortParam.nUserIndex));
|
|
|
|
if (pData)
|
|
|
|
{
|
|
|
|
if ( aSortParam.bCaseSens )
|
2007-02-27 11:09:41 +00:00
|
|
|
nRes = sal::static_int_cast<short>( pData->Compare(aStr1, aStr2) );
|
2000-09-18 23:16:46 +00:00
|
|
|
else
|
2007-02-27 11:09:41 +00:00
|
|
|
nRes = sal::static_int_cast<short>( pData->ICompare(aStr1, aStr2) );
|
2000-09-18 23:16:46 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
bUserDef = FALSE;
|
|
|
|
|
|
|
|
}
|
|
|
|
if (!bUserDef)
|
2001-03-14 14:57:39 +00:00
|
|
|
nRes = (short) pSortCollator->compareString( aStr1, aStr2 );
|
2000-09-18 23:16:46 +00:00
|
|
|
}
|
|
|
|
else if ( bStr1 ) // String <-> Zahl
|
|
|
|
nRes = 1; // Zahl vorne
|
|
|
|
else if ( bStr2 ) // Zahl <-> String
|
|
|
|
nRes = -1; // Zahl vorne
|
|
|
|
else // Zahlen untereinander
|
|
|
|
{
|
|
|
|
double nVal1;
|
|
|
|
double nVal2;
|
|
|
|
if (eType1 == CELLTYPE_VALUE)
|
|
|
|
nVal1 = ((ScValueCell*)pCell1)->GetValue();
|
|
|
|
else if (eType1 == CELLTYPE_FORMULA)
|
|
|
|
nVal1 = ((ScFormulaCell*)pCell1)->GetValue();
|
|
|
|
else
|
|
|
|
nVal1 = 0;
|
|
|
|
if (eType2 == CELLTYPE_VALUE)
|
|
|
|
nVal2 = ((ScValueCell*)pCell2)->GetValue();
|
|
|
|
else if (eType2 == CELLTYPE_FORMULA)
|
|
|
|
nVal2 = ((ScFormulaCell*)pCell2)->GetValue();
|
|
|
|
else
|
|
|
|
nVal2 = 0;
|
|
|
|
if (nVal1 < nVal2)
|
|
|
|
nRes = -1;
|
|
|
|
else if (nVal1 > nVal2)
|
|
|
|
nRes = 1;
|
|
|
|
}
|
|
|
|
if ( !aSortParam.bAscending[nSort] )
|
|
|
|
nRes = -nRes;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
nRes = -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if ( pCell2 )
|
|
|
|
nRes = 1;
|
|
|
|
else
|
|
|
|
nRes = 0; // beide leer
|
|
|
|
}
|
|
|
|
return nRes;
|
|
|
|
}
|
|
|
|
|
2004-06-04 09:28:40 +00:00
|
|
|
short ScTable::Compare( ScSortInfoArray* pArray, SCCOLROW nIndex1, SCCOLROW nIndex2 )
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
|
|
|
short nRes;
|
|
|
|
USHORT nSort = 0;
|
|
|
|
do
|
|
|
|
{
|
|
|
|
ScSortInfo* pInfo1 = pArray->Get( nSort, nIndex1 );
|
|
|
|
ScSortInfo* pInfo2 = pArray->Get( nSort, nIndex2 );
|
|
|
|
if ( aSortParam.bByRow )
|
|
|
|
nRes = CompareCell( nSort,
|
2004-06-04 09:28:40 +00:00
|
|
|
pInfo1->pCell, static_cast<SCCOL>(aSortParam.nField[nSort]), pInfo1->nOrg,
|
|
|
|
pInfo2->pCell, static_cast<SCCOL>(aSortParam.nField[nSort]), pInfo2->nOrg );
|
2000-09-18 23:16:46 +00:00
|
|
|
else
|
|
|
|
nRes = CompareCell( nSort,
|
2004-06-04 09:28:40 +00:00
|
|
|
pInfo1->pCell, static_cast<SCCOL>(pInfo1->nOrg), aSortParam.nField[nSort],
|
|
|
|
pInfo2->pCell, static_cast<SCCOL>(pInfo2->nOrg), aSortParam.nField[nSort] );
|
2000-09-18 23:16:46 +00:00
|
|
|
} while ( nRes == 0 && ++nSort < pArray->GetUsedSorts() );
|
|
|
|
return nRes;
|
|
|
|
}
|
|
|
|
|
2004-06-04 09:28:40 +00:00
|
|
|
void ScTable::QuickSort( ScSortInfoArray* pArray, SCsCOLROW nLo, SCsCOLROW nHi )
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
|
|
|
if ((nHi - nLo) == 1)
|
|
|
|
{
|
|
|
|
if (Compare(pArray, nLo, nHi) > 0)
|
|
|
|
pArray->Swap( nLo, nHi );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-06-04 09:28:40 +00:00
|
|
|
SCsCOLROW ni = nLo;
|
|
|
|
SCsCOLROW nj = nHi;
|
2000-09-18 23:16:46 +00:00
|
|
|
do
|
|
|
|
{
|
|
|
|
while ((ni <= nHi) && (Compare(pArray, ni, nLo)) < 0)
|
|
|
|
ni++;
|
|
|
|
while ((nj >= nLo) && (Compare(pArray, nLo, nj)) < 0)
|
|
|
|
nj--;
|
|
|
|
if (ni <= nj)
|
|
|
|
{
|
|
|
|
if (ni != nj)
|
|
|
|
pArray->Swap( ni, nj );
|
|
|
|
ni++;
|
|
|
|
nj--;
|
|
|
|
}
|
|
|
|
} while (ni < nj);
|
|
|
|
if ((nj - nLo) < (nHi - ni))
|
|
|
|
{
|
|
|
|
if (nLo < nj)
|
|
|
|
QuickSort(pArray, nLo, nj);
|
|
|
|
if (ni < nHi)
|
|
|
|
QuickSort(pArray, ni, nHi);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (ni < nHi)
|
|
|
|
QuickSort(pArray, ni, nHi);
|
|
|
|
if (nLo < nj)
|
|
|
|
QuickSort(pArray, nLo, nj);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-06-04 09:28:40 +00:00
|
|
|
void ScTable::SwapCol(SCCOL nCol1, SCCOL nCol2)
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
2004-06-04 09:28:40 +00:00
|
|
|
for (SCROW nRow = aSortParam.nRow1; nRow <= aSortParam.nRow2; nRow++)
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
|
|
|
aCol[nCol1].SwapCell(nRow, aCol[nCol2]);
|
|
|
|
if (aSortParam.bIncludePattern)
|
|
|
|
{
|
|
|
|
const ScPatternAttr* pPat1 = GetPattern(nCol1, nRow);
|
|
|
|
const ScPatternAttr* pPat2 = GetPattern(nCol2, nRow);
|
|
|
|
if (pPat1 != pPat2)
|
|
|
|
{
|
|
|
|
SetPattern(nCol1, nRow, *pPat2, TRUE);
|
|
|
|
SetPattern(nCol2, nRow, *pPat1, TRUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-06-04 09:28:40 +00:00
|
|
|
void ScTable::SwapRow(SCROW nRow1, SCROW nRow2)
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
2004-06-04 09:28:40 +00:00
|
|
|
for (SCCOL nCol = aSortParam.nCol1; nCol <= aSortParam.nCol2; nCol++)
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
|
|
|
aCol[nCol].SwapRow(nRow1, nRow2);
|
|
|
|
if (aSortParam.bIncludePattern)
|
|
|
|
{
|
|
|
|
const ScPatternAttr* pPat1 = GetPattern(nCol, nRow1);
|
|
|
|
const ScPatternAttr* pPat2 = GetPattern(nCol, nRow2);
|
|
|
|
if (pPat1 != pPat2)
|
|
|
|
{
|
|
|
|
SetPattern(nCol, nRow1, *pPat2, TRUE);
|
|
|
|
SetPattern(nCol, nRow2, *pPat1, TRUE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (bGlobalKeepQuery && pRowFlags)
|
|
|
|
{
|
2004-08-20 08:11:23 +00:00
|
|
|
BYTE nRow1Flags = pRowFlags->GetValue(nRow1);
|
|
|
|
BYTE nRow2Flags = pRowFlags->GetValue(nRow2);
|
|
|
|
BYTE nFlags1 = nRow1Flags & ( CR_HIDDEN | CR_FILTERED );
|
|
|
|
BYTE nFlags2 = nRow2Flags & ( CR_HIDDEN | CR_FILTERED );
|
|
|
|
pRowFlags->SetValue( nRow1, (nRow1Flags & ~( CR_HIDDEN | CR_FILTERED )) | nFlags2);
|
|
|
|
pRowFlags->SetValue( nRow2, (nRow2Flags & ~( CR_HIDDEN | CR_FILTERED )) | nFlags1);
|
2000-09-18 23:16:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-06-04 09:28:40 +00:00
|
|
|
short ScTable::Compare(SCCOLROW nIndex1, SCCOLROW nIndex2)
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
|
|
|
short nRes;
|
|
|
|
USHORT nSort = 0;
|
|
|
|
if (aSortParam.bByRow)
|
|
|
|
{
|
|
|
|
do
|
|
|
|
{
|
2004-06-04 09:28:40 +00:00
|
|
|
SCCOL nCol = static_cast<SCCOL>(aSortParam.nField[nSort]);
|
2000-09-18 23:16:46 +00:00
|
|
|
ScBaseCell* pCell1 = aCol[nCol].GetCell( nIndex1 );
|
|
|
|
ScBaseCell* pCell2 = aCol[nCol].GetCell( nIndex2 );
|
|
|
|
nRes = CompareCell( nSort, pCell1, nCol, nIndex1, pCell2, nCol, nIndex2 );
|
|
|
|
} while ( nRes == 0 && ++nSort < nMaxSorts && aSortParam.bDoSort[nSort] );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
do
|
|
|
|
{
|
2004-06-04 09:28:40 +00:00
|
|
|
SCROW nRow = aSortParam.nField[nSort];
|
2000-09-18 23:16:46 +00:00
|
|
|
ScBaseCell* pCell1 = aCol[nIndex1].GetCell( nRow );
|
|
|
|
ScBaseCell* pCell2 = aCol[nIndex2].GetCell( nRow );
|
2004-06-04 09:28:40 +00:00
|
|
|
nRes = CompareCell( nSort, pCell1, static_cast<SCCOL>(nIndex1),
|
|
|
|
nRow, pCell2, static_cast<SCCOL>(nIndex2), nRow );
|
2000-09-18 23:16:46 +00:00
|
|
|
} while ( nRes == 0 && ++nSort < nMaxSorts && aSortParam.bDoSort[nSort] );
|
|
|
|
}
|
|
|
|
return nRes;
|
|
|
|
}
|
|
|
|
|
2004-06-04 09:28:40 +00:00
|
|
|
BOOL ScTable::IsSorted( SCCOLROW nStart, SCCOLROW nEnd ) // ueber aSortParam
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
2004-06-04 09:28:40 +00:00
|
|
|
for (SCCOLROW i=nStart; i<nEnd; i++)
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
|
|
|
if (Compare( i, i+1 ) > 0)
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2004-06-04 09:28:40 +00:00
|
|
|
void ScTable::DecoladeRow( ScSortInfoArray* pArray, SCROW nRow1, SCROW nRow2 )
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
2004-06-04 09:28:40 +00:00
|
|
|
SCROW nRow;
|
|
|
|
SCROW nMax = nRow2 - nRow1;
|
|
|
|
for (SCROW i = nRow1; (i + 4) <= nRow2; i += 4)
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
|
|
|
nRow = rand() % nMax;
|
|
|
|
pArray->Swap(i, nRow1 + nRow);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScTable::Sort(const ScSortParam& rSortParam, BOOL bKeepQuery)
|
|
|
|
{
|
2001-03-12 18:37:32 +00:00
|
|
|
aSortParam = rSortParam;
|
2001-03-14 14:57:39 +00:00
|
|
|
InitSortCollator( rSortParam );
|
2000-09-18 23:16:46 +00:00
|
|
|
bGlobalKeepQuery = bKeepQuery;
|
|
|
|
if (rSortParam.bByRow)
|
|
|
|
{
|
2004-06-04 09:28:40 +00:00
|
|
|
SCROW nLastRow = 0;
|
|
|
|
for (SCCOL nCol = aSortParam.nCol1; nCol <= aSortParam.nCol2; nCol++)
|
2000-09-18 23:16:46 +00:00
|
|
|
nLastRow = Max(nLastRow, aCol[nCol].GetLastDataPos());
|
|
|
|
nLastRow = Min(nLastRow, aSortParam.nRow2);
|
2004-06-04 09:28:40 +00:00
|
|
|
SCROW nRow1 = (rSortParam.bHasHeader ?
|
2000-09-18 23:16:46 +00:00
|
|
|
aSortParam.nRow1 + 1 : aSortParam.nRow1);
|
|
|
|
if (!IsSorted(nRow1, nLastRow))
|
|
|
|
{
|
|
|
|
ScProgress aProgress( pDocument->GetDocumentShell(),
|
|
|
|
ScGlobal::GetRscString(STR_PROGRESS_SORTING), nLastRow - nRow1 );
|
|
|
|
ScSortInfoArray* pArray = CreateSortInfoArray( nRow1, nLastRow );
|
|
|
|
if ( nLastRow - nRow1 > 255 )
|
|
|
|
DecoladeRow( pArray, nRow1, nLastRow );
|
|
|
|
QuickSort( pArray, nRow1, nLastRow );
|
|
|
|
SortReorder( pArray, aProgress );
|
|
|
|
delete pArray;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2004-06-04 09:28:40 +00:00
|
|
|
SCCOL nLastCol;
|
2000-09-18 23:16:46 +00:00
|
|
|
for (nLastCol = aSortParam.nCol2;
|
|
|
|
(nLastCol > aSortParam.nCol1) && aCol[nLastCol].IsEmptyBlock(aSortParam.nRow1, aSortParam.nRow2); nLastCol--)
|
|
|
|
{
|
|
|
|
}
|
2004-06-04 09:28:40 +00:00
|
|
|
SCCOL nCol1 = (rSortParam.bHasHeader ?
|
2000-09-18 23:16:46 +00:00
|
|
|
aSortParam.nCol1 + 1 : aSortParam.nCol1);
|
|
|
|
if (!IsSorted(nCol1, nLastCol))
|
|
|
|
{
|
|
|
|
ScProgress aProgress( pDocument->GetDocumentShell(),
|
|
|
|
ScGlobal::GetRscString(STR_PROGRESS_SORTING), nLastCol - nCol1 );
|
|
|
|
ScSortInfoArray* pArray = CreateSortInfoArray( nCol1, nLastCol );
|
|
|
|
QuickSort( pArray, nCol1, nLastCol );
|
|
|
|
SortReorder( pArray, aProgress );
|
|
|
|
delete pArray;
|
|
|
|
}
|
|
|
|
}
|
2001-03-14 14:57:39 +00:00
|
|
|
DestroySortCollator();
|
2000-09-18 23:16:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Testen, ob beim Loeschen von Zwischenergebnissen andere Daten mit geloescht werden
|
|
|
|
// (fuer Hinweis-Box)
|
|
|
|
|
|
|
|
BOOL ScTable::TestRemoveSubTotals( const ScSubTotalParam& rParam )
|
|
|
|
{
|
2004-06-04 09:28:40 +00:00
|
|
|
SCCOL nStartCol = rParam.nCol1;
|
|
|
|
SCROW nStartRow = rParam.nRow1 + 1; // Header
|
|
|
|
SCCOL nEndCol = rParam.nCol2;
|
|
|
|
SCROW nEndRow = rParam.nRow2;
|
2000-09-18 23:16:46 +00:00
|
|
|
|
2004-06-04 09:28:40 +00:00
|
|
|
SCCOL nCol;
|
|
|
|
SCROW nRow;
|
2000-09-18 23:16:46 +00:00
|
|
|
ScBaseCell* pCell;
|
|
|
|
|
|
|
|
BOOL bWillDelete = FALSE;
|
|
|
|
for ( nCol=nStartCol; nCol<=nEndCol && !bWillDelete; nCol++ )
|
|
|
|
{
|
|
|
|
ScColumnIterator aIter( &aCol[nCol],nStartRow,nEndRow );
|
|
|
|
while ( aIter.Next( nRow, pCell ) && !bWillDelete )
|
|
|
|
{
|
|
|
|
if ( pCell->GetCellType() == CELLTYPE_FORMULA )
|
|
|
|
if (((ScFormulaCell*)pCell)->IsSubTotal())
|
|
|
|
{
|
2004-06-04 09:28:40 +00:00
|
|
|
for (SCCOL nTestCol=0; nTestCol<=MAXCOL; nTestCol++)
|
2000-09-18 23:16:46 +00:00
|
|
|
if (nTestCol<nStartCol || nTestCol>nEndCol)
|
|
|
|
if (aCol[nTestCol].HasDataAt(nRow))
|
|
|
|
bWillDelete = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return bWillDelete;
|
|
|
|
}
|
|
|
|
|
|
|
|
// alte Ergebnisse loeschen
|
|
|
|
// rParam.nRow2 wird veraendert !
|
|
|
|
|
|
|
|
void ScTable::RemoveSubTotals( ScSubTotalParam& rParam )
|
|
|
|
{
|
2004-06-04 09:28:40 +00:00
|
|
|
SCCOL nStartCol = rParam.nCol1;
|
|
|
|
SCROW nStartRow = rParam.nRow1 + 1; // Header
|
|
|
|
SCCOL nEndCol = rParam.nCol2;
|
|
|
|
SCROW nEndRow = rParam.nRow2; // wird veraendert
|
2000-09-18 23:16:46 +00:00
|
|
|
|
2004-06-04 09:28:40 +00:00
|
|
|
SCCOL nCol;
|
|
|
|
SCROW nRow;
|
2000-09-18 23:16:46 +00:00
|
|
|
ScBaseCell* pCell;
|
|
|
|
|
|
|
|
for ( nCol=nStartCol; nCol<=nEndCol; nCol++ )
|
|
|
|
{
|
|
|
|
ScColumnIterator aIter( &aCol[nCol],nStartRow,nEndRow );
|
|
|
|
while ( aIter.Next( nRow, pCell ) )
|
|
|
|
{
|
|
|
|
if ( pCell->GetCellType() == CELLTYPE_FORMULA )
|
|
|
|
if (((ScFormulaCell*)pCell)->IsSubTotal())
|
|
|
|
{
|
|
|
|
SetRowFlags(nRow+1,GetRowFlags(nRow+1)&(~CR_MANUALBREAK));
|
|
|
|
pDocument->DeleteRow( 0,nTab, MAXCOL,nTab, nRow, 1 );
|
|
|
|
--nEndRow;
|
|
|
|
aIter = ScColumnIterator( &aCol[nCol],nRow,nEndRow );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rParam.nRow2 = nEndRow; // neues Ende
|
|
|
|
}
|
|
|
|
|
|
|
|
// harte Zahlenformate loeschen (fuer Ergebnisformeln)
|
|
|
|
|
2004-06-04 09:28:40 +00:00
|
|
|
void lcl_RemoveNumberFormat( ScTable* pTab, SCCOL nCol, SCROW nRow )
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
|
|
|
const ScPatternAttr* pPattern = pTab->GetPattern( nCol, nRow );
|
|
|
|
if ( pPattern->GetItemSet().GetItemState( ATTR_VALUE_FORMAT, FALSE )
|
|
|
|
== SFX_ITEM_SET )
|
|
|
|
{
|
|
|
|
ScPatternAttr aNewPattern( *pPattern );
|
|
|
|
SfxItemSet& rSet = aNewPattern.GetItemSet();
|
|
|
|
rSet.ClearItem( ATTR_VALUE_FORMAT );
|
|
|
|
rSet.ClearItem( ATTR_LANGUAGE_FORMAT );
|
|
|
|
pTab->SetPattern( nCol, nRow, aNewPattern, TRUE );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-11-27 20:40:50 +00:00
|
|
|
|
|
|
|
// at least MSC needs this at linkage level to be able to use it in a template
|
|
|
|
typedef struct lcl_ScTable_DoSubTotals_RowEntry
|
|
|
|
{
|
|
|
|
USHORT nGroupNo;
|
2004-06-04 09:28:40 +00:00
|
|
|
SCROW nSubStartRow;
|
|
|
|
SCROW nDestRow;
|
|
|
|
SCROW nFuncStart;
|
|
|
|
SCROW nFuncEnd;
|
2002-11-27 20:40:50 +00:00
|
|
|
} RowEntry;
|
|
|
|
|
2000-09-18 23:16:46 +00:00
|
|
|
// neue Zwischenergebnisse
|
|
|
|
// rParam.nRow2 wird veraendert !
|
|
|
|
|
|
|
|
BOOL ScTable::DoSubTotals( ScSubTotalParam& rParam )
|
|
|
|
{
|
2004-06-04 09:28:40 +00:00
|
|
|
SCCOL nStartCol = rParam.nCol1;
|
|
|
|
SCROW nStartRow = rParam.nRow1 + 1; // Header
|
|
|
|
SCCOL nEndCol = rParam.nCol2;
|
|
|
|
SCROW nEndRow = rParam.nRow2; // wird veraendert
|
2000-09-18 23:16:46 +00:00
|
|
|
USHORT i;
|
|
|
|
|
|
|
|
// Leerzeilen am Ende weglassen,
|
|
|
|
// damit alle Ueberlaeufe (MAXROW) bei InsertRow gefunden werden (#35180#)
|
|
|
|
// Wenn sortiert wurde, sind alle Leerzeilen am Ende.
|
2004-06-04 09:28:40 +00:00
|
|
|
SCSIZE nEmpty = GetEmptyLinesInBlock( nStartCol, nStartRow, nEndCol, nEndRow, DIR_BOTTOM );
|
2000-09-18 23:16:46 +00:00
|
|
|
nEndRow -= nEmpty;
|
|
|
|
|
|
|
|
USHORT nLevelCount = 0; // Anzahl Gruppierungen
|
|
|
|
BOOL bDoThis = TRUE;
|
|
|
|
for (i=0; i<MAXSUBTOTAL && bDoThis; i++)
|
|
|
|
if (rParam.bGroupActive[i])
|
|
|
|
nLevelCount = i+1;
|
|
|
|
else
|
|
|
|
bDoThis = FALSE;
|
|
|
|
|
|
|
|
if (nLevelCount==0) // nichts tun
|
|
|
|
return TRUE;
|
|
|
|
|
2004-06-04 09:28:40 +00:00
|
|
|
SCCOL* nGroupCol = rParam.nField; // Spalten nach denen
|
2000-09-18 23:16:46 +00:00
|
|
|
// gruppiert wird
|
|
|
|
|
|
|
|
// #44444# Durch (leer) als eigene Kategorie muss immer auf
|
|
|
|
// Teilergebniszeilen aus den anderen Spalten getestet werden
|
|
|
|
// (frueher nur, wenn eine Spalte mehrfach vorkam)
|
|
|
|
BOOL bTestPrevSub = ( nLevelCount > 1 );
|
|
|
|
|
|
|
|
String aSubString;
|
|
|
|
String aOutString;
|
|
|
|
|
2000-09-29 14:48:30 +00:00
|
|
|
BOOL bIgnoreCase = !rParam.bCaseSens;
|
|
|
|
|
2000-09-18 23:16:46 +00:00
|
|
|
String *pCompString[MAXSUBTOTAL]; // Pointer wegen Compiler-Problemen
|
|
|
|
for (i=0; i<MAXSUBTOTAL; i++)
|
|
|
|
pCompString[i] = new String;
|
|
|
|
|
|
|
|
//! sortieren?
|
|
|
|
|
|
|
|
ScStyleSheet* pStyle = (ScStyleSheet*) pDocument->GetStyleSheetPool()->Find(
|
|
|
|
ScGlobal::GetRscString(STR_STYLENAME_RESULT), SFX_STYLE_FAMILY_PARA );
|
|
|
|
|
|
|
|
BOOL bSpaceLeft = TRUE; // Erfolg beim Einfuegen?
|
|
|
|
|
2002-11-27 20:40:50 +00:00
|
|
|
// #90279# For performance reasons collect formula entries so their
|
|
|
|
// references don't have to be tested for updates each time a new row is
|
|
|
|
// inserted
|
|
|
|
RowEntry aRowEntry;
|
|
|
|
::std::vector< RowEntry > aRowVector;
|
|
|
|
|
|
|
|
for (USHORT nLevel=0; nLevel<=nLevelCount && bSpaceLeft; nLevel++) // incl. Gesamtergebnis
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
|
|
|
BOOL bTotal = ( nLevel == nLevelCount );
|
2002-11-27 20:40:50 +00:00
|
|
|
aRowEntry.nGroupNo = bTotal ? 0 : (nLevelCount-nLevel-1);
|
2000-09-18 23:16:46 +00:00
|
|
|
|
2002-11-27 20:40:50 +00:00
|
|
|
// how many results per level
|
2004-06-04 09:28:40 +00:00
|
|
|
SCCOL nResCount = rParam.nSubTotals[aRowEntry.nGroupNo];
|
2002-11-27 20:40:50 +00:00
|
|
|
// result functions
|
|
|
|
ScSubTotalFunc* eResFunc = rParam.pFunctions[aRowEntry.nGroupNo];
|
2000-09-18 23:16:46 +00:00
|
|
|
|
2004-06-04 09:28:40 +00:00
|
|
|
if (nResCount > 0) // sonst nur sortieren
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
2002-11-27 20:40:50 +00:00
|
|
|
for (i=0; i<=aRowEntry.nGroupNo; i++)
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
|
|
|
GetString( nGroupCol[i], nStartRow, aSubString );
|
2002-11-27 20:40:50 +00:00
|
|
|
if ( bIgnoreCase )
|
|
|
|
*pCompString[i] = ScGlobal::pCharClass->upper( aSubString );
|
|
|
|
else
|
|
|
|
*pCompString[i] = aSubString;
|
2000-09-18 23:16:46 +00:00
|
|
|
} // aSubString bleibt auf dem letzten stehen
|
|
|
|
|
|
|
|
BOOL bBlockVis = FALSE; // Gruppe eingeblendet?
|
2002-11-27 20:40:50 +00:00
|
|
|
aRowEntry.nSubStartRow = nStartRow;
|
2004-06-04 09:28:40 +00:00
|
|
|
for (SCROW nRow=nStartRow; nRow<=nEndRow+1 && bSpaceLeft; nRow++)
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
2002-11-27 20:40:50 +00:00
|
|
|
BOOL bChanged;
|
2000-09-18 23:16:46 +00:00
|
|
|
if (nRow>nEndRow)
|
|
|
|
bChanged = TRUE;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
bChanged = FALSE;
|
|
|
|
if (!bTotal)
|
|
|
|
{
|
2002-11-27 20:40:50 +00:00
|
|
|
String aString;
|
|
|
|
for (i=0; i<=aRowEntry.nGroupNo && !bChanged; i++)
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
|
|
|
GetString( nGroupCol[i], nRow, aString );
|
2000-09-29 14:48:30 +00:00
|
|
|
if (bIgnoreCase)
|
|
|
|
ScGlobal::pCharClass->toUpper( aString );
|
2000-09-18 23:16:46 +00:00
|
|
|
// #41427# wenn sortiert, ist "leer" eine eigene Gruppe
|
|
|
|
// sonst sind leere Zellen unten erlaubt
|
|
|
|
bChanged = ( ( aString.Len() || rParam.bDoSort ) &&
|
|
|
|
aString != *pCompString[i] );
|
|
|
|
}
|
|
|
|
if ( bChanged && bTestPrevSub )
|
|
|
|
{
|
2003-04-28 14:31:41 +00:00
|
|
|
// No group change on rows that will contain subtotal formulas
|
|
|
|
for ( ::std::vector< RowEntry >::const_iterator
|
|
|
|
iEntry( aRowVector.begin());
|
|
|
|
iEntry != aRowVector.end(); ++iEntry)
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
2003-04-28 14:31:41 +00:00
|
|
|
if ( iEntry->nDestRow == nRow )
|
|
|
|
{
|
|
|
|
bChanged = FALSE;
|
|
|
|
break;
|
|
|
|
}
|
2000-09-18 23:16:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( bChanged )
|
|
|
|
{
|
2002-11-27 20:40:50 +00:00
|
|
|
aRowEntry.nDestRow = nRow;
|
|
|
|
aRowEntry.nFuncStart = aRowEntry.nSubStartRow;
|
|
|
|
aRowEntry.nFuncEnd = nRow-1;
|
|
|
|
|
|
|
|
bSpaceLeft = pDocument->InsertRow( 0, nTab, MAXCOL, nTab,
|
|
|
|
aRowEntry.nDestRow, 1 );
|
|
|
|
DBShowRow( aRowEntry.nDestRow, bBlockVis );
|
2000-09-18 23:16:46 +00:00
|
|
|
bBlockVis = FALSE;
|
2002-11-27 20:40:50 +00:00
|
|
|
if ( rParam.bPagebreak && nRow < MAXROW &&
|
|
|
|
aRowEntry.nSubStartRow != nStartRow && nLevel == 0)
|
|
|
|
SetRowFlags( aRowEntry.nSubStartRow,
|
|
|
|
GetRowFlags(aRowEntry.nSubStartRow) |
|
|
|
|
CR_MANUALBREAK);
|
|
|
|
|
2000-09-18 23:16:46 +00:00
|
|
|
if (bSpaceLeft)
|
|
|
|
{
|
2002-11-27 20:40:50 +00:00
|
|
|
for ( ::std::vector< RowEntry >::iterator iMove(
|
|
|
|
aRowVector.begin() );
|
|
|
|
iMove != aRowVector.end(); ++iMove)
|
|
|
|
{
|
|
|
|
if ( aRowEntry.nDestRow <= iMove->nSubStartRow )
|
|
|
|
++iMove->nSubStartRow;
|
|
|
|
if ( aRowEntry.nDestRow <= iMove->nDestRow )
|
|
|
|
++iMove->nDestRow;
|
|
|
|
if ( aRowEntry.nDestRow <= iMove->nFuncStart )
|
|
|
|
++iMove->nFuncStart;
|
|
|
|
if ( aRowEntry.nDestRow <= iMove->nFuncEnd )
|
|
|
|
++iMove->nFuncEnd;
|
|
|
|
}
|
|
|
|
// collect formula positions
|
|
|
|
aRowVector.push_back( aRowEntry );
|
|
|
|
|
2000-09-18 23:16:46 +00:00
|
|
|
if (bTotal) // "Gesamtergebnis"
|
|
|
|
aOutString = ScGlobal::GetRscString( STR_TABLE_GESAMTERGEBNIS );
|
|
|
|
else
|
|
|
|
{ // " Ergebnis"
|
|
|
|
aOutString = aSubString;
|
|
|
|
if (!aOutString.Len())
|
|
|
|
aOutString = ScGlobal::GetRscString( STR_EMPTYDATA );
|
|
|
|
aOutString += ' ';
|
|
|
|
USHORT nStrId = STR_TABLE_ERGEBNIS;
|
|
|
|
if ( nResCount == 1 )
|
|
|
|
switch ( eResFunc[0] )
|
|
|
|
{
|
|
|
|
case SUBTOTAL_FUNC_AVE: nStrId = STR_FUN_TEXT_AVG; break;
|
|
|
|
case SUBTOTAL_FUNC_CNT:
|
|
|
|
case SUBTOTAL_FUNC_CNT2: nStrId = STR_FUN_TEXT_COUNT; break;
|
|
|
|
case SUBTOTAL_FUNC_MAX: nStrId = STR_FUN_TEXT_MAX; break;
|
|
|
|
case SUBTOTAL_FUNC_MIN: nStrId = STR_FUN_TEXT_MIN; break;
|
|
|
|
case SUBTOTAL_FUNC_PROD: nStrId = STR_FUN_TEXT_PRODUCT; break;
|
|
|
|
case SUBTOTAL_FUNC_STD:
|
|
|
|
case SUBTOTAL_FUNC_STDP: nStrId = STR_FUN_TEXT_STDDEV; break;
|
|
|
|
case SUBTOTAL_FUNC_SUM: nStrId = STR_FUN_TEXT_SUM; break;
|
|
|
|
case SUBTOTAL_FUNC_VAR:
|
|
|
|
case SUBTOTAL_FUNC_VARP: nStrId = STR_FUN_TEXT_VAR; break;
|
2007-02-27 11:09:41 +00:00
|
|
|
default:
|
|
|
|
{
|
|
|
|
// added to avoid warnings
|
|
|
|
}
|
2000-09-18 23:16:46 +00:00
|
|
|
}
|
|
|
|
aOutString += ScGlobal::GetRscString( nStrId );
|
|
|
|
}
|
2002-11-27 20:40:50 +00:00
|
|
|
SetString( nGroupCol[aRowEntry.nGroupNo], aRowEntry.nDestRow, nTab, aOutString );
|
|
|
|
ApplyStyle( nGroupCol[aRowEntry.nGroupNo], aRowEntry.nDestRow, *pStyle );
|
2000-09-18 23:16:46 +00:00
|
|
|
|
|
|
|
/* if (rParam.bPagebreak && nRow < MAXROW)
|
|
|
|
{
|
|
|
|
BYTE nFlags = GetRowFlags( nRow+1 );
|
|
|
|
nFlags |= CR_MANUALBREAK;
|
|
|
|
SetRowFlags( nRow+1, nFlags );
|
|
|
|
}
|
|
|
|
*/
|
|
|
|
++nRow;
|
|
|
|
++nEndRow;
|
2002-11-27 20:40:50 +00:00
|
|
|
aRowEntry.nSubStartRow = nRow;
|
|
|
|
for (i=0; i<=aRowEntry.nGroupNo; i++)
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
|
|
|
GetString( nGroupCol[i], nRow, aSubString );
|
2002-11-27 20:40:50 +00:00
|
|
|
if ( bIgnoreCase )
|
|
|
|
*pCompString[i] = ScGlobal::pCharClass->upper( aSubString );
|
|
|
|
else
|
|
|
|
*pCompString[i] = aSubString;
|
2000-09-18 23:16:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!pRowFlags)
|
|
|
|
bBlockVis = TRUE;
|
|
|
|
else
|
2004-08-20 08:11:23 +00:00
|
|
|
if ( (pRowFlags->GetValue(nRow) & CR_FILTERED) == 0 )
|
2000-09-18 23:16:46 +00:00
|
|
|
bBlockVis = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// DBG_ERROR( "nSubTotals==0 bei DoSubTotals" );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-11-27 20:40:50 +00:00
|
|
|
// now insert the formulas
|
|
|
|
ComplRefData aRef;
|
|
|
|
aRef.InitFlags();
|
|
|
|
aRef.Ref1.nTab = nTab;
|
|
|
|
aRef.Ref2.nTab = nTab;
|
|
|
|
for ( ::std::vector< RowEntry >::const_iterator iEntry( aRowVector.begin());
|
|
|
|
iEntry != aRowVector.end(); ++iEntry)
|
|
|
|
{
|
2004-06-04 09:28:40 +00:00
|
|
|
SCCOL nResCount = rParam.nSubTotals[iEntry->nGroupNo];
|
|
|
|
SCCOL* nResCols = rParam.pSubTotals[iEntry->nGroupNo];
|
2002-11-27 20:40:50 +00:00
|
|
|
ScSubTotalFunc* eResFunc = rParam.pFunctions[iEntry->nGroupNo];
|
2007-02-27 11:09:41 +00:00
|
|
|
for ( SCCOL nResult=0; nResult < nResCount; ++nResult )
|
2002-11-27 20:40:50 +00:00
|
|
|
{
|
2007-02-27 11:09:41 +00:00
|
|
|
aRef.Ref1.nCol = nResCols[nResult];
|
2002-11-27 20:40:50 +00:00
|
|
|
aRef.Ref1.nRow = iEntry->nFuncStart;
|
2007-02-27 11:09:41 +00:00
|
|
|
aRef.Ref2.nCol = nResCols[nResult];
|
2002-11-27 20:40:50 +00:00
|
|
|
aRef.Ref2.nRow = iEntry->nFuncEnd;
|
|
|
|
|
|
|
|
ScTokenArray aArr;
|
|
|
|
aArr.AddOpCode( ocSubTotal );
|
|
|
|
aArr.AddOpCode( ocOpen );
|
2007-02-27 11:09:41 +00:00
|
|
|
aArr.AddDouble( (double) eResFunc[nResult] );
|
2002-11-27 20:40:50 +00:00
|
|
|
aArr.AddOpCode( ocSep );
|
|
|
|
aArr.AddDoubleReference( aRef );
|
|
|
|
aArr.AddOpCode( ocClose );
|
|
|
|
aArr.AddOpCode( ocStop );
|
|
|
|
ScBaseCell* pCell = new ScFormulaCell( pDocument, ScAddress(
|
2007-02-27 11:09:41 +00:00
|
|
|
nResCols[nResult], iEntry->nDestRow, nTab), &aArr );
|
|
|
|
PutCell( nResCols[nResult], iEntry->nDestRow, pCell );
|
2002-11-27 20:40:50 +00:00
|
|
|
|
2007-02-27 11:09:41 +00:00
|
|
|
if ( nResCols[nResult] != nGroupCol[iEntry->nGroupNo] )
|
2002-11-27 20:40:50 +00:00
|
|
|
{
|
2007-02-27 11:09:41 +00:00
|
|
|
ApplyStyle( nResCols[nResult], iEntry->nDestRow, *pStyle );
|
2002-11-27 20:40:50 +00:00
|
|
|
|
|
|
|
// Zahlformat loeschen
|
2007-02-27 11:09:41 +00:00
|
|
|
lcl_RemoveNumberFormat( this, nResCols[nResult], iEntry->nDestRow );
|
2002-11-27 20:40:50 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2000-09-18 23:16:46 +00:00
|
|
|
//! je nach Einstellung Zwischensummen-Zeilen nach oben verschieben ?
|
|
|
|
|
|
|
|
//! Outlines direkt erzeugen?
|
|
|
|
|
|
|
|
if (bSpaceLeft)
|
|
|
|
DoAutoOutline( nStartCol, nStartRow, nEndCol, nEndRow );
|
|
|
|
|
|
|
|
for (i=0; i<MAXSUBTOTAL; i++)
|
|
|
|
delete pCompString[i];
|
|
|
|
|
|
|
|
rParam.nRow2 = nEndRow; // neues Ende
|
|
|
|
return bSpaceLeft;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-06-04 09:28:40 +00:00
|
|
|
BOOL ScTable::ValidQuery(SCROW nRow, const ScQueryParam& rParam,
|
2001-09-05 08:41:51 +00:00
|
|
|
BOOL* pSpecial /* =NULL */ , ScBaseCell* pCell /* =NULL */ ,
|
|
|
|
BOOL* pbTestEqualCondition /* = NULL */ )
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
|
|
|
if (!rParam.GetEntry(0).bDoQuery)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
//---------------------------------------------------------------
|
|
|
|
|
2004-06-04 09:28:40 +00:00
|
|
|
const SCSIZE nFixedBools = 32;
|
2000-09-18 23:16:46 +00:00
|
|
|
BOOL aBool[nFixedBools];
|
2001-09-05 08:41:51 +00:00
|
|
|
BOOL aTest[nFixedBools];
|
2004-06-04 09:28:40 +00:00
|
|
|
SCSIZE nEntryCount = rParam.GetEntryCount();
|
2000-09-18 23:16:46 +00:00
|
|
|
BOOL* pPasst = ( nEntryCount <= nFixedBools ? &aBool[0] : new BOOL[nEntryCount] );
|
2001-09-05 08:41:51 +00:00
|
|
|
BOOL* pTest = ( nEntryCount <= nFixedBools ? &aTest[0] : new BOOL[nEntryCount] );
|
2000-09-18 23:16:46 +00:00
|
|
|
|
2004-06-04 09:28:40 +00:00
|
|
|
long nPos = -1;
|
|
|
|
SCSIZE i = 0;
|
2000-09-18 23:16:46 +00:00
|
|
|
BOOL bMatchWholeCell = pDocument->GetDocOptions().IsMatchWholeCell();
|
2001-03-14 14:57:39 +00:00
|
|
|
CollatorWrapper* pCollator = (rParam.bCaseSens ? ScGlobal::pCaseCollator :
|
|
|
|
ScGlobal::pCollator);
|
2001-07-11 14:22:13 +00:00
|
|
|
::utl::TransliterationWrapper* pTransliteration = (rParam.bCaseSens ?
|
|
|
|
ScGlobal::pCaseTransliteration : ScGlobal::pTransliteration);
|
2000-09-18 23:16:46 +00:00
|
|
|
|
|
|
|
while ( (i < nEntryCount) && rParam.GetEntry(i).bDoQuery )
|
|
|
|
{
|
|
|
|
ScQueryEntry& rEntry = rParam.GetEntry(i);
|
2001-07-12 10:09:11 +00:00
|
|
|
// we can only handle one single direct query
|
|
|
|
if ( !pCell || i > 0 )
|
2004-06-04 09:28:40 +00:00
|
|
|
pCell = GetCell( static_cast<SCCOL>(rEntry.nField), nRow );
|
2000-09-18 23:16:46 +00:00
|
|
|
|
|
|
|
BOOL bOk = FALSE;
|
2001-09-05 08:41:51 +00:00
|
|
|
BOOL bTestEqual = FALSE;
|
2000-09-18 23:16:46 +00:00
|
|
|
|
|
|
|
if ( pSpecial && pSpecial[i] )
|
|
|
|
{
|
|
|
|
if (rEntry.nVal == SC_EMPTYFIELDS)
|
|
|
|
bOk = !( aCol[rEntry.nField].HasDataAt( nRow ) );
|
|
|
|
else // if (rEntry.nVal == SC_NONEMPTYFIELDS)
|
|
|
|
bOk = aCol[rEntry.nField].HasDataAt( nRow );
|
|
|
|
}
|
2004-06-04 09:28:40 +00:00
|
|
|
else if ( !rEntry.bQueryByString && (pCell ? pCell->HasValueData() :
|
|
|
|
HasValueData( static_cast<SCCOL>(rEntry.nField), nRow)))
|
2000-09-18 23:16:46 +00:00
|
|
|
{ // by Value
|
2001-06-21 11:08:38 +00:00
|
|
|
double nCellVal;
|
|
|
|
if ( pCell )
|
|
|
|
{
|
|
|
|
switch ( pCell->GetCellType() )
|
|
|
|
{
|
|
|
|
case CELLTYPE_VALUE :
|
|
|
|
nCellVal = ((ScValueCell*)pCell)->GetValue();
|
|
|
|
break;
|
|
|
|
case CELLTYPE_FORMULA :
|
|
|
|
nCellVal = ((ScFormulaCell*)pCell)->GetValue();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
nCellVal = 0.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
else
|
2004-06-04 09:28:40 +00:00
|
|
|
nCellVal = GetValue( static_cast<SCCOL>(rEntry.nField), nRow );
|
2000-09-18 23:16:46 +00:00
|
|
|
switch (rEntry.eOp)
|
|
|
|
{
|
|
|
|
case SC_EQUAL :
|
2003-03-26 17:07:02 +00:00
|
|
|
bOk = ::rtl::math::approxEqual( nCellVal, rEntry.nVal );
|
2000-09-18 23:16:46 +00:00
|
|
|
break;
|
|
|
|
case SC_LESS :
|
2003-03-26 17:07:02 +00:00
|
|
|
bOk = (nCellVal < rEntry.nVal) && !::rtl::math::approxEqual( nCellVal, rEntry.nVal );
|
2000-09-18 23:16:46 +00:00
|
|
|
break;
|
|
|
|
case SC_GREATER :
|
2003-03-26 17:07:02 +00:00
|
|
|
bOk = (nCellVal > rEntry.nVal) && !::rtl::math::approxEqual( nCellVal, rEntry.nVal );
|
2000-09-18 23:16:46 +00:00
|
|
|
break;
|
|
|
|
case SC_LESS_EQUAL :
|
2003-03-26 17:07:02 +00:00
|
|
|
bOk = (nCellVal < rEntry.nVal) || ::rtl::math::approxEqual( nCellVal, rEntry.nVal );
|
2001-09-05 08:41:51 +00:00
|
|
|
if ( bOk && pbTestEqualCondition )
|
2003-03-26 17:07:02 +00:00
|
|
|
bTestEqual = ::rtl::math::approxEqual( nCellVal, rEntry.nVal );
|
2000-09-18 23:16:46 +00:00
|
|
|
break;
|
|
|
|
case SC_GREATER_EQUAL :
|
2003-03-26 17:07:02 +00:00
|
|
|
bOk = (nCellVal > rEntry.nVal) || ::rtl::math::approxEqual( nCellVal, rEntry.nVal );
|
2001-09-05 08:41:51 +00:00
|
|
|
if ( bOk && pbTestEqualCondition )
|
2003-03-26 17:07:02 +00:00
|
|
|
bTestEqual = ::rtl::math::approxEqual( nCellVal, rEntry.nVal );
|
2000-09-18 23:16:46 +00:00
|
|
|
break;
|
|
|
|
case SC_NOT_EQUAL :
|
2003-03-26 17:07:02 +00:00
|
|
|
bOk = !::rtl::math::approxEqual( nCellVal, rEntry.nVal );
|
2000-09-18 23:16:46 +00:00
|
|
|
break;
|
2007-02-27 11:09:41 +00:00
|
|
|
default:
|
|
|
|
{
|
|
|
|
// added to avoid warnings
|
|
|
|
}
|
2000-09-18 23:16:46 +00:00
|
|
|
}
|
|
|
|
}
|
2004-06-04 09:28:40 +00:00
|
|
|
else if ( (rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL) ||
|
|
|
|
(rEntry.bQueryByString && (pCell ? pCell->HasStringData() :
|
|
|
|
HasStringData(
|
|
|
|
static_cast<SCCOL>(rEntry.nField),
|
|
|
|
nRow))))
|
2000-09-18 23:16:46 +00:00
|
|
|
{ // by String
|
|
|
|
String aCellStr;
|
2001-06-21 11:08:38 +00:00
|
|
|
if ( pCell )
|
|
|
|
{
|
|
|
|
if (pCell->GetCellType() != CELLTYPE_NOTE)
|
|
|
|
{
|
2004-06-04 09:28:40 +00:00
|
|
|
ULONG nFormat = GetNumberFormat( static_cast<SCCOL>(rEntry.nField), nRow );
|
2001-06-21 11:08:38 +00:00
|
|
|
ScCellFormat::GetInputString( pCell, nFormat, aCellStr, *(pDocument->GetFormatTable()) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
2004-06-04 09:28:40 +00:00
|
|
|
GetInputString( static_cast<SCCOL>(rEntry.nField), nRow, aCellStr );
|
2000-09-18 23:16:46 +00:00
|
|
|
|
2001-09-05 08:41:51 +00:00
|
|
|
BOOL bRealRegExp = (rParam.bRegExp && ((rEntry.eOp == SC_EQUAL)
|
|
|
|
|| (rEntry.eOp == SC_NOT_EQUAL)));
|
|
|
|
BOOL bTestRegExp = (pbTestEqualCondition && rParam.bRegExp
|
|
|
|
&& ((rEntry.eOp == SC_LESS_EQUAL)
|
|
|
|
|| (rEntry.eOp == SC_GREATER_EQUAL)));
|
|
|
|
if ( bRealRegExp || bTestRegExp )
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
|
|
|
xub_StrLen nStart = 0;
|
|
|
|
xub_StrLen nEnd = aCellStr.Len();
|
2001-09-05 08:41:51 +00:00
|
|
|
BOOL bMatch = (BOOL) rEntry.GetSearchTextPtr( rParam.bCaseSens )
|
2000-09-18 23:16:46 +00:00
|
|
|
->SearchFrwrd( aCellStr, &nStart, &nEnd );
|
2000-11-20 09:31:47 +00:00
|
|
|
// from 614 on, nEnd is behind the found text
|
2001-09-05 08:41:51 +00:00
|
|
|
if ( bMatch && bMatchWholeCell
|
2000-11-20 09:31:47 +00:00
|
|
|
&& (nStart != 0 || nEnd != aCellStr.Len()) )
|
2001-09-05 08:41:51 +00:00
|
|
|
bMatch = FALSE; // RegExp must match entire cell string
|
|
|
|
if ( bRealRegExp )
|
|
|
|
bOk = ((rEntry.eOp == SC_NOT_EQUAL) ? !bMatch : bMatch);
|
|
|
|
else
|
|
|
|
bTestEqual = bMatch;
|
2000-09-18 23:16:46 +00:00
|
|
|
}
|
2001-09-05 08:41:51 +00:00
|
|
|
if ( !bRealRegExp )
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
|
|
|
if ( rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL )
|
|
|
|
{
|
2004-10-22 06:58:04 +00:00
|
|
|
if ( !rEntry.bQueryByString && rEntry.pStr->Len() == 0 )
|
|
|
|
{
|
|
|
|
// #i18374# When used from functions (match, countif, sumif, vlookup, hlookup, lookup),
|
|
|
|
// the query value is assigned directly, and the string is empty. In that case,
|
|
|
|
// don't find any string (isEqual would find empty string results in formula cells).
|
|
|
|
bOk = FALSE;
|
|
|
|
}
|
|
|
|
else if ( bMatchWholeCell )
|
2001-08-06 09:21:02 +00:00
|
|
|
bOk = pTransliteration->isEqual( aCellStr, *rEntry.pStr );
|
2000-09-18 23:16:46 +00:00
|
|
|
else
|
|
|
|
{
|
2006-04-07 07:25:33 +00:00
|
|
|
::com::sun::star::uno::Sequence< sal_Int32 > xOff;
|
2001-09-05 08:41:51 +00:00
|
|
|
String aCell( pTransliteration->transliterate(
|
|
|
|
aCellStr, ScGlobal::eLnge, 0, aCellStr.Len(),
|
|
|
|
&xOff ) );
|
|
|
|
String aQuer( pTransliteration->transliterate(
|
|
|
|
*rEntry.pStr, ScGlobal::eLnge, 0, rEntry.pStr->Len(),
|
|
|
|
&xOff ) );
|
|
|
|
bOk = (aCell.Search( aQuer ) != STRING_NOTFOUND);
|
2000-09-18 23:16:46 +00:00
|
|
|
}
|
|
|
|
if ( rEntry.eOp == SC_NOT_EQUAL )
|
|
|
|
bOk = !bOk;
|
|
|
|
}
|
|
|
|
else
|
2001-09-05 08:41:51 +00:00
|
|
|
{ // use collator here because data was probably sorted
|
2001-03-14 14:57:39 +00:00
|
|
|
sal_Int32 nCompare = pCollator->compareString(
|
|
|
|
aCellStr, *rEntry.pStr );
|
2000-09-18 23:16:46 +00:00
|
|
|
switch (rEntry.eOp)
|
|
|
|
{
|
|
|
|
case SC_LESS :
|
2001-09-05 08:41:51 +00:00
|
|
|
bOk = (nCompare < 0);
|
2000-09-18 23:16:46 +00:00
|
|
|
break;
|
|
|
|
case SC_GREATER :
|
2001-09-05 08:41:51 +00:00
|
|
|
bOk = (nCompare > 0);
|
2000-09-18 23:16:46 +00:00
|
|
|
break;
|
|
|
|
case SC_LESS_EQUAL :
|
2001-09-05 08:41:51 +00:00
|
|
|
bOk = (nCompare <= 0);
|
|
|
|
if ( bOk && pbTestEqualCondition && !bTestEqual )
|
|
|
|
bTestEqual = (nCompare == 0);
|
2000-09-18 23:16:46 +00:00
|
|
|
break;
|
|
|
|
case SC_GREATER_EQUAL :
|
2001-09-05 08:41:51 +00:00
|
|
|
bOk = (nCompare >= 0);
|
|
|
|
if ( bOk && pbTestEqualCondition && !bTestEqual )
|
|
|
|
bTestEqual = (nCompare == 0);
|
2000-09-18 23:16:46 +00:00
|
|
|
break;
|
2007-02-27 11:09:41 +00:00
|
|
|
default:
|
|
|
|
{
|
|
|
|
// added to avoid warnings
|
|
|
|
}
|
2000-09-18 23:16:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2004-11-15 15:34:51 +00:00
|
|
|
else if (rParam.bMixedComparison)
|
2004-09-08 14:56:02 +00:00
|
|
|
{
|
2004-11-15 15:34:51 +00:00
|
|
|
if (rEntry.bQueryByString &&
|
|
|
|
(rEntry.eOp == SC_LESS || rEntry.eOp == SC_LESS_EQUAL) &&
|
|
|
|
(pCell ? pCell->HasValueData() :
|
|
|
|
HasValueData( static_cast<SCCOL>(rEntry.nField), nRow)))
|
|
|
|
{
|
|
|
|
bOk = TRUE;
|
|
|
|
}
|
|
|
|
else if (!rEntry.bQueryByString &&
|
|
|
|
(rEntry.eOp == SC_GREATER || rEntry.eOp == SC_GREATER_EQUAL) &&
|
|
|
|
(pCell ? pCell->HasStringData() :
|
|
|
|
HasStringData( static_cast<SCCOL>(rEntry.nField), nRow)))
|
|
|
|
{
|
|
|
|
bOk = TRUE;
|
|
|
|
}
|
2004-09-08 14:56:02 +00:00
|
|
|
}
|
2000-09-18 23:16:46 +00:00
|
|
|
|
|
|
|
if (nPos == -1)
|
|
|
|
{
|
|
|
|
nPos++;
|
|
|
|
pPasst[nPos] = bOk;
|
2001-09-05 08:41:51 +00:00
|
|
|
pTest[nPos] = bTestEqual;
|
2000-09-18 23:16:46 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (rEntry.eConnect == SC_AND)
|
2001-09-05 08:41:51 +00:00
|
|
|
{
|
2000-09-18 23:16:46 +00:00
|
|
|
pPasst[nPos] = pPasst[nPos] && bOk;
|
2001-09-05 08:41:51 +00:00
|
|
|
pTest[nPos] = pTest[nPos] && bTestEqual;
|
|
|
|
}
|
2000-09-18 23:16:46 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
nPos++;
|
|
|
|
pPasst[nPos] = bOk;
|
2001-09-05 08:41:51 +00:00
|
|
|
pTest[nPos] = bTestEqual;
|
2000-09-18 23:16:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
2004-06-04 09:28:40 +00:00
|
|
|
for ( long j=1; j <= nPos; j++ )
|
2001-09-05 08:41:51 +00:00
|
|
|
{
|
2004-06-04 09:28:40 +00:00
|
|
|
pPasst[0] = pPasst[0] || pPasst[j];
|
|
|
|
pTest[0] = pTest[0] || pTest[j];
|
2001-09-05 08:41:51 +00:00
|
|
|
}
|
2000-09-18 23:16:46 +00:00
|
|
|
|
|
|
|
BOOL bRet = pPasst[0];
|
|
|
|
if ( pPasst != &aBool[0] )
|
|
|
|
delete [] pPasst;
|
2001-09-05 08:41:51 +00:00
|
|
|
if ( pbTestEqualCondition )
|
|
|
|
*pbTestEqualCondition = pTest[0];
|
|
|
|
if ( pTest != &aTest[0] )
|
|
|
|
delete [] pTest;
|
2000-09-18 23:16:46 +00:00
|
|
|
|
|
|
|
return bRet;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScTable::TopTenQuery( ScQueryParam& rParam )
|
|
|
|
{
|
2001-03-14 14:57:39 +00:00
|
|
|
BOOL bSortCollatorInitialized = FALSE;
|
2004-06-04 09:28:40 +00:00
|
|
|
SCSIZE nEntryCount = rParam.GetEntryCount();
|
|
|
|
SCROW nRow1 = (rParam.bHasHeader ? rParam.nRow1 + 1 : rParam.nRow1);
|
|
|
|
SCSIZE nCount = static_cast<SCSIZE>(rParam.nRow2 - nRow1 + 1);
|
|
|
|
for ( SCSIZE i=0; (i<nEntryCount) && (rParam.GetEntry(i).bDoQuery); i++ )
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
|
|
|
ScQueryEntry& rEntry = rParam.GetEntry(i);
|
|
|
|
switch ( rEntry.eOp )
|
|
|
|
{
|
|
|
|
case SC_TOPVAL:
|
|
|
|
case SC_BOTVAL:
|
|
|
|
case SC_TOPPERC:
|
|
|
|
case SC_BOTPERC:
|
|
|
|
{
|
2004-06-04 09:28:40 +00:00
|
|
|
ScSortParam aLocalSortParam( rParam, static_cast<SCCOL>(rEntry.nField) );
|
2001-06-22 08:34:29 +00:00
|
|
|
aSortParam = aLocalSortParam; // used in CreateSortInfoArray, Compare
|
2001-03-14 14:57:39 +00:00
|
|
|
if ( !bSortCollatorInitialized )
|
|
|
|
{
|
|
|
|
bSortCollatorInitialized = TRUE;
|
|
|
|
InitSortCollator( aLocalSortParam );
|
|
|
|
}
|
2000-09-18 23:16:46 +00:00
|
|
|
ScSortInfoArray* pArray = CreateSortInfoArray( nRow1, rParam.nRow2 );
|
|
|
|
DecoladeRow( pArray, nRow1, rParam.nRow2 );
|
|
|
|
QuickSort( pArray, nRow1, rParam.nRow2 );
|
|
|
|
ScSortInfo** ppInfo = pArray->GetFirstArray();
|
2004-06-04 09:28:40 +00:00
|
|
|
SCSIZE nValidCount = nCount;
|
2000-09-18 23:16:46 +00:00
|
|
|
// keine Note-/Leerzellen zaehlen, sind ans Ende sortiert
|
2006-01-13 15:53:47 +00:00
|
|
|
while ( nValidCount > 0 && ( ppInfo[nValidCount-1]->pCell == NULL ||
|
|
|
|
ppInfo[nValidCount-1]->pCell->GetCellType() == CELLTYPE_NOTE ) )
|
2000-09-18 23:16:46 +00:00
|
|
|
nValidCount--;
|
|
|
|
// keine Strings zaehlen, sind zwischen Value und Leer
|
2004-06-04 09:28:40 +00:00
|
|
|
while ( nValidCount > 0
|
2000-09-18 23:16:46 +00:00
|
|
|
&& ppInfo[nValidCount-1]->pCell->HasStringData() )
|
|
|
|
nValidCount--;
|
2004-06-04 09:28:40 +00:00
|
|
|
if ( nValidCount > 0 )
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
|
|
|
if ( rEntry.bQueryByString )
|
|
|
|
{ // dat wird nix
|
|
|
|
rEntry.bQueryByString = FALSE;
|
|
|
|
rEntry.nVal = 10; // 10 bzw. 10%
|
|
|
|
}
|
2004-06-04 09:28:40 +00:00
|
|
|
SCSIZE nVal = (rEntry.nVal >= 1 ? static_cast<SCSIZE>(rEntry.nVal) : 1);
|
|
|
|
SCSIZE nOffset = 0;
|
2000-09-18 23:16:46 +00:00
|
|
|
switch ( rEntry.eOp )
|
|
|
|
{
|
|
|
|
case SC_TOPVAL:
|
|
|
|
{
|
|
|
|
rEntry.eOp = SC_GREATER_EQUAL;
|
|
|
|
if ( nVal > nValidCount )
|
|
|
|
nVal = nValidCount;
|
|
|
|
nOffset = nValidCount - nVal; // 1 <= nVal <= nValidCount
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SC_BOTVAL:
|
|
|
|
{
|
|
|
|
rEntry.eOp = SC_LESS_EQUAL;
|
|
|
|
if ( nVal > nValidCount )
|
|
|
|
nVal = nValidCount;
|
|
|
|
nOffset = nVal - 1; // 1 <= nVal <= nValidCount
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SC_TOPPERC:
|
|
|
|
{
|
|
|
|
rEntry.eOp = SC_GREATER_EQUAL;
|
|
|
|
if ( nVal > 100 )
|
|
|
|
nVal = 100;
|
2004-06-04 09:28:40 +00:00
|
|
|
nOffset = nValidCount - (nValidCount * nVal / 100);
|
2000-09-18 23:16:46 +00:00
|
|
|
if ( nOffset >= nValidCount )
|
|
|
|
nOffset = nValidCount - 1;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case SC_BOTPERC:
|
|
|
|
{
|
|
|
|
rEntry.eOp = SC_LESS_EQUAL;
|
|
|
|
if ( nVal > 100 )
|
|
|
|
nVal = 100;
|
2004-06-04 09:28:40 +00:00
|
|
|
nOffset = (nValidCount * nVal / 100);
|
2000-09-18 23:16:46 +00:00
|
|
|
if ( nOffset >= nValidCount )
|
|
|
|
nOffset = nValidCount - 1;
|
|
|
|
}
|
|
|
|
break;
|
2007-02-27 11:09:41 +00:00
|
|
|
default:
|
|
|
|
{
|
|
|
|
// added to avoid warnings
|
|
|
|
}
|
2000-09-18 23:16:46 +00:00
|
|
|
}
|
|
|
|
ScBaseCell* pCell = ppInfo[nOffset]->pCell;
|
|
|
|
if ( pCell->HasValueData() )
|
|
|
|
{
|
|
|
|
if ( pCell->GetCellType() == CELLTYPE_VALUE )
|
|
|
|
rEntry.nVal = ((ScValueCell*)pCell)->GetValue();
|
|
|
|
else
|
|
|
|
rEntry.nVal = ((ScFormulaCell*)pCell)->GetValue();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
DBG_ERRORFILE( "TopTenQuery: pCell kein ValueData" );
|
|
|
|
rEntry.eOp = SC_GREATER_EQUAL;
|
|
|
|
rEntry.nVal = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
rEntry.eOp = SC_GREATER_EQUAL;
|
|
|
|
rEntry.bQueryByString = FALSE;
|
|
|
|
rEntry.nVal = 0;
|
|
|
|
}
|
|
|
|
delete pArray;
|
|
|
|
}
|
2007-02-27 11:09:41 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
// added to avoid warnings
|
|
|
|
}
|
2000-09-18 23:16:46 +00:00
|
|
|
}
|
|
|
|
}
|
2001-03-14 14:57:39 +00:00
|
|
|
if ( bSortCollatorInitialized )
|
|
|
|
DestroySortCollator();
|
2000-09-18 23:16:46 +00:00
|
|
|
}
|
|
|
|
|
2004-06-04 09:28:40 +00:00
|
|
|
SCSIZE ScTable::Query(ScQueryParam& rParamOrg, BOOL bKeepSub)
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
|
|
|
StrCollection aStrCollection;
|
|
|
|
StrData* pStrData = NULL;
|
|
|
|
|
|
|
|
BOOL bStarted = FALSE;
|
|
|
|
BOOL bOldResult = TRUE;
|
2004-06-04 09:28:40 +00:00
|
|
|
SCROW nOldStart = 0;
|
|
|
|
SCROW nOldEnd = 0;
|
2000-09-18 23:16:46 +00:00
|
|
|
|
2004-06-04 09:28:40 +00:00
|
|
|
SCSIZE nCount = 0;
|
|
|
|
SCROW nOutRow = 0;
|
|
|
|
SCROW nHeader = rParamOrg.bHasHeader ? 1 : 0;
|
|
|
|
SCSIZE i = 0;
|
2000-09-18 23:16:46 +00:00
|
|
|
|
2004-06-04 09:28:40 +00:00
|
|
|
SCSIZE nEntryCount = rParamOrg.GetEntryCount();
|
2000-09-18 23:16:46 +00:00
|
|
|
|
|
|
|
BOOL* pSpecial = new BOOL[nEntryCount];
|
|
|
|
for (i=0; i<nEntryCount; i++)
|
|
|
|
pSpecial[i] = FALSE;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Dialog liefert die ausgezeichneten Feldwerte "leer"/"nicht leer"
|
|
|
|
* als Konstanten in nVal in Verbindung mit dem Schalter
|
|
|
|
* bQueryByString auf FALSE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
BOOL bTopTen = FALSE;
|
|
|
|
for ( i=0; (i<nEntryCount) && (rParamOrg.GetEntry(i).bDoQuery); i++ )
|
|
|
|
{
|
|
|
|
ScQueryEntry& rEntry = rParamOrg.GetEntry(i);
|
|
|
|
|
|
|
|
if ( rEntry.bQueryByString )
|
|
|
|
{
|
2005-12-14 14:05:24 +00:00
|
|
|
sal_uInt32 nIndex = 0;
|
2000-09-18 23:16:46 +00:00
|
|
|
rEntry.bQueryByString = !(pDocument->GetFormatTable()->
|
|
|
|
IsNumberFormat( *rEntry.pStr, nIndex, rEntry.nVal ));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
double nTemp = rEntry.nVal;
|
|
|
|
if (nTemp == SC_EMPTYFIELDS || nTemp == SC_NONEMPTYFIELDS)
|
|
|
|
pSpecial[i] = TRUE;
|
|
|
|
// #58736# QueryParam mit !bQueryByString kann per Uno oder zweitem
|
|
|
|
// Aufruf per AutoFilter kommen - hier keine Assertion mehr
|
|
|
|
}
|
|
|
|
if ( !bTopTen )
|
|
|
|
{
|
|
|
|
switch ( rEntry.eOp )
|
|
|
|
{
|
|
|
|
case SC_TOPVAL:
|
|
|
|
case SC_BOTVAL:
|
|
|
|
case SC_TOPPERC:
|
|
|
|
case SC_BOTPERC:
|
|
|
|
bTopTen = TRUE;
|
2007-02-27 11:09:41 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
// added to avoid warnings
|
|
|
|
}
|
2000-09-18 23:16:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ScQueryParam* pTopTenParam;
|
|
|
|
if ( bTopTen )
|
|
|
|
{ // original Param erhalten und Kopie anpassen
|
|
|
|
pTopTenParam = new ScQueryParam( rParamOrg );
|
|
|
|
TopTenQuery( *pTopTenParam );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
pTopTenParam = NULL;
|
|
|
|
ScQueryParam& rParam = (bTopTen ? *pTopTenParam : rParamOrg);
|
|
|
|
|
|
|
|
if (!rParam.bInplace)
|
|
|
|
{
|
|
|
|
nOutRow = rParam.nDestRow + nHeader;
|
2004-06-04 09:28:40 +00:00
|
|
|
if (nHeader > 0)
|
2000-09-18 23:16:46 +00:00
|
|
|
CopyData( rParam.nCol1, rParam.nRow1, rParam.nCol2, rParam.nRow1,
|
|
|
|
rParam.nDestCol, rParam.nDestRow, rParam.nDestTab );
|
|
|
|
}
|
|
|
|
|
2004-06-04 09:28:40 +00:00
|
|
|
for (SCROW j=rParam.nRow1 + nHeader; j<=rParam.nRow2; j++)
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
|
|
|
BOOL bResult; // Filterergebnis
|
2004-06-04 09:28:40 +00:00
|
|
|
BOOL bValid = ValidQuery(j, rParam, pSpecial);
|
2000-09-18 23:16:46 +00:00
|
|
|
if (!bValid && bKeepSub) // Subtotals stehenlassen
|
|
|
|
{
|
2004-06-04 09:28:40 +00:00
|
|
|
for (SCCOL nCol=rParam.nCol1; nCol<=rParam.nCol2 && !bValid; nCol++)
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
|
|
|
ScBaseCell* pCell;
|
2004-06-04 09:28:40 +00:00
|
|
|
pCell = GetCell( nCol, j );
|
2000-09-18 23:16:46 +00:00
|
|
|
if ( pCell )
|
|
|
|
if ( pCell->GetCellType() == CELLTYPE_FORMULA )
|
|
|
|
if (((ScFormulaCell*)pCell)->IsSubTotal())
|
|
|
|
if (RefVisible((ScFormulaCell*)pCell))
|
|
|
|
bValid = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (bValid)
|
|
|
|
{
|
|
|
|
if (rParam.bDuplicate)
|
|
|
|
bResult = TRUE;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
String aStr;
|
2004-06-04 09:28:40 +00:00
|
|
|
for (SCCOL k=rParam.nCol1; k <= rParam.nCol2; k++)
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
|
|
|
String aCellStr;
|
2004-06-04 09:28:40 +00:00
|
|
|
GetString(k, j, aCellStr);
|
2000-09-18 23:16:46 +00:00
|
|
|
aStr += aCellStr;
|
|
|
|
aStr += (sal_Unicode)1;
|
|
|
|
}
|
|
|
|
pStrData = new StrData(aStr);
|
|
|
|
|
|
|
|
BOOL bIsUnique = TRUE;
|
|
|
|
if (pStrData)
|
|
|
|
bIsUnique = aStrCollection.Insert(pStrData);
|
|
|
|
if (bIsUnique)
|
|
|
|
bResult = TRUE;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
delete pStrData;
|
|
|
|
bResult = FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
bResult = FALSE;
|
|
|
|
|
|
|
|
if (rParam.bInplace)
|
|
|
|
{
|
|
|
|
if (bResult == bOldResult && bStarted)
|
2004-06-04 09:28:40 +00:00
|
|
|
nOldEnd = j;
|
2000-09-18 23:16:46 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
if (bStarted)
|
|
|
|
DBShowRows(nOldStart,nOldEnd, bOldResult);
|
2004-06-04 09:28:40 +00:00
|
|
|
nOldStart = nOldEnd = j;
|
2000-09-18 23:16:46 +00:00
|
|
|
bOldResult = bResult;
|
|
|
|
}
|
|
|
|
bStarted = TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (bResult)
|
|
|
|
{
|
2004-06-04 09:28:40 +00:00
|
|
|
CopyData( rParam.nCol1,j, rParam.nCol2,j, rParam.nDestCol,nOutRow,rParam.nDestTab );
|
2000-09-18 23:16:46 +00:00
|
|
|
++nOutRow;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (bResult)
|
|
|
|
++nCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rParam.bInplace && bStarted)
|
|
|
|
DBShowRows(nOldStart,nOldEnd, bOldResult);
|
|
|
|
|
|
|
|
delete[] pSpecial;
|
|
|
|
if ( pTopTenParam )
|
|
|
|
delete pTopTenParam;
|
|
|
|
|
|
|
|
return nCount;
|
|
|
|
}
|
|
|
|
|
2004-06-04 09:28:40 +00:00
|
|
|
BOOL ScTable::CreateExcelQuery(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam& rQueryParam)
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
|
|
|
BOOL bValid = TRUE;
|
2004-06-04 09:28:40 +00:00
|
|
|
SCCOL* pFields = new SCCOL[nCol2-nCol1+1];
|
2000-09-18 23:16:46 +00:00
|
|
|
String aCellStr;
|
2004-06-04 09:28:40 +00:00
|
|
|
SCCOL nCol = nCol1;
|
|
|
|
DBG_ASSERT( rQueryParam.nTab != SCTAB_MAX, "rQueryParam.nTab no value, not bad but no good" );
|
|
|
|
SCTAB nDBTab = (rQueryParam.nTab == SCTAB_MAX ? nTab : rQueryParam.nTab);
|
|
|
|
SCROW nDBRow1 = rQueryParam.nRow1;
|
|
|
|
SCCOL nDBCol2 = rQueryParam.nCol2;
|
2000-09-18 23:16:46 +00:00
|
|
|
// Erste Zeile muessen Spaltenkoepfe sein
|
|
|
|
while (bValid && (nCol <= nCol2))
|
|
|
|
{
|
|
|
|
String aQueryStr;
|
|
|
|
GetUpperCellString(nCol, nRow1, aQueryStr);
|
|
|
|
BOOL bFound = FALSE;
|
2004-06-04 09:28:40 +00:00
|
|
|
SCCOL i = rQueryParam.nCol1;
|
2000-09-18 23:16:46 +00:00
|
|
|
while (!bFound && (i <= nDBCol2))
|
|
|
|
{
|
|
|
|
if ( nTab == nDBTab )
|
|
|
|
GetUpperCellString(i, nDBRow1, aCellStr);
|
|
|
|
else
|
|
|
|
pDocument->GetUpperCellString(i, nDBRow1, nDBTab, aCellStr);
|
|
|
|
bFound = (aCellStr == aQueryStr);
|
|
|
|
if (!bFound) i++;
|
|
|
|
}
|
|
|
|
if (bFound)
|
|
|
|
pFields[nCol - nCol1] = i;
|
|
|
|
else
|
|
|
|
bValid = FALSE;
|
|
|
|
nCol++;
|
|
|
|
}
|
|
|
|
if (bValid)
|
|
|
|
{
|
2004-06-04 09:28:40 +00:00
|
|
|
ULONG nVisible = 0;
|
2000-09-18 23:16:46 +00:00
|
|
|
for ( nCol=nCol1; nCol<=nCol2; nCol++ )
|
|
|
|
nVisible += aCol[nCol].VisibleCount( nRow1+1, nRow2 );
|
|
|
|
|
2004-06-04 09:28:40 +00:00
|
|
|
if ( nVisible > SCSIZE_MAX / sizeof(void*) )
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
|
|
|
DBG_ERROR("zu viele Filterkritierien");
|
|
|
|
nVisible = 0;
|
|
|
|
}
|
|
|
|
|
2004-06-04 09:28:40 +00:00
|
|
|
SCSIZE nNewEntries = nVisible;
|
2000-09-18 23:16:46 +00:00
|
|
|
rQueryParam.Resize( nNewEntries );
|
|
|
|
|
2004-06-04 09:28:40 +00:00
|
|
|
SCSIZE nIndex = 0;
|
|
|
|
SCROW nRow = nRow1 + 1;
|
2000-09-18 23:16:46 +00:00
|
|
|
while (nRow <= nRow2)
|
|
|
|
{
|
|
|
|
nCol = nCol1;
|
|
|
|
while (nCol <= nCol2)
|
|
|
|
{
|
2002-01-22 16:47:17 +00:00
|
|
|
GetInputString( nCol, nRow, aCellStr );
|
|
|
|
ScGlobal::pCharClass->toUpper( aCellStr );
|
2000-09-18 23:16:46 +00:00
|
|
|
if (aCellStr.Len() > 0)
|
|
|
|
{
|
|
|
|
if (nIndex < nNewEntries)
|
|
|
|
{
|
|
|
|
rQueryParam.GetEntry(nIndex).nField = pFields[nCol - nCol1];
|
|
|
|
rQueryParam.FillInExcelSyntax(aCellStr, nIndex);
|
|
|
|
nIndex++;
|
|
|
|
if (nIndex < nNewEntries)
|
|
|
|
rQueryParam.GetEntry(nIndex).eConnect = SC_AND;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
bValid = FALSE;
|
|
|
|
}
|
|
|
|
nCol++;
|
|
|
|
}
|
|
|
|
nRow++;
|
|
|
|
if (nIndex < nNewEntries)
|
|
|
|
rQueryParam.GetEntry(nIndex).eConnect = SC_OR;
|
|
|
|
}
|
|
|
|
}
|
2004-09-08 14:56:02 +00:00
|
|
|
delete [] pFields;
|
2000-09-18 23:16:46 +00:00
|
|
|
return bValid;
|
|
|
|
}
|
|
|
|
|
2004-06-04 09:28:40 +00:00
|
|
|
BOOL ScTable::CreateStarQuery(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam& rQueryParam)
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
2006-01-13 15:53:47 +00:00
|
|
|
// A valid StarQuery must be at least 4 columns wide. To be precise it
|
|
|
|
// should be exactly 4 columns ...
|
|
|
|
// Additionally, if this wasn't checked, a formula pointing to a valid 1-3
|
|
|
|
// column Excel style query range immediately left to itself would result
|
|
|
|
// in a circular reference when the field name or operator or value (first
|
|
|
|
// to third query range column) is obtained (#i58354#). Furthermore, if the
|
|
|
|
// range wasn't sufficiently specified data changes wouldn't flag formula
|
|
|
|
// cells for recalculation.
|
|
|
|
if (nCol2 - nCol1 < 3)
|
|
|
|
return FALSE;
|
|
|
|
|
2000-09-18 23:16:46 +00:00
|
|
|
BOOL bValid;
|
|
|
|
BOOL bFound;
|
|
|
|
String aCellStr;
|
2004-06-04 09:28:40 +00:00
|
|
|
SCSIZE nIndex = 0;
|
|
|
|
SCROW nRow = nRow1;
|
|
|
|
DBG_ASSERT( rQueryParam.nTab != SCTAB_MAX, "rQueryParam.nTab no value, not bad but no good" );
|
|
|
|
SCTAB nDBTab = (rQueryParam.nTab == SCTAB_MAX ? nTab : rQueryParam.nTab);
|
|
|
|
SCROW nDBRow1 = rQueryParam.nRow1;
|
|
|
|
SCCOL nDBCol2 = rQueryParam.nCol2;
|
|
|
|
|
|
|
|
SCSIZE nNewEntries = static_cast<SCSIZE>(nRow2-nRow1+1);
|
2000-09-18 23:16:46 +00:00
|
|
|
rQueryParam.Resize( nNewEntries );
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
ScQueryEntry& rEntry = rQueryParam.GetEntry(nIndex);
|
|
|
|
|
|
|
|
bValid = FALSE;
|
|
|
|
// Erste Spalte UND/ODER
|
|
|
|
if (nIndex > 0)
|
|
|
|
{
|
|
|
|
GetUpperCellString(nCol1, nRow, aCellStr);
|
|
|
|
if ( aCellStr == ScGlobal::GetRscString(STR_TABLE_UND) )
|
|
|
|
{
|
|
|
|
rEntry.eConnect = SC_AND;
|
|
|
|
bValid = TRUE;
|
|
|
|
}
|
|
|
|
else if ( aCellStr == ScGlobal::GetRscString(STR_TABLE_ODER) )
|
|
|
|
{
|
|
|
|
rEntry.eConnect = SC_OR;
|
|
|
|
bValid = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Zweite Spalte FeldName
|
|
|
|
if ((nIndex < 1) || bValid)
|
|
|
|
{
|
|
|
|
bFound = FALSE;
|
|
|
|
GetUpperCellString(nCol1 + 1, nRow, aCellStr);
|
2004-06-04 09:28:40 +00:00
|
|
|
for (SCCOL i=rQueryParam.nCol1; (i <= nDBCol2) && (!bFound); i++)
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
|
|
|
String aFieldStr;
|
|
|
|
if ( nTab == nDBTab )
|
|
|
|
GetUpperCellString(i, nDBRow1, aFieldStr);
|
|
|
|
else
|
|
|
|
pDocument->GetUpperCellString(i, nDBRow1, nDBTab, aFieldStr);
|
|
|
|
bFound = (aCellStr == aFieldStr);
|
|
|
|
if (bFound)
|
|
|
|
{
|
|
|
|
rEntry.nField = i;
|
|
|
|
bValid = TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
bValid = FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Dritte Spalte Operator =<>...
|
|
|
|
if (bValid)
|
|
|
|
{
|
|
|
|
bFound = FALSE;
|
|
|
|
GetUpperCellString(nCol1 + 2, nRow, aCellStr);
|
|
|
|
if (aCellStr.GetChar(0) == '<')
|
|
|
|
{
|
|
|
|
if (aCellStr.GetChar(1) == '>')
|
|
|
|
rEntry.eOp = SC_NOT_EQUAL;
|
|
|
|
else if (aCellStr.GetChar(1) == '=')
|
|
|
|
rEntry.eOp = SC_LESS_EQUAL;
|
|
|
|
else
|
|
|
|
rEntry.eOp = SC_LESS;
|
|
|
|
}
|
|
|
|
else if (aCellStr.GetChar(0) == '>')
|
|
|
|
{
|
|
|
|
if (aCellStr.GetChar(1) == '=')
|
|
|
|
rEntry.eOp = SC_GREATER_EQUAL;
|
|
|
|
else
|
|
|
|
rEntry.eOp = SC_GREATER;
|
|
|
|
}
|
|
|
|
else if (aCellStr.GetChar(0) == '=')
|
|
|
|
rEntry.eOp = SC_EQUAL;
|
|
|
|
|
|
|
|
}
|
|
|
|
// Vierte Spalte Wert
|
|
|
|
if (bValid)
|
|
|
|
{
|
|
|
|
GetString(nCol1 + 3, nRow, *rEntry.pStr);
|
|
|
|
rEntry.bDoQuery = TRUE;
|
|
|
|
}
|
|
|
|
nIndex++;
|
|
|
|
nRow++;
|
|
|
|
}
|
|
|
|
while (bValid && (nRow <= nRow2) /* && (nIndex < MAXQUERY) */ );
|
|
|
|
return bValid;
|
|
|
|
}
|
|
|
|
|
2004-06-04 09:28:40 +00:00
|
|
|
BOOL ScTable::CreateQueryParam(SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2, ScQueryParam& rQueryParam)
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
2004-06-04 09:28:40 +00:00
|
|
|
SCSIZE i, nCount;
|
2000-09-18 23:16:46 +00:00
|
|
|
PutInOrder(nCol1, nCol2);
|
|
|
|
PutInOrder(nRow1, nRow2);
|
|
|
|
|
|
|
|
nCount = rQueryParam.GetEntryCount();
|
|
|
|
for (i=0; i < nCount; i++)
|
|
|
|
rQueryParam.GetEntry(i).Clear();
|
|
|
|
|
|
|
|
// Standard QueryTabelle
|
|
|
|
BOOL bValid = CreateStarQuery(nCol1, nRow1, nCol2, nRow2, rQueryParam);
|
|
|
|
// Excel QueryTabelle
|
|
|
|
if (!bValid)
|
|
|
|
bValid = CreateExcelQuery(nCol1, nRow1, nCol2, nRow2, rQueryParam);
|
|
|
|
|
|
|
|
nCount = rQueryParam.GetEntryCount();
|
|
|
|
if (bValid)
|
|
|
|
{
|
|
|
|
// bQueryByString muss gesetzt sein
|
|
|
|
for (i=0; i < nCount; i++)
|
|
|
|
rQueryParam.GetEntry(i).bQueryByString = TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// nix
|
|
|
|
for (i=0; i < nCount; i++)
|
|
|
|
rQueryParam.GetEntry(i).Clear();
|
|
|
|
}
|
|
|
|
return bValid;
|
|
|
|
}
|
|
|
|
|
2007-02-27 11:09:41 +00:00
|
|
|
BOOL ScTable::HasColHeader( SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW /* nEndRow */ )
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
2004-06-04 09:28:40 +00:00
|
|
|
for (SCCOL nCol=nStartCol; nCol<=nEndCol; nCol++)
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
|
|
|
CellType eType = GetCellType( nCol, nStartRow );
|
|
|
|
if (eType != CELLTYPE_STRING && eType != CELLTYPE_EDIT)
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2007-02-27 11:09:41 +00:00
|
|
|
BOOL ScTable::HasRowHeader( SCCOL nStartCol, SCROW nStartRow, SCCOL /* nEndCol */, SCROW nEndRow )
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
2004-06-04 09:28:40 +00:00
|
|
|
for (SCROW nRow=nStartRow; nRow<=nEndRow; nRow++)
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
|
|
|
CellType eType = GetCellType( nStartCol, nRow );
|
|
|
|
if (eType != CELLTYPE_STRING && eType != CELLTYPE_EDIT)
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2004-06-04 09:28:40 +00:00
|
|
|
void ScTable::GetFilterEntries(SCCOL nCol, SCROW nRow1, SCROW nRow2, TypedStrCollection& rStrings)
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
|
|
|
aCol[nCol].GetFilterEntries( nRow1, nRow2, rStrings );
|
|
|
|
}
|
|
|
|
|
2004-06-04 09:28:40 +00:00
|
|
|
BOOL ScTable::GetDataEntries(SCCOL nCol, SCROW nRow, TypedStrCollection& rStrings, BOOL bLimit)
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
|
|
|
return aCol[nCol].GetDataEntries( nRow, rStrings, bLimit );
|
|
|
|
}
|
|
|
|
|
2004-06-04 09:28:40 +00:00
|
|
|
ULONG ScTable::GetCellCount() const
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
2004-06-04 09:28:40 +00:00
|
|
|
ULONG nCellCount = 0;
|
2000-09-18 23:16:46 +00:00
|
|
|
|
2004-06-04 09:28:40 +00:00
|
|
|
for ( SCCOL nCol=0; nCol<=MAXCOL; nCol++ )
|
2000-09-18 23:16:46 +00:00
|
|
|
nCellCount += aCol[nCol].GetCellCount();
|
|
|
|
|
|
|
|
return nCellCount;
|
|
|
|
}
|
|
|
|
|
2004-06-04 09:28:40 +00:00
|
|
|
ULONG ScTable::GetWeightedCount() const
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
2004-06-04 09:28:40 +00:00
|
|
|
ULONG nCellCount = 0;
|
2000-09-18 23:16:46 +00:00
|
|
|
|
2004-06-04 09:28:40 +00:00
|
|
|
for ( SCCOL nCol=0; nCol<=MAXCOL; nCol++ )
|
2000-09-18 23:16:46 +00:00
|
|
|
if ( aCol[nCol].GetCellCount() ) // GetCellCount ist inline
|
|
|
|
nCellCount += aCol[nCol].GetWeightedCount();
|
|
|
|
|
|
|
|
return nCellCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG ScTable::GetCodeCount() const
|
|
|
|
{
|
|
|
|
ULONG nCodeCount = 0;
|
|
|
|
|
2004-06-04 09:28:40 +00:00
|
|
|
for ( SCCOL nCol=0; nCol<=MAXCOL; nCol++ )
|
2000-09-18 23:16:46 +00:00
|
|
|
if ( aCol[nCol].GetCellCount() ) // GetCellCount ist inline
|
|
|
|
nCodeCount += aCol[nCol].GetCodeCount();
|
|
|
|
|
|
|
|
return nCodeCount;
|
|
|
|
}
|
|
|
|
|
2007-01-25 10:05:39 +00:00
|
|
|
sal_Int32 ScTable::GetMaxStringLen( SCCOL nCol, SCROW nRowStart,
|
|
|
|
SCROW nRowEnd, CharSet eCharSet ) const
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
2004-06-04 09:28:40 +00:00
|
|
|
if ( ValidCol(nCol) )
|
2007-01-25 10:05:39 +00:00
|
|
|
return aCol[nCol].GetMaxStringLen( nRowStart, nRowEnd, eCharSet );
|
2000-09-18 23:16:46 +00:00
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-06-04 09:28:40 +00:00
|
|
|
xub_StrLen ScTable::GetMaxNumberStringLen( USHORT& nPrecision, SCCOL nCol,
|
|
|
|
SCROW nRowStart, SCROW nRowEnd ) const
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
2004-06-04 09:28:40 +00:00
|
|
|
if ( ValidCol(nCol) )
|
2000-09-18 23:16:46 +00:00
|
|
|
return aCol[nCol].GetMaxNumberStringLen( nPrecision, nRowStart, nRowEnd );
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScTable::UpdateSelectionFunction( ScFunctionData& rData,
|
2004-06-04 09:28:40 +00:00
|
|
|
SCCOL nStartCol, SCROW nStartRow, SCCOL nEndCol, SCROW nEndRow,
|
2000-09-18 23:16:46 +00:00
|
|
|
const ScMarkData& rMark )
|
|
|
|
{
|
|
|
|
// Cursor neben einer Markierung nicht beruecksichtigen:
|
|
|
|
//! nur noch MarkData uebergeben, Cursorposition ggf. hineinselektieren!!!
|
|
|
|
BOOL bSingle = ( rMark.IsMarked() || !rMark.IsMultiMarked() );
|
|
|
|
|
|
|
|
// Mehrfachselektion:
|
|
|
|
|
2004-06-04 09:28:40 +00:00
|
|
|
SCCOL nCol;
|
2000-09-18 23:16:46 +00:00
|
|
|
if ( rMark.IsMultiMarked() )
|
|
|
|
for (nCol=0; nCol<=MAXCOL && !rData.bError; nCol++)
|
|
|
|
if ( !pColFlags || !( pColFlags[nCol] & CR_HIDDEN ) )
|
|
|
|
aCol[nCol].UpdateSelectionFunction( rMark, rData, pRowFlags,
|
|
|
|
bSingle && ( nCol >= nStartCol && nCol <= nEndCol ),
|
|
|
|
nStartRow, nEndRow );
|
|
|
|
|
|
|
|
// Einfachselektion (oder Cursor) nur wenn nicht negativ (und s.o.):
|
|
|
|
|
|
|
|
if ( bSingle && !rMark.IsMarkNegative() )
|
|
|
|
for (nCol=nStartCol; nCol<=nEndCol && !rData.bError; nCol++)
|
|
|
|
if ( !pColFlags || !( pColFlags[nCol] & CR_HIDDEN ) )
|
|
|
|
aCol[nCol].UpdateAreaFunction( rData, pRowFlags, nStartRow, nEndRow );
|
|
|
|
}
|
|
|
|
|
|
|
|
void ScTable::FindConditionalFormat( ULONG nKey, ScRangeList& rList )
|
|
|
|
{
|
2004-06-04 09:28:40 +00:00
|
|
|
SCROW nStartRow, nEndRow;
|
|
|
|
for (SCCOL nCol=0; nCol<=MAXCOL; nCol++)
|
2000-09-18 23:16:46 +00:00
|
|
|
{
|
2004-06-04 09:28:40 +00:00
|
|
|
ScAttrIterator* pIter = aCol[nCol].CreateAttrIterator( 0, MAXROW );
|
2000-09-18 23:16:46 +00:00
|
|
|
const ScPatternAttr* pPattern = pIter->Next( nStartRow, nEndRow );
|
|
|
|
while (pPattern)
|
|
|
|
{
|
|
|
|
if (((SfxUInt32Item&)pPattern->GetItem(ATTR_CONDITIONAL)).GetValue() == nKey)
|
|
|
|
rList.Join( ScRange(nCol,nStartRow,nTab, nCol,nEndRow,nTab) );
|
|
|
|
pPattern = pIter->Next( nStartRow, nEndRow );
|
|
|
|
}
|
|
|
|
delete pIter;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|