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 #include <unotextmarkup.hxx> 27 28 #include <vos/mutex.hxx> 29 #include <vcl/svapp.hxx> 30 #include <SwSmartTagMgr.hxx> 31 #include <com/sun/star/text/TextMarkupType.hpp> 32 #include <com/sun/star/text/TextMarkupDescriptor.hpp> 33 #include <com/sun/star/container/XStringKeyMap.hpp> 34 #include <ndtxt.hxx> 35 #include <SwGrammarMarkUp.hxx> 36 37 #include <IGrammarContact.hxx> 38 39 #include <com/sun/star/lang/XUnoTunnel.hpp> 40 #include <com/sun/star/text/XTextRange.hpp> 41 42 #include <pam.hxx> 43 44 #include <unotextrange.hxx> 45 #include <unotextcursor.hxx> 46 47 48 using namespace ::com::sun::star; 49 50 /* 51 * SwXTextMarkup 52 */ 53 SwXTextMarkup::SwXTextMarkup( SwTxtNode& rTxtNode, const ModelToViewHelper::ConversionMap* pMap ) 54 : mpTxtNode( &rTxtNode ), mpConversionMap( pMap ) 55 { 56 // FME 2007-07-16 #i79641# SwXTextMarkup is allowed to be removed ... 57 SetIsAllowedToBeRemovedInModifyCall(true); 58 mpTxtNode->Add(this); 59 } 60 61 SwXTextMarkup::~SwXTextMarkup() 62 { 63 delete mpConversionMap; 64 } 65 66 uno::Reference< container::XStringKeyMap > SAL_CALL SwXTextMarkup::getMarkupInfoContainer() throw (uno::RuntimeException) 67 { 68 vos::OGuard aGuard(Application::GetSolarMutex()); 69 70 uno::Reference< container::XStringKeyMap > xProp = new SwXStringKeyMap; 71 return xProp; 72 } 73 74 void SAL_CALL SwXTextMarkup::commitTextRangeMarkup(::sal_Int32 nType, const ::rtl::OUString & aIdentifier, const uno::Reference< text::XTextRange> & xRange, 75 const uno::Reference< container::XStringKeyMap > & xMarkupInfoContainer) throw (uno::RuntimeException) 76 { 77 vos::OGuard aGuard(Application::GetSolarMutex()); 78 79 uno::Reference<lang::XUnoTunnel> xRangeTunnel( xRange, uno::UNO_QUERY); 80 81 if(!xRangeTunnel.is()) return; 82 83 SwXTextRange* pRange = 0; 84 OTextCursorHelper* pCursor = 0; 85 86 if(xRangeTunnel.is()) 87 { 88 pRange = reinterpret_cast<SwXTextRange*>( sal::static_int_cast< sal_IntPtr >( xRangeTunnel->getSomething(SwXTextRange::getUnoTunnelId()))); 89 pCursor = reinterpret_cast<OTextCursorHelper*>( sal::static_int_cast< sal_IntPtr >( xRangeTunnel->getSomething(OTextCursorHelper::getUnoTunnelId()))); 90 } 91 92 if (pRange) 93 { 94 SwDoc* pDoc = reinterpret_cast<SwDoc*>(pRange->GetDoc()); 95 96 if (!pDoc) return; 97 98 SwUnoInternalPaM aPam(*pDoc); 99 100 ::sw::XTextRangeToSwPaM(aPam, xRange); 101 102 SwPosition* startPos = aPam.Start(); 103 SwPosition* endPos = aPam.End(); 104 105 commitStringMarkup (nType, aIdentifier, startPos->nContent.GetIndex(), endPos->nContent.GetIndex() - startPos->nContent.GetIndex(), xMarkupInfoContainer); 106 } 107 else if (pCursor) 108 { 109 SwPaM aPam(*pCursor->GetPaM()); 110 111 SwPosition* startPos = aPam.Start(); 112 SwPosition* endPos = aPam.End(); 113 114 commitStringMarkup (nType, aIdentifier, startPos->nContent.GetIndex(), endPos->nContent.GetIndex() - startPos->nContent.GetIndex(), xMarkupInfoContainer); 115 } 116 } 117 118 119 void SAL_CALL SwXTextMarkup::commitStringMarkup( 120 ::sal_Int32 nType, 121 const ::rtl::OUString & rIdentifier, 122 ::sal_Int32 nStart, 123 ::sal_Int32 nLength, 124 const uno::Reference< container::XStringKeyMap > & xMarkupInfoContainer) 125 throw (uno::RuntimeException) 126 { 127 vos::OGuard aGuard(Application::GetSolarMutex()); 128 129 // paragraph already dead or modified? 130 if ( !mpTxtNode || nLength <= 0 ) 131 return; 132 133 if ( nType == text::TextMarkupType::SMARTTAG && 134 !SwSmartTagMgr::Get().IsSmartTagTypeEnabled( rIdentifier ) ) 135 return; 136 137 // get appropriate list to use... 138 SwWrongList* pWList = 0; 139 bool bRepaint = false; 140 if ( nType == text::TextMarkupType::SPELLCHECK ) 141 { 142 pWList = mpTxtNode->GetWrong(); 143 if ( !pWList ) 144 { 145 pWList = new SwWrongList( WRONGLIST_SPELL ); 146 mpTxtNode->SetWrong( pWList ); 147 } 148 } 149 else if ( nType == text::TextMarkupType::PROOFREADING || nType == text::TextMarkupType::SENTENCE ) 150 { 151 IGrammarContact *pGrammarContact = getGrammarContact( *mpTxtNode ); 152 if( pGrammarContact ) 153 { 154 pWList = pGrammarContact->getGrammarCheck( *mpTxtNode, true ); 155 ASSERT( pWList, "GrammarContact _has_ to deliver a wrong list" ) 156 } 157 else 158 { 159 pWList = mpTxtNode->GetGrammarCheck(); 160 if ( !pWList ) 161 { 162 mpTxtNode->SetGrammarCheck( new SwGrammarMarkUp() ); 163 pWList = mpTxtNode->GetGrammarCheck(); 164 } 165 } 166 bRepaint = pWList == mpTxtNode->GetGrammarCheck(); 167 if( pWList->GetBeginInv() < STRING_LEN ) 168 ((SwGrammarMarkUp*)pWList)->ClearGrammarList(); 169 } 170 else if ( nType == text::TextMarkupType::SMARTTAG ) 171 { 172 pWList = mpTxtNode->GetSmartTags(); 173 if ( !pWList ) 174 { 175 pWList = new SwWrongList( WRONGLIST_SMARTTAG ); 176 mpTxtNode->SetSmartTags( pWList ); 177 } 178 } 179 else 180 { 181 ASSERT( false, "Unknown mark-up type" ) 182 return; 183 } 184 185 186 const ModelToViewHelper::ModelPosition aStartPos = 187 ModelToViewHelper::ConvertToModelPosition( mpConversionMap, nStart ); 188 const ModelToViewHelper::ModelPosition aEndPos = 189 ModelToViewHelper::ConvertToModelPosition( mpConversionMap, nStart + nLength - 1); 190 191 const bool bStartInField = aStartPos.mbIsField; 192 const bool bEndInField = aEndPos.mbIsField; 193 bool bCommit = false; 194 195 if ( bStartInField && bEndInField && aStartPos.mnPos == aEndPos.mnPos ) 196 { 197 nStart = aStartPos.mnSubPos; 198 const xub_StrLen nFieldPosModel = static_cast< xub_StrLen >(aStartPos.mnPos); 199 const sal_uInt16 nInsertPos = pWList->GetWrongPos( nFieldPosModel ); 200 201 SwWrongList* pSubList = pWList->SubList( nInsertPos ); 202 if ( !pSubList ) 203 { 204 if( nType == text::TextMarkupType::PROOFREADING || nType == text::TextMarkupType::SENTENCE ) 205 pSubList = new SwGrammarMarkUp(); 206 else 207 pSubList = new SwWrongList( pWList->GetWrongListType() ); 208 pWList->InsertSubList( nFieldPosModel, 1, nInsertPos, pSubList ); 209 } 210 211 pWList = pSubList; 212 bCommit = true; 213 } 214 else if ( !bStartInField && !bEndInField ) 215 { 216 nStart = aStartPos.mnPos; 217 bCommit = true; 218 nLength = aEndPos.mnPos + 1 - aStartPos.mnPos; 219 } 220 else if( nType == text::TextMarkupType::PROOFREADING || nType == text::TextMarkupType::SENTENCE ) 221 { 222 bCommit = true; 223 nStart = aStartPos.mnPos; 224 sal_Int32 nEnd = aEndPos.mnPos; 225 if( bStartInField && nType != text::TextMarkupType::SENTENCE ) 226 { 227 const xub_StrLen nFieldPosModel = static_cast< xub_StrLen >(aStartPos.mnPos); 228 const sal_uInt16 nInsertPos = pWList->GetWrongPos( nFieldPosModel ); 229 SwWrongList* pSubList = pWList->SubList( nInsertPos ); 230 if ( !pSubList ) 231 { 232 pSubList = new SwGrammarMarkUp(); 233 pWList->InsertSubList( nFieldPosModel, 1, nInsertPos, pSubList ); 234 } 235 const sal_uInt32 nTmpStart = ModelToViewHelper::ConvertToViewPosition( mpConversionMap, aStartPos.mnPos ); 236 const sal_uInt32 nTmpLen = ModelToViewHelper::ConvertToViewPosition( mpConversionMap, aStartPos.mnPos + 1 ) 237 - nTmpStart - aStartPos.mnSubPos; 238 if( nTmpLen > 0 ) 239 { 240 if( nType == text::TextMarkupType::SENTENCE ) 241 { 242 ((SwGrammarMarkUp*)pSubList)->setSentence( static_cast< xub_StrLen >(aStartPos.mnSubPos) ); 243 bCommit = false; 244 } 245 else 246 pSubList->Insert( rIdentifier, xMarkupInfoContainer, 247 static_cast< xub_StrLen >(aStartPos.mnSubPos), static_cast< xub_StrLen >(nTmpLen) ); 248 } 249 ++nStart; 250 } 251 if( bEndInField && nType != text::TextMarkupType::SENTENCE ) 252 { 253 const xub_StrLen nFieldPosModel = static_cast< xub_StrLen >(aEndPos.mnPos); 254 const sal_uInt16 nInsertPos = pWList->GetWrongPos( nFieldPosModel ); 255 SwWrongList* pSubList = pWList->SubList( nInsertPos ); 256 if ( !pSubList ) 257 { 258 pSubList = new SwGrammarMarkUp(); 259 pWList->InsertSubList( nFieldPosModel, 1, nInsertPos, pSubList ); 260 } 261 const sal_uInt32 nTmpLen = aEndPos.mnSubPos + 1; 262 pSubList->Insert( rIdentifier, xMarkupInfoContainer, 0, static_cast< xub_StrLen >(nTmpLen) ); 263 } 264 else 265 ++nEnd; 266 if( nEnd > nStart ) 267 nLength = nEnd - nStart; 268 else 269 bCommit = false; 270 } 271 272 if ( bCommit ) 273 { 274 if( nType == text::TextMarkupType::SENTENCE ) 275 ((SwGrammarMarkUp*)pWList)->setSentence( static_cast< xub_StrLen >(nStart) ); 276 else 277 pWList->Insert( rIdentifier, xMarkupInfoContainer, 278 static_cast< xub_StrLen >(nStart), static_cast< xub_StrLen >(nLength) ); 279 } 280 281 if( bRepaint ) 282 finishGrammarCheck( *mpTxtNode ); 283 } 284 285 286 void lcl_commitGrammarMarkUp( 287 const ModelToViewHelper::ConversionMap* pConversionMap, 288 SwGrammarMarkUp* pWList, 289 ::sal_Int32 nType, 290 const ::rtl::OUString & rIdentifier, 291 ::sal_Int32 nStart, 292 ::sal_Int32 nLength, 293 const uno::Reference< container::XStringKeyMap > & xMarkupInfoContainer) 294 { 295 ASSERT( nType == text::TextMarkupType::PROOFREADING || nType == text::TextMarkupType::SENTENCE, "Wrong mark-up type" ) 296 const ModelToViewHelper::ModelPosition aStartPos = 297 ModelToViewHelper::ConvertToModelPosition( pConversionMap, nStart ); 298 const ModelToViewHelper::ModelPosition aEndPos = 299 ModelToViewHelper::ConvertToModelPosition( pConversionMap, nStart + nLength - 1); 300 301 const bool bStartInField = aStartPos.mbIsField; 302 const bool bEndInField = aEndPos.mbIsField; 303 bool bCommit = false; 304 305 if ( bStartInField && bEndInField && aStartPos.mnPos == aEndPos.mnPos ) 306 { 307 nStart = aStartPos.mnSubPos; 308 const xub_StrLen nFieldPosModel = static_cast< xub_StrLen >(aStartPos.mnPos); 309 const sal_uInt16 nInsertPos = pWList->GetWrongPos( nFieldPosModel ); 310 311 SwGrammarMarkUp* pSubList = (SwGrammarMarkUp*)pWList->SubList( nInsertPos ); 312 if ( !pSubList ) 313 { 314 pSubList = new SwGrammarMarkUp(); 315 pWList->InsertSubList( nFieldPosModel, 1, nInsertPos, pSubList ); 316 } 317 318 pWList = pSubList; 319 bCommit = true; 320 } 321 else if ( !bStartInField && !bEndInField ) 322 { 323 nStart = aStartPos.mnPos; 324 bCommit = true; 325 nLength = aEndPos.mnPos + 1 - aStartPos.mnPos; 326 } 327 else 328 { 329 bCommit = true; 330 nStart = aStartPos.mnPos; 331 sal_Int32 nEnd = aEndPos.mnPos; 332 if( bStartInField && nType != text::TextMarkupType::SENTENCE ) 333 { 334 const xub_StrLen nFieldPosModel = static_cast< xub_StrLen >(aStartPos.mnPos); 335 const sal_uInt16 nInsertPos = pWList->GetWrongPos( nFieldPosModel ); 336 SwGrammarMarkUp* pSubList = (SwGrammarMarkUp*)pWList->SubList( nInsertPos ); 337 if ( !pSubList ) 338 { 339 pSubList = new SwGrammarMarkUp(); 340 pWList->InsertSubList( nFieldPosModel, 1, nInsertPos, pSubList ); 341 } 342 const sal_uInt32 nTmpStart = ModelToViewHelper::ConvertToViewPosition( pConversionMap, aStartPos.mnPos ); 343 const sal_uInt32 nTmpLen = ModelToViewHelper::ConvertToViewPosition( pConversionMap, aStartPos.mnPos + 1 ) 344 - nTmpStart - aStartPos.mnSubPos; 345 if( nTmpLen > 0 ) 346 pSubList->Insert( rIdentifier, xMarkupInfoContainer, 347 static_cast< xub_StrLen >(aStartPos.mnSubPos), static_cast< xub_StrLen >(nTmpLen) ); 348 ++nStart; 349 } 350 if( bEndInField && nType != text::TextMarkupType::SENTENCE ) 351 { 352 const xub_StrLen nFieldPosModel = static_cast< xub_StrLen >(aEndPos.mnPos); 353 const sal_uInt16 nInsertPos = pWList->GetWrongPos( nFieldPosModel ); 354 SwGrammarMarkUp* pSubList = (SwGrammarMarkUp*)pWList->SubList( nInsertPos ); 355 if ( !pSubList ) 356 { 357 pSubList = new SwGrammarMarkUp(); 358 pWList->InsertSubList( nFieldPosModel, 1, nInsertPos, pSubList ); 359 } 360 const sal_uInt32 nTmpLen = aEndPos.mnSubPos + 1; 361 pSubList->Insert( rIdentifier, xMarkupInfoContainer, 0, static_cast< xub_StrLen >(nTmpLen) ); 362 } 363 else 364 ++nEnd; 365 if( nEnd > nStart ) 366 nLength = nEnd - nStart; 367 else 368 bCommit = false; 369 } 370 371 if ( bCommit ) 372 { 373 if( nType == text::TextMarkupType::SENTENCE ) 374 ((SwGrammarMarkUp*)pWList)->setSentence( static_cast< xub_StrLen >(nStart+nLength) ); 375 else 376 pWList->Insert( rIdentifier, xMarkupInfoContainer, 377 static_cast< xub_StrLen >(nStart), static_cast< xub_StrLen >(nLength) ); 378 } 379 } 380 381 382 void SAL_CALL SwXTextMarkup::commitMultiTextMarkup( 383 const uno::Sequence< text::TextMarkupDescriptor > &rMarkups ) 384 throw (lang::IllegalArgumentException, uno::RuntimeException) 385 { 386 vos::OGuard aGuard(Application::GetSolarMutex()); 387 388 // paragraph already dead or modified? 389 if ( !mpTxtNode ) 390 return; 391 392 // check for equal length of all sequnces 393 sal_Int32 nLen = rMarkups.getLength(); 394 395 // for grammar checking there should be exactly one sentence markup 396 // and 0..n grammar markups. 397 // Different markups are not expected but may be applied anyway since 398 // that should be no problem... 399 // but it has to be implemented, at the moment only this function is for 400 // grammar markups and sentence markup only! 401 sal_Int32 nSentenceMarkUpIndex = -1; 402 const text::TextMarkupDescriptor *pMarkups = rMarkups.getConstArray(); 403 sal_Int32 i; 404 for( i = 0; i < nLen; ++i ) 405 { 406 if (pMarkups[i].nType == text::TextMarkupType::SENTENCE) 407 { 408 if (nSentenceMarkUpIndex == -1) 409 nSentenceMarkUpIndex = i; 410 else // there is already one sentence markup 411 throw lang::IllegalArgumentException(); 412 } 413 else if( pMarkups[i].nType != text::TextMarkupType::PROOFREADING ) 414 return; 415 } 416 417 if( nSentenceMarkUpIndex == -1 ) 418 return; 419 420 // get appropriate list to use... 421 SwGrammarMarkUp* pWList = 0; 422 bool bRepaint = false; 423 IGrammarContact *pGrammarContact = getGrammarContact( *mpTxtNode ); 424 if( pGrammarContact ) 425 { 426 pWList = pGrammarContact->getGrammarCheck( *mpTxtNode, true ); 427 ASSERT( pWList, "GrammarContact _has_ to deliver a wrong list" ) 428 } 429 else 430 { 431 pWList = mpTxtNode->GetGrammarCheck(); 432 if ( !pWList ) 433 { 434 mpTxtNode->SetGrammarCheck( new SwGrammarMarkUp() ); 435 pWList = mpTxtNode->GetGrammarCheck(); 436 pWList->SetInvalid( 0, STRING_LEN ); 437 } 438 } 439 bRepaint = pWList == mpTxtNode->GetGrammarCheck(); 440 441 bool bAcceptGrammarError = false; 442 if( pWList->GetBeginInv() < STRING_LEN ) 443 { 444 const ModelToViewHelper::ModelPosition aSentenceEnd = 445 ModelToViewHelper::ConvertToModelPosition( mpConversionMap, 446 pMarkups[nSentenceMarkUpIndex].nOffset + pMarkups[nSentenceMarkUpIndex].nLength ); 447 bAcceptGrammarError = (xub_StrLen)aSentenceEnd.mnPos > pWList->GetBeginInv(); 448 pWList->ClearGrammarList( (xub_StrLen)aSentenceEnd.mnPos ); 449 } 450 451 if( bAcceptGrammarError ) 452 { 453 for( i = 0; i < nLen; ++i ) 454 { 455 const text::TextMarkupDescriptor &rDesc = pMarkups[i]; 456 lcl_commitGrammarMarkUp( mpConversionMap, pWList, rDesc.nType, 457 rDesc.aIdentifier, rDesc.nOffset, rDesc.nLength, rDesc.xMarkupInfoContainer ); 458 } 459 } 460 else 461 { 462 bRepaint = false; 463 i = nSentenceMarkUpIndex; 464 const text::TextMarkupDescriptor &rDesc = pMarkups[i]; 465 lcl_commitGrammarMarkUp( mpConversionMap, pWList, rDesc.nType, 466 rDesc.aIdentifier, rDesc.nOffset, rDesc.nLength, rDesc.xMarkupInfoContainer ); 467 } 468 469 if( bRepaint ) 470 finishGrammarCheck( *mpTxtNode ); 471 472 return; 473 } 474 475 476 void SwXTextMarkup::Modify( const SfxPoolItem* /*pOld*/, const SfxPoolItem* /*pNew*/ ) 477 { 478 // FME 2007-07-16 #i79641# In my opinion this is perfectly legal, 479 // therefore I remove the assertion in SwModify::_Remove() 480 if ( GetRegisteredIn() ) 481 GetRegisteredInNonConst()->Remove( this ); 482 // <-- 483 484 vos::OGuard aGuard(Application::GetSolarMutex()); 485 mpTxtNode = 0; 486 } 487 488 /* 489 * SwXStringKeyMap 490 */ 491 SwXStringKeyMap::SwXStringKeyMap() 492 { 493 } 494 495 uno::Any SAL_CALL SwXStringKeyMap::getValue(const ::rtl::OUString & aKey) throw (uno::RuntimeException, container::NoSuchElementException) 496 { 497 std::map< rtl::OUString, uno::Any >::const_iterator aIter = maMap.find( aKey ); 498 if ( aIter == maMap.end() ) 499 throw container::NoSuchElementException(); 500 501 return (*aIter).second; 502 } 503 504 ::sal_Bool SAL_CALL SwXStringKeyMap::hasValue(const ::rtl::OUString & aKey) throw (uno::RuntimeException) 505 { 506 return maMap.find( aKey ) != maMap.end(); 507 } 508 509 void SAL_CALL SwXStringKeyMap::insertValue(const ::rtl::OUString & aKey, const uno::Any & aValue) throw (uno::RuntimeException, lang::IllegalArgumentException, container::ElementExistException) 510 { 511 std::map< rtl::OUString, uno::Any >::const_iterator aIter = maMap.find( aKey ); 512 if ( aIter != maMap.end() ) 513 throw container::ElementExistException(); 514 515 maMap[ aKey ] = aValue; 516 } 517 518 ::sal_Int32 SAL_CALL SwXStringKeyMap::getCount() throw (uno::RuntimeException) 519 { 520 return maMap.size(); 521 } 522 523 ::rtl::OUString SAL_CALL SwXStringKeyMap::getKeyByIndex(::sal_Int32 nIndex) throw (uno::RuntimeException, lang::IndexOutOfBoundsException) 524 { 525 if ( (sal_uInt32)nIndex >= maMap.size() ) 526 throw lang::IndexOutOfBoundsException(); 527 528 return ::rtl::OUString(); 529 } 530 531 uno::Any SAL_CALL SwXStringKeyMap::getValueByIndex(::sal_Int32 nIndex) throw (uno::RuntimeException, lang::IndexOutOfBoundsException) 532 { 533 if ( (sal_uInt32)nIndex >= maMap.size() ) 534 throw lang::IndexOutOfBoundsException(); 535 536 return uno::Any(); 537 } 538 539