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