1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: wrong.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sw.hxx"
35 #include <tools/string.hxx>
36 #include <tools/debug.hxx>
38 #include "swtypes.hxx"
39 #include "txttypes.hxx"
41 #include "SwGrammarMarkUp.hxx"
44 /*************************************************************************
45 * SwWrongList::SwWrongList()
46 *************************************************************************/
47 SwWrongList::SwWrongList( WrongListType eType
) :
49 nBeginInvalid(STRING_LEN
), // everything correct... (the invalid area starts beyond the string)
50 nEndInvalid (STRING_LEN
)
55 SwWrongList::~SwWrongList()
60 /*************************************************************************
61 * SwWrongList* SwWrongList::Clone()
62 *************************************************************************/
64 SwWrongList
* SwWrongList::Clone()
66 SwWrongList
* pClone
= new SwWrongList( meType
);
67 pClone
->CopyFrom( *this );
71 /*************************************************************************
72 * void SwWrongList::CopyFrom( const SwWrongList& rCopy )
73 *************************************************************************/
75 void SwWrongList::CopyFrom( const SwWrongList
& rCopy
)
77 maList
= rCopy
.maList
;
78 meType
= rCopy
.meType
;
79 nBeginInvalid
= rCopy
.nBeginInvalid
;
80 nEndInvalid
= rCopy
.nEndInvalid
;
81 for( size_t i
= 0; i
< maList
.size(); ++i
)
83 if( maList
[i
].mpSubList
)
84 maList
[i
].mpSubList
= maList
[i
].mpSubList
->Clone();
88 /*************************************************************************
89 * SwWrongList::ClearList()
90 *************************************************************************/
91 void SwWrongList::ClearList()
93 for ( size_t i
= 0; i
< maList
.size(); ++i
)
95 if (maList
[i
].mpSubList
)
96 delete maList
[i
].mpSubList
;
97 maList
[i
].mpSubList
= NULL
;
102 /*************************************************************************
103 * sal_Bool SwWrongList::InWrongWord() gibt den Anfang und die Laenge des
104 * Wortes zurueck, wenn es als falsch markiert ist.
105 *************************************************************************/
106 sal_Bool
SwWrongList::InWrongWord( xub_StrLen
&rChk
, xub_StrLen
&rLn
) const
108 MSHORT nPos
= GetWrongPos( rChk
);
110 if( nPos
< Count() && ( nWrPos
= Pos( nPos
) ) <= rChk
)
113 if( nWrPos
+ rLn
<= rChk
)
121 /*************************************************************************
122 * sal_Bool SwWrongList::Check() liefert den ersten falschen Bereich
123 *************************************************************************/
124 sal_Bool
SwWrongList::Check( xub_StrLen
&rChk
, xub_StrLen
&rLn
) const
126 MSHORT nPos
= GetWrongPos( rChk
);
130 if( nPos
== Count() )
133 xub_StrLen nEnd
= Len( nPos
);
134 nEnd
= nEnd
+ ( nWrPos
= Pos( nPos
) );
138 if( nPos
== Count() )
143 nEnd
= nEnd
+ ( nWrPos
= Pos( nPos
) );
146 if( nEnd
> rChk
&& nWrPos
< rLn
)
158 /*************************************************************************
159 * xub_StrLen SwWrongList::NextWrong() liefert die naechste Fehlerposition
160 *************************************************************************/
162 xub_StrLen
SwWrongList::NextWrong( xub_StrLen nChk
) const
165 xub_StrLen nPos
= GetWrongPos( nChk
);
169 if( nRet
< nChk
&& nRet
+ Len( nPos
) <= nChk
)
171 if( ++nPos
< Count() )
179 if( nRet
> GetBeginInv() && nChk
< GetEndInv() )
180 nRet
= nChk
> GetBeginInv() ? nChk
: GetBeginInv();
184 /*************************************************************************
185 * MSHORT SwWrongList::GetWrongPos( xub_StrLen nValue )
186 * sucht die erste Position im Array, die groessergleich nValue ist,
187 * dies kann natuerlich auch hinter dem letzten Element sein!
188 *************************************************************************/
190 MSHORT
SwWrongList::GetWrongPos( xub_StrLen nValue
) const
192 MSHORT nOben
= Count(), nMitte
= 0, nUnten
= 0;
196 // For smart tag lists, we may not use a binary search. We return the
197 // position of the first smart tag which coveres nValue
198 if ( 0 != maList
[0].maType
.getLength() || maList
[0].mpSubList
)
200 std::vector
<SwWrongArea
>::const_iterator aIter
= maList
.begin();
201 while ( aIter
!= maList
.end() )
203 const xub_StrLen nSTPos
= (*aIter
).mnPos
;
204 const xub_StrLen nSTLen
= (*aIter
).mnLen
;
205 if ( nSTPos
<= nValue
&& nValue
< nSTPos
+ nSTLen
)
207 else if ( nSTPos
> nValue
)
217 while( nUnten
<= nOben
)
219 nMitte
= nUnten
+ ( nOben
- nUnten
) / 2;
220 xub_StrLen nTmp
= Pos( nMitte
);
226 else if( nTmp
< nValue
)
228 if( nTmp
+ Len( nMitte
) >= nValue
)
235 else if( nMitte
== 0 )
244 // nUnten now points to an index i into the wrong list which
245 // 1. nValue is inside [ Area[i].pos, Area[i].pos + Area[i].len ] (inkl!!!)
246 // 2. nValue < Area[i].pos
251 /*************************************************************************
252 * void SwWrongList::_Invalidate()
253 *************************************************************************/
255 void SwWrongList::_Invalidate( xub_StrLen nBegin
, xub_StrLen nEnd
)
257 if ( nBegin
< GetBeginInv() )
258 nBeginInvalid
= nBegin
;
259 if ( nEnd
> GetEndInv() )
263 void SwWrongList::SetInvalid( xub_StrLen nBegin
, xub_StrLen nEnd
)
265 nBeginInvalid
= nBegin
;
270 /*************************************************************************
271 * SwWrongList::Move( xub_StrLen nPos, long nDiff )
272 * veraendert alle Positionen ab nPos um den angegebenen Wert,
273 * wird nach Einfuegen oder Loeschen von Buchstaben benoetigt.
274 *************************************************************************/
276 void SwWrongList::Move( xub_StrLen nPos
, long nDiff
)
278 MSHORT i
= GetWrongPos( nPos
);
281 xub_StrLen nEnd
= nPos
+ xub_StrLen( -nDiff
);
285 sal_Bool bJump
= sal_False
;
286 while( nLst
< Count() && Pos( nLst
) < nEnd
)
288 if( nLst
> i
&& ( nWrPos
= Pos( nLst
- 1 ) ) <= nPos
)
290 nWrLen
= Len( nLst
- 1 );
291 // calculate new length of word
292 nWrLen
= ( nEnd
> nWrPos
+ nWrLen
) ?
294 static_cast<xub_StrLen
>(nWrLen
+ nDiff
);
297 maList
[--nLst
].mnLen
= nWrLen
;
301 Remove( i
, nLst
- i
);
305 if( STRING_LEN
== GetBeginInv() )
306 SetInvalid( nPos
? nPos
- 1 : nPos
, nPos
+ 1 );
309 ShiftLeft( nBeginInvalid
, nPos
, nEnd
);
310 ShiftLeft( nEndInvalid
, nPos
, nEnd
);
311 _Invalidate( nPos
? nPos
- 1 : nPos
, nPos
+ 1 );
317 xub_StrLen nEnd
= nPos
+ xub_StrLen( nDiff
);
318 if( STRING_LEN
!= GetBeginInv() )
320 if( nBeginInvalid
> nPos
)
321 nBeginInvalid
= nBeginInvalid
+ xub_StrLen( nDiff
);
322 if( nEndInvalid
>= nPos
)
323 nEndInvalid
= nEndInvalid
+ xub_StrLen( nDiff
);
325 // Wenn wir mitten in einem falschen Wort stehen, muss vom Wortanfang
326 // invalidiert werden.
327 if( i
< Count() && nPos
>= ( nWrPos
= Pos( i
) ) )
329 Invalidate( nWrPos
, nEnd
);
330 xub_StrLen nWrLen
= Len( i
) + xub_StrLen( nDiff
);
331 maList
[i
++].mnLen
= nWrLen
;
332 nWrLen
= nWrLen
+ nWrPos
;
333 Invalidate( nWrPos
, nWrLen
);
336 Invalidate( nPos
, nEnd
);
340 const xub_StrLen nTmp
= static_cast<xub_StrLen
>(nDiff
+ maList
[i
].mnPos
);
341 maList
[i
++].mnPos
= nTmp
;
345 /*************************************************************************
348 * For a given range [nPos, nPos + nLen[ and an index nIndex, this function
349 * basically counts the number of SwWrongArea entries starting with nIndex
350 * up to nPos + nLen. All these entries are removed.
351 *************************************************************************/
352 sal_Bool
SwWrongList::Fresh( xub_StrLen
&rStart
, xub_StrLen
&rEnd
, xub_StrLen nPos
,
353 xub_StrLen nLen
, MSHORT nIndex
, xub_StrLen nCursorPos
)
355 // length of word must be greater than 0 and cursor position must be outside the word
356 sal_Bool bRet
= nLen
&& ( nCursorPos
> nPos
+ nLen
|| nCursorPos
< nPos
);
358 xub_StrLen nWrPos
= 0;
359 xub_StrLen nWrEnd
= rEnd
;
360 MSHORT nCnt
= nIndex
;
361 if( nCnt
< Count() && ( nWrPos
= Pos( nIndex
) ) < nPos
)
363 if( rStart
> nWrPos
)
367 while( nCnt
< Count() && ( nWrPos
= Pos( nCnt
) ) < nPos
)
368 nWrEnd
= nWrPos
+ Len( nCnt
++ );
370 if( nCnt
< Count() && nWrPos
== nPos
&& Len( nCnt
) == nLen
)
381 nWrEnd
= nPos
+ nLen
;
387 if( nCnt
< Count() && ( nWrPos
= Pos( nCnt
) ) < nPos
)
389 if( rStart
> nWrPos
)
393 while( nCnt
< Count() && ( nWrPos
= Pos( nCnt
) ) < nPos
)
394 nWrEnd
= nWrPos
+ Len( nCnt
++ );
399 Remove( nIndex
, nCnt
- nIndex
);
404 void SwWrongList::Invalidate( xub_StrLen nBegin
, xub_StrLen nEnd
)
406 if (STRING_LEN
== GetBeginInv())
407 SetInvalid( nBegin
, nEnd
);
409 _Invalidate( nBegin
, nEnd
);
412 sal_Bool
SwWrongList::InvalidateWrong( )
416 xub_StrLen nFirst
= Pos( 0 );
417 xub_StrLen nLast
= Pos( Count() - 1 ) + Len( Count() - 1 );
418 Invalidate( nFirst
, nLast
);
425 SwWrongList
* SwWrongList::SplitList( xub_StrLen nSplitPos
)
427 SwWrongList
*pRet
= NULL
;
431 while( nLst
< Count() && Pos( nLst
) < nSplitPos
)
433 if( nLst
&& ( nWrPos
= Pos( nLst
- 1 ) )
434 + ( nWrLen
= Len( nLst
- 1 ) ) > nSplitPos
)
436 nWrLen
+= nWrPos
- nSplitPos
;
437 maList
[--nLst
].mnPos
= nSplitPos
;
438 maList
[nLst
].mnLen
= nWrLen
;
442 if( WRONGLIST_GRAMMAR
== GetWrongListType() )
443 pRet
= new SwGrammarMarkUp();
445 pRet
= new SwWrongList( GetWrongListType() );
446 pRet
->Insert(0, maList
.begin(), ( nLst
>= maList
.size() ? maList
.end() : maList
.begin() + nLst
) );
447 pRet
->SetInvalid( GetBeginInv(), GetEndInv() );
448 pRet
->_Invalidate( nSplitPos
? nSplitPos
- 1 : nSplitPos
, nSplitPos
);
451 if( STRING_LEN
== GetBeginInv() )
455 ShiftLeft( nBeginInvalid
, 0, nSplitPos
);
456 ShiftLeft( nEndInvalid
, 0, nSplitPos
);
460 while( nLst
< Count() )
462 nWrPos
= maList
[nLst
].mnPos
- nSplitPos
;
463 maList
[nLst
++].mnPos
= nWrPos
;
468 void SwWrongList::JoinList( SwWrongList
* pNext
, xub_StrLen nInsertPos
)
472 DBG_ASSERT( GetWrongListType() == pNext
->GetWrongListType(), "type mismatch with next list" );
476 USHORT nCnt
= Count();
477 pNext
->Move( 0, nInsertPos
);
478 Insert(nCnt
, pNext
->maList
.begin(), pNext
->maList
.end());
480 Invalidate( pNext
->GetBeginInv(), pNext
->GetEndInv() );
481 if( nCnt
&& Count() > nCnt
)
483 xub_StrLen nWrPos
= Pos( nCnt
);
484 xub_StrLen nWrLen
= Len( nCnt
);
487 nWrPos
= nWrPos
+ nInsertPos
;
488 nWrLen
= nWrLen
- nInsertPos
;
489 maList
[nCnt
].mnPos
= nWrPos
;
490 maList
[nCnt
].mnLen
= nWrLen
;
492 if( nWrPos
== Pos( nCnt
- 1 ) + Len( nCnt
- 1 ) )
494 nWrLen
= nWrLen
+ Len( nCnt
- 1 );
495 maList
[nCnt
- 1].mnLen
= nWrLen
;
500 Invalidate( nInsertPos
? nInsertPos
- 1 : nInsertPos
, nInsertPos
+ 1 );
504 void SwWrongList::InsertSubList( xub_StrLen nNewPos
, xub_StrLen nNewLen
, USHORT nWhere
, SwWrongList
* pSubList
)
508 DBG_ASSERT( GetWrongListType() == pSubList
->GetWrongListType(), "type mismatch with sub list" );
510 std::vector
<SwWrongArea
>::iterator i
= maList
.begin();
511 if ( nWhere
>= maList
.size() )
512 i
= maList
.end(); // robust
515 maList
.insert(i
, SwWrongArea( rtl::OUString(), 0, nNewPos
, nNewLen
, pSubList
) );
519 // New functions: Necessary because SwWrongList has been changed to use std::vector
520 void SwWrongList::Insert(USHORT nWhere
, std::vector
<SwWrongArea
>::iterator startPos
, std::vector
<SwWrongArea
>::iterator endPos
)
522 std::vector
<SwWrongArea
>::iterator i
= maList
.begin();
523 if ( nWhere
>= maList
.size() )
524 i
= maList
.end(); // robust
527 maList
.insert(i
, startPos
, endPos
); // insert [startPos, endPos[ before i
529 // ownership of the sublist is passed to maList, therefore we have to set the
530 // pSubList-Pointers to 0
531 while ( startPos
!= endPos
)
533 (*startPos
).mpSubList
= 0;
538 void SwWrongList::Remove(USHORT nIdx
, USHORT nLen
)
540 if ( nIdx
>= maList
.size() ) return;
541 std::vector
<SwWrongArea
>::iterator i1
= maList
.begin();
544 std::vector
<SwWrongArea
>::iterator i2
= i1
;
545 if ( nIdx
+ nLen
>= static_cast<USHORT
>(maList
.size()) )
546 i2
= maList
.end(); // robust
550 std::vector
<SwWrongArea
>::iterator iLoop
= i1
;
551 while ( iLoop
!= i2
)
553 if ( (*iLoop
).mpSubList
)
554 delete (*iLoop
).mpSubList
;
558 #if OSL_DEBUG_LEVEL > 1
559 const int nOldSize
= Count();
563 maList
.erase(i1
, i2
);
565 #if OSL_DEBUG_LEVEL > 1
566 ASSERT( Count() + nLen
== nOldSize
, "SwWrongList::Remove() trouble" )
570 void SwWrongList::RemoveEntry( xub_StrLen nBegin
, xub_StrLen nEnd
) {
573 std::vector
<SwWrongArea
>::iterator aIter
= maList
.begin();
574 while( aIter
!= maList
.end() && (*aIter
).mnPos
< nBegin
)
579 if( WRONGLIST_GRAMMAR
== GetWrongListType() )
581 while( aIter
!= maList
.end() && nBegin
< nEnd
&& nEnd
> (*aIter
).mnPos
)
589 while( aIter
!= maList
.end() && nBegin
== (*aIter
).mnPos
&& nEnd
== (*aIter
).mnPos
+(*aIter
).mnLen
)
596 Remove( nDelPos
, nDel
);
599 bool SwWrongList::LookForEntry( xub_StrLen nBegin
, xub_StrLen nEnd
) {
600 std::vector
<SwWrongArea
>::iterator aIter
= maList
.begin();
601 while( aIter
!= maList
.end() && (*aIter
).mnPos
< nBegin
)
603 if( aIter
!= maList
.end() && nBegin
== (*aIter
).mnPos
&& nEnd
== (*aIter
).mnPos
+(*aIter
).mnLen
)
608 void SwWrongList::Insert( const rtl::OUString
& rType
,
609 com::sun::star::uno::Reference
< com::sun::star::container::XStringKeyMap
> xPropertyBag
,
610 xub_StrLen nNewPos
, xub_StrLen nNewLen
)
612 std::vector
<SwWrongArea
>::iterator aIter
= maList
.begin();
614 while ( aIter
!= maList
.end() )
616 const xub_StrLen nSTPos
= (*aIter
).mnPos
;
618 if ( nNewPos
< nSTPos
)
620 // insert at current position
623 else if ( nNewPos
== nSTPos
)
625 while ( aIter
!= maList
.end() && (*aIter
).mnPos
== nSTPos
)
627 const xub_StrLen nSTLen
= (*aIter
).mnLen
;
629 if ( nNewLen
< nSTLen
)
631 // insert at current position
644 maList
.insert(aIter
, SwWrongArea( rType
, xPropertyBag
, nNewPos
, nNewLen
, 0 ) );