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