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