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