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