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