1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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>
32 #include <IDocumentLayoutAccess.hxx>
33 #include <IDocumentStylePoolAccess.hxx>
35 #include <viewimp.hxx>
36 #include <breakit.hxx>
38 #include <unotextrange.hxx>
39 #include <pagefrm.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
))
71 , maOrigText(rTextNode
.GetText())
75 SwXFlatParagraph::~SwXFlatParagraph()
81 uno::Reference
< beans::XPropertySetInfo
> SAL_CALL
82 SwXFlatParagraph::getPropertySetInfo()
84 static const comphelper::PropertyMapEntry s_Entries
[] = {
85 { u
"FieldPositions"_ustr
, -1, ::cppu::UnoType
<uno::Sequence
<sal_Int32
>>::get(), beans::PropertyAttribute::READONLY
, 0 },
86 { u
"FootnotePositions"_ustr
, -1, ::cppu::UnoType
<uno::Sequence
<sal_Int32
>>::get(), beans::PropertyAttribute::READONLY
, 0 },
87 { u
"SortedTextId"_ustr
, -1, ::cppu::UnoType
<sal_Int32
>::get(), beans::PropertyAttribute::READONLY
, 0 },
88 { u
"DocumentElementsCount"_ustr
, -1, ::cppu::UnoType
<sal_Int32
>::get(), beans::PropertyAttribute::READONLY
, 0 },
90 return new comphelper::PropertySetInfo(s_Entries
);
94 SwXFlatParagraph::setPropertyValue(const OUString
&, const uno::Any
&)
96 throw lang::IllegalArgumentException(u
"no values can be set"_ustr
,
101 SwXFlatParagraph::getPropertyValue(const OUString
& rPropertyName
)
105 if (rPropertyName
== "FieldPositions")
107 return uno::Any( comphelper::containerToSequence( GetConversionMap().getFieldPositions() ) );
109 else if (rPropertyName
== "FootnotePositions")
111 return uno::Any( comphelper::containerToSequence( GetConversionMap().getFootnotePositions() ) );
113 else if (rPropertyName
== "SortedTextId")
115 SwTextNode
const*const pCurrentNode
= GetTextNode();
116 sal_Int32 nIndex
= -1;
118 nIndex
= pCurrentNode
->GetIndex().get();
119 return uno::Any( nIndex
);
121 else if (rPropertyName
== "DocumentElementsCount")
123 SwTextNode
const*const pCurrentNode
= GetTextNode();
124 sal_Int32 nCount
= -1;
126 nCount
= pCurrentNode
->GetDoc().GetNodes().Count().get();
127 return uno::Any( nCount
);
133 SwXFlatParagraph::addPropertyChangeListener(
134 const OUString
& /*rPropertyName*/,
135 const uno::Reference
< beans::XPropertyChangeListener
>& /*xListener*/)
138 "SwXFlatParagraph::addPropertyChangeListener(): not implemented");
142 SwXFlatParagraph::removePropertyChangeListener(
143 const OUString
& /*rPropertyName*/,
144 const uno::Reference
< beans::XPropertyChangeListener
>& /*xListener*/)
147 "SwXFlatParagraph::removePropertyChangeListener(): not implemented");
151 SwXFlatParagraph::addVetoableChangeListener(
152 const OUString
& /*rPropertyName*/,
153 const uno::Reference
< beans::XVetoableChangeListener
>& /*xListener*/)
156 "SwXFlatParagraph::addVetoableChangeListener(): not implemented");
160 SwXFlatParagraph::removeVetoableChangeListener(
161 const OUString
& /*rPropertyName*/,
162 const uno::Reference
< beans::XVetoableChangeListener
>& /*xListener*/)
165 "SwXFlatParagraph::removeVetoableChangeListener(): not implemented");
169 css::uno::Reference
< css::container::XStringKeyMap
> SAL_CALL
SwXFlatParagraph::getMarkupInfoContainer()
171 return SwXTextMarkup::getMarkupInfoContainer();
174 void SAL_CALL
SwXFlatParagraph::commitTextRangeMarkup(::sal_Int32 nType
, const OUString
& aIdentifier
, const uno::Reference
< text::XTextRange
> & xRange
,
175 const css::uno::Reference
< css::container::XStringKeyMap
> & xMarkupInfoContainer
)
177 SolarMutexGuard aGuard
;
178 SwXTextMarkup::commitTextRangeMarkup( nType
, aIdentifier
, xRange
, xMarkupInfoContainer
);
181 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
)
183 SolarMutexGuard aGuard
;
184 SwXTextMarkup::commitStringMarkup( nType
, rIdentifier
, nStart
, nLength
, rxMarkupInfoContainer
);
187 // text::XFlatParagraph:
188 OUString SAL_CALL
SwXFlatParagraph::getText()
193 // text::XFlatParagraph:
194 void SAL_CALL
SwXFlatParagraph::setChecked( ::sal_Int32 nType
, sal_Bool bVal
)
196 SolarMutexGuard aGuard
;
201 if ( text::TextMarkupType::SPELLCHECK
== nType
)
203 GetTextNode()->SetWrongDirty(
204 bVal
? sw::WrongState::DONE
: sw::WrongState::TODO
);
206 else if ( text::TextMarkupType::SMARTTAG
== nType
)
207 GetTextNode()->SetSmartTagDirty( !bVal
);
208 else if( text::TextMarkupType::PROOFREADING
== nType
)
210 GetTextNode()->SetGrammarCheckDirty( !bVal
);
212 sw::finishGrammarCheckFor(*GetTextNode());
216 // text::XFlatParagraph:
217 sal_Bool SAL_CALL
SwXFlatParagraph::isChecked( ::sal_Int32 nType
)
219 SolarMutexGuard aGuard
;
222 if ( text::TextMarkupType::SPELLCHECK
== nType
)
223 return !GetTextNode()->IsWrongDirty();
224 else if ( text::TextMarkupType::PROOFREADING
== nType
)
225 return !GetTextNode()->IsGrammarCheckDirty();
226 else if ( text::TextMarkupType::SMARTTAG
== nType
)
227 return !GetTextNode()->IsSmartTagDirty();
233 // text::XFlatParagraph:
234 sal_Bool SAL_CALL
SwXFlatParagraph::isModified()
236 SolarMutexGuard aGuard
;
237 return !GetTextNode() || GetTextNode()->GetText() != maOrigText
;
240 // text::XFlatParagraph:
241 lang::Locale SAL_CALL
SwXFlatParagraph::getLanguageOfText(::sal_Int32 nPos
, ::sal_Int32 nLen
)
243 SolarMutexGuard aGuard
;
245 return LanguageTag::convertToLocale( LANGUAGE_NONE
);
247 const lang::Locale
aLocale( SW_BREAKITER()->GetLocale( GetTextNode()->GetLang(nPos
, nLen
) ) );
251 // text::XFlatParagraph:
252 lang::Locale SAL_CALL
SwXFlatParagraph::getPrimaryLanguageOfText(::sal_Int32 nPos
, ::sal_Int32 nLen
)
254 SolarMutexGuard aGuard
;
257 return LanguageTag::convertToLocale( LANGUAGE_NONE
);
259 const lang::Locale
aLocale( SW_BREAKITER()->GetLocale( GetTextNode()->GetLang(nPos
, nLen
) ) );
263 // text::XFlatParagraph:
264 void SAL_CALL
SwXFlatParagraph::changeText(::sal_Int32 nPos
, ::sal_Int32 nLen
, const OUString
& aNewText
, const css::uno::Sequence
< css::beans::PropertyValue
> & aAttributes
)
266 SolarMutexGuard aGuard
;
271 SwTextNode
*const pOldTextNode
= GetTextNode();
273 if (nPos
< 0 || pOldTextNode
->Len() < nPos
|| nLen
< 0 || o3tl::make_unsigned(pOldTextNode
->Len()) < static_cast<sal_uInt32
>(nPos
) + nLen
)
275 throw lang::IllegalArgumentException();
278 SwPaM
aPaM( *GetTextNode(), nPos
, *GetTextNode(), nPos
+nLen
);
280 UnoActionContext
aAction( &GetTextNode()->GetDoc() );
282 const rtl::Reference
<SwXTextRange
> xRange
=
283 SwXTextRange::CreateXTextRange(
284 GetTextNode()->GetDoc(), *aPaM
.GetPoint(), aPaM
.GetMark() );
287 for ( const auto& rAttribute
: aAttributes
)
288 xRange
->setPropertyValue( rAttribute
.Name
, rAttribute
.Value
);
291 IDocumentContentOperations
& rIDCO
= pOldTextNode
->getIDocumentContentOperations();
292 rIDCO
.ReplaceRange( aPaM
, aNewText
, false );
294 ClearTextNode(); // TODO: is this really needed?
297 // text::XFlatParagraph:
298 void SAL_CALL
SwXFlatParagraph::changeAttributes(::sal_Int32 nPos
, ::sal_Int32 nLen
, const css::uno::Sequence
< css::beans::PropertyValue
> & aAttributes
)
300 SolarMutexGuard aGuard
;
305 if (nPos
< 0 || GetTextNode()->Len() < nPos
|| nLen
< 0 || o3tl::make_unsigned(GetTextNode()->Len()) < static_cast<sal_uInt32
>(nPos
) + nLen
)
307 throw lang::IllegalArgumentException();
310 SwPaM
aPaM( *GetTextNode(), nPos
, *GetTextNode(), nPos
+nLen
);
312 UnoActionContext
aAction( &GetTextNode()->GetDoc() );
314 const rtl::Reference
<SwXTextRange
> xRange
=
315 SwXTextRange::CreateXTextRange(
316 GetTextNode()->GetDoc(), *aPaM
.GetPoint(), aPaM
.GetMark() );
319 for ( const auto& rAttribute
: aAttributes
)
320 xRange
->setPropertyValue( rAttribute
.Name
, rAttribute
.Value
);
323 ClearTextNode(); // TODO: is this really needed?
326 // text::XFlatParagraph:
327 css::uno::Sequence
< ::sal_Int32
> SAL_CALL
SwXFlatParagraph::getLanguagePortions()
329 return css::uno::Sequence
< ::sal_Int32
>();
332 SwXFlatParagraphIterator::SwXFlatParagraphIterator( SwDoc
& rDoc
, sal_Int32 nType
, bool bAutomatic
)
335 mbAutomatic( bAutomatic
),
337 mnEndNode( rDoc
.GetNodes().Count() )
339 //mnStartNode = mnCurrentNode = get node from current cursor TODO!
341 // register as listener and get notified when document is closed
342 StartListening(mpDoc
->getIDocumentStylePoolAccess().GetPageDescFromPool( RES_POOLPAGE_STANDARD
)->GetNotifier());
345 SwXFlatParagraphIterator::~SwXFlatParagraphIterator()
347 SolarMutexGuard aGuard
;
351 void SwXFlatParagraphIterator::Notify( const SfxHint
& rHint
)
353 if(rHint
.GetId() == SfxHintId::Dying
)
355 SolarMutexGuard aGuard
;
360 uno::Reference
< text::XFlatParagraph
> SwXFlatParagraphIterator::getFirstPara()
362 return getNextPara(); // TODO
365 uno::Reference
< text::XFlatParagraph
> SwXFlatParagraphIterator::getNextPara()
367 SolarMutexGuard aGuard
;
369 uno::Reference
< text::XFlatParagraph
> xRet
;
373 SwTextNode
* pRet
= nullptr;
376 SwViewShell
* pViewShell
= mpDoc
->getIDocumentLayoutAccess().GetCurrentViewShell();
378 SwPageFrame
* pCurrentPage
= pViewShell
? pViewShell
->Imp()->GetFirstVisPage(pViewShell
->GetOut()) : nullptr;
379 SwPageFrame
* pStartPage
= pCurrentPage
;
380 SwPageFrame
* pStopPage
= nullptr;
382 while ( pCurrentPage
&& pCurrentPage
!= pStopPage
)
384 if (mnType
!= text::TextMarkupType::SPELLCHECK
|| pCurrentPage
->IsInvalidSpelling() )
386 // this method is supposed to return an empty paragraph in case Online Checking is disabled
387 if ( ( mnType
== text::TextMarkupType::PROOFREADING
|| mnType
== text::TextMarkupType::SPELLCHECK
)
388 && !pViewShell
->GetViewOptions()->IsOnlineSpell() )
391 // search for invalid content:
392 SwContentFrame
* pCnt
= pCurrentPage
->ContainsContent();
394 while( pCnt
&& pCurrentPage
->IsAnLower( pCnt
) )
396 if (pCnt
->IsTextFrame())
398 SwTextFrame
const*const pText(static_cast<SwTextFrame
const*>(pCnt
));
399 if (sw::MergedPara
const*const pMergedPara
= pText
->GetMergedPara()
402 SwTextNode
* pTextNode(nullptr);
403 for (auto const& e
: pMergedPara
->extents
)
405 if (e
.pNode
!= pTextNode
)
408 if ((mnType
== text::TextMarkupType::SPELLCHECK
409 && pTextNode
->IsWrongDirty()) ||
410 (mnType
== text::TextMarkupType::PROOFREADING
411 && pTextNode
->IsGrammarCheckDirty()))
421 SwTextNode
const*const pTextNode(pText
->GetTextNodeFirst());
422 if ((mnType
== text::TextMarkupType::SPELLCHECK
423 && pTextNode
->IsWrongDirty()) ||
424 (mnType
== text::TextMarkupType::PROOFREADING
425 && pTextNode
->IsGrammarCheckDirty()))
428 pRet
= const_cast<SwTextNode
*>(pTextNode
);
438 pCnt
= pCnt
->GetNextContentFrame();
445 // if there is no invalid text node on the current page,
446 // we validate the page
447 pCurrentPage
->ValidateSpelling();
449 // proceed with next page, wrap at end of document if required:
450 pCurrentPage
= static_cast<SwPageFrame
*>(pCurrentPage
->GetNext());
452 if ( !pCurrentPage
&& !pStopPage
)
454 pStopPage
= pStartPage
;
455 pCurrentPage
= static_cast<SwPageFrame
*>(pViewShell
->GetLayout()->Lower());
459 else // non-automatic checking
461 const SwNodes
& rNodes
= mpDoc
->GetNodes();
462 const SwNodeOffset nMaxNodes
= rNodes
.Count();
464 while ( mnCurrentNode
< mnEndNode
&& mnCurrentNode
< nMaxNodes
)
466 SwNode
* pNd
= rNodes
[ mnCurrentNode
];
470 pRet
= pNd
->GetTextNode();
474 if ( mnCurrentNode
== mnEndNode
)
476 mnCurrentNode
= SwNodeOffset(0);
477 mnEndNode
= SwNodeOffset(0);
484 // Expand the string:
485 const ModelToViewHelper
aConversionMap(*pRet
, mpDoc
->getIDocumentLayoutAccess().GetCurrentLayout());
486 const OUString
& aExpandText
= aConversionMap
.getViewText();
488 xRet
= new SwXFlatParagraph( *pRet
, aExpandText
, aConversionMap
);
494 uno::Reference
< text::XFlatParagraph
> SwXFlatParagraphIterator::getLastPara()
496 return getNextPara();
499 uno::Reference
< text::XFlatParagraph
> SwXFlatParagraphIterator::getParaAfter(const uno::Reference
< text::XFlatParagraph
> & xPara
)
501 SolarMutexGuard aGuard
;
503 uno::Reference
< text::XFlatParagraph
> xRet
;
507 SwXFlatParagraph
* const pFlatParagraph(dynamic_cast<SwXFlatParagraph
*>(xPara
.get()));
508 SAL_WARN_IF(!pFlatParagraph
, "sw.core", "invalid argument");
509 if ( !pFlatParagraph
)
512 SwTextNode
const*const pCurrentNode
= pFlatParagraph
->GetTextNode();
517 SwTextNode
* pNextTextNode
= nullptr;
518 const SwNodes
& rNodes
= pCurrentNode
->GetDoc().GetNodes();
520 for( SwNodeOffset nCurrentNode
= pCurrentNode
->GetIndex() + 1; nCurrentNode
< rNodes
.Count(); ++nCurrentNode
)
522 SwNode
* pNd
= rNodes
[ nCurrentNode
];
523 pNextTextNode
= pNd
->GetTextNode();
530 // Expand the string:
531 const ModelToViewHelper
aConversionMap(*pNextTextNode
, mpDoc
->getIDocumentLayoutAccess().GetCurrentLayout());
532 const OUString
& aExpandText
= aConversionMap
.getViewText();
534 xRet
= new SwXFlatParagraph( *pNextTextNode
, aExpandText
, aConversionMap
);
540 uno::Reference
< text::XFlatParagraph
> SwXFlatParagraphIterator::getParaBefore(const uno::Reference
< text::XFlatParagraph
> & xPara
)
542 SolarMutexGuard aGuard
;
544 uno::Reference
< text::XFlatParagraph
> xRet
;
548 SwXFlatParagraph
* const pFlatParagraph(dynamic_cast<SwXFlatParagraph
*>(xPara
.get()));
549 SAL_WARN_IF(!pFlatParagraph
, "sw.core", "invalid argument");
550 if ( !pFlatParagraph
)
553 SwTextNode
const*const pCurrentNode
= pFlatParagraph
->GetTextNode();
558 SwTextNode
* pPrevTextNode
= nullptr;
559 const SwNodes
& rNodes
= pCurrentNode
->GetDoc().GetNodes();
561 for( SwNodeOffset nCurrentNode
= pCurrentNode
->GetIndex() - 1; nCurrentNode
> SwNodeOffset(0); --nCurrentNode
)
563 SwNode
* pNd
= rNodes
[ nCurrentNode
];
564 pPrevTextNode
= pNd
->GetTextNode();
571 // Expand the string:
572 const ModelToViewHelper
aConversionMap(*pPrevTextNode
, mpDoc
->getIDocumentLayoutAccess().GetCurrentLayout());
573 const OUString
& aExpandText
= aConversionMap
.getViewText();
575 xRet
= new SwXFlatParagraph( *pPrevTextNode
, aExpandText
, aConversionMap
);
581 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */