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