xref: /AOO41X/main/sw/source/core/unocore/unotextmarkup.cxx (revision f1574e09b220bf6f1b3f5e31386497c5128ef9e8)
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