xref: /aoo41x/main/sw/source/core/text/wrong.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sw.hxx"
30 
31 
32 #include <tools/string.hxx>
33 #include <tools/debug.hxx>
34 #include "errhdl.hxx"
35 #include "swtypes.hxx"
36 #include "txttypes.hxx"
37 
38 #include "SwGrammarMarkUp.hxx"
39 
40 
41 /*************************************************************************
42  * SwWrongList::SwWrongList()
43  *************************************************************************/
44 SwWrongList::SwWrongList( WrongListType eType ) :
45     meType       (eType),
46     nBeginInvalid(STRING_LEN),  // everything correct... (the invalid area starts beyond the string)
47     nEndInvalid  (STRING_LEN)
48 {
49     maList.reserve( 5 );
50 }
51 
52 SwWrongList::~SwWrongList()
53 {
54     ClearList();
55 }
56 
57 /*************************************************************************
58  * SwWrongList* SwWrongList::Clone()
59  *************************************************************************/
60 
61 SwWrongList* SwWrongList::Clone()
62 {
63     SwWrongList* pClone = new SwWrongList( meType );
64     pClone->CopyFrom( *this );
65     return pClone;
66 }
67 
68 /*************************************************************************
69  * void SwWrongList::CopyFrom( const SwWrongList& rCopy )
70  *************************************************************************/
71 
72 void SwWrongList::CopyFrom( const SwWrongList& rCopy )
73 {
74     maList = rCopy.maList;
75     meType = rCopy.meType;
76     nBeginInvalid = rCopy.nBeginInvalid;
77     nEndInvalid = rCopy.nEndInvalid;
78     for( size_t i = 0; i < maList.size(); ++i )
79     {
80         if( maList[i].mpSubList )
81             maList[i].mpSubList = maList[i].mpSubList->Clone();
82     }
83 }
84 
85 /*************************************************************************
86  * SwWrongList::ClearList()
87  *************************************************************************/
88 void SwWrongList::ClearList()
89 {
90     for ( size_t i = 0; i < maList.size(); ++i)
91     {
92         if (maList[i].mpSubList)
93             delete maList[i].mpSubList;
94         maList[i].mpSubList = NULL;
95     }
96     maList.clear();
97 }
98 
99 /*************************************************************************
100  * sal_Bool SwWrongList::InWrongWord() gibt den Anfang und die Laenge des
101  * Wortes zurueck, wenn es als falsch markiert ist.
102  *************************************************************************/
103 sal_Bool SwWrongList::InWrongWord( xub_StrLen &rChk, xub_StrLen &rLn ) const
104 {
105     MSHORT nPos = GetWrongPos( rChk );
106     xub_StrLen nWrPos;
107     if( nPos < Count() && ( nWrPos = Pos( nPos ) ) <= rChk )
108     {
109         rLn = Len( nPos );
110         if( nWrPos + rLn <= rChk )
111 			return sal_False;
112 		rChk = nWrPos;
113 		return sal_True;
114 	}
115 	return sal_False;
116 }
117 
118 /*************************************************************************
119  * sal_Bool SwWrongList::Check() liefert den ersten falschen Bereich
120  *************************************************************************/
121 sal_Bool SwWrongList::Check( xub_StrLen &rChk, xub_StrLen &rLn ) const
122 {
123     MSHORT nPos = GetWrongPos( rChk );
124     rLn = rLn + rChk;
125     xub_StrLen nWrPos;
126 
127     if( nPos == Count() )
128         return sal_False;
129 
130     xub_StrLen nEnd = Len( nPos );
131     nEnd = nEnd + ( nWrPos = Pos( nPos ) );
132 	if( nEnd == rChk )
133 	{
134 		++nPos;
135 		if( nPos == Count()	)
136 			return sal_False;
137 		else
138 		{
139             nEnd = Len( nPos );
140             nEnd = nEnd + ( nWrPos = Pos( nPos ) );
141 		}
142 	}
143 	if( nEnd > rChk && nWrPos < rLn )
144 	{
145 		if( nWrPos > rChk )
146 			rChk = nWrPos;
147 		if( nEnd < rLn )
148 			rLn = nEnd;
149 		rLn = rLn - rChk;
150 		return 0 != rLn;
151 	}
152 	return sal_False;
153 }
154 
155 /*************************************************************************
156  * xub_StrLen SwWrongList::NextWrong() liefert die naechste Fehlerposition
157  *************************************************************************/
158 
159 xub_StrLen SwWrongList::NextWrong( xub_StrLen nChk ) const
160 {
161     xub_StrLen nRet;
162     xub_StrLen nPos = GetWrongPos( nChk );
163     if( nPos < Count() )
164     {
165         nRet = Pos( nPos );
166         if( nRet < nChk && nRet + Len( nPos ) <= nChk )
167         {
168             if( ++nPos < Count() )
169                 nRet = Pos( nPos );
170             else
171                 nRet = STRING_LEN;
172         }
173     }
174     else
175         nRet = STRING_LEN;
176     if( nRet > GetBeginInv() && nChk < GetEndInv() )
177         nRet = nChk > GetBeginInv() ? nChk : GetBeginInv();
178     return nRet;
179 }
180 
181 /*************************************************************************
182  *                 MSHORT SwWrongList::GetWrongPos( xub_StrLen nValue )
183  *  sucht die erste Position im Array, die groessergleich nValue ist,
184  * dies kann natuerlich auch hinter dem letzten Element sein!
185  *************************************************************************/
186 
187 MSHORT SwWrongList::GetWrongPos( xub_StrLen nValue ) const
188 {
189     MSHORT nOben = Count(), nMitte = 0, nUnten = 0;
190 
191     if( nOben > 0 )
192     {
193         // For smart tag lists, we may not use a binary search. We return the
194         // position of the first smart tag which coveres nValue
195         if ( 0 != maList[0].maType.getLength() || maList[0].mpSubList )
196         {
197             std::vector<SwWrongArea>::const_iterator aIter = maList.begin();
198             while ( aIter != maList.end() )
199             {
200                 const xub_StrLen nSTPos = (*aIter).mnPos;
201                 const xub_StrLen nSTLen = (*aIter).mnLen;
202                 if ( nSTPos <= nValue && nValue < nSTPos + nSTLen )
203                     break;
204                 else if ( nSTPos > nValue )
205                     break;
206 
207                 ++aIter;
208                 ++nUnten;
209             }
210             return nUnten;
211         }
212 
213         --nOben;
214         while( nUnten <= nOben )
215         {
216             nMitte = nUnten + ( nOben - nUnten ) / 2;
217             xub_StrLen nTmp = Pos( nMitte );
218             if( nTmp == nValue )
219             {
220                 nUnten = nMitte;
221                 break;
222             }
223             else if( nTmp < nValue )
224             {
225                 if( nTmp + Len( nMitte ) >= nValue )
226                 {
227                     nUnten = nMitte;
228                     break;
229                 }
230                 nUnten = nMitte + 1;
231             }
232             else if( nMitte == 0 )
233             {
234                 break;
235             }
236             else
237                 nOben = nMitte - 1;
238         }
239     }
240 
241     // nUnten now points to an index i into the wrong list which
242     // 1. nValue is inside [ Area[i].pos, Area[i].pos + Area[i].len ] (inkl!!!)
243     // 2. nValue < Area[i].pos
244 
245     return nUnten;
246 }
247 
248 /*************************************************************************
249  *                 void SwWrongList::_Invalidate()
250  *************************************************************************/
251 
252 void SwWrongList::_Invalidate( xub_StrLen nBegin, xub_StrLen nEnd )
253 {
254     if ( nBegin < GetBeginInv() )
255         nBeginInvalid = nBegin;
256     if ( nEnd > GetEndInv() )
257         nEndInvalid = nEnd;
258 }
259 
260 void SwWrongList::SetInvalid( xub_StrLen nBegin, xub_StrLen nEnd )
261 {
262     nBeginInvalid = nBegin;
263     nEndInvalid = nEnd;
264 }
265 
266 
267 /*************************************************************************
268  *                      SwWrongList::Move( xub_StrLen nPos, long nDiff )
269  *  veraendert alle Positionen ab nPos um den angegebenen Wert,
270  *  wird nach Einfuegen oder Loeschen von Buchstaben benoetigt.
271  *************************************************************************/
272 
273 void SwWrongList::Move( xub_StrLen nPos, long nDiff )
274 {
275     MSHORT i = GetWrongPos( nPos );
276     if( nDiff < 0 )
277     {
278         xub_StrLen nEnd = nPos + xub_StrLen( -nDiff );
279         MSHORT nLst = i;
280         xub_StrLen nWrPos;
281         xub_StrLen nWrLen;
282         sal_Bool bJump = sal_False;
283         while( nLst < Count() && Pos( nLst ) < nEnd )
284             ++nLst;
285         if( nLst > i && ( nWrPos = Pos( nLst - 1 ) ) <= nPos )
286         {
287             nWrLen = Len( nLst - 1 );
288             // calculate new length of word
289             nWrLen = ( nEnd > nWrPos + nWrLen ) ?
290                        nPos - nWrPos :
291                        static_cast<xub_StrLen>(nWrLen + nDiff);
292             if( nWrLen )
293             {
294                 maList[--nLst].mnLen = nWrLen;
295                 bJump = sal_True;
296             }
297         }
298         Remove( i, nLst - i );
299 
300         if ( bJump )
301             ++i;
302         if( STRING_LEN == GetBeginInv() )
303             SetInvalid( nPos ? nPos - 1 : nPos, nPos + 1 );
304         else
305         {
306             ShiftLeft( nBeginInvalid, nPos, nEnd );
307             ShiftLeft( nEndInvalid, nPos, nEnd );
308             _Invalidate( nPos ? nPos - 1 : nPos, nPos + 1 );
309 		}
310 	}
311 	else
312 	{
313 		xub_StrLen nWrPos;
314 		xub_StrLen nEnd = nPos + xub_StrLen( nDiff );
315 		if( STRING_LEN != GetBeginInv() )
316 		{
317 			if( nBeginInvalid > nPos )
318 				nBeginInvalid = nBeginInvalid + xub_StrLen( nDiff );
319 			if( nEndInvalid >= nPos )
320 				nEndInvalid = nEndInvalid + xub_StrLen( nDiff );
321 		}
322 		// Wenn wir mitten in einem falschen Wort stehen, muss vom Wortanfang
323 		// invalidiert werden.
324         if( i < Count() && nPos >= ( nWrPos = Pos( i ) ) )
325         {
326             Invalidate( nWrPos, nEnd );
327             xub_StrLen nWrLen = Len( i ) + xub_StrLen( nDiff );
328             maList[i++].mnLen = nWrLen;
329             nWrLen = nWrLen + nWrPos;
330             Invalidate( nWrPos, nWrLen );
331         }
332         else
333             Invalidate( nPos, nEnd );
334     }
335     while( i < Count() )
336     {
337         const xub_StrLen nTmp = static_cast<xub_StrLen>(nDiff + maList[i].mnPos);
338         maList[i++].mnPos = nTmp;
339     }
340 }
341 
342 /*************************************************************************
343  *                      SwWrongList::Fresh
344  *
345  * For a given range [nPos, nPos + nLen[ and an index nIndex, this function
346  * basically counts the number of SwWrongArea entries starting with nIndex
347  * up to nPos + nLen. All these entries are removed.
348  *************************************************************************/
349 sal_Bool SwWrongList::Fresh( xub_StrLen &rStart, xub_StrLen &rEnd, xub_StrLen nPos,
350                              xub_StrLen nLen, MSHORT nIndex, xub_StrLen nCursorPos )
351 {
352     // length of word must be greater than 0 and cursor position must be outside the word
353     sal_Bool bRet = nLen && ( nCursorPos > nPos + nLen || nCursorPos < nPos );
354 
355     xub_StrLen nWrPos = 0;
356     xub_StrLen nWrEnd = rEnd;
357     MSHORT nCnt = nIndex;
358     if( nCnt < Count() && ( nWrPos = Pos( nIndex ) ) < nPos )
359     {
360         if( rStart > nWrPos )
361             rStart = nWrPos;
362     }
363 
364     while( nCnt < Count() && ( nWrPos = Pos( nCnt ) ) < nPos )
365         nWrEnd = nWrPos + Len( nCnt++ );
366 
367     if( nCnt < Count() && nWrPos == nPos && Len( nCnt ) == nLen )
368     {
369         ++nCnt;
370         bRet = sal_True;
371     }
372     else
373     {
374         if( bRet )
375         {
376             if( rStart > nPos )
377                 rStart = nPos;
378             nWrEnd = nPos + nLen;
379         }
380     }
381 
382     nPos = nPos + nLen;
383 
384     if( nCnt < Count() && ( nWrPos = Pos( nCnt ) ) < nPos )
385     {
386         if( rStart > nWrPos )
387             rStart = nWrPos;
388     }
389 
390     while( nCnt < Count() && ( nWrPos = Pos( nCnt ) ) < nPos )
391         nWrEnd = nWrPos + Len( nCnt++ );
392 
393     if( rEnd < nWrEnd )
394         rEnd = nWrEnd;
395 
396     Remove( nIndex, nCnt - nIndex );
397 
398     return bRet;
399 }
400 
401 void SwWrongList::Invalidate( xub_StrLen nBegin, xub_StrLen nEnd )
402 {
403     if (STRING_LEN == GetBeginInv())
404         SetInvalid( nBegin, nEnd );
405     else
406         _Invalidate( nBegin, nEnd );
407 }
408 
409 sal_Bool SwWrongList::InvalidateWrong( )
410 {
411 	if( Count() )
412 	{
413         xub_StrLen nFirst = Pos( 0 );
414         xub_StrLen nLast = Pos( Count() - 1 ) + Len( Count() - 1 );
415 		Invalidate( nFirst, nLast );
416 		return sal_True;
417 	}
418 	else
419 		return sal_False;
420 }
421 
422 SwWrongList* SwWrongList::SplitList( xub_StrLen nSplitPos )
423 {
424     SwWrongList *pRet = NULL;
425     MSHORT nLst = 0;
426     xub_StrLen nWrPos;
427     xub_StrLen nWrLen;
428     while( nLst < Count() && Pos( nLst ) < nSplitPos )
429         ++nLst;
430     if( nLst && ( nWrPos = Pos( nLst - 1 ) )
431         + ( nWrLen = Len( nLst - 1 ) ) > nSplitPos )
432     {
433         nWrLen += nWrPos - nSplitPos;
434         maList[--nLst].mnPos = nSplitPos;
435         maList[nLst].mnLen = nWrLen;
436     }
437     if( nLst )
438     {
439         if( WRONGLIST_GRAMMAR == GetWrongListType() )
440             pRet = new SwGrammarMarkUp();
441         else
442             pRet = new SwWrongList( GetWrongListType() );
443         pRet->Insert(0, maList.begin(), ( nLst >= maList.size() ? maList.end() : maList.begin() + nLst ) );
444         pRet->SetInvalid( GetBeginInv(), GetEndInv() );
445         pRet->_Invalidate( nSplitPos ? nSplitPos - 1 : nSplitPos, nSplitPos );
446         Remove( 0, nLst );
447     }
448     if( STRING_LEN == GetBeginInv() )
449         SetInvalid( 0, 1 );
450     else
451     {
452         ShiftLeft( nBeginInvalid, 0, nSplitPos );
453         ShiftLeft( nEndInvalid, 0, nSplitPos );
454         _Invalidate( 0, 1 );
455 	}
456     nLst = 0;
457     while( nLst < Count() )
458 	{
459         nWrPos = maList[nLst].mnPos - nSplitPos;
460         maList[nLst++].mnPos = nWrPos;
461     }
462     return pRet;
463 }
464 
465 void SwWrongList::JoinList( SwWrongList* pNext, xub_StrLen nInsertPos )
466 {
467     if (pNext)
468     {
469         DBG_ASSERT( GetWrongListType() == pNext->GetWrongListType(), "type mismatch with next list" );
470     }
471     if( pNext )
472     {
473         sal_uInt16 nCnt = Count();
474         pNext->Move( 0, nInsertPos );
475         Insert(nCnt, pNext->maList.begin(), pNext->maList.end());
476 
477         Invalidate( pNext->GetBeginInv(), pNext->GetEndInv() );
478         if( nCnt && Count() > nCnt )
479         {
480             xub_StrLen nWrPos = Pos( nCnt );
481             xub_StrLen nWrLen = Len( nCnt );
482             if( !nWrPos )
483             {
484                 nWrPos = nWrPos + nInsertPos;
485                 nWrLen = nWrLen - nInsertPos;
486                 maList[nCnt].mnPos = nWrPos;
487                 maList[nCnt].mnLen = nWrLen;
488             }
489             if( nWrPos == Pos( nCnt - 1 ) + Len( nCnt - 1 ) )
490             {
491                 nWrLen = nWrLen + Len( nCnt - 1 );
492                 maList[nCnt - 1].mnLen = nWrLen;
493                 Remove( nCnt, 1 );
494             }
495         }
496     }
497     Invalidate( nInsertPos ? nInsertPos - 1 : nInsertPos, nInsertPos + 1 );
498 }
499 
500 
501 void SwWrongList::InsertSubList( xub_StrLen nNewPos, xub_StrLen nNewLen, sal_uInt16 nWhere, SwWrongList* pSubList )
502 {
503     if (pSubList)
504     {
505         DBG_ASSERT( GetWrongListType() == pSubList->GetWrongListType(), "type mismatch with sub list" );
506     }
507     std::vector<SwWrongArea>::iterator i = maList.begin();
508     if ( nWhere >= maList.size() )
509         i = maList.end(); // robust
510     else
511         i += nWhere;
512     maList.insert(i, SwWrongArea( rtl::OUString(), 0, nNewPos, nNewLen, pSubList ) );
513 }
514 
515 
516 // New functions: Necessary because SwWrongList has been changed to use std::vector
517 void SwWrongList::Insert(sal_uInt16 nWhere, std::vector<SwWrongArea>::iterator startPos, std::vector<SwWrongArea>::iterator endPos)
518 {
519     std::vector<SwWrongArea>::iterator i = maList.begin();
520     if ( nWhere >= maList.size() )
521         i = maList.end(); // robust
522     else
523         i += nWhere;
524     maList.insert(i, startPos, endPos); // insert [startPos, endPos[ before i
525 
526     // ownership of the sublist is passed to maList, therefore we have to set the
527     // pSubList-Pointers to 0
528     while ( startPos != endPos )
529     {
530         (*startPos).mpSubList = 0;
531         ++startPos;
532     }
533 }
534 
535 void SwWrongList::Remove(sal_uInt16 nIdx, sal_uInt16 nLen )
536 {
537     if ( nIdx >= maList.size() ) return;
538     std::vector<SwWrongArea>::iterator i1 = maList.begin();
539     i1 += nIdx;
540 
541     std::vector<SwWrongArea>::iterator i2 = i1;
542     if ( nIdx + nLen >= static_cast<sal_uInt16>(maList.size()) )
543         i2 = maList.end(); // robust
544     else
545         i2 += nLen;
546 
547     std::vector<SwWrongArea>::iterator iLoop = i1;
548     while ( iLoop != i2 )
549     {
550         if ( (*iLoop).mpSubList )
551             delete (*iLoop).mpSubList;
552         ++iLoop;
553     }
554 
555 #if OSL_DEBUG_LEVEL > 1
556     const int nOldSize = Count();
557     (void) nOldSize;
558 #endif
559 
560     maList.erase(i1, i2);
561 
562 #if OSL_DEBUG_LEVEL > 1
563     ASSERT( Count() + nLen == nOldSize, "SwWrongList::Remove() trouble" )
564 #endif
565 }
566 
567 void SwWrongList::RemoveEntry( xub_StrLen nBegin, xub_StrLen nEnd ) {
568     sal_uInt16 nDelPos = 0;
569     sal_uInt16 nDel = 0;
570     std::vector<SwWrongArea>::iterator aIter = maList.begin();
571     while( aIter != maList.end() && (*aIter).mnPos < nBegin )
572     {
573         ++aIter;
574         ++nDelPos;
575     }
576     if( WRONGLIST_GRAMMAR == GetWrongListType() )
577     {
578         while( aIter != maList.end() && nBegin < nEnd && nEnd > (*aIter).mnPos )
579         {
580             ++aIter;
581             ++nDel;
582         }
583     }
584     else
585     {
586         while( aIter != maList.end() && nBegin == (*aIter).mnPos && nEnd == (*aIter).mnPos +(*aIter).mnLen )
587         {
588             ++aIter;
589             ++nDel;
590         }
591     }
592     if( nDel )
593         Remove( nDelPos, nDel );
594 }
595 
596 bool SwWrongList::LookForEntry( xub_StrLen nBegin, xub_StrLen nEnd ) {
597     std::vector<SwWrongArea>::iterator aIter = maList.begin();
598     while( aIter != maList.end() && (*aIter).mnPos < nBegin )
599         ++aIter;
600     if( aIter != maList.end() && nBegin == (*aIter).mnPos && nEnd == (*aIter).mnPos +(*aIter).mnLen )
601         return true;
602     return false;
603 }
604 
605 void SwWrongList::Insert( const rtl::OUString& rType,
606                           com::sun::star::uno::Reference< com::sun::star::container::XStringKeyMap > xPropertyBag,
607                           xub_StrLen nNewPos, xub_StrLen nNewLen )
608 {
609     std::vector<SwWrongArea>::iterator aIter = maList.begin();
610 
611     while ( aIter != maList.end() )
612     {
613         const xub_StrLen nSTPos = (*aIter).mnPos;
614 
615         if ( nNewPos < nSTPos )
616         {
617             // insert at current position
618             break;
619         }
620         else if ( nNewPos == nSTPos )
621         {
622             while ( aIter != maList.end() && (*aIter).mnPos == nSTPos )
623             {
624                 const xub_StrLen nSTLen = (*aIter).mnLen;
625 
626                 if ( nNewLen < nSTLen )
627                 {
628                     // insert at current position
629                     break;
630                 }
631 
632                 ++aIter;
633             }
634 
635             break;
636         }
637 
638         ++aIter;
639     }
640 
641     maList.insert(aIter, SwWrongArea( rType, xPropertyBag, nNewPos, nNewLen, 0 ) );
642 }
643 
644 
645