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
))
74 SwXFlatParagraph::~SwXFlatParagraph()
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
);
93 SwXFlatParagraph::setPropertyValue(const OUString
&, const uno::Any
&)
95 throw lang::IllegalArgumentException("no values can be set",
96 static_cast< ::cppu::OWeakObject
*>(this), 0);
100 SwXFlatParagraph::getPropertyValue(const OUString
& rPropertyName
)
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;
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;
125 nCount
= pCurrentNode
->GetDoc().GetNodes().Count().get();
126 return uno::Any( nCount
);
132 SwXFlatParagraph::addPropertyChangeListener(
133 const OUString
& /*rPropertyName*/,
134 const uno::Reference
< beans::XPropertyChangeListener
>& /*xListener*/)
137 "SwXFlatParagraph::addPropertyChangeListener(): not implemented");
141 SwXFlatParagraph::removePropertyChangeListener(
142 const OUString
& /*rPropertyName*/,
143 const uno::Reference
< beans::XPropertyChangeListener
>& /*xListener*/)
146 "SwXFlatParagraph::removePropertyChangeListener(): not implemented");
150 SwXFlatParagraph::addVetoableChangeListener(
151 const OUString
& /*rPropertyName*/,
152 const uno::Reference
< beans::XVetoableChangeListener
>& /*xListener*/)
155 "SwXFlatParagraph::addVetoableChangeListener(): not implemented");
159 SwXFlatParagraph::removeVetoableChangeListener(
160 const OUString
& /*rPropertyName*/,
161 const uno::Reference
< beans::XVetoableChangeListener
>& /*xListener*/)
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()
192 // text::XFlatParagraph:
193 void SAL_CALL
SwXFlatParagraph::setChecked( ::sal_Int32 nType
, sal_Bool bVal
)
195 SolarMutexGuard aGuard
;
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
);
211 sw::finishGrammarCheckFor(*GetTextNode());
215 // text::XFlatParagraph:
216 sal_Bool SAL_CALL
SwXFlatParagraph::isChecked( ::sal_Int32 nType
)
218 SolarMutexGuard aGuard
;
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();
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
;
244 return LanguageTag::convertToLocale( LANGUAGE_NONE
);
246 const lang::Locale
aLocale( SW_BREAKITER()->GetLocale( GetTextNode()->GetLang(nPos
, nLen
) ) );
250 // text::XFlatParagraph:
251 lang::Locale SAL_CALL
SwXFlatParagraph::getPrimaryLanguageOfText(::sal_Int32 nPos
, ::sal_Int32 nLen
)
253 SolarMutexGuard aGuard
;
256 return LanguageTag::convertToLocale( LANGUAGE_NONE
);
258 const lang::Locale
aLocale( SW_BREAKITER()->GetLocale( GetTextNode()->GetLang(nPos
, nLen
) ) );
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
;
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() );
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
;
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() );
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
)
334 mbAutomatic( bAutomatic
),
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
;
350 void SwXFlatParagraphIterator::Notify( const SfxHint
& rHint
)
352 if(rHint
.GetId() == SfxHintId::Dying
)
354 SolarMutexGuard aGuard
;
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
;
372 SwTextNode
* pRet
= nullptr;
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() )
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
)
407 if ((mnType
== text::TextMarkupType::SPELLCHECK
408 && pTextNode
->IsWrongDirty()) ||
409 (mnType
== text::TextMarkupType::PROOFREADING
410 && pTextNode
->IsGrammarCheckDirty()))
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
);
437 pCnt
= pCnt
->GetNextContentFrame();
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
];
469 pRet
= pNd
->GetTextNode();
473 if ( mnCurrentNode
== mnEndNode
)
475 mnCurrentNode
= SwNodeOffset(0);
476 mnEndNode
= SwNodeOffset(0);
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
);
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
;
506 SwXFlatParagraph
* const pFlatParagraph(dynamic_cast<SwXFlatParagraph
*>(xPara
.get()));
507 SAL_WARN_IF(!pFlatParagraph
, "sw.core", "invalid argument");
508 if ( !pFlatParagraph
)
511 SwTextNode
const*const pCurrentNode
= pFlatParagraph
->GetTextNode();
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();
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
);
539 uno::Reference
< text::XFlatParagraph
> SwXFlatParagraphIterator::getParaBefore(const uno::Reference
< text::XFlatParagraph
> & xPara
)
541 SolarMutexGuard aGuard
;
543 uno::Reference
< text::XFlatParagraph
> xRet
;
547 SwXFlatParagraph
* const pFlatParagraph(dynamic_cast<SwXFlatParagraph
*>(xPara
.get()));
548 SAL_WARN_IF(!pFlatParagraph
, "sw.core", "invalid argument");
549 if ( !pFlatParagraph
)
552 SwTextNode
const*const pCurrentNode
= pFlatParagraph
->GetTextNode();
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();
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
);
580 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */