Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sw / source / core / unocore / unoflatpara.cxx
blobc5c2ef94e44165cbc16fd2582b65ec3a6ba227e8
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <unobaseclass.hxx>
21 #include <unocrsrhelper.hxx>
22 #include <unoflatpara.hxx>
24 #include <o3tl/safeint.hxx>
25 #include <utility>
26 #include <vcl/svapp.hxx>
27 #include <com/sun/star/text/TextMarkupType.hpp>
28 #include <com/sun/star/beans/PropertyAttribute.hpp>
29 #include <unotextmarkup.hxx>
30 #include <ndtxt.hxx>
31 #include <doc.hxx>
32 #include <IDocumentLayoutAccess.hxx>
33 #include <IDocumentStylePoolAccess.hxx>
34 #include <viewsh.hxx>
35 #include <viewimp.hxx>
36 #include <breakit.hxx>
37 #include <pam.hxx>
38 #include <unotextrange.hxx>
39 #include <pagefrm.hxx>
40 #include <cntfrm.hxx>
41 #include <txtfrm.hxx>
42 #include <rootfrm.hxx>
43 #include <poolfmt.hxx>
44 #include <pagedesc.hxx>
45 #include <GrammarContact.hxx>
46 #include <viewopt.hxx>
47 #include <comphelper/servicehelper.hxx>
48 #include <comphelper/propertysetinfo.hxx>
49 #include <comphelper/sequence.hxx>
50 #include <sal/log.hxx>
52 #include <com/sun/star/lang/XUnoTunnel.hpp>
53 #include <com/sun/star/text/XTextRange.hpp>
55 using namespace ::com::sun::star;
57 namespace SwUnoCursorHelper {
59 uno::Reference<text::XFlatParagraphIterator>
60 CreateFlatParagraphIterator(SwDoc & rDoc, sal_Int32 const nTextMarkupType,
61 bool const bAutomatic)
63 return new SwXFlatParagraphIterator(rDoc, nTextMarkupType, bAutomatic);
68 SwXFlatParagraph::SwXFlatParagraph( SwTextNode& rTextNode, OUString aExpandText, const ModelToViewHelper& rMap )
69 : SwXFlatParagraph_Base(& rTextNode, rMap)
70 , maExpandText(std::move(aExpandText))
74 SwXFlatParagraph::~SwXFlatParagraph()
79 // XPropertySet
80 uno::Reference< beans::XPropertySetInfo > SAL_CALL
81 SwXFlatParagraph::getPropertySetInfo()
83 static const comphelper::PropertyMapEntry s_Entries[] = {
84 { OUString("FieldPositions"), -1, ::cppu::UnoType<uno::Sequence<sal_Int32>>::get(), beans::PropertyAttribute::READONLY, 0 },
85 { OUString("FootnotePositions"), -1, ::cppu::UnoType<uno::Sequence<sal_Int32>>::get(), beans::PropertyAttribute::READONLY, 0 },
86 { OUString("SortedTextId"), -1, ::cppu::UnoType<sal_Int32>::get(), beans::PropertyAttribute::READONLY, 0 },
87 { OUString("DocumentElementsCount"), -1, ::cppu::UnoType<sal_Int32>::get(), beans::PropertyAttribute::READONLY, 0 },
89 return new comphelper::PropertySetInfo(s_Entries);
92 void SAL_CALL
93 SwXFlatParagraph::setPropertyValue(const OUString&, const uno::Any&)
95 throw lang::IllegalArgumentException("no values can be set",
96 static_cast< ::cppu::OWeakObject*>(this), 0);
99 uno::Any SAL_CALL
100 SwXFlatParagraph::getPropertyValue(const OUString& rPropertyName)
102 SolarMutexGuard g;
104 if (rPropertyName == "FieldPositions")
106 return uno::Any( comphelper::containerToSequence( GetConversionMap().getFieldPositions() ) );
108 else if (rPropertyName == "FootnotePositions")
110 return uno::Any( comphelper::containerToSequence( GetConversionMap().getFootnotePositions() ) );
112 else if (rPropertyName == "SortedTextId")
114 SwTextNode const*const pCurrentNode = GetTextNode();
115 sal_Int32 nIndex = -1;
116 if ( pCurrentNode )
117 nIndex = pCurrentNode->GetIndex().get();
118 return uno::Any( nIndex );
120 else if (rPropertyName == "DocumentElementsCount")
122 SwTextNode const*const pCurrentNode = GetTextNode();
123 sal_Int32 nCount = -1;
124 if ( pCurrentNode )
125 nCount = pCurrentNode->GetDoc().GetNodes().Count().get();
126 return uno::Any( nCount );
128 return uno::Any();
131 void SAL_CALL
132 SwXFlatParagraph::addPropertyChangeListener(
133 const OUString& /*rPropertyName*/,
134 const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/)
136 SAL_WARN("sw.uno",
137 "SwXFlatParagraph::addPropertyChangeListener(): not implemented");
140 void SAL_CALL
141 SwXFlatParagraph::removePropertyChangeListener(
142 const OUString& /*rPropertyName*/,
143 const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/)
145 SAL_WARN("sw.uno",
146 "SwXFlatParagraph::removePropertyChangeListener(): not implemented");
149 void SAL_CALL
150 SwXFlatParagraph::addVetoableChangeListener(
151 const OUString& /*rPropertyName*/,
152 const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/)
154 SAL_WARN("sw.uno",
155 "SwXFlatParagraph::addVetoableChangeListener(): not implemented");
158 void SAL_CALL
159 SwXFlatParagraph::removeVetoableChangeListener(
160 const OUString& /*rPropertyName*/,
161 const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/)
163 SAL_WARN("sw.uno",
164 "SwXFlatParagraph::removeVetoableChangeListener(): not implemented");
168 css::uno::Reference< css::container::XStringKeyMap > SAL_CALL SwXFlatParagraph::getMarkupInfoContainer()
170 return SwXTextMarkup::getMarkupInfoContainer();
173 void SAL_CALL SwXFlatParagraph::commitTextRangeMarkup(::sal_Int32 nType, const OUString & aIdentifier, const uno::Reference< text::XTextRange> & xRange,
174 const css::uno::Reference< css::container::XStringKeyMap > & xMarkupInfoContainer)
176 SolarMutexGuard aGuard;
177 SwXTextMarkup::commitTextRangeMarkup( nType, aIdentifier, xRange, xMarkupInfoContainer );
180 void SAL_CALL SwXFlatParagraph::commitStringMarkup(::sal_Int32 nType, const OUString & rIdentifier, ::sal_Int32 nStart, ::sal_Int32 nLength, const css::uno::Reference< css::container::XStringKeyMap > & rxMarkupInfoContainer)
182 SolarMutexGuard aGuard;
183 SwXTextMarkup::commitStringMarkup( nType, rIdentifier, nStart, nLength, rxMarkupInfoContainer );
186 // text::XFlatParagraph:
187 OUString SAL_CALL SwXFlatParagraph::getText()
189 return maExpandText;
192 // text::XFlatParagraph:
193 void SAL_CALL SwXFlatParagraph::setChecked( ::sal_Int32 nType, sal_Bool bVal )
195 SolarMutexGuard aGuard;
197 if (!GetTextNode())
198 return;
200 if ( text::TextMarkupType::SPELLCHECK == nType )
202 GetTextNode()->SetWrongDirty(
203 bVal ? sw::WrongState::DONE : sw::WrongState::TODO);
205 else if ( text::TextMarkupType::SMARTTAG == nType )
206 GetTextNode()->SetSmartTagDirty( !bVal );
207 else if( text::TextMarkupType::PROOFREADING == nType )
209 GetTextNode()->SetGrammarCheckDirty( !bVal );
210 if( bVal )
211 sw::finishGrammarCheckFor(*GetTextNode());
215 // text::XFlatParagraph:
216 sal_Bool SAL_CALL SwXFlatParagraph::isChecked( ::sal_Int32 nType )
218 SolarMutexGuard aGuard;
219 if (GetTextNode())
221 if ( text::TextMarkupType::SPELLCHECK == nType )
222 return !GetTextNode()->IsWrongDirty();
223 else if ( text::TextMarkupType::PROOFREADING == nType )
224 return !GetTextNode()->IsGrammarCheckDirty();
225 else if ( text::TextMarkupType::SMARTTAG == nType )
226 return !GetTextNode()->IsSmartTagDirty();
229 return true;
232 // text::XFlatParagraph:
233 sal_Bool SAL_CALL SwXFlatParagraph::isModified()
235 SolarMutexGuard aGuard;
236 return nullptr == GetTextNode();
239 // text::XFlatParagraph:
240 lang::Locale SAL_CALL SwXFlatParagraph::getLanguageOfText(::sal_Int32 nPos, ::sal_Int32 nLen)
242 SolarMutexGuard aGuard;
243 if (!GetTextNode())
244 return LanguageTag::convertToLocale( LANGUAGE_NONE );
246 const lang::Locale aLocale( SW_BREAKITER()->GetLocale( GetTextNode()->GetLang(nPos, nLen) ) );
247 return aLocale;
250 // text::XFlatParagraph:
251 lang::Locale SAL_CALL SwXFlatParagraph::getPrimaryLanguageOfText(::sal_Int32 nPos, ::sal_Int32 nLen)
253 SolarMutexGuard aGuard;
255 if (!GetTextNode())
256 return LanguageTag::convertToLocale( LANGUAGE_NONE );
258 const lang::Locale aLocale( SW_BREAKITER()->GetLocale( GetTextNode()->GetLang(nPos, nLen) ) );
259 return aLocale;
262 // text::XFlatParagraph:
263 void SAL_CALL SwXFlatParagraph::changeText(::sal_Int32 nPos, ::sal_Int32 nLen, const OUString & aNewText, const css::uno::Sequence< css::beans::PropertyValue > & aAttributes)
265 SolarMutexGuard aGuard;
267 if (!GetTextNode())
268 return;
270 SwTextNode *const pOldTextNode = GetTextNode();
272 if (nPos < 0 || pOldTextNode->Len() < nPos || nLen < 0 || o3tl::make_unsigned(pOldTextNode->Len()) < static_cast<sal_uInt32>(nPos) + nLen)
274 throw lang::IllegalArgumentException();
277 SwPaM aPaM( *GetTextNode(), nPos, *GetTextNode(), nPos+nLen );
279 UnoActionContext aAction( &GetTextNode()->GetDoc() );
281 const rtl::Reference<SwXTextRange> xRange =
282 SwXTextRange::CreateXTextRange(
283 GetTextNode()->GetDoc(), *aPaM.GetPoint(), aPaM.GetMark() );
284 if ( xRange.is() )
286 for ( const auto& rAttribute : aAttributes )
287 xRange->setPropertyValue( rAttribute.Name, rAttribute.Value );
290 IDocumentContentOperations& rIDCO = pOldTextNode->getIDocumentContentOperations();
291 rIDCO.ReplaceRange( aPaM, aNewText, false );
293 ClearTextNode(); // TODO: is this really needed?
296 // text::XFlatParagraph:
297 void SAL_CALL SwXFlatParagraph::changeAttributes(::sal_Int32 nPos, ::sal_Int32 nLen, const css::uno::Sequence< css::beans::PropertyValue > & aAttributes)
299 SolarMutexGuard aGuard;
301 if (!GetTextNode())
302 return;
304 if (nPos < 0 || GetTextNode()->Len() < nPos || nLen < 0 || o3tl::make_unsigned(GetTextNode()->Len()) < static_cast<sal_uInt32>(nPos) + nLen)
306 throw lang::IllegalArgumentException();
309 SwPaM aPaM( *GetTextNode(), nPos, *GetTextNode(), nPos+nLen );
311 UnoActionContext aAction( &GetTextNode()->GetDoc() );
313 const rtl::Reference<SwXTextRange> xRange =
314 SwXTextRange::CreateXTextRange(
315 GetTextNode()->GetDoc(), *aPaM.GetPoint(), aPaM.GetMark() );
316 if ( xRange.is() )
318 for ( const auto& rAttribute : aAttributes )
319 xRange->setPropertyValue( rAttribute.Name, rAttribute.Value );
322 ClearTextNode(); // TODO: is this really needed?
325 // text::XFlatParagraph:
326 css::uno::Sequence< ::sal_Int32 > SAL_CALL SwXFlatParagraph::getLanguagePortions()
328 return css::uno::Sequence< ::sal_Int32>();
331 SwXFlatParagraphIterator::SwXFlatParagraphIterator( SwDoc& rDoc, sal_Int32 nType, bool bAutomatic )
332 : mpDoc( &rDoc ),
333 mnType( nType ),
334 mbAutomatic( bAutomatic ),
335 mnCurrentNode( 0 ),
336 mnEndNode( rDoc.GetNodes().Count() )
338 //mnStartNode = mnCurrentNode = get node from current cursor TODO!
340 // register as listener and get notified when document is closed
341 StartListening(mpDoc->getIDocumentStylePoolAccess().GetPageDescFromPool( RES_POOLPAGE_STANDARD )->GetNotifier());
344 SwXFlatParagraphIterator::~SwXFlatParagraphIterator()
346 SolarMutexGuard aGuard;
347 EndListeningAll();
350 void SwXFlatParagraphIterator::Notify( const SfxHint& rHint )
352 if(rHint.GetId() == SfxHintId::Dying)
354 SolarMutexGuard aGuard;
355 mpDoc = nullptr;
359 uno::Reference< text::XFlatParagraph > SwXFlatParagraphIterator::getFirstPara()
361 return getNextPara(); // TODO
364 uno::Reference< text::XFlatParagraph > SwXFlatParagraphIterator::getNextPara()
366 SolarMutexGuard aGuard;
368 uno::Reference< text::XFlatParagraph > xRet;
369 if (!mpDoc)
370 return xRet;
372 SwTextNode* pRet = nullptr;
373 if ( mbAutomatic )
375 SwViewShell* pViewShell = mpDoc->getIDocumentLayoutAccess().GetCurrentViewShell();
377 SwPageFrame* pCurrentPage = pViewShell ? pViewShell->Imp()->GetFirstVisPage(pViewShell->GetOut()) : nullptr;
378 SwPageFrame* pStartPage = pCurrentPage;
379 SwPageFrame* pStopPage = nullptr;
381 while ( pCurrentPage && pCurrentPage != pStopPage )
383 if (mnType != text::TextMarkupType::SPELLCHECK || pCurrentPage->IsInvalidSpelling() )
385 // this method is supposed to return an empty paragraph in case Online Checking is disabled
386 if ( ( mnType == text::TextMarkupType::PROOFREADING || mnType == text::TextMarkupType::SPELLCHECK )
387 && !pViewShell->GetViewOptions()->IsOnlineSpell() )
388 return xRet;
390 // search for invalid content:
391 SwContentFrame* pCnt = pCurrentPage->ContainsContent();
393 while( pCnt && pCurrentPage->IsAnLower( pCnt ) )
395 if (pCnt->IsTextFrame())
397 SwTextFrame const*const pText(static_cast<SwTextFrame const*>(pCnt));
398 if (sw::MergedPara const*const pMergedPara = pText->GetMergedPara()
401 SwTextNode * pTextNode(nullptr);
402 for (auto const& e : pMergedPara->extents)
404 if (e.pNode != pTextNode)
406 pTextNode = e.pNode;
407 if ((mnType == text::TextMarkupType::SPELLCHECK
408 && pTextNode->IsWrongDirty()) ||
409 (mnType == text::TextMarkupType::PROOFREADING
410 && pTextNode->IsGrammarCheckDirty()))
412 pRet = pTextNode;
413 break;
418 else
420 SwTextNode const*const pTextNode(pText->GetTextNodeFirst());
421 if ((mnType == text::TextMarkupType::SPELLCHECK
422 && pTextNode->IsWrongDirty()) ||
423 (mnType == text::TextMarkupType::PROOFREADING
424 && pTextNode->IsGrammarCheckDirty()))
427 pRet = const_cast<SwTextNode*>(pTextNode);
431 if (pRet)
433 break;
437 pCnt = pCnt->GetNextContentFrame();
441 if ( pRet )
442 break;
444 // if there is no invalid text node on the current page,
445 // we validate the page
446 pCurrentPage->ValidateSpelling();
448 // proceed with next page, wrap at end of document if required:
449 pCurrentPage = static_cast<SwPageFrame*>(pCurrentPage->GetNext());
451 if ( !pCurrentPage && !pStopPage )
453 pStopPage = pStartPage;
454 pCurrentPage = static_cast<SwPageFrame*>(pViewShell->GetLayout()->Lower());
458 else // non-automatic checking
460 const SwNodes& rNodes = mpDoc->GetNodes();
461 const SwNodeOffset nMaxNodes = rNodes.Count();
463 while ( mnCurrentNode < mnEndNode && mnCurrentNode < nMaxNodes )
465 SwNode* pNd = rNodes[ mnCurrentNode ];
467 ++mnCurrentNode;
469 pRet = pNd->GetTextNode();
470 if ( pRet )
471 break;
473 if ( mnCurrentNode == mnEndNode )
475 mnCurrentNode = SwNodeOffset(0);
476 mnEndNode = SwNodeOffset(0);
481 if ( pRet )
483 // Expand the string:
484 const ModelToViewHelper aConversionMap(*pRet, mpDoc->getIDocumentLayoutAccess().GetCurrentLayout());
485 const OUString& aExpandText = aConversionMap.getViewText();
487 xRet = new SwXFlatParagraph( *pRet, aExpandText, aConversionMap );
490 return xRet;
493 uno::Reference< text::XFlatParagraph > SwXFlatParagraphIterator::getLastPara()
495 return getNextPara();
498 uno::Reference< text::XFlatParagraph > SwXFlatParagraphIterator::getParaAfter(const uno::Reference< text::XFlatParagraph > & xPara)
500 SolarMutexGuard aGuard;
502 uno::Reference< text::XFlatParagraph > xRet;
503 if (!mpDoc)
504 return xRet;
506 SwXFlatParagraph* const pFlatParagraph(dynamic_cast<SwXFlatParagraph*>(xPara.get()));
507 SAL_WARN_IF(!pFlatParagraph, "sw.core", "invalid argument");
508 if ( !pFlatParagraph )
509 return xRet;
511 SwTextNode const*const pCurrentNode = pFlatParagraph->GetTextNode();
513 if ( !pCurrentNode )
514 return xRet;
516 SwTextNode* pNextTextNode = nullptr;
517 const SwNodes& rNodes = pCurrentNode->GetDoc().GetNodes();
519 for( SwNodeOffset nCurrentNode = pCurrentNode->GetIndex() + 1; nCurrentNode < rNodes.Count(); ++nCurrentNode )
521 SwNode* pNd = rNodes[ nCurrentNode ];
522 pNextTextNode = pNd->GetTextNode();
523 if ( pNextTextNode )
524 break;
527 if ( pNextTextNode )
529 // Expand the string:
530 const ModelToViewHelper aConversionMap(*pNextTextNode, mpDoc->getIDocumentLayoutAccess().GetCurrentLayout());
531 const OUString& aExpandText = aConversionMap.getViewText();
533 xRet = new SwXFlatParagraph( *pNextTextNode, aExpandText, aConversionMap );
536 return xRet;
539 uno::Reference< text::XFlatParagraph > SwXFlatParagraphIterator::getParaBefore(const uno::Reference< text::XFlatParagraph > & xPara )
541 SolarMutexGuard aGuard;
543 uno::Reference< text::XFlatParagraph > xRet;
544 if (!mpDoc)
545 return xRet;
547 SwXFlatParagraph* const pFlatParagraph(dynamic_cast<SwXFlatParagraph*>(xPara.get()));
548 SAL_WARN_IF(!pFlatParagraph, "sw.core", "invalid argument");
549 if ( !pFlatParagraph )
550 return xRet;
552 SwTextNode const*const pCurrentNode = pFlatParagraph->GetTextNode();
554 if ( !pCurrentNode )
555 return xRet;
557 SwTextNode* pPrevTextNode = nullptr;
558 const SwNodes& rNodes = pCurrentNode->GetDoc().GetNodes();
560 for( SwNodeOffset nCurrentNode = pCurrentNode->GetIndex() - 1; nCurrentNode > SwNodeOffset(0); --nCurrentNode )
562 SwNode* pNd = rNodes[ nCurrentNode ];
563 pPrevTextNode = pNd->GetTextNode();
564 if ( pPrevTextNode )
565 break;
568 if ( pPrevTextNode )
570 // Expand the string:
571 const ModelToViewHelper aConversionMap(*pPrevTextNode, mpDoc->getIDocumentLayoutAccess().GetCurrentLayout());
572 const OUString& aExpandText = aConversionMap.getViewText();
574 xRet = new SwXFlatParagraph( *pPrevTextNode, aExpandText, aConversionMap );
577 return xRet;
580 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */