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 
27 #include <editeng/unolingu.hxx>
28 
29 #include <unobaseclass.hxx>
30 #include <unoflatpara.hxx>
31 
32 #include <vos/mutex.hxx>
33 #include <vcl/svapp.hxx>
34 #include <com/sun/star/text/TextMarkupType.hpp>
35 #include <unotextmarkup.hxx>
36 #include <ndtxt.hxx>
37 #include <doc.hxx>
38 #include <docsh.hxx>
39 #include <viewsh.hxx>
40 #include <viewimp.hxx>
41 #include <breakit.hxx>
42 #include <pam.hxx>
43 #include <unobaseclass.hxx>
44 #include <unotextrange.hxx>
45 #include <pagefrm.hxx>
46 #include <cntfrm.hxx>
47 #include <rootfrm.hxx>
48 #include <poolfmt.hxx>
49 #include <pagedesc.hxx>
50 #include <IGrammarContact.hxx>
51 #include <viewopt.hxx>
52 
53 #include <com/sun/star/lang/XUnoTunnel.hpp>
54 #include <com/sun/star/text/XTextRange.hpp>
55 
56 using namespace ::com::sun::star;
57 
58 /******************************************************************************
59  * SwXFlatParagraph
60  ******************************************************************************/
61 
SwXFlatParagraph(SwTxtNode & rTxtNode,rtl::OUString aExpandText,const ModelToViewHelper::ConversionMap * pMap)62 SwXFlatParagraph::SwXFlatParagraph( SwTxtNode& rTxtNode, rtl::OUString aExpandText, const ModelToViewHelper::ConversionMap* pMap ) :
63     SwXTextMarkup( rTxtNode, pMap ),
64     maExpandText( aExpandText )
65 {
66 }
67 
~SwXFlatParagraph()68 SwXFlatParagraph::~SwXFlatParagraph()
69 {
70 }
71 
getTypes()72 uno::Sequence< uno::Type > SwXFlatParagraph::getTypes(  ) throw(uno::RuntimeException)
73 {
74 	uno::Sequence< uno::Type > aTypes = SwXTextMarkup::getTypes();
75 	aTypes.realloc( aTypes.getLength() + 1 );
76     aTypes[aTypes.getLength()-1] = ::getCppuType((uno::Reference< text::XFlatParagraph >*)0);
77 	return aTypes;
78 }
79 
getImplementationId()80 uno::Sequence< sal_Int8 > SwXFlatParagraph::getImplementationId(  ) throw(uno::RuntimeException)
81 {
82     vos::OGuard aGuard(Application::GetSolarMutex());
83     static uno::Sequence< sal_Int8 > aId( 16 );
84     static sal_Bool bInit = sal_False;
85     if(!bInit)
86     {
87         rtl_createUuid( (sal_uInt8 *)(aId.getArray() ), 0, sal_True );
88         bInit = sal_True;
89     }
90     return aId;
91 }
92 
queryInterface(const uno::Type & rType)93 uno::Any SAL_CALL SwXFlatParagraph::queryInterface( const uno::Type& rType ) throw(uno::RuntimeException)
94 {
95 	if ( rType == ::getCppuType((uno::Reference< text::XFlatParagraph >*)0) )
96 	{
97 		return uno::makeAny( uno::Reference < text::XFlatParagraph >(this) );
98 	}
99 	else
100 		return SwXTextMarkup::queryInterface( rType );
101 }
102 
acquire()103 void SAL_CALL SwXFlatParagraph::acquire() throw()
104 {
105     SwXTextMarkup::acquire();
106 }
107 
release()108 void SAL_CALL SwXFlatParagraph::release() throw()
109 {
110     SwXTextMarkup::release();
111 }
112 
getTxtNode() const113 const SwTxtNode* SwXFlatParagraph::getTxtNode() const
114 {
115     return mpTxtNode;
116 }
117 
getMarkupInfoContainer()118 css::uno::Reference< css::container::XStringKeyMap > SAL_CALL SwXFlatParagraph::getMarkupInfoContainer() throw (css::uno::RuntimeException)
119 {
120     return SwXTextMarkup::getMarkupInfoContainer();
121 }
122 
commitTextRangeMarkup(::sal_Int32 nType,const::rtl::OUString & aIdentifier,const uno::Reference<text::XTextRange> & xRange,const css::uno::Reference<css::container::XStringKeyMap> & xMarkupInfoContainer)123 void SAL_CALL SwXFlatParagraph::commitTextRangeMarkup(::sal_Int32 nType, const ::rtl::OUString & aIdentifier, const uno::Reference< text::XTextRange> & xRange,
124                                                       const css::uno::Reference< css::container::XStringKeyMap > & xMarkupInfoContainer) throw (uno::RuntimeException)
125 {
126     vos::OGuard aGuard(Application::GetSolarMutex());
127     SwXTextMarkup::commitTextRangeMarkup( nType, aIdentifier, xRange,  xMarkupInfoContainer );
128 }
129 
130 
commitStringMarkup(::sal_Int32 nType,const::rtl::OUString & rIdentifier,::sal_Int32 nStart,::sal_Int32 nLength,const css::uno::Reference<css::container::XStringKeyMap> & rxMarkupInfoContainer)131 void SAL_CALL SwXFlatParagraph::commitStringMarkup(::sal_Int32 nType, const ::rtl::OUString & rIdentifier, ::sal_Int32 nStart, ::sal_Int32 nLength, const css::uno::Reference< css::container::XStringKeyMap > & rxMarkupInfoContainer) throw (css::uno::RuntimeException)
132 {
133     vos::OGuard aGuard(Application::GetSolarMutex());
134     SwXTextMarkup::commitStringMarkup( nType, rIdentifier, nStart, nLength,  rxMarkupInfoContainer );
135 }
136 
137 // text::XFlatParagraph:
getText()138 ::rtl::OUString SAL_CALL SwXFlatParagraph::getText() throw (uno::RuntimeException)
139 {
140     return maExpandText;
141 }
142 
143 // text::XFlatParagraph:
setChecked(::sal_Int32 nType,::sal_Bool bVal)144 void SAL_CALL SwXFlatParagraph::setChecked( ::sal_Int32 nType, ::sal_Bool bVal ) throw (uno::RuntimeException)
145 {
146     vos::OGuard aGuard(Application::GetSolarMutex());
147 
148     if ( mpTxtNode )
149     {
150         if ( text::TextMarkupType::SPELLCHECK == nType )
151             mpTxtNode->SetWrongDirty( !bVal );
152         else if ( text::TextMarkupType::SMARTTAG == nType )
153             mpTxtNode->SetSmartTagDirty( !bVal );
154         else if( text::TextMarkupType::PROOFREADING == nType )
155         {
156             mpTxtNode->SetGrammarCheckDirty( !bVal );
157             if( bVal )
158                 ::finishGrammarCheck( *mpTxtNode );
159         }
160     }
161 }
162 
163 // text::XFlatParagraph:
isChecked(::sal_Int32 nType)164 ::sal_Bool SAL_CALL SwXFlatParagraph::isChecked( ::sal_Int32 nType ) throw (uno::RuntimeException)
165 {
166     vos::OGuard aGuard(Application::GetSolarMutex());
167     if ( mpTxtNode )
168     {
169         if ( text::TextMarkupType::SPELLCHECK == nType )
170             return mpTxtNode->IsWrongDirty();
171         else if ( text::TextMarkupType::PROOFREADING == nType )
172             return mpTxtNode->IsGrammarCheckDirty();
173         else if ( text::TextMarkupType::SMARTTAG == nType )
174             return mpTxtNode->IsSmartTagDirty();
175     }
176 
177     return sal_False;
178 }
179 
180 // text::XFlatParagraph:
isModified()181 ::sal_Bool SAL_CALL SwXFlatParagraph::isModified() throw (uno::RuntimeException)
182 {
183     vos::OGuard aGuard(Application::GetSolarMutex());
184     return 0 == mpTxtNode;
185 }
186 
187 // text::XFlatParagraph:
getLanguageOfText(::sal_Int32 nPos,::sal_Int32 nLen)188 lang::Locale SAL_CALL SwXFlatParagraph::getLanguageOfText(::sal_Int32 nPos, ::sal_Int32 nLen)
189 	throw (uno::RuntimeException, lang::IllegalArgumentException)
190 {
191     vos::OGuard aGuard(Application::GetSolarMutex());
192     if (!mpTxtNode)
193         return SvxCreateLocale( LANGUAGE_NONE );
194 
195     const lang::Locale aLocale( SW_BREAKITER()->GetLocale( mpTxtNode->GetLang( static_cast<sal_uInt16>(nPos), static_cast<sal_uInt16>(nLen) ) ) );
196     return aLocale;
197 }
198 
199 // text::XFlatParagraph:
getPrimaryLanguageOfText(::sal_Int32 nPos,::sal_Int32 nLen)200 lang::Locale SAL_CALL SwXFlatParagraph::getPrimaryLanguageOfText(::sal_Int32 nPos, ::sal_Int32 nLen)
201 	throw (uno::RuntimeException, lang::IllegalArgumentException)
202 {
203     vos::OGuard aGuard(Application::GetSolarMutex());
204 
205     if (!mpTxtNode)
206         return SvxCreateLocale( LANGUAGE_NONE );
207 
208     const lang::Locale aLocale( SW_BREAKITER()->GetLocale( mpTxtNode->GetLang( static_cast<sal_uInt16>(nPos), static_cast<sal_uInt16>(nLen) ) ) );
209     return aLocale;
210 }
211 
212 // text::XFlatParagraph:
changeText(::sal_Int32 nPos,::sal_Int32 nLen,const::rtl::OUString & aNewText,const css::uno::Sequence<css::beans::PropertyValue> & aAttributes)213 void SAL_CALL SwXFlatParagraph::changeText(::sal_Int32 nPos, ::sal_Int32 nLen, const ::rtl::OUString & aNewText, const css::uno::Sequence< css::beans::PropertyValue > & aAttributes) throw (css::uno::RuntimeException, css::lang::IllegalArgumentException)
214 {
215     vos::OGuard aGuard(Application::GetSolarMutex());
216 
217     if ( !mpTxtNode )
218         return;
219 
220     SwTxtNode* pOldTxtNode = mpTxtNode;
221 
222     SwPaM aPaM( *mpTxtNode, static_cast<sal_uInt16>(nPos), *mpTxtNode, static_cast<sal_uInt16>(nPos + nLen) );
223 
224     UnoActionContext aAction( mpTxtNode->GetDoc() );
225 
226     const uno::Reference< text::XTextRange > xRange =
227         SwXTextRange::CreateXTextRange(
228             *mpTxtNode->GetDoc(), *aPaM.GetPoint(), aPaM.GetMark() );
229     uno::Reference< beans::XPropertySet > xPropSet( xRange, uno::UNO_QUERY );
230     if ( xPropSet.is() )
231     {
232         for ( sal_uInt16 i = 0; i < aAttributes.getLength(); ++i )
233             xPropSet->setPropertyValue( aAttributes[i].Name, aAttributes[i].Value );
234     }
235 
236     mpTxtNode = pOldTxtNode; // setPropertyValue() modifies this. We restore the old state.
237 
238     IDocumentContentOperations* pIDCO = mpTxtNode->getIDocumentContentOperations();
239     pIDCO->ReplaceRange( aPaM, aNewText, false );
240 
241     mpTxtNode = 0;
242 }
243 
244 // text::XFlatParagraph:
changeAttributes(::sal_Int32 nPos,::sal_Int32 nLen,const css::uno::Sequence<css::beans::PropertyValue> & aAttributes)245 void SAL_CALL SwXFlatParagraph::changeAttributes(::sal_Int32 nPos, ::sal_Int32 nLen, const css::uno::Sequence< css::beans::PropertyValue > & aAttributes) throw (css::uno::RuntimeException, css::lang::IllegalArgumentException)
246 {
247     vos::OGuard aGuard(Application::GetSolarMutex());
248 
249     if ( !mpTxtNode )
250         return;
251 
252     SwPaM aPaM( *mpTxtNode, static_cast<sal_uInt16>(nPos), *mpTxtNode, static_cast<sal_uInt16>(nPos + nLen) );
253 
254     UnoActionContext aAction( mpTxtNode->GetDoc() );
255 
256     const uno::Reference< text::XTextRange > xRange =
257         SwXTextRange::CreateXTextRange(
258             *mpTxtNode->GetDoc(), *aPaM.GetPoint(), aPaM.GetMark() );
259     uno::Reference< beans::XPropertySet > xPropSet( xRange, uno::UNO_QUERY );
260     if ( xPropSet.is() )
261     {
262         for ( sal_uInt16 i = 0; i < aAttributes.getLength(); ++i )
263             xPropSet->setPropertyValue( aAttributes[i].Name, aAttributes[i].Value );
264     }
265 
266     mpTxtNode = 0;
267 }
268 
269 // text::XFlatParagraph:
getLanguagePortions()270 css::uno::Sequence< ::sal_Int32 > SAL_CALL SwXFlatParagraph::getLanguagePortions() throw (css::uno::RuntimeException)
271 {
272     vos::OGuard aGuard(Application::GetSolarMutex());
273     return css::uno::Sequence< ::sal_Int32>();
274 }
275 
276 
277 const uno::Sequence< sal_Int8 >&
getUnoTunnelId()278 SwXFlatParagraph::getUnoTunnelId()
279 {
280     static uno::Sequence<sal_Int8> aSeq(CreateUnoTunnelId());
281     return aSeq;
282 }
283 
284 
285 sal_Int64 SAL_CALL
getSomething(const uno::Sequence<sal_Int8> & rId)286 SwXFlatParagraph::getSomething(
287         const uno::Sequence< sal_Int8 >& rId)
288     throw (uno::RuntimeException)
289 {
290     return sw::UnoTunnelImpl(rId, this);
291 }
292 
293 
294 /******************************************************************************
295  * SwXFlatParagraphIterator
296  ******************************************************************************/
297 
SwXFlatParagraphIterator(SwDoc & rDoc,sal_Int32 nType,sal_Bool bAutomatic)298 SwXFlatParagraphIterator::SwXFlatParagraphIterator( SwDoc& rDoc, sal_Int32 nType, sal_Bool bAutomatic )
299     : mpDoc( &rDoc ),
300       mnType( nType ),
301       mbAutomatic( bAutomatic ),
302       mnCurrentNode( 0 ),
303       mnStartNode( 0 ),
304       mnEndNode( rDoc.GetNodes().Count() ),
305       mbWrapped( sal_False )
306 {
307     //mnStartNode = mnCurrentNode = get node from current cursor TODO!
308 
309     // register as listener and get notified when document is closed
310     mpDoc->GetPageDescFromPool( RES_POOLPAGE_STANDARD )->Add(this);
311 }
312 
~SwXFlatParagraphIterator()313 SwXFlatParagraphIterator::~SwXFlatParagraphIterator()
314 {
315 }
316 
317 
Modify(const SfxPoolItem * pOld,const SfxPoolItem * pNew)318 void SwXFlatParagraphIterator::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew )
319 {
320     ClientModify( this, pOld, pNew );
321     // check if document gets closed...
322     if(!GetRegisteredIn())
323     {
324         vos::OGuard aGuard(Application::GetSolarMutex());
325         mpDoc = 0;
326     }
327 }
328 
329 
getFirstPara()330 uno::Reference< text::XFlatParagraph > SwXFlatParagraphIterator::getFirstPara()
331 	throw( uno::RuntimeException )
332 {
333     return getNextPara();   // TODO
334 }
335 
getNextPara()336 uno::Reference< text::XFlatParagraph > SwXFlatParagraphIterator::getNextPara()
337 	throw( uno::RuntimeException )
338 {
339     vos::OGuard aGuard(Application::GetSolarMutex());
340 
341     uno::Reference< text::XFlatParagraph > xRet;
342     if (!mpDoc)
343         return xRet;
344 
345     SwTxtNode* pRet = 0;
346     if ( mbAutomatic )
347     {
348         ViewShell* pViewShell = 0;
349         mpDoc->GetEditShell( &pViewShell );
350 
351         SwPageFrm* pCurrentPage = pViewShell ? pViewShell->Imp()->GetFirstVisPage() : 0;
352         SwPageFrm* pStartPage = pCurrentPage;
353         SwPageFrm* pStopPage = 0;
354 
355         while ( pCurrentPage != pStopPage )
356         {
357             if (mnType != text::TextMarkupType::SPELLCHECK || pCurrentPage->IsInvalidSpelling() )
358             {
359 				// this method is supposed to return an empty paragraph in case Online Checking is disabled
360 				if ( ( mnType == text::TextMarkupType::PROOFREADING || mnType == text::TextMarkupType::SPELLCHECK )
361 					&& !pViewShell->GetViewOptions()->IsOnlineSpell() )
362 					return xRet;
363 
364                 // search for invalid content:
365                 SwCntntFrm* pCnt = pCurrentPage->ContainsCntnt();
366 
367                 while( pCnt && pCurrentPage->IsAnLower( pCnt ) )
368                 {
369                     SwTxtNode* pTxtNode = dynamic_cast<SwTxtNode*>( pCnt->GetNode()->GetTxtNode() );
370 
371                     if ( pTxtNode &&
372                         ((mnType == text::TextMarkupType::SPELLCHECK &&
373                                 pTxtNode->IsWrongDirty()) ||
374                          (mnType == text::TextMarkupType::PROOFREADING &&
375                                 pTxtNode->IsGrammarCheckDirty())) )
376                     {
377                         pRet = pTxtNode;
378                         break;
379                     }
380 
381                     pCnt = pCnt->GetNextCntntFrm();
382                 }
383             }
384 
385             if ( pRet )
386                 break;
387 
388             // if there is no invalid text node on the current page,
389             // we validate the page
390             pCurrentPage->ValidateSpelling();
391 
392             // proceed with next page, wrap at end of document if required:
393             pCurrentPage = static_cast<SwPageFrm*>(pCurrentPage->GetNext());
394 
395             if ( !pCurrentPage && !pStopPage )
396             {
397                 pStopPage = pStartPage;
398                 pCurrentPage = static_cast<SwPageFrm*>(pViewShell->GetLayout()->Lower());
399             }
400         }
401     }
402     else    // non-automatic checking
403     {
404         const SwNodes& rNodes = mpDoc->GetNodes();
405         const sal_uLong nMaxNodes = rNodes.Count();
406 
407         while ( mnCurrentNode < mnEndNode && mnCurrentNode < nMaxNodes )
408         {
409             SwNode* pNd = rNodes[ mnCurrentNode ];
410 
411             ++mnCurrentNode;
412 
413             pRet = dynamic_cast<SwTxtNode*>(pNd);
414             if ( pRet )
415                 break;
416 
417             if ( mnCurrentNode == mnEndNode && !mbWrapped )
418             {
419                 mnCurrentNode = 0;
420                 mnEndNode = mnStartNode;
421             }
422         }
423     }
424 
425     if ( pRet )
426     {
427         // Expand the string:
428         rtl::OUString aExpandText;
429         const ModelToViewHelper::ConversionMap* pConversionMap =
430                 pRet->BuildConversionMap( aExpandText );
431 
432         xRet = new SwXFlatParagraph( *pRet, aExpandText, pConversionMap );
433 		// keep hard references...
434 		m_aFlatParaList.insert( xRet );
435     }
436 
437 	return xRet;
438 }
439 
getLastPara()440 uno::Reference< text::XFlatParagraph > SwXFlatParagraphIterator::getLastPara()
441 	throw( uno::RuntimeException )
442 {
443     return getNextPara();
444 }
445 
getParaAfter(const uno::Reference<text::XFlatParagraph> & xPara)446 uno::Reference< text::XFlatParagraph > SwXFlatParagraphIterator::getParaAfter(const uno::Reference< text::XFlatParagraph > & xPara)
447 	throw ( uno::RuntimeException, lang::IllegalArgumentException )
448 {
449     vos::OGuard aGuard(Application::GetSolarMutex());
450 
451     uno::Reference< text::XFlatParagraph > xRet;
452     if (!mpDoc)
453         return xRet;
454 
455     const uno::Reference<lang::XUnoTunnel> xFPTunnel(xPara, uno::UNO_QUERY);
456     OSL_ASSERT(xFPTunnel.is());
457     SwXFlatParagraph* const pFlatParagraph(sw::UnoTunnelGetImplementation<SwXFlatParagraph>(xFPTunnel));
458 
459     if ( !pFlatParagraph )
460         return xRet;
461 
462     const SwTxtNode* pCurrentNode = pFlatParagraph->getTxtNode();
463 
464     if ( !pCurrentNode )
465         return xRet;
466 
467     SwTxtNode* pNextTxtNode = 0;
468     const SwNodes& rNodes = pCurrentNode->GetDoc()->GetNodes();
469 
470     for( sal_uLong nCurrentNode = pCurrentNode->GetIndex() + 1; nCurrentNode < rNodes.Count(); ++nCurrentNode )
471     {
472         SwNode* pNd = rNodes[ nCurrentNode ];
473         pNextTxtNode = dynamic_cast<SwTxtNode*>(pNd);
474         if ( pNextTxtNode )
475             break;
476     }
477 
478     if ( pNextTxtNode )
479     {
480         // Expand the string:
481         rtl::OUString aExpandText;
482         const ModelToViewHelper::ConversionMap* pConversionMap =
483                 pNextTxtNode->BuildConversionMap( aExpandText );
484 
485         xRet = new SwXFlatParagraph( *pNextTxtNode, aExpandText, pConversionMap );
486 		// keep hard references...
487 		m_aFlatParaList.insert( xRet );
488     }
489 
490     return xRet;
491 }
492 
getParaBefore(const uno::Reference<text::XFlatParagraph> & xPara)493 uno::Reference< text::XFlatParagraph > SwXFlatParagraphIterator::getParaBefore(const uno::Reference< text::XFlatParagraph > & xPara )
494 	throw ( uno::RuntimeException, lang::IllegalArgumentException )
495 {
496     vos::OGuard aGuard(Application::GetSolarMutex());
497 
498     uno::Reference< text::XFlatParagraph > xRet;
499     if (!mpDoc)
500         return xRet;
501 
502     const uno::Reference<lang::XUnoTunnel> xFPTunnel(xPara, uno::UNO_QUERY);
503     OSL_ASSERT(xFPTunnel.is());
504     SwXFlatParagraph* const pFlatParagraph(sw::UnoTunnelGetImplementation<SwXFlatParagraph>(xFPTunnel));
505 
506     if ( !pFlatParagraph )
507         return xRet;
508 
509     const SwTxtNode* pCurrentNode = pFlatParagraph->getTxtNode();
510 
511     if ( !pCurrentNode )
512         return xRet;
513 
514     SwTxtNode* pPrevTxtNode = 0;
515     const SwNodes& rNodes = pCurrentNode->GetDoc()->GetNodes();
516 
517     for( sal_uLong nCurrentNode = pCurrentNode->GetIndex() - 1; nCurrentNode > 0; --nCurrentNode )
518     {
519         SwNode* pNd = rNodes[ nCurrentNode ];
520         pPrevTxtNode = dynamic_cast<SwTxtNode*>(pNd);
521         if ( pPrevTxtNode )
522             break;
523     }
524 
525     if ( pPrevTxtNode )
526     {
527         // Expand the string:
528         rtl::OUString aExpandText;
529         const ModelToViewHelper::ConversionMap* pConversionMap =
530                 pPrevTxtNode->BuildConversionMap( aExpandText );
531 
532         xRet = new SwXFlatParagraph( *pPrevTxtNode, aExpandText, pConversionMap );
533 		// keep hard references...
534 		m_aFlatParaList.insert( xRet );
535     }
536 
537     return xRet;
538 }
539