Files
libreoffice/sw/source/core/crsr/findattr.cxx
Stephan Bergmann 7c704c78d3 Removed some unused parameters; added SAL_UNUSED_PARAMETER.
SAL_UNUSED_PARAMETER (expanding to __attribute__ ((unused)) for GCC)
is used to annotate legitimately unused parameters, so that static
analysis tools can tell legitimately unused parameters from truly
unnecessary ones.  To that end, some patches for external modules
are also added, that are only applied when compiling with GCC and
add necessary __attribute__ ((unused)) in headers.
2012-01-21 15:21:16 +01:00

1293 lines
42 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* Copyright 2000, 2010 Oracle and/or its affiliates.
*
* OpenOffice.org - a multi-platform office productivity suite
*
* This file is part of OpenOffice.org.
*
* OpenOffice.org is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 3
* only, as published by the Free Software Foundation.
*
* OpenOffice.org 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 version 3 for more details
* (a copy is included in the LICENSE file that accompanied this code).
*
* You should have received a copy of the GNU Lesser General Public License
* version 3 along with OpenOffice.org. If not, see
* <http://www.openoffice.org/license.html>
* for a copy of the LGPLv3 License.
*
************************************************************************/
#include <com/sun/star/lang/Locale.hpp>
#include <com/sun/star/util/SearchOptions.hpp>
#include <com/sun/star/util/SearchFlags.hpp>
#include <i18npool/mslangid.hxx>
#include <hintids.hxx>
#include <vcl/svapp.hxx>
#include <svl/itemiter.hxx>
#include <svl/whiter.hxx>
#include <editeng/brkitem.hxx>
#include <editeng/colritem.hxx>
#include <editeng/fontitem.hxx>
#include <fmtpdsc.hxx>
#include <txatbase.hxx>
#include <fchrfmt.hxx>
#include <charfmt.hxx>
#include <doc.hxx>
#include <IDocumentUndoRedo.hxx>
#include <swcrsr.hxx>
#include <editsh.hxx>
#include <ndtxt.hxx>
#include <pamtyp.hxx>
#include <swundo.hxx>
#include <crsskip.hxx>
using namespace ::com::sun::star;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::util;
SV_DECL_PTRARR_SORT( SwpFmts, SwFmt*, 0 )
SV_IMPL_PTRARR_SORT( SwpFmts, SwFmt* )
// Sonderbehandlung fuer SvxFontItem, nur den Namen vergleichen:
int CmpAttr( const SfxPoolItem& rItem1, const SfxPoolItem& rItem2 )
{
switch( rItem1.Which() )
{
case RES_CHRATR_FONT:
return ((SvxFontItem&)rItem1).GetFamilyName() ==
((SvxFontItem&)rItem2).GetFamilyName();
case RES_CHRATR_COLOR:
return ((SvxColorItem&)rItem1).GetValue().IsRGBEqual(
((SvxColorItem&)rItem2).GetValue() );
case RES_PAGEDESC:
return ((SwFmtPageDesc&)rItem1).GetNumOffset() ==
((SwFmtPageDesc&)rItem2).GetNumOffset() &&
((SwFmtPageDesc&)rItem1).GetPageDesc() ==
((SwFmtPageDesc&)rItem2).GetPageDesc();
}
return rItem1 == rItem2;
}
const SwTxtAttr* GetFrwrdTxtHint( const SwpHints& rHtsArr, sal_uInt16& rPos,
xub_StrLen nCntntPos )
{
while( rPos < rHtsArr.Count() )
{
const SwTxtAttr *pTxtHt = rHtsArr.GetStart( rPos++ );
// der Start vom Attribut muss innerhalb des Bereiches liegen !!
if( *pTxtHt->GetStart() >= nCntntPos )
return pTxtHt; // gueltiges TextAttribut
}
return 0; // kein gueltiges TextAttribut
}
const SwTxtAttr* GetBkwrdTxtHint( const SwpHints& rHtsArr, sal_uInt16& rPos,
xub_StrLen nCntntPos )
{
while( rPos > 0 )
{
//Hack mit cast fuer das Update
const SwTxtAttr *pTxtHt = rHtsArr.GetStart( --rPos );
// der Start vom Attribut muss innerhalb des Bereiches liegen !!
if( *pTxtHt->GetStart() < nCntntPos )
return pTxtHt; // gueltiges TextAttribut
}
return 0; // kein gueltiges TextAttribut
}
void lcl_SetAttrPam( SwPaM & rPam, xub_StrLen nStart, const xub_StrLen* pEnde,
const sal_Bool bSaveMark )
{
xub_StrLen nCntntPos;
if( bSaveMark )
nCntntPos = rPam.GetMark()->nContent.GetIndex();
else
nCntntPos = rPam.GetPoint()->nContent.GetIndex();
sal_Bool bTstEnde = rPam.GetPoint()->nNode == rPam.GetMark()->nNode;
SwCntntNode* pCNd = rPam.GetCntntNode();
rPam.GetPoint()->nContent.Assign( pCNd, nStart );
rPam.SetMark(); // Point == GetMark
// Point zeigt auf das Ende vom SuchBereich oder Ende vom Attribut
if( pEnde )
{
if( bTstEnde && *pEnde > nCntntPos )
rPam.GetPoint()->nContent = nCntntPos;
else
rPam.GetPoint()->nContent = *pEnde;
}
}
//------------------ Suche nach einem Text Attribut -----------------------
// diese Funktion sucht in einem TextNode nach dem vorgegebenen Attribut.
// Wird es gefunden, dann hat der SwPaM den Bereich der das Attribut
// umspannt, unter Beachtung des Suchbereiches
sal_Bool lcl_Search( const SwTxtNode& rTxtNd, SwPaM& rPam,
const SfxPoolItem& rCmpItem,
SwMoveFn fnMove, sal_Bool bValue )
{
if ( !rTxtNd.HasHints() )
return sal_False;
const SwTxtAttr *pTxtHt = 0;
sal_Bool bForward = fnMove == fnMoveForward;
sal_uInt16 nPos = bForward ? 0 : rTxtNd.GetSwpHints().Count();
xub_StrLen nCntntPos = rPam.GetPoint()->nContent.GetIndex();
while( 0 != ( pTxtHt=(*fnMove->fnGetHint)(rTxtNd.GetSwpHints(),nPos,nCntntPos)))
if( pTxtHt->Which() == rCmpItem.Which() &&
( !bValue || CmpAttr( pTxtHt->GetAttr(), rCmpItem )))
{
lcl_SetAttrPam( rPam, *pTxtHt->GetStart(), pTxtHt->GetEnd(), bForward );
return sal_True;
}
return sal_False;
}
//------------------ Suche nach mehren Text Attributen -------------------
struct _SwSrchChrAttr
{
sal_uInt16 nWhich;
xub_StrLen nStt, nEnd;
_SwSrchChrAttr( const SfxPoolItem& rItem,
xub_StrLen nStart, xub_StrLen nAnyEnd )
: nWhich( rItem.Which() ), nStt( nStart ), nEnd( nAnyEnd )
{}
};
class SwAttrCheckArr
{
_SwSrchChrAttr *pFndArr, *pStackArr;
xub_StrLen nNdStt, nNdEnd;
sal_uInt16 nArrStart, nArrLen;
sal_uInt16 nFound, nStackCnt;
SfxItemSet aCmpSet;
sal_Bool bNoColls;
sal_Bool bForward;
public:
SwAttrCheckArr( const SfxItemSet& rSet, int bForward, int bNoCollections );
~SwAttrCheckArr();
void SetNewSet( const SwTxtNode& rTxtNd, const SwPaM& rPam );
// wieviele Attribute ueberhaupt ??
sal_uInt16 Count() const { return aCmpSet.Count(); }
int Found() const { return nFound == aCmpSet.Count(); }
int CheckStack();
xub_StrLen Start() const;
xub_StrLen End() const;
xub_StrLen GetNdStt() const { return nNdStt; }
xub_StrLen GetNdEnd() const { return nNdEnd; }
int SetAttrFwd( const SwTxtAttr& rAttr );
int SetAttrBwd( const SwTxtAttr& rAttr );
};
SwAttrCheckArr::SwAttrCheckArr( const SfxItemSet& rSet, int bFwd,
int bNoCollections )
: aCmpSet( *rSet.GetPool(), RES_CHRATR_BEGIN, RES_TXTATR_END-1 )
{
aCmpSet.Put( rSet, sal_False );
bNoColls = 0 != bNoCollections;
bForward = 0 != bFwd;
// Bestimmen den Bereich des Fnd/Stack-Arrays (Min/Max)
SfxItemIter aIter( aCmpSet );
nArrStart = aCmpSet.GetWhichByPos( aIter.GetFirstPos() );
nArrLen = aCmpSet.GetWhichByPos( aIter.GetLastPos() ) - nArrStart+1;
char* pFndChar = new char[ nArrLen * sizeof(_SwSrchChrAttr) ];
char* pStackChar = new char[ nArrLen * sizeof(_SwSrchChrAttr) ];
pFndArr = (_SwSrchChrAttr*)pFndChar;
pStackArr = (_SwSrchChrAttr*)pStackChar;
}
SwAttrCheckArr::~SwAttrCheckArr()
{
delete[] (char*)pFndArr;
delete[] (char*)pStackArr;
}
void SwAttrCheckArr::SetNewSet( const SwTxtNode& rTxtNd, const SwPaM& rPam )
{
memset( pFndArr, 0, nArrLen * sizeof(_SwSrchChrAttr) );
memset( pStackArr, 0, nArrLen * sizeof(_SwSrchChrAttr) );
nFound = 0;
nStackCnt = 0;
if( bForward )
{
nNdStt = rPam.GetPoint()->nContent.GetIndex();
nNdEnd = rPam.GetPoint()->nNode == rPam.GetMark()->nNode
? rPam.GetMark()->nContent.GetIndex()
: rTxtNd.GetTxt().Len();
}
else
{
nNdEnd = rPam.GetPoint()->nContent.GetIndex();
nNdStt = rPam.GetPoint()->nNode == rPam.GetMark()->nNode
? rPam.GetMark()->nContent.GetIndex()
: 0;
}
if( bNoColls && !rTxtNd.HasSwAttrSet() )
return ;
const SfxItemSet& rSet = rTxtNd.GetSwAttrSet();
// if( !rSet.Count() )
// return;
SfxItemIter aIter( aCmpSet );
const SfxPoolItem* pItem = aIter.GetCurItem();
const SfxPoolItem* pFndItem;
sal_uInt16 nWhich;
while( sal_True )
{
// nur testen, ob vorhanden ist ?
if( IsInvalidItem( pItem ) )
{
nWhich = aCmpSet.GetWhichByPos( aIter.GetCurPos() );
if( RES_TXTATR_END <= nWhich )
break; // Ende der TextAttribute
if( SFX_ITEM_SET == rSet.GetItemState( nWhich, !bNoColls, &pFndItem )
&& !CmpAttr( *pFndItem, rSet.GetPool()->GetDefaultItem( nWhich ) ))
{
pFndArr[ nWhich - nArrStart ] =
_SwSrchChrAttr( *pFndItem, nNdStt, nNdEnd );
nFound++;
}
}
else
{
if( RES_TXTATR_END <= (nWhich = pItem->Which() ))
break; // Ende der TextAttribute
//JP 27.02.95: wenn nach defaults gesucht wird, dann muss man bis zum Pool
// runter
// if( SFX_ITEM_SET == rSet.GetItemState( nWhich, !bNoColls, &pFndItem )
// && *pFndItem == *pItem )
if( CmpAttr( rSet.Get( nWhich, !bNoColls ), *pItem ) )
{
pFndArr[ nWhich - nArrStart ] =
_SwSrchChrAttr( *pItem, nNdStt, nNdEnd );
nFound++;
}
}
if( aIter.IsAtEnd() )
break;
pItem = aIter.NextItem();
}
}
static bool
lcl_IsAttributeIgnorable(xub_StrLen const nNdStart, xub_StrLen const nNdEnd,
_SwSrchChrAttr const& rTmp)
{
// #i115528#: if there is a paragraph attribute, it has been added by the
// SwAttrCheckArr ctor, and nFound is 1.
// if the paragraph is entirely covered by hints that override the paragraph
// attribute, then this function must find an attribute to decrement nFound!
// so check for an empty search range, let attributes that start/end there
// cover it, and hope for the best...
return ((nNdEnd == nNdStart)
? ((rTmp.nEnd < nNdStart) || (nNdEnd < rTmp.nStt))
: ((rTmp.nEnd <= nNdStart) || (nNdEnd <= rTmp.nStt)));
}
int SwAttrCheckArr::SetAttrFwd( const SwTxtAttr& rAttr )
{
_SwSrchChrAttr aTmp( rAttr.GetAttr(), *rAttr.GetStart(), *rAttr.GetAnyEnd() );
// ignore all attributes not in search range
if (lcl_IsAttributeIgnorable(nNdStt, nNdEnd, aTmp))
{
return Found();
}
const SfxPoolItem* pItem;
// --------------------------------------------------------------
// Hier wird jetzt ausdruecklich auch in Zeichenvorlagen gesucht
// --------------------------------------------------------------
sal_uInt16 nWhch = rAttr.Which();
SfxWhichIter* pIter = NULL;
const SfxPoolItem* pTmpItem = NULL;
const SfxItemSet* pSet = NULL;
if( RES_TXTATR_CHARFMT == nWhch || RES_TXTATR_AUTOFMT == nWhch )
{
if( bNoColls && RES_TXTATR_CHARFMT == nWhch )
return Found();
pTmpItem = NULL;
pSet = CharFmt::GetItemSet( rAttr.GetAttr() );
if ( pSet )
{
pIter = new SfxWhichIter( *pSet );
nWhch = pIter->FirstWhich();
while( nWhch &&
SFX_ITEM_SET != pSet->GetItemState( nWhch, sal_True, &pTmpItem ) )
nWhch = pIter->NextWhich();
if( !nWhch )
pTmpItem = NULL;
}
}
else
pTmpItem = &rAttr.GetAttr();
while( pTmpItem )
{
SfxItemState eState = aCmpSet.GetItemState( nWhch, sal_False, &pItem );
if( SFX_ITEM_DONTCARE == eState || SFX_ITEM_SET == eState )
{
sal_uInt16 n;
_SwSrchChrAttr* pCmp;
// loesche erstmal alle, die bis zu der Start Position schon wieder
// ungueltig sind:
_SwSrchChrAttr* pArrPtr;
if( nFound )
for( pArrPtr = pFndArr, n = 0; n < nArrLen;
++n, ++pArrPtr )
if( pArrPtr->nWhich && pArrPtr->nEnd <= aTmp.nStt )
{
pArrPtr->nWhich = 0; // geloescht
nFound--;
}
// loesche erstmal alle, die bis zu der Start Position schon wieder
// ungueltig sind. Und verschiebe alle die "offen" sind, heisst ueber
// die Start Position ragen, vom Stack in den FndSet
if( nStackCnt )
for( pArrPtr = pStackArr, n=0; n < nArrLen; ++n, ++pArrPtr )
{
if( !pArrPtr->nWhich )
continue;
if( pArrPtr->nEnd <= aTmp.nStt )
{
pArrPtr->nWhich = 0; // geloescht
if( !--nStackCnt )
break;
}
else if( pArrPtr->nStt <= aTmp.nStt )
{
if( ( pCmp = &pFndArr[ n ])->nWhich )
{
if( pCmp->nEnd < pArrPtr->nEnd ) // erweitern
pCmp->nEnd = pArrPtr->nEnd;
}
else
{
*pCmp = *pArrPtr;
nFound++;
}
pArrPtr->nWhich = 0;
if( !--nStackCnt )
break;
}
}
sal_Bool bContinue = sal_False;
if( SFX_ITEM_DONTCARE == eState )
{
// wird Attribut gueltig ?
if( !CmpAttr( aCmpSet.GetPool()->GetDefaultItem( nWhch ),
*pTmpItem ))
{
// suche das Attribut und erweiter es gegebenenfalls
if( !( pCmp = &pFndArr[ nWhch - nArrStart ])->nWhich )
{
*pCmp = aTmp; // nicht gefunden, eintragen
nFound++;
}
else if( pCmp->nEnd < aTmp.nEnd ) // erweitern ?
pCmp->nEnd = aTmp.nEnd;
bContinue = sal_True;
}
}
// wird Attribut gueltig ?
else if( CmpAttr( *pItem, *pTmpItem ) )
{
pFndArr[ nWhch - nArrStart ] = aTmp;
++nFound;
bContinue = sal_True;
}
// tja, dann muss es auf den Stack
if( !bContinue && ( pCmp = &pFndArr[ nWhch - nArrStart ])->nWhich )
{
// vorhanden, auf den Stack. Aber nur wenn es noch grosser ist
if( pCmp->nEnd > aTmp.nEnd )
{
OSL_ENSURE( !pStackArr[ nWhch - nArrStart ].nWhich,
"Stack-Platz ist noch belegt" );
if( aTmp.nStt <= pCmp->nStt )
pCmp->nStt = aTmp.nEnd;
else
pCmp->nEnd = aTmp.nStt;
// ---------
pStackArr[ nWhch - nArrStart ] = *pCmp;
nStackCnt++;
}
pCmp->nWhich = 0;
nFound--;
}
}
if( pIter )
{
nWhch = pIter->NextWhich();
while( nWhch &&
SFX_ITEM_SET != pSet->GetItemState( nWhch, sal_True, &pTmpItem ) )
nWhch = pIter->NextWhich();
if( !nWhch )
break;
}
else
break;
}
return Found();
}
int SwAttrCheckArr::SetAttrBwd( const SwTxtAttr& rAttr )
{
_SwSrchChrAttr aTmp( rAttr.GetAttr(), *rAttr.GetStart(), *rAttr.GetAnyEnd() );
// ignore all attributes not in search range
if (lcl_IsAttributeIgnorable(nNdStt, nNdEnd, aTmp))
{
return Found();
}
const SfxPoolItem* pItem;
// --------------------------------------------------------------
// Hier wird jetzt ausdruecklich auch in Zeichenvorlagen gesucht
// --------------------------------------------------------------
sal_uInt16 nWhch = rAttr.Which();
SfxWhichIter* pIter = NULL;
const SfxPoolItem* pTmpItem = NULL;
const SfxItemSet* pSet = NULL;
if( RES_TXTATR_CHARFMT == nWhch || RES_TXTATR_AUTOFMT == nWhch )
{
if( bNoColls && RES_TXTATR_CHARFMT == nWhch )
return Found();
pSet = CharFmt::GetItemSet( rAttr.GetAttr() );
if ( pSet )
{
pIter = new SfxWhichIter( *pSet );
nWhch = pIter->FirstWhich();
while( nWhch &&
SFX_ITEM_SET != pSet->GetItemState( nWhch, sal_True, &pTmpItem ) )
nWhch = pIter->NextWhich();
if( !nWhch )
pTmpItem = NULL;
}
}
else
pTmpItem = &rAttr.GetAttr();
while( pTmpItem )
{
SfxItemState eState = aCmpSet.GetItemState( nWhch, sal_False, &pItem );
if( SFX_ITEM_DONTCARE == eState || SFX_ITEM_SET == eState )
{
sal_uInt16 n;
_SwSrchChrAttr* pCmp;
// loesche erstmal alle, die bis zu der Start Position schon wieder
// ungueltig sind:
_SwSrchChrAttr* pArrPtr;
if( nFound )
for( pArrPtr = pFndArr, n = 0; n < nArrLen; ++n, ++pArrPtr )
if( pArrPtr->nWhich && pArrPtr->nStt >= aTmp.nEnd )
{
pArrPtr->nWhich = 0; // geloescht
nFound--;
}
// loesche erstmal alle, die bis zu der Start Position schon wieder
// ungueltig sind. Und verschiebe alle die "offen" sind, heisst ueber
// die Start Position ragen, vom Stack in den FndSet
if( nStackCnt )
for( pArrPtr = pStackArr, n = 0; n < nArrLen; ++n, ++pArrPtr )
{
if( !pArrPtr->nWhich )
continue;
if( pArrPtr->nStt >= aTmp.nEnd )
{
pArrPtr->nWhich = 0; // geloescht
if( !--nStackCnt )
break;
}
else if( pArrPtr->nEnd >= aTmp.nEnd )
{
if( ( pCmp = &pFndArr[ n ])->nWhich )
{
if( pCmp->nStt > pArrPtr->nStt ) // erweitern
pCmp->nStt = pArrPtr->nStt;
}
else
{
*pCmp = *pArrPtr;
nFound++;
}
pArrPtr->nWhich = 0;
if( !--nStackCnt )
break;
}
}
sal_Bool bContinue = sal_False;
if( SFX_ITEM_DONTCARE == eState )
{
// wird Attribut gueltig ?
if( !CmpAttr( aCmpSet.GetPool()->GetDefaultItem( nWhch ),
*pTmpItem ) )
{
// suche das Attribut und erweiter es gegebenenfalls
if( !( pCmp = &pFndArr[ nWhch - nArrStart ])->nWhich )
{
*pCmp = aTmp; // nicht gefunden, eintragen
nFound++;
}
else if( pCmp->nStt > aTmp.nStt ) // erweitern ?
pCmp->nStt = aTmp.nStt;
bContinue = sal_True;
}
}
// wird Attribut gueltig ?
else if( CmpAttr( *pItem, *pTmpItem ))
{
pFndArr[ nWhch - nArrStart ] = aTmp;
++nFound;
bContinue = sal_True;
}
// tja, dann muss es auf den Stack
if( !bContinue && ( pCmp = &pFndArr[ nWhch - nArrStart ])->nWhich )
{
// vorhanden, auf den Stack. Aber nur wenn es noch grosser ist
if( pCmp->nStt < aTmp.nStt )
{
OSL_ENSURE( !pStackArr[ nWhch - nArrStart ].nWhich,
"Stack-Platz ist noch belegt" );
if( aTmp.nEnd <= pCmp->nEnd )
pCmp->nEnd = aTmp.nStt;
else
pCmp->nStt = aTmp.nEnd;
// ---------
pStackArr[ nWhch - nArrStart ] = *pCmp;
nStackCnt++;
}
pCmp->nWhich = 0;
nFound--;
}
}
if( pIter )
{
nWhch = pIter->NextWhich();
while( nWhch &&
SFX_ITEM_SET != pSet->GetItemState( nWhch, sal_True, &pTmpItem ) )
nWhch = pIter->NextWhich();
if( !nWhch )
break;
}
else
break;
}
return Found();
}
xub_StrLen SwAttrCheckArr::Start() const
{
xub_StrLen nStart = nNdStt;
_SwSrchChrAttr* pArrPtr = pFndArr;
for( sal_uInt16 n = 0; n < nArrLen; ++n, ++pArrPtr )
if( pArrPtr->nWhich && pArrPtr->nStt > nStart )
nStart = pArrPtr->nStt;
return nStart;
}
xub_StrLen SwAttrCheckArr::End() const
{
_SwSrchChrAttr* pArrPtr = pFndArr;
xub_StrLen nEnd = nNdEnd;
for( sal_uInt16 n = 0; n < nArrLen; ++n, ++pArrPtr )
if( pArrPtr->nWhich && pArrPtr->nEnd < nEnd )
nEnd = pArrPtr->nEnd;
return nEnd;
}
int SwAttrCheckArr::CheckStack()
{
if( !nStackCnt )
return sal_False;
sal_uInt16 n;
xub_StrLen nSttPos = Start(), nEndPos = End();
_SwSrchChrAttr* pArrPtr;
for( pArrPtr = pStackArr, n = 0; n < nArrLen; ++n, ++pArrPtr )
{
if( !pArrPtr->nWhich )
continue;
if( bForward ? pArrPtr->nEnd <= nSttPos : pArrPtr->nStt >= nEndPos )
{
pArrPtr->nWhich = 0; // geloescht
if( !--nStackCnt )
return nFound == aCmpSet.Count();
}
else if( bForward ? pArrPtr->nStt < nEndPos : pArrPtr->nEnd > nSttPos )
{
// alle die "offen" sind, heisst ueber die Start Position ragen,
// im FndSet setzen
OSL_ENSURE( !pFndArr[ n ].nWhich, "Array-Platz ist noch belegt" );
pFndArr[ n ] = *pArrPtr;
pArrPtr->nWhich = 0;
nFound++;
if( !--nStackCnt )
return nFound == aCmpSet.Count();
}
}
return nFound == aCmpSet.Count();
}
int lcl_SearchForward( const SwTxtNode& rTxtNd, SwAttrCheckArr& rCmpArr,
SwPaM& rPam )
{
xub_StrLen nEndPos, nSttPos;
rCmpArr.SetNewSet( rTxtNd, rPam );
if( !rTxtNd.HasHints() )
{
if( !rCmpArr.Found() )
return sal_False;
nEndPos = rCmpArr.GetNdEnd();
lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(), &nEndPos, sal_True );
return sal_True;
}
// dann gehe mal durch das nach "Start" sortierte Array
const SwpHints& rHtArr = rTxtNd.GetSwpHints();
const SwTxtAttr* pAttr;
sal_uInt16 nPos = 0;
// sollte jetzt schon alles vorhanden sein, dann teste, mit welchem
// das wieder beendet wird.
if( rCmpArr.Found() )
{
for( ; nPos < rHtArr.Count(); ++nPos )
if( !rCmpArr.SetAttrFwd( *( pAttr = rHtArr.GetStart( nPos )) ) )
{
if( rCmpArr.GetNdStt() < *pAttr->GetStart() )
{
// dann haben wir unser Ende:
lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(),
pAttr->GetStart(), sal_True );
return sal_True;
}
// ansonsten muessen wir weiter suchen
break;
}
if( nPos == rHtArr.Count() && rCmpArr.Found() )
{
// dann haben wir unseren Bereich
nEndPos = rCmpArr.GetNdEnd();
lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(), &nEndPos, sal_True );
return sal_True;
}
}
for( ; nPos < rHtArr.Count(); ++nPos )
if( rCmpArr.SetAttrFwd( *( pAttr = rHtArr.GetStart( nPos )) ) )
{
// sollten noch mehr auf der gleichen Position anfangen ??
// auch die noch mit testen !!
nSttPos = *pAttr->GetStart();
while( ++nPos < rHtArr.Count() && nSttPos ==
*( pAttr = rHtArr.GetStart( nPos ))->GetStart() &&
rCmpArr.SetAttrFwd( *pAttr ) )
;
if( !rCmpArr.Found() )
continue;
// dann haben wir den Bereich zusammen
if( (nSttPos = rCmpArr.Start()) > (nEndPos = rCmpArr.End()) )
return sal_False;
lcl_SetAttrPam( rPam, nSttPos, &nEndPos, sal_True );
return sal_True;
}
if( !rCmpArr.CheckStack() ||
(nSttPos = rCmpArr.Start()) > (nEndPos = rCmpArr.End()) )
return sal_False;
lcl_SetAttrPam( rPam, nSttPos, &nEndPos, sal_True );
return sal_True;
}
int lcl_SearchBackward( const SwTxtNode& rTxtNd, SwAttrCheckArr& rCmpArr,
SwPaM& rPam )
{
xub_StrLen nEndPos, nSttPos;
rCmpArr.SetNewSet( rTxtNd, rPam );
if( !rTxtNd.HasHints() )
{
if( !rCmpArr.Found() )
return sal_False;
nEndPos = rCmpArr.GetNdEnd();
lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(), &nEndPos, sal_False );
return sal_True;
}
// dann gehe mal durch das nach "Start" sortierte Array
const SwpHints& rHtArr = rTxtNd.GetSwpHints();
const SwTxtAttr* pAttr;
sal_uInt16 nPos = rHtArr.Count();
// sollte jetzt schon alles vorhanden sein, dann teste, mit welchem
// das wieder beendet wird.
if( rCmpArr.Found() )
{
while( nPos )
if( !rCmpArr.SetAttrBwd( *( pAttr = rHtArr.GetEnd( --nPos )) ) )
{
nSttPos = *pAttr->GetAnyEnd();
if( nSttPos < rCmpArr.GetNdEnd() )
{
// dann haben wir unser Ende:
nEndPos = rCmpArr.GetNdEnd();
lcl_SetAttrPam( rPam, nSttPos, &nEndPos, sal_False );
return sal_True;
}
// ansonsten muessen wir weiter suchen
break;
}
if( !nPos && rCmpArr.Found() )
{
// dann haben wir unseren Bereich
nEndPos = rCmpArr.GetNdEnd();
lcl_SetAttrPam( rPam, rCmpArr.GetNdStt(), &nEndPos, sal_False );
return sal_True;
}
}
while( nPos )
if( rCmpArr.SetAttrBwd( *( pAttr = rHtArr.GetEnd( --nPos )) ) )
{
// sollten noch mehr auf der gleichen Position anfangen ??
// auch die noch mit testen !!
if( nPos )
{
nEndPos = *pAttr->GetAnyEnd();
while( --nPos && nEndPos ==
*( pAttr = rHtArr.GetEnd( nPos ))->GetAnyEnd() &&
rCmpArr.SetAttrBwd( *pAttr ) )
;
}
if( !rCmpArr.Found() )
continue;
// dann haben wir den Bereich zusammen
if( (nSttPos = rCmpArr.Start()) > (nEndPos = rCmpArr.End()) )
return sal_False;
lcl_SetAttrPam( rPam, nSttPos, &nEndPos, sal_False );
return sal_True;
}
if( !rCmpArr.CheckStack() ||
(nSttPos = rCmpArr.Start()) > (nEndPos = rCmpArr.End()) )
return sal_False;
lcl_SetAttrPam( rPam, nSttPos, &nEndPos, sal_False );
return sal_True;
}
int lcl_Search( const SwCntntNode& rCNd, const SfxItemSet& rCmpSet, sal_Bool bNoColls )
{
// nur die harte Attributierung suchen ?
if( bNoColls && !rCNd.HasSwAttrSet() )
return sal_False;
const SfxItemSet& rNdSet = rCNd.GetSwAttrSet();
SfxItemIter aIter( rCmpSet );
const SfxPoolItem* pItem = aIter.GetCurItem();
const SfxPoolItem* pNdItem;
sal_uInt16 nWhich;
while( sal_True )
{
// nur testen, ob vorhanden ist ?
if( IsInvalidItem( pItem ))
{
nWhich = rCmpSet.GetWhichByPos( aIter.GetCurPos() );
if( SFX_ITEM_SET != rNdSet.GetItemState( nWhich, !bNoColls, &pNdItem )
|| CmpAttr( *pNdItem, rNdSet.GetPool()->GetDefaultItem( nWhich ) ))
return sal_False;
}
else
{
nWhich = pItem->Which();
if( !CmpAttr( rNdSet.Get( nWhich, !bNoColls ), *pItem ))
return sal_False;
}
if( aIter.IsAtEnd() )
break;
pItem = aIter.NextItem();
}
return sal_True; // wurde gefunden
}
sal_Bool SwPaM::Find( const SfxPoolItem& rAttr, sal_Bool bValue, SwMoveFn fnMove,
const SwPaM *pRegion, sal_Bool bInReadOnly )
{
// stelle fest welches Attribut gesucht wird:
sal_uInt16 nWhich = rAttr.Which();
int bCharAttr = isCHRATR(nWhich) || isTXTATR(nWhich);
SwPaM* pPam = MakeRegion( fnMove, pRegion );
sal_Bool bFound = sal_False;
sal_Bool bFirst = sal_True;
sal_Bool bSrchForward = fnMove == fnMoveForward;
SwCntntNode * pNode;
const SfxPoolItem* pItem;
SwpFmts aFmtArr;
// Wenn am Anfang/Ende, aus dem Node moven
if( bSrchForward
? pPam->GetPoint()->nContent.GetIndex() == pPam->GetCntntNode()->Len()
: !pPam->GetPoint()->nContent.GetIndex() )
{
if( !(*fnMove->fnNds)( &pPam->GetPoint()->nNode, sal_False ))
{
delete pPam;
return sal_False;
}
SwCntntNode *pNd = pPam->GetCntntNode();
xub_StrLen nTmpPos = bSrchForward ? 0 : pNd->Len();
pPam->GetPoint()->nContent.Assign( pNd, nTmpPos );
}
while( 0 != ( pNode = ::GetNode( *pPam, bFirst, fnMove, bInReadOnly ) ) )
{
if( bCharAttr )
{
if( !pNode->IsTxtNode() ) // CharAttr sind nur in TextNodes
continue;
if( ((SwTxtNode*)pNode)->HasHints() &&
lcl_Search( *(SwTxtNode*)pNode, *pPam, rAttr, fnMove, bValue ))
{
// setze auf die Werte vom Attribut
SetMark();
*GetPoint() = *pPam->GetPoint();
*GetMark() = *pPam->GetMark();
bFound = sal_True;
break;
}
else if (isTXTATR(nWhich))
continue; // --> also weiter
}
// keine harte Attributierung, dann pruefe, ob die Vorlage schon
// mal nach dem Attribut befragt wurde
if( !pNode->HasSwAttrSet() )
{
const SwFmt* pTmpFmt = pNode->GetFmtColl();
if( aFmtArr.Count() && aFmtArr.Seek_Entry( pTmpFmt ))
continue; // die Collection wurde schon mal befragt
aFmtArr.Insert( pTmpFmt );
}
if( SFX_ITEM_SET == pNode->GetSwAttrSet().GetItemState( nWhich,
sal_True, &pItem ) && ( !bValue || *pItem == rAttr ) )
{
// FORWARD: Point an das Ende, GetMark zum Anfanf vom Node
// BACKWARD: Point zum Anfang, GetMark an das Ende vom Node
// und immer nach der Logik: inkl. Start, exkl. End !!!
*GetPoint() = *pPam->GetPoint();
SetMark();
pNode->MakeEndIndex( &GetPoint()->nContent );
bFound = sal_True;
break;
}
}
// beim rueckwaerts Suchen noch Point und Mark vertauschen
if( bFound && !bSrchForward )
Exchange();
delete pPam;
return bFound;
}
typedef int (*FnSearchAttr)( const SwTxtNode&, SwAttrCheckArr&, SwPaM& );
sal_Bool SwPaM::Find( const SfxItemSet& rSet, sal_Bool bNoColls, SwMoveFn fnMove,
const SwPaM *pRegion, sal_Bool bInReadOnly, sal_Bool bMoveFirst )
{
SwPaM* pPam = MakeRegion( fnMove, pRegion );
sal_Bool bFound = sal_False;
sal_Bool bFirst = sal_True;
sal_Bool bSrchForward = fnMove == fnMoveForward;
SwCntntNode * pNode;
SwpFmts aFmtArr;
// teste doch mal welche Text/Char-Attribute gesucht werden
SwAttrCheckArr aCmpArr( rSet, bSrchForward, bNoColls );
SfxItemSet aOtherSet( GetDoc()->GetAttrPool(),
RES_PARATR_BEGIN, RES_GRFATR_END-1 );
aOtherSet.Put( rSet, sal_False ); // alle Invalid-Items erhalten!
FnSearchAttr fnSearch = bSrchForward
? (&::lcl_SearchForward)
: (&::lcl_SearchBackward);
// Wenn am Anfang/Ende, aus dem Node moven
// Wenn am Anfang/Ende, aus dem Node moven
if( bMoveFirst &&
( bSrchForward
? pPam->GetPoint()->nContent.GetIndex() == pPam->GetCntntNode()->Len()
: !pPam->GetPoint()->nContent.GetIndex() ) )
{
if( !(*fnMove->fnNds)( &pPam->GetPoint()->nNode, sal_False ))
{
delete pPam;
return sal_False;
}
SwCntntNode *pNd = pPam->GetCntntNode();
xub_StrLen nTmpPos = bSrchForward ? 0 : pNd->Len();
pPam->GetPoint()->nContent.Assign( pNd, nTmpPos );
}
while( 0 != ( pNode = ::GetNode( *pPam, bFirst, fnMove, bInReadOnly ) ) )
{
if( aCmpArr.Count() )
{
if( !pNode->IsTxtNode() ) // CharAttr sind nur in TextNodes
continue;
if( (!aOtherSet.Count() ||
lcl_Search( *pNode, aOtherSet, bNoColls )) &&
(*fnSearch)( *(SwTxtNode*)pNode, aCmpArr, *pPam ))
{
// setze auf die Werte vom Attribut
SetMark();
*GetPoint() = *pPam->GetPoint();
*GetMark() = *pPam->GetMark();
bFound = sal_True;
break;
}
continue; // TextAttribute
}
if( !aOtherSet.Count() )
continue;
// keine harte Attributierung, dann pruefe, ob die Vorlage schon
// mal nach dem Attribut befragt wurde
if( !pNode->HasSwAttrSet() )
{
const SwFmt* pTmpFmt = pNode->GetFmtColl();
if( aFmtArr.Count() && aFmtArr.Seek_Entry( pTmpFmt ))
continue; // die Collection wurde schon mal befragt
aFmtArr.Insert( pTmpFmt );
}
if( lcl_Search( *pNode, aOtherSet, bNoColls ))
{
// FORWARD: Point an das Ende, GetMark zum Anfanf vom Node
// BACKWARD: Point zum Anfang, GetMark an das Ende vom Node
// und immer nach der Logik: inkl. Start, exkl. End !!!
*GetPoint() = *pPam->GetPoint();
SetMark();
pNode->MakeEndIndex( &GetPoint()->nContent );
bFound = sal_True;
break;
}
}
// beim rueckwaerts Suchen noch Point und Mark vertauschen
if( bFound && !bSrchForward )
Exchange();
delete pPam;
return bFound;
}
//------------------ Methoden vom SwCursor ---------------------------
// Parameter fuer das Suchen vom Attributen
struct SwFindParaAttr : public SwFindParas
{
sal_Bool bValue;
const SfxItemSet *pSet, *pReplSet;
const SearchOptions *pSearchOpt;
SwCursor& rCursor;
utl::TextSearch* pSTxt;
SwFindParaAttr( const SfxItemSet& rSet, sal_Bool bNoCollection,
const SearchOptions* pOpt, const SfxItemSet* pRSet,
SwCursor& rCrsr )
: bValue( bNoCollection ), pSet( &rSet ), pReplSet( pRSet ),
pSearchOpt( pOpt ), rCursor( rCrsr ),pSTxt( 0 ) {}
virtual ~SwFindParaAttr() { delete pSTxt; }
virtual int Find( SwPaM* , SwMoveFn , const SwPaM*, sal_Bool bInReadOnly );
virtual int IsReplaceMode() const;
};
int SwFindParaAttr::Find( SwPaM* pCrsr, SwMoveFn fnMove, const SwPaM* pRegion,
sal_Bool bInReadOnly )
{
// String ersetzen ?? (nur wenn Text angegeben oder nicht attributiert
// gesucht wird)
sal_Bool bReplaceTxt = pSearchOpt && ( !pSearchOpt->replaceString.isEmpty() ||
!pSet->Count() );
sal_Bool bReplaceAttr = pReplSet && pReplSet->Count();
sal_Bool bMoveFirst = !bReplaceAttr;
if( bInReadOnly && (bReplaceAttr || bReplaceTxt ))
bInReadOnly = sal_False;
// wir suchen nach Attributen, soll zusaetzlich Text gesucht werden ?
{
SwPaM aRegion( *pRegion->GetMark(), *pRegion->GetPoint() );
SwPaM* pTextRegion = &aRegion;
SwPaM aSrchPam( *pCrsr->GetPoint() );
while( sal_True )
{
if( pSet->Count() ) // gibts ueberhaupt Attributierung?
{
// zuerst die Attributierung
if( !aSrchPam.Find( *pSet, bValue, fnMove, &aRegion, bInReadOnly, bMoveFirst ) )
//JP 17.11.95: was ist mit Attributen in leeren Absaetzen !!
// || *pCrsr->GetMark() == *pCrsr->GetPoint() ) // kein Bereich ??
return FIND_NOT_FOUND;
bMoveFirst = sal_True;
if( !pSearchOpt )
break; // ok, nur Attribute, also gefunden
pTextRegion = &aSrchPam;
}
else if( !pSearchOpt )
return FIND_NOT_FOUND;
// dann darin den Text
if( !pSTxt )
{
SearchOptions aTmp( *pSearchOpt );
// search in selection
aTmp.searchFlag |= (SearchFlags::REG_NOT_BEGINOFLINE |
SearchFlags::REG_NOT_ENDOFLINE);
MsLangId::convertLanguageToLocale( LANGUAGE_SYSTEM, aTmp.Locale );
pSTxt = new utl::TextSearch( aTmp );
}
// todo/mba: searching for attributes in Outliner text?!
sal_Bool bSearchInNotes = sal_False;
// Bug 24665: suche im richtigen Bereich weiter (pTextRegion!)
if( aSrchPam.Find( *pSearchOpt, bSearchInNotes, *pSTxt, fnMove, pTextRegion, bInReadOnly ) &&
*aSrchPam.GetMark() != *aSrchPam.GetPoint() ) // gefunden ?
break; // also raus
else if( !pSet->Count() )
return FIND_NOT_FOUND; // nur Text und nicht gefunden
*aRegion.GetMark() = *aSrchPam.GetPoint();
}
*pCrsr->GetPoint() = *aSrchPam.GetPoint();
pCrsr->SetMark();
*pCrsr->GetMark() = *aSrchPam.GetMark();
}
if( bReplaceTxt )
{
const bool bRegExp(
SearchAlgorithms_REGEXP == pSearchOpt->algorithmType);
SwIndex& rSttCntIdx = pCrsr->Start()->nContent;
xub_StrLen nSttCnt = rSttCntIdx.GetIndex();
// damit die Region auch verschoben wird, in den Shell-Cursr-Ring
// mit aufnehmen !!
Ring *pPrevRing = 0;
if( bRegExp )
{
pPrevRing = pRegion->GetPrev();
((Ring*)pRegion)->MoveRingTo( &rCursor );
}
::std::auto_ptr<String> pRepl( (bRegExp) ?
ReplaceBackReferences( *pSearchOpt, pCrsr ) : 0 );
rCursor.GetDoc()->ReplaceRange( *pCrsr,
(pRepl.get()) ? *pRepl : String(pSearchOpt->replaceString),
bRegExp );
rCursor.SaveTblBoxCntnt( pCrsr->GetPoint() );
if( bRegExp )
{
// und die Region wieder herausnehmen:
Ring *p, *pNext = (Ring*)pRegion;
do {
p = pNext;
pNext = p->GetNext();
p->MoveTo( (Ring*)pRegion );
} while( p != pPrevRing );
}
rSttCntIdx = nSttCnt;
}
if( bReplaceAttr )
{
// --- Ist die Selection noch da ??????
//JP 13.07.95: alle gesuchten Attribute werden, wenn nicht im
// ReplaceSet angegeben, auf Default zurueck gesetzt
if( !pSet->Count() )
{
pCrsr->GetDoc()->InsertItemSet( *pCrsr, *pReplSet, 0 );
}
else
{
SfxItemPool* pPool = pReplSet->GetPool();
SfxItemSet aSet( *pPool, pReplSet->GetRanges() );
SfxItemIter aIter( *pSet );
const SfxPoolItem* pItem = aIter.GetCurItem();
while( sal_True )
{
// alle die nicht gesetzt sind mit Pool-Defaults aufuellen
if( !IsInvalidItem( pItem ) && SFX_ITEM_SET !=
pReplSet->GetItemState( pItem->Which(), sal_False ))
aSet.Put( pPool->GetDefaultItem( pItem->Which() ));
if( aIter.IsAtEnd() )
break;
pItem = aIter.NextItem();
}
aSet.Put( *pReplSet );
pCrsr->GetDoc()->InsertItemSet( *pCrsr, aSet, 0 );
}
return FIND_NO_RING;
}
else
return FIND_FOUND;
}
int SwFindParaAttr::IsReplaceMode() const
{
return ( pSearchOpt && !pSearchOpt->replaceString.isEmpty() ) ||
( pReplSet && pReplSet->Count() );
}
// Suchen nach Attributen
sal_uLong SwCursor::Find( const SfxItemSet& rSet, sal_Bool bNoCollections,
SwDocPositions nStart, SwDocPositions nEnde, sal_Bool& bCancel,
FindRanges eFndRngs,
const SearchOptions* pSearchOpt, const SfxItemSet* pReplSet )
{
// OLE-Benachrichtigung abschalten !!
SwDoc* pDoc = GetDoc();
Link aLnk( pDoc->GetOle2Link() );
pDoc->SetOle2Link( Link() );
sal_Bool bReplace = ( pSearchOpt && ( !pSearchOpt->replaceString.isEmpty() ||
!rSet.Count() ) ) ||
(pReplSet && pReplSet->Count());
bool const bStartUndo = pDoc->GetIDocumentUndoRedo().DoesUndo() && bReplace;
if (bStartUndo)
{
pDoc->GetIDocumentUndoRedo().StartUndo( UNDO_REPLACE, NULL );
}
SwFindParaAttr aSwFindParaAttr( rSet, bNoCollections, pSearchOpt,
pReplSet, *this );
sal_uLong nRet = FindAll(aSwFindParaAttr, nStart, nEnde, eFndRngs, bCancel );
pDoc->SetOle2Link( aLnk );
if( nRet && bReplace )
pDoc->SetModified();
if (bStartUndo)
{
pDoc->GetIDocumentUndoRedo().EndUndo( UNDO_REPLACE, NULL );
}
return nRet;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */