Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include <unotextmarkup.hxx>
21 :
22 : #include <osl/mutex.hxx>
23 : #include <vcl/svapp.hxx>
24 : #include <SwSmartTagMgr.hxx>
25 : #include <com/sun/star/text/TextMarkupType.hpp>
26 : #include <com/sun/star/text/TextMarkupDescriptor.hpp>
27 : #include <com/sun/star/container/XStringKeyMap.hpp>
28 : #include <ndtxt.hxx>
29 : #include <SwGrammarMarkUp.hxx>
30 :
31 : #include <IGrammarContact.hxx>
32 :
33 : #include <com/sun/star/lang/XUnoTunnel.hpp>
34 : #include <com/sun/star/text/XTextRange.hpp>
35 :
36 : #include <pam.hxx>
37 :
38 : #include <unotextrange.hxx>
39 : #include <unotextcursor.hxx>
40 :
41 : using namespace ::com::sun::star;
42 :
43 : /*
44 : * SwXTextMarkup
45 : */
46 0 : SwXTextMarkup::SwXTextMarkup(
47 : SwTxtNode *const pTxtNode, const ModelToViewHelper& rMap)
48 : : mpTxtNode(pTxtNode)
49 0 : , maConversionMap(rMap)
50 : {
51 : // FME 2007-07-16 #i79641# SwXTextMarkup is allowed to be removed ...
52 0 : SetIsAllowedToBeRemovedInModifyCall(true);
53 0 : mpTxtNode->Add(this);
54 0 : }
55 :
56 0 : SwXTextMarkup::~SwXTextMarkup()
57 : {
58 0 : }
59 :
60 0 : uno::Reference< container::XStringKeyMap > SAL_CALL SwXTextMarkup::getMarkupInfoContainer() throw (uno::RuntimeException, std::exception)
61 : {
62 0 : SolarMutexGuard aGuard;
63 :
64 0 : uno::Reference< container::XStringKeyMap > xProp = new SwXStringKeyMap;
65 0 : return xProp;
66 : }
67 :
68 0 : void SAL_CALL SwXTextMarkup::commitTextRangeMarkup(::sal_Int32 nType, const ::rtl::OUString & aIdentifier, const uno::Reference< text::XTextRange> & xRange,
69 : const uno::Reference< container::XStringKeyMap > & xMarkupInfoContainer) throw (uno::RuntimeException, std::exception)
70 : {
71 0 : SolarMutexGuard aGuard;
72 :
73 0 : uno::Reference<lang::XUnoTunnel> xRangeTunnel( xRange, uno::UNO_QUERY);
74 :
75 0 : if(!xRangeTunnel.is()) return;
76 :
77 0 : SwXTextRange* pRange = 0;
78 0 : OTextCursorHelper* pCursor = 0;
79 :
80 0 : if(xRangeTunnel.is())
81 : {
82 0 : pRange = reinterpret_cast<SwXTextRange*>( sal::static_int_cast< sal_IntPtr >( xRangeTunnel->getSomething(SwXTextRange::getUnoTunnelId())));
83 0 : pCursor = reinterpret_cast<OTextCursorHelper*>( sal::static_int_cast< sal_IntPtr >( xRangeTunnel->getSomething(OTextCursorHelper::getUnoTunnelId())));
84 : }
85 :
86 0 : if (pRange)
87 : {
88 0 : SwDoc* pDoc = reinterpret_cast<SwDoc*>(pRange->GetDoc());
89 :
90 0 : if (!pDoc) return;
91 :
92 0 : SwUnoInternalPaM aPam(*pDoc);
93 :
94 0 : ::sw::XTextRangeToSwPaM(aPam, xRange);
95 :
96 0 : SwPosition* startPos = aPam.Start();
97 0 : SwPosition* endPos = aPam.End();
98 :
99 0 : commitStringMarkup (nType, aIdentifier, startPos->nContent.GetIndex(), endPos->nContent.GetIndex() - startPos->nContent.GetIndex(), xMarkupInfoContainer);
100 : }
101 0 : else if (pCursor)
102 : {
103 0 : SwPaM aPam(*pCursor->GetPaM());
104 :
105 0 : SwPosition* startPos = aPam.Start();
106 0 : SwPosition* endPos = aPam.End();
107 :
108 0 : commitStringMarkup (nType, aIdentifier, startPos->nContent.GetIndex(), endPos->nContent.GetIndex() - startPos->nContent.GetIndex(), xMarkupInfoContainer);
109 0 : }
110 : }
111 :
112 0 : void SAL_CALL SwXTextMarkup::commitStringMarkup(
113 : ::sal_Int32 nType,
114 : const OUString & rIdentifier,
115 : ::sal_Int32 nStart,
116 : ::sal_Int32 nLength,
117 : const uno::Reference< container::XStringKeyMap > & xMarkupInfoContainer)
118 : throw (uno::RuntimeException, std::exception)
119 : {
120 0 : SolarMutexGuard aGuard;
121 :
122 : // paragraph already dead or modified?
123 0 : if ( !mpTxtNode || nLength <= 0 )
124 0 : return;
125 :
126 0 : if ( nType == text::TextMarkupType::SMARTTAG &&
127 0 : !SwSmartTagMgr::Get().IsSmartTagTypeEnabled( rIdentifier ) )
128 0 : return;
129 :
130 : // get appropriate list to use...
131 0 : SwWrongList* pWList = 0;
132 0 : bool bRepaint = false;
133 0 : if ( nType == text::TextMarkupType::SPELLCHECK )
134 : {
135 0 : pWList = mpTxtNode->GetWrong();
136 0 : if ( !pWList )
137 : {
138 0 : pWList = new SwWrongList( WRONGLIST_SPELL );
139 0 : mpTxtNode->SetWrong( pWList );
140 : }
141 : }
142 0 : else if ( nType == text::TextMarkupType::PROOFREADING || nType == text::TextMarkupType::SENTENCE )
143 : {
144 0 : IGrammarContact *pGrammarContact = getGrammarContact( *mpTxtNode );
145 0 : if( pGrammarContact )
146 : {
147 0 : pWList = pGrammarContact->getGrammarCheck( *mpTxtNode, true );
148 : OSL_ENSURE( pWList, "GrammarContact _has_ to deliver a wrong list" );
149 : }
150 : else
151 : {
152 0 : pWList = mpTxtNode->GetGrammarCheck();
153 0 : if ( !pWList )
154 : {
155 0 : mpTxtNode->SetGrammarCheck( new SwGrammarMarkUp() );
156 0 : pWList = mpTxtNode->GetGrammarCheck();
157 : }
158 : }
159 0 : bRepaint = pWList == mpTxtNode->GetGrammarCheck();
160 0 : if( pWList->GetBeginInv() < COMPLETE_STRING )
161 0 : ((SwGrammarMarkUp*)pWList)->ClearGrammarList();
162 : }
163 0 : else if ( nType == text::TextMarkupType::SMARTTAG )
164 : {
165 0 : pWList = mpTxtNode->GetSmartTags();
166 0 : if ( !pWList )
167 : {
168 0 : pWList = new SwWrongList( WRONGLIST_SMARTTAG );
169 0 : mpTxtNode->SetSmartTags( pWList );
170 : }
171 : }
172 : else
173 : {
174 : OSL_FAIL( "Unknown mark-up type" );
175 0 : return;
176 : }
177 :
178 : const ModelToViewHelper::ModelPosition aStartPos =
179 0 : maConversionMap.ConvertToModelPosition( nStart );
180 : const ModelToViewHelper::ModelPosition aEndPos =
181 0 : maConversionMap.ConvertToModelPosition( nStart + nLength - 1);
182 :
183 0 : const bool bStartInField = aStartPos.mbIsField;
184 0 : const bool bEndInField = aEndPos.mbIsField;
185 0 : bool bCommit = false;
186 :
187 0 : if ( bStartInField && bEndInField && aStartPos.mnPos == aEndPos.mnPos )
188 : {
189 0 : nStart = aStartPos.mnSubPos;
190 0 : const sal_Int32 nFieldPosModel = aStartPos.mnPos;
191 0 : const sal_uInt16 nInsertPos = pWList->GetWrongPos( nFieldPosModel );
192 :
193 0 : SwWrongList* pSubList = pWList->SubList( nInsertPos );
194 0 : if ( !pSubList )
195 : {
196 0 : if( nType == text::TextMarkupType::PROOFREADING || nType == text::TextMarkupType::SENTENCE )
197 0 : pSubList = new SwGrammarMarkUp();
198 : else
199 0 : pSubList = new SwWrongList( pWList->GetWrongListType() );
200 0 : pWList->InsertSubList( nFieldPosModel, 1, nInsertPos, pSubList );
201 : }
202 :
203 0 : pWList = pSubList;
204 0 : bCommit = true;
205 : }
206 0 : else if ( !bStartInField && !bEndInField )
207 : {
208 0 : nStart = aStartPos.mnPos;
209 0 : bCommit = true;
210 0 : nLength = aEndPos.mnPos + 1 - aStartPos.mnPos;
211 : }
212 0 : else if( nType == text::TextMarkupType::PROOFREADING || nType == text::TextMarkupType::SENTENCE )
213 : {
214 0 : bCommit = true;
215 0 : nStart = aStartPos.mnPos;
216 0 : sal_Int32 nEnd = aEndPos.mnPos;
217 0 : if( bStartInField && nType != text::TextMarkupType::SENTENCE )
218 : {
219 0 : const sal_Int32 nFieldPosModel = aStartPos.mnPos;
220 0 : const sal_uInt16 nInsertPos = pWList->GetWrongPos( nFieldPosModel );
221 0 : SwWrongList* pSubList = pWList->SubList( nInsertPos );
222 0 : if ( !pSubList )
223 : {
224 0 : pSubList = new SwGrammarMarkUp();
225 0 : pWList->InsertSubList( nFieldPosModel, 1, nInsertPos, pSubList );
226 : }
227 0 : const sal_Int32 nTmpStart = maConversionMap.ConvertToViewPosition( aStartPos.mnPos );
228 0 : const sal_Int32 nTmpLen = maConversionMap.ConvertToViewPosition( aStartPos.mnPos + 1 )
229 0 : - nTmpStart - aStartPos.mnSubPos;
230 0 : if( nTmpLen > 0 )
231 : {
232 0 : pSubList->Insert( rIdentifier, xMarkupInfoContainer, aStartPos.mnSubPos, nTmpLen );
233 : }
234 0 : ++nStart;
235 : }
236 0 : if( bEndInField && nType != text::TextMarkupType::SENTENCE )
237 : {
238 0 : const sal_Int32 nFieldPosModel = aEndPos.mnPos;
239 0 : const sal_uInt16 nInsertPos = pWList->GetWrongPos( nFieldPosModel );
240 0 : SwWrongList* pSubList = pWList->SubList( nInsertPos );
241 0 : if ( !pSubList )
242 : {
243 0 : pSubList = new SwGrammarMarkUp();
244 0 : pWList->InsertSubList( nFieldPosModel, 1, nInsertPos, pSubList );
245 : }
246 0 : const sal_Int32 nTmpLen = aEndPos.mnSubPos + 1;
247 0 : pSubList->Insert( rIdentifier, xMarkupInfoContainer, 0, nTmpLen );
248 : }
249 : else
250 0 : ++nEnd;
251 0 : if( nEnd > nStart )
252 0 : nLength = nEnd - nStart;
253 : else
254 0 : bCommit = false;
255 : }
256 :
257 0 : if ( bCommit )
258 : {
259 0 : if( nType == text::TextMarkupType::SENTENCE )
260 0 : ((SwGrammarMarkUp*)pWList)->setSentence( nStart );
261 : else
262 0 : pWList->Insert( rIdentifier, xMarkupInfoContainer, nStart, nLength );
263 : }
264 :
265 0 : if( bRepaint )
266 0 : finishGrammarCheck( *mpTxtNode );
267 : }
268 :
269 0 : static void lcl_commitGrammarMarkUp(
270 : const ModelToViewHelper& rConversionMap,
271 : SwGrammarMarkUp* pWList,
272 : ::sal_Int32 nType,
273 : const OUString & rIdentifier,
274 : ::sal_Int32 nStart,
275 : ::sal_Int32 nLength,
276 : const uno::Reference< container::XStringKeyMap > & xMarkupInfoContainer)
277 : {
278 : OSL_ENSURE( nType == text::TextMarkupType::PROOFREADING || nType == text::TextMarkupType::SENTENCE, "Wrong mark-up type" );
279 : const ModelToViewHelper::ModelPosition aStartPos =
280 0 : rConversionMap.ConvertToModelPosition( nStart );
281 : const ModelToViewHelper::ModelPosition aEndPos =
282 0 : rConversionMap.ConvertToModelPosition( nStart + nLength - 1);
283 :
284 0 : const bool bStartInField = aStartPos.mbIsField;
285 0 : const bool bEndInField = aEndPos.mbIsField;
286 0 : bool bCommit = false;
287 :
288 0 : if ( bStartInField && bEndInField && aStartPos.mnPos == aEndPos.mnPos )
289 : {
290 0 : nStart = aStartPos.mnSubPos;
291 0 : const sal_Int32 nFieldPosModel = aStartPos.mnPos;
292 0 : const sal_uInt16 nInsertPos = pWList->GetWrongPos( nFieldPosModel );
293 :
294 0 : SwGrammarMarkUp* pSubList = (SwGrammarMarkUp*)pWList->SubList( nInsertPos );
295 0 : if ( !pSubList )
296 : {
297 0 : pSubList = new SwGrammarMarkUp();
298 0 : pWList->InsertSubList( nFieldPosModel, 1, nInsertPos, pSubList );
299 : }
300 :
301 0 : pWList = pSubList;
302 0 : bCommit = true;
303 : }
304 0 : else if ( !bStartInField && !bEndInField )
305 : {
306 0 : nStart = aStartPos.mnPos;
307 0 : bCommit = true;
308 0 : nLength = aEndPos.mnPos + 1 - aStartPos.mnPos;
309 : }
310 : else
311 : {
312 0 : bCommit = true;
313 0 : nStart = aStartPos.mnPos;
314 0 : sal_Int32 nEnd = aEndPos.mnPos;
315 0 : if( bStartInField && nType != text::TextMarkupType::SENTENCE )
316 : {
317 0 : const sal_Int32 nFieldPosModel = aStartPos.mnPos;
318 0 : const sal_uInt16 nInsertPos = pWList->GetWrongPos( nFieldPosModel );
319 0 : SwGrammarMarkUp* pSubList = (SwGrammarMarkUp*)pWList->SubList( nInsertPos );
320 0 : if ( !pSubList )
321 : {
322 0 : pSubList = new SwGrammarMarkUp();
323 0 : pWList->InsertSubList( nFieldPosModel, 1, nInsertPos, pSubList );
324 : }
325 0 : const sal_Int32 nTmpStart = rConversionMap.ConvertToViewPosition( aStartPos.mnPos );
326 0 : const sal_Int32 nTmpLen = rConversionMap.ConvertToViewPosition( aStartPos.mnPos + 1 )
327 0 : - nTmpStart - aStartPos.mnSubPos;
328 0 : if( nTmpLen > 0 )
329 0 : pSubList->Insert( rIdentifier, xMarkupInfoContainer, aStartPos.mnSubPos, nTmpLen );
330 0 : ++nStart;
331 : }
332 0 : if( bEndInField && nType != text::TextMarkupType::SENTENCE )
333 : {
334 0 : const sal_Int32 nFieldPosModel = aEndPos.mnPos;
335 0 : const sal_uInt16 nInsertPos = pWList->GetWrongPos( nFieldPosModel );
336 0 : SwGrammarMarkUp* pSubList = (SwGrammarMarkUp*)pWList->SubList( nInsertPos );
337 0 : if ( !pSubList )
338 : {
339 0 : pSubList = new SwGrammarMarkUp();
340 0 : pWList->InsertSubList( nFieldPosModel, 1, nInsertPos, pSubList );
341 : }
342 0 : const sal_Int32 nTmpLen = aEndPos.mnSubPos + 1;
343 0 : pSubList->Insert( rIdentifier, xMarkupInfoContainer, 0, nTmpLen );
344 : }
345 : else
346 0 : ++nEnd;
347 0 : if( nEnd > nStart )
348 0 : nLength = nEnd - nStart;
349 : else
350 0 : bCommit = false;
351 : }
352 :
353 0 : if ( bCommit )
354 : {
355 0 : if( nType == text::TextMarkupType::SENTENCE )
356 0 : ((SwGrammarMarkUp*)pWList)->setSentence( nStart+nLength );
357 : else
358 0 : pWList->Insert( rIdentifier, xMarkupInfoContainer, nStart, nLength );
359 : }
360 0 : }
361 :
362 0 : void SAL_CALL SwXTextMarkup::commitMultiTextMarkup(
363 : const uno::Sequence< text::TextMarkupDescriptor > &rMarkups )
364 : throw (lang::IllegalArgumentException, uno::RuntimeException, std::exception)
365 : {
366 0 : SolarMutexGuard aGuard;
367 :
368 : // paragraph already dead or modified?
369 0 : if ( !mpTxtNode )
370 0 : return;
371 :
372 : // check for equal length of all sequnces
373 0 : sal_Int32 nLen = rMarkups.getLength();
374 :
375 : // for grammar checking there should be exactly one sentence markup
376 : // and 0..n grammar markups.
377 : // Different markups are not expected but may be applied anyway since
378 : // that should be no problem...
379 : // but it has to be implemented, at the moment only this function is for
380 : // grammar markups and sentence markup only!
381 0 : sal_Int32 nSentenceMarkUpIndex = -1;
382 0 : const text::TextMarkupDescriptor *pMarkups = rMarkups.getConstArray();
383 : sal_Int32 i;
384 0 : for( i = 0; i < nLen; ++i )
385 : {
386 0 : if (pMarkups[i].nType == text::TextMarkupType::SENTENCE)
387 : {
388 0 : if (nSentenceMarkUpIndex == -1)
389 0 : nSentenceMarkUpIndex = i;
390 : else // there is already one sentence markup
391 0 : throw lang::IllegalArgumentException();
392 : }
393 0 : else if( pMarkups[i].nType != text::TextMarkupType::PROOFREADING )
394 0 : return;
395 : }
396 :
397 0 : if( nSentenceMarkUpIndex == -1 )
398 0 : return;
399 :
400 : // get appropriate list to use...
401 0 : SwGrammarMarkUp* pWList = 0;
402 0 : bool bRepaint = false;
403 0 : IGrammarContact *pGrammarContact = getGrammarContact( *mpTxtNode );
404 0 : if( pGrammarContact )
405 : {
406 0 : pWList = pGrammarContact->getGrammarCheck( *mpTxtNode, true );
407 : OSL_ENSURE( pWList, "GrammarContact _has_ to deliver a wrong list" );
408 : }
409 : else
410 : {
411 0 : pWList = mpTxtNode->GetGrammarCheck();
412 0 : if ( !pWList )
413 : {
414 0 : mpTxtNode->SetGrammarCheck( new SwGrammarMarkUp() );
415 0 : pWList = mpTxtNode->GetGrammarCheck();
416 0 : pWList->SetInvalid( 0, COMPLETE_STRING );
417 : }
418 : }
419 0 : bRepaint = pWList == mpTxtNode->GetGrammarCheck();
420 :
421 0 : bool bAcceptGrammarError = false;
422 0 : if( pWList->GetBeginInv() < COMPLETE_STRING )
423 : {
424 : const ModelToViewHelper::ModelPosition aSentenceEnd =
425 : maConversionMap.ConvertToModelPosition(
426 0 : pMarkups[nSentenceMarkUpIndex].nOffset + pMarkups[nSentenceMarkUpIndex].nLength );
427 0 : bAcceptGrammarError = aSentenceEnd.mnPos > pWList->GetBeginInv();
428 0 : pWList->ClearGrammarList( aSentenceEnd.mnPos );
429 : }
430 :
431 0 : if( bAcceptGrammarError )
432 : {
433 0 : for( i = 0; i < nLen; ++i )
434 : {
435 0 : const text::TextMarkupDescriptor &rDesc = pMarkups[i];
436 : lcl_commitGrammarMarkUp( maConversionMap, pWList, rDesc.nType,
437 0 : rDesc.aIdentifier, rDesc.nOffset, rDesc.nLength, rDesc.xMarkupInfoContainer );
438 : }
439 : }
440 : else
441 : {
442 0 : bRepaint = false;
443 0 : i = nSentenceMarkUpIndex;
444 0 : const text::TextMarkupDescriptor &rDesc = pMarkups[i];
445 : lcl_commitGrammarMarkUp( maConversionMap, pWList, rDesc.nType,
446 0 : rDesc.aIdentifier, rDesc.nOffset, rDesc.nLength, rDesc.xMarkupInfoContainer );
447 : }
448 :
449 0 : if( bRepaint )
450 0 : finishGrammarCheck( *mpTxtNode );
451 :
452 0 : return;
453 : }
454 :
455 0 : void SwXTextMarkup::Modify( const SfxPoolItem* /*pOld*/, const SfxPoolItem* /*pNew*/ )
456 : {
457 : // FME 2007-07-16 #i79641# In my opinion this is perfectly legal,
458 : // therefore I remove the assertion in SwModify::_Remove()
459 0 : if ( GetRegisteredIn() )
460 0 : GetRegisteredInNonConst()->Remove( this );
461 :
462 0 : SolarMutexGuard aGuard;
463 0 : mpTxtNode = 0;
464 0 : }
465 :
466 : /*
467 : * SwXStringKeyMap
468 : */
469 0 : SwXStringKeyMap::SwXStringKeyMap()
470 : {
471 0 : }
472 :
473 0 : uno::Any SAL_CALL SwXStringKeyMap::getValue(const OUString & aKey) throw (uno::RuntimeException, container::NoSuchElementException, std::exception)
474 : {
475 0 : std::map< OUString, uno::Any >::const_iterator aIter = maMap.find( aKey );
476 0 : if ( aIter == maMap.end() )
477 0 : throw container::NoSuchElementException();
478 :
479 0 : return (*aIter).second;
480 : }
481 :
482 0 : sal_Bool SAL_CALL SwXStringKeyMap::hasValue(const OUString & aKey) throw (uno::RuntimeException, std::exception)
483 : {
484 0 : return maMap.find( aKey ) != maMap.end();
485 : }
486 :
487 0 : void SAL_CALL SwXStringKeyMap::insertValue(const OUString & aKey, const uno::Any & aValue) throw (uno::RuntimeException, lang::IllegalArgumentException, container::ElementExistException, std::exception)
488 : {
489 0 : std::map< OUString, uno::Any >::const_iterator aIter = maMap.find( aKey );
490 0 : if ( aIter != maMap.end() )
491 0 : throw container::ElementExistException();
492 :
493 0 : maMap[ aKey ] = aValue;
494 0 : }
495 :
496 0 : ::sal_Int32 SAL_CALL SwXStringKeyMap::getCount() throw (uno::RuntimeException, std::exception)
497 : {
498 0 : return maMap.size();
499 : }
500 :
501 0 : OUString SAL_CALL SwXStringKeyMap::getKeyByIndex(::sal_Int32 nIndex) throw (uno::RuntimeException, lang::IndexOutOfBoundsException, std::exception)
502 : {
503 0 : if ( (sal_uInt32)nIndex >= maMap.size() )
504 0 : throw lang::IndexOutOfBoundsException();
505 :
506 0 : return OUString();
507 : }
508 :
509 0 : uno::Any SAL_CALL SwXStringKeyMap::getValueByIndex(::sal_Int32 nIndex) throw (uno::RuntimeException, lang::IndexOutOfBoundsException, std::exception)
510 : {
511 0 : if ( (sal_uInt32)nIndex >= maMap.size() )
512 0 : throw lang::IndexOutOfBoundsException();
513 :
514 0 : return uno::Any();
515 : }
516 :
517 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|