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