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