940 lines
30 KiB
C++
940 lines
30 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*
|
|
* This file is part of the LibreOffice project.
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* This file incorporates work covered by the following license notice:
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one or more
|
|
* contributor license agreements. See the NOTICE file distributed
|
|
* with this work for additional information regarding copyright
|
|
* ownership. The ASF licenses this file to you under the Apache
|
|
* License, Version 2.0 (the "License"); you may not use this file
|
|
* except in compliance with the License. You may obtain a copy of
|
|
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
|
|
*/
|
|
|
|
#include <swtypes.hxx>
|
|
|
|
#include <SwGrammarMarkUp.hxx>
|
|
#include <ndtxt.hxx>
|
|
#include <txtfrm.hxx>
|
|
#include <utility>
|
|
|
|
#include <osl/diagnose.h>
|
|
|
|
SwWrongArea::SwWrongArea( OUString aType, WrongListType listType,
|
|
css::uno::Reference< css::container::XStringKeyMap > const & xPropertyBag,
|
|
sal_Int32 nPos,
|
|
sal_Int32 nLen)
|
|
: maType(std::move(aType)), mxPropertyBag(xPropertyBag), mnPos(nPos), mnLen(nLen), mpSubList(nullptr)
|
|
{
|
|
mColor = getWrongAreaColor(listType, xPropertyBag);
|
|
mLineType = getWrongAreaLineType(listType, xPropertyBag);
|
|
}
|
|
|
|
SwWrongArea::SwWrongArea( OUString aType,
|
|
css::uno::Reference< css::container::XStringKeyMap > const & xPropertyBag,
|
|
sal_Int32 nPos,
|
|
sal_Int32 nLen,
|
|
SwWrongList* pSubList)
|
|
: maType(std::move(aType)), mxPropertyBag(xPropertyBag), mnPos(nPos), mnLen(nLen), mpSubList(pSubList), mLineType(WRONGAREA_NONE)
|
|
{
|
|
if (pSubList != nullptr)
|
|
{
|
|
mColor = getWrongAreaColor(pSubList->GetWrongListType(), xPropertyBag);
|
|
mLineType = getWrongAreaLineType(pSubList->GetWrongListType(), xPropertyBag);
|
|
}
|
|
}
|
|
|
|
SwWrongList::SwWrongList( WrongListType eType ) :
|
|
meType (eType),
|
|
mnBeginInvalid(COMPLETE_STRING), // everything correct... (the invalid area starts beyond the string)
|
|
mnEndInvalid (COMPLETE_STRING)
|
|
{
|
|
maList.reserve( 5 );
|
|
}
|
|
|
|
SwWrongList::~SwWrongList()
|
|
{
|
|
ClearList();
|
|
}
|
|
|
|
SwWrongList* SwWrongList::Clone()
|
|
{
|
|
SwWrongList* pClone = new SwWrongList( meType );
|
|
pClone->CopyFrom( *this );
|
|
return pClone;
|
|
}
|
|
|
|
void SwWrongList::CopyFrom( const SwWrongList& rCopy )
|
|
{
|
|
maList = rCopy.maList;
|
|
meType = rCopy.meType;
|
|
mnBeginInvalid = rCopy.mnBeginInvalid;
|
|
mnEndInvalid = rCopy.mnEndInvalid;
|
|
for(SwWrongArea & i : maList)
|
|
{
|
|
if( i.mpSubList )
|
|
i.mpSubList = i.mpSubList->Clone();
|
|
}
|
|
}
|
|
|
|
void SwWrongList::ClearList()
|
|
{
|
|
for (SwWrongArea & i : maList)
|
|
{
|
|
delete i.mpSubList;
|
|
i.mpSubList = nullptr;
|
|
}
|
|
maList.clear();
|
|
}
|
|
|
|
/** If a word is incorrectly selected, this method returns begin and length of it.
|
|
|
|
@param[in,out] rChk starting position of the word to check
|
|
@param[out] rLn length of the word
|
|
|
|
@return <true> if incorrectly selected, <false> otherwise
|
|
*/
|
|
bool SwWrongList::InWrongWord( sal_Int32 &rChk, sal_Int32 &rLn ) const
|
|
{
|
|
const sal_uInt16 nPos = GetWrongPos( rChk );
|
|
if ( nPos >= Count() )
|
|
return false;
|
|
const sal_Int32 nWrPos = Pos( nPos );
|
|
if ( nWrPos <= rChk )
|
|
{
|
|
rLn = Len( nPos );
|
|
if( nWrPos + rLn <= rChk )
|
|
return false;
|
|
rChk = nWrPos;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/** Calculate first incorrectly selected area.
|
|
|
|
@param[in,out] rChk starting position of the word to check
|
|
@param[in,out] rLn length of the word
|
|
|
|
@return <true> if incorrectly selected area was found, <false> otherwise
|
|
*/
|
|
bool SwWrongList::Check( sal_Int32 &rChk, sal_Int32 &rLn ) const
|
|
{
|
|
sal_uInt16 nPos = GetWrongPos( rChk );
|
|
rLn += rChk;
|
|
|
|
if( nPos == Count() )
|
|
return false;
|
|
|
|
sal_Int32 nWrPos = Pos( nPos );
|
|
sal_Int32 nEnd = nWrPos + Len( nPos );
|
|
if( nEnd == rChk )
|
|
{
|
|
++nPos;
|
|
if( nPos == Count() )
|
|
return false;
|
|
|
|
nWrPos = Pos( nPos );
|
|
nEnd = nWrPos + Len( nPos );
|
|
}
|
|
if( nEnd > rChk && nWrPos < rLn )
|
|
{
|
|
if( nWrPos > rChk )
|
|
rChk = nWrPos;
|
|
if( nEnd < rLn )
|
|
rLn = nEnd;
|
|
rLn -= rChk;
|
|
return 0 != rLn;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/** Find next incorrectly selected position.
|
|
|
|
@param[in] rChk starting position of the word to check
|
|
|
|
@return starting position of incorrectly selected area, <COMPLETE_STRING> otherwise
|
|
*/
|
|
sal_Int32 SwWrongList::NextWrong( sal_Int32 nChk ) const
|
|
{
|
|
sal_Int32 nRet = COMPLETE_STRING;
|
|
sal_uInt16 nPos = GetWrongPos( nChk );
|
|
if( nPos < Count() )
|
|
{
|
|
nRet = Pos( nPos );
|
|
if( nRet < nChk && nRet + Len( nPos ) <= nChk )
|
|
{
|
|
if( ++nPos < Count() )
|
|
nRet = Pos( nPos );
|
|
else
|
|
nRet = COMPLETE_STRING;
|
|
}
|
|
}
|
|
if( nRet > GetBeginInv() && nChk < GetEndInv() )
|
|
nRet = std::max(nChk, GetBeginInv());
|
|
return nRet;
|
|
}
|
|
|
|
/** Find the first position that is greater or equal to the given value.
|
|
|
|
@note Resulting position might be behind the last element of the array.
|
|
@param[in] nValue value for comparison
|
|
|
|
@return first position that is greater or equal to the given value
|
|
*/
|
|
sal_uInt16 SwWrongList::GetWrongPos( sal_Int32 nValue ) const
|
|
{
|
|
sal_uInt16 nMax = Count();
|
|
sal_uInt16 nMin = 0;
|
|
|
|
if( nMax > 0 )
|
|
{
|
|
// For smart tag lists, we may not use a binary search. We return the
|
|
// position of the first smart tag which covers nValue
|
|
if ( !maList[0].maType.isEmpty() || maList[0].mpSubList )
|
|
{
|
|
auto aIter = std::find_if(maList.begin(), maList.end(),
|
|
[nValue](const SwWrongArea& rST) {
|
|
return (rST.mnPos <= nValue && nValue < rST.mnPos + rST.mnLen)
|
|
|| (rST.mnPos > nValue);
|
|
});
|
|
return o3tl::narrowing<sal_uInt16>(std::distance(maList.begin(), aIter));
|
|
}
|
|
|
|
--nMax;
|
|
sal_uInt16 nMid = 0;
|
|
while( nMin <= nMax )
|
|
{
|
|
nMid = nMin + ( nMax - nMin ) / 2;
|
|
const sal_Int32 nTmp = Pos( nMid );
|
|
if( nTmp == nValue )
|
|
{
|
|
nMin = nMid;
|
|
break;
|
|
}
|
|
else if( nTmp < nValue )
|
|
{
|
|
if( nTmp + Len( nMid ) >= nValue )
|
|
{
|
|
nMin = nMid;
|
|
break;
|
|
}
|
|
nMin = nMid + 1;
|
|
}
|
|
else if( nMid == 0 )
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
nMax = nMid - 1;
|
|
}
|
|
}
|
|
|
|
// nMin now points to an index i into the wrong list which
|
|
// 1. nValue is inside [ Area[i].pos, Area[i].pos + Area[i].len ] (inclusive!!!)
|
|
// 2. nValue < Area[i].pos
|
|
|
|
return nMin;
|
|
}
|
|
|
|
void SwWrongList::Invalidate_( sal_Int32 nBegin, sal_Int32 nEnd )
|
|
{
|
|
if ( nBegin < GetBeginInv() )
|
|
mnBeginInvalid = nBegin;
|
|
if ( nEnd > GetEndInv() || GetEndInv() == COMPLETE_STRING )
|
|
mnEndInvalid = nEnd;
|
|
}
|
|
|
|
void SwWrongList::SetInvalid( sal_Int32 nBegin, sal_Int32 nEnd )
|
|
{
|
|
mnBeginInvalid = nBegin;
|
|
mnEndInvalid = nEnd;
|
|
}
|
|
|
|
/** Change all values after the given position.
|
|
|
|
Needed after insert/deletion of characters.
|
|
|
|
@param nPos position after that everything should be changed
|
|
@param nDiff amount how much the positions should be moved
|
|
*/
|
|
void SwWrongList::Move( sal_Int32 nPos, sal_Int32 nDiff )
|
|
{
|
|
sal_uInt16 i = GetWrongPos( nPos );
|
|
if( nDiff < 0 )
|
|
{
|
|
const sal_Int32 nEnd = nPos - nDiff;
|
|
sal_uInt16 nLst = i;
|
|
bool bJump = false;
|
|
while( nLst < Count() && Pos( nLst ) < nEnd )
|
|
++nLst;
|
|
if( nLst > i )
|
|
{
|
|
const sal_Int32 nWrPos = Pos( nLst - 1 );
|
|
if ( nWrPos <= nPos )
|
|
{
|
|
sal_Int32 nWrLen = Len( nLst - 1 );
|
|
// calculate new length of word
|
|
nWrLen = ( nEnd > nWrPos + nWrLen ) ?
|
|
nPos - nWrPos :
|
|
nWrLen + nDiff;
|
|
if( nWrLen )
|
|
{
|
|
maList[--nLst].mnLen = nWrLen;
|
|
bJump = true;
|
|
}
|
|
}
|
|
}
|
|
Remove( i, nLst - i );
|
|
|
|
if ( bJump )
|
|
++i;
|
|
if( COMPLETE_STRING == GetBeginInv() )
|
|
SetInvalid( nPos ? nPos - 1 : nPos, nPos + 1 );
|
|
else
|
|
{
|
|
ShiftLeft( mnBeginInvalid, nPos, nEnd );
|
|
if( mnEndInvalid != COMPLETE_STRING )
|
|
ShiftLeft( mnEndInvalid, nPos, nEnd );
|
|
Invalidate_( nPos ? nPos - 1 : nPos, nPos + 1 );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const sal_Int32 nEnd = nPos + nDiff;
|
|
if( COMPLETE_STRING != GetBeginInv() )
|
|
{
|
|
if( mnBeginInvalid > nPos )
|
|
mnBeginInvalid += nDiff;
|
|
if( mnEndInvalid >= nPos && mnEndInvalid != COMPLETE_STRING )
|
|
mnEndInvalid += nDiff;
|
|
}
|
|
// If the pointer is in the middle of a wrong word,
|
|
// invalidation must happen from the beginning of that word.
|
|
if( i < Count() )
|
|
{
|
|
const sal_Int32 nWrPos = Pos( i );
|
|
if (nPos >= nWrPos)
|
|
{
|
|
Invalidate( nWrPos, nEnd );
|
|
const sal_Int32 nWrLen = Len( i ) + nDiff;
|
|
maList[i++].mnLen = nWrLen;
|
|
Invalidate( nWrPos, nWrPos + nWrLen );
|
|
}
|
|
}
|
|
else
|
|
Invalidate( nPos, nEnd );
|
|
}
|
|
while( i < Count() )
|
|
{
|
|
maList[i++].mnPos += nDiff;
|
|
}
|
|
}
|
|
|
|
// TODO: Complete documentation
|
|
/** Remove given range of entries
|
|
|
|
For a given range [nPos, nPos + nLen[ and an index nIndex, this function
|
|
basically counts the number of SwWrongArea entries starting with nIndex
|
|
up to nPos + nLen. All these entries are removed.
|
|
|
|
@param rStart ???
|
|
@param rEnd ???
|
|
@param nPos starting position of the range
|
|
@param nLen length of the range
|
|
@param nIndex index to start lookup at
|
|
@param nCursorPos ???
|
|
|
|
@return <true> if ???
|
|
*/
|
|
auto SwWrongList::Fresh( sal_Int32 &rStart, sal_Int32 &rEnd, sal_Int32 nPos,
|
|
sal_Int32 nLen, sal_uInt16 nIndex, sal_Int32 nCursorPos ) -> FreshState
|
|
{
|
|
// length of word must be greater than 0
|
|
// only report a spelling error if the cursor position is outside the word,
|
|
// so that the user is not annoyed while typing
|
|
FreshState eRet = nLen
|
|
? (nCursorPos > nPos + nLen || nCursorPos < nPos)
|
|
? FreshState::FRESH
|
|
: FreshState::CURSOR
|
|
: FreshState::NOTHING;
|
|
|
|
sal_Int32 nWrPos = 0;
|
|
sal_Int32 nWrEnd = rEnd;
|
|
sal_uInt16 nCnt = nIndex;
|
|
if( nCnt < Count() )
|
|
{
|
|
nWrPos = Pos( nCnt );
|
|
if( nWrPos < nPos && rStart > nWrPos )
|
|
rStart = nWrPos;
|
|
}
|
|
|
|
while( nCnt < Count() )
|
|
{
|
|
nWrPos = Pos( nCnt );
|
|
if ( nWrPos >= nPos )
|
|
break;
|
|
nWrEnd = nWrPos + Len( nCnt++ );
|
|
}
|
|
|
|
if( nCnt < Count() && nWrPos == nPos && Len( nCnt ) == nLen )
|
|
{
|
|
++nCnt;
|
|
eRet = FreshState::FRESH;
|
|
}
|
|
else
|
|
{
|
|
if (FreshState::FRESH == eRet)
|
|
{
|
|
if( rStart > nPos )
|
|
rStart = nPos;
|
|
nWrEnd = nPos + nLen;
|
|
}
|
|
}
|
|
|
|
nPos += nLen;
|
|
|
|
if( nCnt < Count() )
|
|
{
|
|
nWrPos = Pos( nCnt );
|
|
if( nWrPos < nPos && rStart > nWrPos )
|
|
rStart = nWrPos;
|
|
}
|
|
|
|
while( nCnt < Count() )
|
|
{
|
|
nWrPos = Pos( nCnt );
|
|
if ( nWrPos >= nPos )
|
|
break;
|
|
nWrEnd = nWrPos + Len( nCnt++ );
|
|
}
|
|
|
|
if( rEnd < nWrEnd )
|
|
rEnd = nWrEnd;
|
|
|
|
Remove( nIndex, nCnt - nIndex );
|
|
|
|
return eRet;
|
|
}
|
|
|
|
void SwWrongList::Invalidate( sal_Int32 nBegin, sal_Int32 nEnd )
|
|
{
|
|
if (COMPLETE_STRING == GetBeginInv())
|
|
SetInvalid( nBegin, nEnd );
|
|
else
|
|
Invalidate_( nBegin, nEnd );
|
|
}
|
|
|
|
bool SwWrongList::InvalidateWrong( )
|
|
{
|
|
if( Count() )
|
|
{
|
|
const sal_Int32 nFirst = Pos( 0 );
|
|
const sal_Int32 nLast = Pos( Count() - 1 ) + Len( Count() - 1 );
|
|
Invalidate( nFirst, nLast );
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
std::unique_ptr<SwWrongList> SwWrongList::SplitList( sal_Int32 nSplitPos )
|
|
{
|
|
std::unique_ptr<SwWrongList> pRet;
|
|
sal_uInt16 nLst = 0;
|
|
while( nLst < Count() && Pos( nLst ) < nSplitPos )
|
|
++nLst;
|
|
if( nLst )
|
|
{
|
|
sal_Int32 nWrPos = Pos( nLst - 1 );
|
|
sal_Int32 nWrLen = Len( nLst - 1 );
|
|
if ( nWrPos+nWrLen > nSplitPos )
|
|
{
|
|
nWrLen += nWrPos - nSplitPos;
|
|
maList[--nLst].mnPos = nSplitPos;
|
|
maList[nLst].mnLen = nWrLen;
|
|
}
|
|
}
|
|
if( nLst )
|
|
{
|
|
if( WRONGLIST_GRAMMAR == GetWrongListType() )
|
|
pRet.reset(new SwGrammarMarkUp());
|
|
else
|
|
pRet.reset(new SwWrongList( GetWrongListType() ));
|
|
pRet->Insert(0, maList.begin(), ( nLst >= maList.size() ? maList.end() : maList.begin() + nLst ) );
|
|
pRet->SetInvalid( GetBeginInv(), GetEndInv() );
|
|
pRet->Invalidate_( nSplitPos ? nSplitPos - 1 : nSplitPos, nSplitPos );
|
|
Remove( 0, nLst );
|
|
}
|
|
if( COMPLETE_STRING == GetBeginInv() )
|
|
SetInvalid( 0, 1 );
|
|
else
|
|
{
|
|
ShiftLeft( mnBeginInvalid, 0, nSplitPos );
|
|
if( mnEndInvalid != COMPLETE_STRING )
|
|
ShiftLeft( mnEndInvalid, 0, nSplitPos );
|
|
Invalidate_( 0, 1 );
|
|
}
|
|
for (nLst = 0; nLst < Count(); ++nLst )
|
|
{
|
|
maList[nLst].mnPos -= nSplitPos;
|
|
}
|
|
return pRet;
|
|
}
|
|
|
|
void SwWrongList::JoinList( SwWrongList* pNext, sal_Int32 nInsertPos )
|
|
{
|
|
if (pNext)
|
|
{
|
|
OSL_ENSURE( GetWrongListType() == pNext->GetWrongListType(), "type mismatch with next list" );
|
|
|
|
sal_uInt16 nCnt = Count();
|
|
pNext->Move( 0, nInsertPos );
|
|
Insert(nCnt, pNext->maList.begin(), pNext->maList.end());
|
|
|
|
Invalidate( pNext->GetBeginInv(), pNext->GetEndInv() );
|
|
if( nCnt && Count() > nCnt )
|
|
{
|
|
sal_Int32 nWrPos = Pos( nCnt );
|
|
sal_Int32 nWrLen = Len( nCnt );
|
|
if( !nWrPos )
|
|
{
|
|
nWrPos += nInsertPos;
|
|
nWrLen -= nInsertPos;
|
|
maList[nCnt].mnPos = nWrPos;
|
|
maList[nCnt].mnLen = nWrLen;
|
|
}
|
|
if( nWrPos == Pos( nCnt - 1 ) + Len( nCnt - 1 ) )
|
|
{
|
|
nWrLen += Len( nCnt - 1 );
|
|
maList[nCnt - 1].mnLen = nWrLen;
|
|
Remove( nCnt, 1 );
|
|
}
|
|
}
|
|
}
|
|
Invalidate( nInsertPos ? nInsertPos - 1 : nInsertPos, nInsertPos + 1 );
|
|
}
|
|
|
|
void SwWrongList::InsertSubList( sal_Int32 nNewPos, sal_Int32 nNewLen, sal_uInt16 nWhere, SwWrongList* pSubList )
|
|
{
|
|
if (pSubList)
|
|
{
|
|
OSL_ENSURE( GetWrongListType() == pSubList->GetWrongListType(), "type mismatch with sub list" );
|
|
}
|
|
std::vector<SwWrongArea>::iterator i = maList.begin();
|
|
if ( nWhere >= maList.size() )
|
|
i = maList.end(); // robust
|
|
else
|
|
i += nWhere;
|
|
maList.insert(i, SwWrongArea( OUString(), nullptr, nNewPos, nNewLen, pSubList ) );
|
|
}
|
|
|
|
// New functions: Necessary because SwWrongList has been changed to use std::vector
|
|
void SwWrongList::Insert(sal_uInt16 nWhere, std::vector<SwWrongArea>::iterator startPos, std::vector<SwWrongArea>::iterator const & endPos)
|
|
{
|
|
std::vector<SwWrongArea>::iterator i = maList.begin();
|
|
if ( nWhere >= maList.size() )
|
|
i = maList.end(); // robust
|
|
else
|
|
i += nWhere;
|
|
maList.insert(i, startPos, endPos); // insert [startPos, endPos[ before i
|
|
|
|
// ownership of the sublist is passed to maList, therefore we have to set the
|
|
// pSubList-Pointers to 0
|
|
while ( startPos != endPos )
|
|
{
|
|
(*startPos).mpSubList = nullptr;
|
|
++startPos;
|
|
}
|
|
}
|
|
|
|
void SwWrongList::Remove(sal_uInt16 nIdx, sal_uInt16 nLen )
|
|
{
|
|
if ( nIdx >= maList.size() ) return;
|
|
std::vector<SwWrongArea>::iterator i1 = maList.begin();
|
|
i1 += nIdx;
|
|
|
|
std::vector<SwWrongArea>::iterator i2 = i1;
|
|
if ( nIdx + nLen >= o3tl::narrowing<sal_uInt16>(maList.size()) )
|
|
i2 = maList.end(); // robust
|
|
else
|
|
i2 += nLen;
|
|
|
|
std::vector<SwWrongArea>::iterator iLoop = i1;
|
|
while ( iLoop != i2 )
|
|
{
|
|
delete (*iLoop).mpSubList;
|
|
++iLoop;
|
|
}
|
|
|
|
#if OSL_DEBUG_LEVEL > 0
|
|
const int nOldSize = Count();
|
|
#endif
|
|
|
|
maList.erase(i1, i2);
|
|
|
|
#if OSL_DEBUG_LEVEL > 0
|
|
OSL_ENSURE( Count() + nLen == nOldSize, "SwWrongList::Remove() trouble" );
|
|
#endif
|
|
}
|
|
|
|
void SwWrongList::RemoveEntry( sal_Int32 nBegin, sal_Int32 nEnd ) {
|
|
std::vector<SwWrongArea>::const_iterator aEnd(maList.end());
|
|
auto aDelIter = std::find_if(maList.cbegin(), aEnd,
|
|
[nBegin](const SwWrongArea& rST) { return rST.mnPos >= nBegin; });
|
|
auto aIter = aDelIter;
|
|
if( WRONGLIST_GRAMMAR == GetWrongListType() )
|
|
{
|
|
if( nBegin < nEnd )
|
|
{
|
|
aIter = std::find_if(aDelIter, aEnd,
|
|
[nEnd](const SwWrongArea& rST) { return rST.mnPos >= nEnd; });
|
|
}
|
|
}
|
|
else
|
|
{
|
|
aIter = std::find_if(aDelIter, aEnd,
|
|
[nBegin, nEnd](const SwWrongArea& rST) {
|
|
return (rST.mnPos != nBegin) || ((rST.mnPos + rST.mnLen) != nEnd);
|
|
});
|
|
}
|
|
auto nDel = o3tl::narrowing<sal_uInt16>(std::distance(aDelIter, aIter));
|
|
if( nDel )
|
|
{
|
|
auto nDelPos = o3tl::narrowing<sal_uInt16>(std::distance(maList.cbegin(), aDelIter));
|
|
Remove( nDelPos, nDel );
|
|
}
|
|
}
|
|
|
|
bool SwWrongList::LookForEntry( sal_Int32 nBegin, sal_Int32 nEnd ) {
|
|
auto aIter = std::find_if(maList.begin(), maList.end(),
|
|
[nBegin](const SwWrongArea& rST) { return rST.mnPos >= nBegin; });
|
|
return aIter != maList.end()
|
|
&& nBegin == (*aIter).mnPos
|
|
&& nEnd == (*aIter).mnPos + (*aIter).mnLen;
|
|
}
|
|
|
|
void SwWrongList::Insert( const OUString& rType,
|
|
css::uno::Reference< css::container::XStringKeyMap > const & xPropertyBag,
|
|
sal_Int32 nNewPos, sal_Int32 nNewLen )
|
|
{
|
|
auto aIter = std::find_if(maList.begin(), maList.end(),
|
|
[nNewPos](const SwWrongArea& rST) { return nNewPos <= rST.mnPos; });
|
|
if ( aIter != maList.end() && nNewPos == (*aIter).mnPos )
|
|
{
|
|
const sal_Int32 nSTPos = (*aIter).mnPos;
|
|
|
|
aIter = std::find_if(aIter, maList.end(),
|
|
[nSTPos, nNewLen](const SwWrongArea& rST) { return rST.mnPos != nSTPos || nNewLen < rST.mnLen; });
|
|
}
|
|
|
|
maList.insert(aIter, SwWrongArea( rType, meType, xPropertyBag, nNewPos, nNewLen) );
|
|
}
|
|
|
|
namespace sw {
|
|
|
|
WrongListIteratorBase::WrongListIteratorBase(SwTextFrame const& rFrame,
|
|
SwWrongList const* (SwTextNode::*pGetWrongList)() const)
|
|
: m_pGetWrongList(pGetWrongList)
|
|
, m_pMergedPara(rFrame.GetMergedPara())
|
|
, m_CurrentExtent(0)
|
|
, m_CurrentIndex(0)
|
|
, m_pWrongList(m_pMergedPara
|
|
? nullptr
|
|
: (rFrame.GetTextNodeFirst()->*pGetWrongList)())
|
|
{
|
|
}
|
|
|
|
WrongListIteratorBase::WrongListIteratorBase(SwWrongList const& rWrongList)
|
|
: m_pGetWrongList(nullptr)
|
|
, m_pMergedPara(nullptr)
|
|
, m_CurrentExtent(0)
|
|
, m_CurrentIndex(0)
|
|
, m_pWrongList(&rWrongList)
|
|
{
|
|
}
|
|
|
|
WrongListIterator::WrongListIterator(SwTextFrame const& rFrame,
|
|
SwWrongList const* (SwTextNode::*pGetWrongList)() const)
|
|
: WrongListIteratorBase(rFrame, pGetWrongList)
|
|
{
|
|
}
|
|
|
|
WrongListIterator::WrongListIterator(SwWrongList const& rWrongList)
|
|
: WrongListIteratorBase(rWrongList)
|
|
{
|
|
}
|
|
|
|
bool WrongListIterator::Check(TextFrameIndex & rStart, TextFrameIndex & rLen)
|
|
{
|
|
if (m_pMergedPara)
|
|
{
|
|
if (rStart < m_CurrentIndex)
|
|
{ // rewind
|
|
m_CurrentExtent = 0;
|
|
m_CurrentIndex = TextFrameIndex(0);
|
|
}
|
|
while (m_CurrentExtent < m_pMergedPara->extents.size())
|
|
{
|
|
sw::Extent const& rExtent(m_pMergedPara->extents[m_CurrentExtent]);
|
|
if (rStart + rLen <= m_CurrentIndex)
|
|
{
|
|
return false;
|
|
}
|
|
else if (rStart < m_CurrentIndex)
|
|
{
|
|
rLen -= m_CurrentIndex - rStart;
|
|
assert(0 < sal_Int32(rLen));
|
|
rStart = m_CurrentIndex;
|
|
}
|
|
if (m_CurrentIndex <= rStart &&
|
|
rStart < m_CurrentIndex + TextFrameIndex(rExtent.nEnd - rExtent.nStart))
|
|
{
|
|
SwWrongList const*const pWrongList((rExtent.pNode->*m_pGetWrongList)());
|
|
// found the extent containing start - first, call Check
|
|
sal_Int32 nStart(rExtent.nStart + sal_Int32(rStart - m_CurrentIndex)); // (m_CurrentIndex - m_CurrentNodeIndex));
|
|
sal_Int32 nLen;
|
|
if (sal_Int32(rLen) < rExtent.nEnd - nStart)
|
|
{
|
|
nLen = sal_Int32(rLen);
|
|
}
|
|
else
|
|
{
|
|
sal_Int32 nInLen(rLen);
|
|
nLen = rExtent.nEnd - nStart;
|
|
nInLen -= nLen;
|
|
for (size_t i = m_CurrentExtent + 1;
|
|
i < m_pMergedPara->extents.size(); ++i)
|
|
{
|
|
sw::Extent const& rExtentEnd(m_pMergedPara->extents[i]);
|
|
if (rExtentEnd.pNode != rExtent.pNode)
|
|
{
|
|
break;
|
|
}
|
|
// add gap too
|
|
nLen += rExtentEnd.nStart - m_pMergedPara->extents[i-1].nEnd;
|
|
if (nInLen <= rExtentEnd.nEnd - rExtentEnd.nStart)
|
|
{
|
|
nLen += nInLen;
|
|
break;
|
|
}
|
|
nLen += rExtentEnd.nEnd - rExtentEnd.nStart;
|
|
nInLen -= rExtentEnd.nEnd - rExtentEnd.nStart;
|
|
}
|
|
}
|
|
if (pWrongList && pWrongList->Check(nStart, nLen))
|
|
{
|
|
// check if there's overlap with this extent
|
|
if (rExtent.nStart <= nStart && nStart < rExtent.nEnd)
|
|
{
|
|
// yes - now compute end position / length
|
|
sal_Int32 const nEnd(nStart + nLen);
|
|
rStart = m_CurrentIndex + TextFrameIndex(nStart - rExtent.nStart);
|
|
TextFrameIndex const nOrigLen(rLen);
|
|
if (nEnd <= rExtent.nEnd)
|
|
{
|
|
rLen = TextFrameIndex(nEnd - nStart);
|
|
}
|
|
else // have to search other extents for the end...
|
|
{
|
|
rLen = TextFrameIndex(rExtent.nEnd - nStart);
|
|
for (size_t i = m_CurrentExtent + 1;
|
|
i < m_pMergedPara->extents.size(); ++i)
|
|
{
|
|
sw::Extent const& rExtentEnd(m_pMergedPara->extents[i]);
|
|
if (rExtentEnd.pNode != rExtent.pNode
|
|
|| nEnd <= rExtentEnd.nStart)
|
|
{
|
|
break;
|
|
}
|
|
if (nEnd <= rExtentEnd.nEnd)
|
|
{
|
|
rLen += TextFrameIndex(nEnd - rExtentEnd.nStart);
|
|
break;
|
|
}
|
|
rLen += TextFrameIndex(rExtentEnd.nEnd - rExtentEnd.nStart);
|
|
}
|
|
}
|
|
assert(rLen <= nOrigLen); (void) nOrigLen;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
m_CurrentIndex += TextFrameIndex(rExtent.nEnd - rExtent.nStart);
|
|
++m_CurrentExtent;
|
|
}
|
|
return false;
|
|
}
|
|
else if (m_pWrongList)
|
|
{
|
|
sal_Int32 nStart(rStart);
|
|
sal_Int32 nLen(rLen);
|
|
bool const bRet(m_pWrongList->Check(nStart, nLen));
|
|
rStart = TextFrameIndex(nStart);
|
|
rLen = TextFrameIndex(nLen);
|
|
return bRet;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
const SwWrongArea*
|
|
WrongListIterator::GetWrongElement(TextFrameIndex const nStart)
|
|
{
|
|
if (m_pMergedPara)
|
|
{
|
|
if (nStart < m_CurrentIndex)
|
|
{ // rewind
|
|
m_CurrentExtent = 0;
|
|
m_CurrentIndex = TextFrameIndex(0);
|
|
}
|
|
while (m_CurrentExtent < m_pMergedPara->extents.size())
|
|
{
|
|
sw::Extent const& rExtent(m_pMergedPara->extents[m_CurrentExtent]);
|
|
if (m_CurrentIndex <= nStart &&
|
|
nStart <= m_CurrentIndex + TextFrameIndex(rExtent.nEnd - rExtent.nStart))
|
|
{
|
|
// note: the returned object isn't wrapped because fntcache.cxx
|
|
// does not look at its positions, only its formatting props
|
|
SwWrongList const*const pWrongList((rExtent.pNode->*m_pGetWrongList)());
|
|
if (pWrongList)
|
|
{
|
|
sal_Int32 const nNStart(rExtent.nStart + sal_Int32(nStart - m_CurrentIndex)); // (m_CurrentIndex - m_CurrentNodeIndex));
|
|
sal_Int16 const nPos(pWrongList->GetWrongPos(nNStart));
|
|
return pWrongList->GetElement(nPos);
|
|
}
|
|
}
|
|
m_CurrentIndex += TextFrameIndex(rExtent.nEnd - rExtent.nStart);
|
|
++m_CurrentExtent;
|
|
}
|
|
return nullptr;
|
|
}
|
|
else if (m_pWrongList)
|
|
{
|
|
sal_Int16 const nPos(m_pWrongList->GetWrongPos(sal_Int32(nStart)));
|
|
return m_pWrongList->GetElement(nPos);
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
WrongListIteratorCounter::WrongListIteratorCounter(SwTextFrame const& rFrame,
|
|
SwWrongList const* (SwTextNode::*pGetWrongList)() const)
|
|
: WrongListIteratorBase(rFrame, pGetWrongList)
|
|
{
|
|
}
|
|
|
|
WrongListIteratorCounter::WrongListIteratorCounter(SwWrongList const& rWrongList)
|
|
: WrongListIteratorBase(rWrongList)
|
|
{
|
|
}
|
|
|
|
sal_uInt16 WrongListIteratorCounter::GetElementCount()
|
|
{
|
|
if (m_pMergedPara)
|
|
{
|
|
sal_uInt16 nRet(0);
|
|
m_CurrentExtent = 0;
|
|
m_CurrentIndex = TextFrameIndex(0);
|
|
SwNode const* pNode(nullptr);
|
|
sal_uInt16 InCurrentNode(0);
|
|
while (m_CurrentExtent < m_pMergedPara->extents.size())
|
|
{
|
|
sw::Extent const& rExtent(m_pMergedPara->extents[m_CurrentExtent]);
|
|
if (rExtent.pNode != pNode)
|
|
{
|
|
InCurrentNode = 0;
|
|
pNode = rExtent.pNode;
|
|
}
|
|
assert(rExtent.pNode);
|
|
SwWrongList const*const pWrongList((rExtent.pNode->*m_pGetWrongList)());
|
|
for (; pWrongList && InCurrentNode < pWrongList->Count(); ++InCurrentNode)
|
|
{
|
|
SwWrongArea const*const pWrong(pWrongList->GetElement(InCurrentNode));
|
|
TextFrameIndex const nExtentEnd(
|
|
m_CurrentIndex + TextFrameIndex(rExtent.nEnd - rExtent.nStart));
|
|
if (nExtentEnd <= TextFrameIndex(pWrong->mnPos))
|
|
{
|
|
break; // continue outer loop
|
|
}
|
|
if (m_CurrentIndex < TextFrameIndex(pWrong->mnPos + pWrong->mnLen))
|
|
{
|
|
++nRet;
|
|
}
|
|
}
|
|
m_CurrentIndex += TextFrameIndex(rExtent.nEnd - rExtent.nStart);
|
|
++m_CurrentExtent;
|
|
}
|
|
return nRet;
|
|
}
|
|
else if (m_pWrongList)
|
|
{
|
|
return m_pWrongList->Count();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
std::optional<std::pair<TextFrameIndex, TextFrameIndex>>
|
|
WrongListIteratorCounter::GetElementAt(sal_uInt16 nIndex)
|
|
{
|
|
if (m_pMergedPara)
|
|
{
|
|
m_CurrentExtent = 0;
|
|
m_CurrentIndex = TextFrameIndex(0);
|
|
SwNode const* pNode(nullptr);
|
|
sal_uInt16 InCurrentNode(0);
|
|
while (m_CurrentExtent < m_pMergedPara->extents.size())
|
|
{
|
|
sw::Extent const& rExtent(m_pMergedPara->extents[m_CurrentExtent]);
|
|
if (rExtent.pNode != pNode)
|
|
{
|
|
InCurrentNode = 0;
|
|
pNode = rExtent.pNode;
|
|
}
|
|
assert(rExtent.pNode);
|
|
SwWrongList const*const pWrongList((rExtent.pNode->*m_pGetWrongList)());
|
|
for (; pWrongList && InCurrentNode < pWrongList->Count(); ++InCurrentNode)
|
|
{
|
|
SwWrongArea const*const pWrong(pWrongList->GetElement(InCurrentNode));
|
|
TextFrameIndex const nExtentEnd(
|
|
m_CurrentIndex + TextFrameIndex(rExtent.nEnd - rExtent.nStart));
|
|
if (nExtentEnd <= TextFrameIndex(pWrong->mnPos))
|
|
{
|
|
break; // continue outer loop
|
|
}
|
|
if (m_CurrentIndex < TextFrameIndex(pWrong->mnPos + pWrong->mnLen))
|
|
{
|
|
if (nIndex == 0)
|
|
{
|
|
return std::optional<std::pair<TextFrameIndex, TextFrameIndex>>(
|
|
std::pair<TextFrameIndex, TextFrameIndex>(
|
|
m_CurrentIndex - TextFrameIndex(rExtent.nStart -
|
|
std::max(rExtent.nStart, pWrong->mnPos)),
|
|
m_CurrentIndex - TextFrameIndex(rExtent.nStart -
|
|
std::min(pWrong->mnPos + pWrong->mnLen, rExtent.nEnd))));
|
|
}
|
|
--nIndex;
|
|
}
|
|
}
|
|
m_CurrentIndex += TextFrameIndex(rExtent.nEnd - rExtent.nStart);
|
|
++m_CurrentExtent;
|
|
}
|
|
return std::optional<std::pair<TextFrameIndex, TextFrameIndex>>();
|
|
}
|
|
else if (m_pWrongList)
|
|
{
|
|
SwWrongArea const*const pWrong(m_pWrongList->GetElement(nIndex));
|
|
return std::optional<std::pair<TextFrameIndex, TextFrameIndex>>(
|
|
std::pair<TextFrameIndex, TextFrameIndex>(
|
|
TextFrameIndex(pWrong->mnPos),
|
|
TextFrameIndex(pWrong->mnPos + pWrong->mnLen)));
|
|
}
|
|
return std::optional<std::pair<TextFrameIndex, TextFrameIndex>>();
|
|
}
|
|
|
|
} // namespace sw
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|