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