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 <com/sun/star/table/TableSortField.hpp>
21 #include <cppuhelper/exc_hlp.hxx>
22 #include <cppuhelper/supportsservice.hxx>
23 #include <svl/itemprop.hxx>
24 #include <o3tl/any.hxx>
25 #include <o3tl/safeint.hxx>
26 #include <osl/endian.h>
27 #include <unotools/collatorwrapper.hxx>
29 #include <autostyle_helper.hxx>
30 #include <swtypes.hxx>
31 #include <hintids.hxx>
36 #include <IDocumentUndoRedo.hxx>
37 #include <istyleaccess.hxx>
39 #include <unocrsr.hxx>
40 #include <unocrsrhelper.hxx>
41 #include <unoport.hxx>
43 #include <rootfrm.hxx>
46 #include <shellio.hxx>
48 #include <fmtruby.hxx>
50 #include <docstyle.hxx>
51 #include <fmtpdsc.hxx>
52 #include <pagedesc.hxx>
54 #include <fchrfmt.hxx>
55 #include <fmtautofmt.hxx>
56 #include <unotextrange.hxx>
57 #include <unotextcursor.hxx>
59 #include <unoprnms.hxx>
60 #include <unometa.hxx>
61 #include <unocontentcontrol.hxx>
62 #include <unotext.hxx>
63 #include <com/sun/star/text/TextMarkupType.hpp>
65 #include <vcl/svapp.hxx>
66 #include <unotools/syslocale.hxx>
67 #include <i18nlangtag/languagetag.hxx>
68 #include <SwStyleNameMapper.hxx>
69 #include <sortopt.hxx>
70 #include <com/sun/star/beans/PropertyAttribute.hpp>
71 #include <com/sun/star/beans/NamedValue.hpp>
72 #include <com/sun/star/i18n/WordType.hpp>
74 #include <unoparaframeenum.hxx>
75 #include <unoparagraph.hxx>
76 #include <iodetect.hxx>
77 #include <comphelper/propertyvalue.hxx>
78 #include <comphelper/servicehelper.hxx>
79 #include <comphelper/profilezone.hxx>
80 #include <comphelper/flagguard.hxx>
81 #include <swmodule.hxx>
84 using namespace ::com::sun::star
;
87 SwUnoInternalPaM::SwUnoInternalPaM(SwDoc
& rDoc
) :
88 SwPaM(rDoc
.GetNodes())
92 SwUnoInternalPaM::~SwUnoInternalPaM()
94 while( GetNext() != this)
96 // coverity[deref_arg] - the delete moves a new entry into GetNext()
101 SwUnoInternalPaM
& SwUnoInternalPaM::operator=(const SwPaM
& rPaM
)
103 const SwPaM
* pTmp
= &rPaM
;
104 *GetPoint() = *rPaM
.GetPoint();
108 *GetMark() = *rPaM
.GetMark();
112 while(&rPaM
!= (pTmp
= pTmp
->GetNext()))
115 new SwPaM(*pTmp
->GetMark(), *pTmp
->GetPoint(), this);
117 new SwPaM(*pTmp
->GetPoint(), this);
122 void SwUnoCursorHelper::SelectPam(SwPaM
& rPam
, const bool bExpand
)
131 else if (rPam
.HasMark())
137 void SwUnoCursorHelper::GetTextFromPam(SwPaM
& rPam
, OUString
& rBuffer
,
138 SwRootFrame
const*const pLayout
)
144 SvMemoryStream aStream
;
146 aStream
.SetEndian( SvStreamEndian::BIG
);
148 aStream
.SetEndian( SvStreamEndian::LITTLE
);
151 // TODO/MBA: looks like a BaseURL doesn't make sense here
152 SwReaderWriter::GetWriter( FILTER_TEXT_DLG
, OUString(), xWrt
);
156 SwWriter
aWriter( aStream
, rPam
);
157 xWrt
->m_bASCII_NoLastLineEnd
= true;
158 xWrt
->m_bExportParagraphNumbering
= false;
159 SwAsciiOptions aOpt
= xWrt
->GetAsciiOptions();
160 aOpt
.SetCharSet( RTL_TEXTENCODING_UNICODE
);
161 xWrt
->SetAsciiOptions( aOpt
);
162 xWrt
->m_bUCS2_WithStartChar
= false;
164 const bool bOldShowProgress
= xWrt
->m_bShowProgress
;
165 xWrt
->m_bShowProgress
= false;
166 xWrt
->m_bHideDeleteRedlines
= pLayout
&& pLayout
->IsHideRedlines();
167 // tdf#155951 SwWriter::Write calls EndAllAction, and that
168 // called SelectShell(), triggering selection change event, which
169 // resulted infinite recursion, if selectionChanged() calls
170 // XTextRange::getString() e.g. on the selected range.
171 ::comphelper::FlagRestorationGuard
g(g_bNoInterrupt
, true);
173 if( ! aWriter
.Write( xWrt
).IsError() )
175 const sal_uInt64 lUniLen
= aStream
.GetSize()/sizeof( sal_Unicode
);
176 if (lUniLen
< o3tl::make_unsigned(SAL_MAX_INT32
-1))
178 aStream
.WriteUInt16( '\0' );
181 aStream
.ResetError();
183 rtl_uString
*pStr
= rtl_uString_alloc(lUniLen
);
184 aStream
.ReadBytes(pStr
->buffer
, lUniLen
* sizeof(sal_Unicode
));
185 rBuffer
= OUString(pStr
, SAL_NO_ACQUIRE
);
188 xWrt
->m_bShowProgress
= bOldShowProgress
;
192 /// @throws lang::IllegalArgumentException
193 /// @throws uno::RuntimeException
195 lcl_setCharStyle(SwDoc
& rDoc
, const uno::Any
& rValue
, SfxItemSet
& rSet
)
197 SwDocShell
*const pDocSh
= rDoc
.GetDocShell();
202 if (!(rValue
>>= uStyle
))
204 throw lang::IllegalArgumentException();
207 SwStyleNameMapper::FillUIName(ProgName(uStyle
), sStyle
,
208 SwGetPoolIdFromName::ChrFmt
);
209 SwDocStyleSheet
*const pStyle
= static_cast<SwDocStyleSheet
*>(
210 pDocSh
->GetStyleSheetPool()->Find(sStyle
, SfxStyleFamily::Char
));
213 throw lang::IllegalArgumentException();
215 const SwFormatCharFormat
aFormat(pStyle
->GetCharFormat());
219 /// @throws lang::IllegalArgumentException
221 lcl_setAutoStyle(IStyleAccess
& rStyleAccess
, const uno::Any
& rValue
,
222 SfxItemSet
& rSet
, const bool bPara
)
225 if (!(rValue
>>= uStyle
))
227 throw lang::IllegalArgumentException();
229 std::shared_ptr
<SfxItemSet
> pStyle
= bPara
?
230 rStyleAccess
.getByName(uStyle
, IStyleAccess::AUTO_STYLE_PARA
):
231 rStyleAccess
.getByName(uStyle
, IStyleAccess::AUTO_STYLE_CHAR
);
234 throw lang::IllegalArgumentException();
237 SwFormatAutoFormat
aFormat( bPara
238 ? sal::static_int_cast
< sal_uInt16
>(RES_AUTO_STYLE
)
239 : sal::static_int_cast
< sal_uInt16
>(RES_TXTATR_AUTOFMT
) );
240 aFormat
.SetStyleHandle( pStyle
);
245 SwUnoCursorHelper::SetTextFormatColl(const uno::Any
& rAny
, SwPaM
& rPaM
)
247 SwDoc
& rDoc
= rPaM
.GetDoc();
248 SwDocShell
*const pDocSh
= rDoc
.GetDocShell();
254 SwStyleNameMapper::FillUIName(ProgName(uStyle
), sStyle
,
255 SwGetPoolIdFromName::TxtColl
);
256 SwDocStyleSheet
*const pStyle
= static_cast<SwDocStyleSheet
*>(
257 pDocSh
->GetStyleSheetPool()->Find(sStyle
, SfxStyleFamily::Para
));
260 throw lang::IllegalArgumentException();
263 SwTextFormatColl
*const pLocal
= pStyle
->GetCollection();
264 UnoActionContext
aAction(&rDoc
);
265 rDoc
.GetIDocumentUndoRedo().StartUndo( SwUndoId::START
, nullptr );
266 SwPaM
*pTmpCursor
= &rPaM
;
268 rDoc
.SetTextFormatColl(*pTmpCursor
, pLocal
);
269 pTmpCursor
= pTmpCursor
->GetNext();
270 } while ( pTmpCursor
!= &rPaM
);
271 rDoc
.GetIDocumentUndoRedo().EndUndo( SwUndoId::END
, nullptr );
275 SwUnoCursorHelper::SetPageDesc(
276 const uno::Any
& rValue
, SwDoc
& rDoc
, SfxItemSet
& rSet
)
279 if (!(rValue
>>= uDescName
))
283 std::unique_ptr
<SwFormatPageDesc
> pNewDesc
;
284 if(const SwFormatPageDesc
* pItem
= rSet
.GetItemIfSet( RES_PAGEDESC
))
286 pNewDesc
.reset(new SwFormatPageDesc(*pItem
));
290 pNewDesc
.reset(new SwFormatPageDesc());
293 SwStyleNameMapper::FillUIName(ProgName(uDescName
), sDescName
,
294 SwGetPoolIdFromName::PageDesc
);
295 if (!pNewDesc
->GetPageDesc() ||
296 (pNewDesc
->GetPageDesc()->GetName() != sDescName
))
299 if (!sDescName
.isEmpty())
301 SwPageDesc
*const pPageDesc
= SwPageDesc::GetByName(rDoc
, sDescName
);
304 throw lang::IllegalArgumentException();
306 pNewDesc
->RegisterToPageDesc(*pPageDesc
);
311 rSet
.ClearItem(RES_BREAK
);
312 rSet
.Put(SwFormatPageDesc());
316 rSet
.Put(std::move(pNewDesc
));
323 lcl_SetNodeNumStart(SwPaM
& rCursor
, uno::Any
const& rValue
)
327 sal_uInt16 nStt
= (nTmp
< 0 ? USHRT_MAX
: o3tl::narrowing
<sal_uInt16
>(nTmp
));
328 SwDoc
& rDoc
= rCursor
.GetDoc();
329 UnoActionContext
aAction(&rDoc
);
331 if( rCursor
.GetNext() != &rCursor
) // MultiSelection?
333 rDoc
.GetIDocumentUndoRedo().StartUndo( SwUndoId::START
, nullptr );
334 SwPamRanges
aRangeArr( rCursor
);
335 SwPaM
aPam( *rCursor
.GetPoint() );
336 for( size_t n
= 0; n
< aRangeArr
.Count(); ++n
)
338 rDoc
.SetNumRuleStart(*aRangeArr
.SetPam( n
, aPam
).GetPoint());
339 rDoc
.SetNodeNumStart(*aRangeArr
.SetPam( n
, aPam
).GetPoint(),
342 rDoc
.GetIDocumentUndoRedo().EndUndo( SwUndoId::END
, nullptr );
346 rDoc
.SetNumRuleStart( *rCursor
.GetPoint());
347 rDoc
.SetNodeNumStart( *rCursor
.GetPoint(), nStt
);
352 lcl_setCharFormatSequence(SwPaM
& rPam
, uno::Any
const& rValue
)
354 uno::Sequence
<OUString
> aCharStyles
;
355 if (!(rValue
>>= aCharStyles
))
360 for (sal_Int32 nStyle
= 0; nStyle
< aCharStyles
.getLength(); nStyle
++)
363 rPam
.GetDoc().GetIDocumentUndoRedo().StartUndo(SwUndoId::START
, nullptr);
364 aStyle
<<= aCharStyles
.getConstArray()[nStyle
];
365 // create a local set and apply each format directly
366 SfxItemSetFixed
<RES_TXTATR_CHARFMT
, RES_TXTATR_CHARFMT
> aSet(rPam
.GetDoc().GetAttrPool());
367 lcl_setCharStyle(rPam
.GetDoc(), aStyle
, aSet
);
368 // the first style should replace the current attributes,
369 // all other have to be added
370 SwUnoCursorHelper::SetCursorAttr(rPam
, aSet
, nStyle
371 ? SetAttrMode::DONTREPLACE
372 : SetAttrMode::DEFAULT
);
373 rPam
.GetDoc().GetIDocumentUndoRedo().EndUndo(SwUndoId::START
, nullptr);
379 lcl_setDropcapCharStyle(SwPaM
const & rPam
, SfxItemSet
& rItemSet
,
380 uno::Any
const& rValue
)
383 if (!(rValue
>>= uStyle
))
385 throw lang::IllegalArgumentException();
388 SwStyleNameMapper::FillUIName(ProgName(uStyle
), sStyle
,
389 SwGetPoolIdFromName::ChrFmt
);
390 SwDoc
& rDoc
= rPam
.GetDoc();
391 //default character style must not be set as default format
392 SwDocStyleSheet
*const pStyle
= static_cast<SwDocStyleSheet
*>(
394 ->GetStyleSheetPool()->Find(sStyle
, SfxStyleFamily::Char
));
395 if (!pStyle
|| pStyle
->GetCharFormat() == rDoc
.GetDfltCharFormat())
397 throw lang::IllegalArgumentException();
399 std::unique_ptr
<SwFormatDrop
> pDrop
;
400 if (const SwFormatDrop
* pItem
= rItemSet
.GetItemIfSet(RES_PARATR_DROP
))
402 pDrop
.reset(new SwFormatDrop(*pItem
));
406 pDrop
.reset(new SwFormatDrop
);
408 const rtl::Reference
<SwDocStyleSheet
> xStyle(new SwDocStyleSheet(*pStyle
));
409 pDrop
->SetCharFormat(xStyle
->GetCharFormat());
410 rItemSet
.Put(std::move(pDrop
));
414 lcl_setRubyCharstyle(SfxItemSet
& rItemSet
, uno::Any
const& rValue
)
417 if (!(rValue
>>= sTmp
))
419 throw lang::IllegalArgumentException();
422 std::unique_ptr
<SwFormatRuby
> pRuby
;
423 if (const SwFormatRuby
* pItem
= rItemSet
.GetItemIfSet(RES_TXTATR_CJK_RUBY
))
425 pRuby
.reset(new SwFormatRuby(*pItem
));
429 pRuby
.reset(new SwFormatRuby(OUString()));
432 SwStyleNameMapper::FillUIName(ProgName(sTmp
), sStyle
,
433 SwGetPoolIdFromName::ChrFmt
);
434 pRuby
->SetCharFormatName(sStyle
);
435 pRuby
->SetCharFormatId(0);
436 if (!sStyle
.isEmpty())
438 const sal_uInt16 nId
= SwStyleNameMapper::GetPoolIdFromUIName(
439 sStyle
, SwGetPoolIdFromName::ChrFmt
);
440 pRuby
->SetCharFormatId(nId
);
442 rItemSet
.Put(std::move(pRuby
));
446 SwUnoCursorHelper::SetCursorPropertyValue(
447 SfxItemPropertyMapEntry
const& rEntry
, const uno::Any
& rValue
,
448 SwPaM
& rPam
, SfxItemSet
& rItemSet
)
450 if (!(rEntry
.nFlags
& beans::PropertyAttribute::MAYBEVOID
) &&
451 (rValue
.getValueType() == cppu::UnoType
<void>::get()))
458 case RES_TXTATR_CHARFMT
:
459 lcl_setCharStyle(rPam
.GetDoc(), rValue
, rItemSet
);
461 case RES_TXTATR_AUTOFMT
:
462 lcl_setAutoStyle(rPam
.GetDoc().GetIStyleAccess(),
463 rValue
, rItemSet
, false);
465 case FN_UNO_CHARFMT_SEQUENCE
:
466 lcl_setCharFormatSequence(rPam
, rValue
);
468 case FN_UNO_PARA_STYLE
:
469 SwUnoCursorHelper::SetTextFormatColl(rValue
, rPam
);
472 lcl_setAutoStyle(rPam
.GetDoc().GetIStyleAccess(),
473 rValue
, rItemSet
, true);
475 case FN_UNO_PAGE_STYLE
:
476 //FIXME nothing here?
478 case FN_UNO_NUM_START_VALUE
:
479 lcl_SetNodeNumStart( rPam
, rValue
);
481 case FN_UNO_NUM_LEVEL
:
484 case FN_UNO_IS_NUMBER
:
485 case FN_UNO_PARA_NUM_AUTO_FORMAT
:
487 // multi selection is not considered
488 SwTextNode
*const pTextNd
= rPam
.GetPointNode().GetTextNode();
491 throw lang::IllegalArgumentException();
493 if (FN_UNO_NUM_LEVEL
== rEntry
.nWID
)
495 sal_Int16 nLevel
= 0;
496 if (rValue
>>= nLevel
)
498 if (nLevel
< 0 || MAXLEVEL
<= nLevel
)
500 throw lang::IllegalArgumentException(
501 u
"invalid NumberingLevel"_ustr
, nullptr, 0);
503 pTextNd
->SetAttrListLevel(nLevel
);
507 else if (FN_UNO_LIST_ID
== rEntry
.nWID
)
510 if (rValue
>>= sListId
)
512 pTextNd
->SetListId( sListId
);
515 else if (FN_UNO_IS_NUMBER
== rEntry
.nWID
)
517 bool bIsNumber(false);
518 if ((rValue
>>= bIsNumber
) && !bIsNumber
)
520 pTextNd
->SetCountedInList( false );
523 else if (FN_UNO_PARA_NUM_AUTO_FORMAT
== rEntry
.nWID
)
525 std::shared_ptr
<SfxItemSet
> pAutoStyle
;
526 if (uno::Sequence
<beans::NamedValue
> props
; rValue
>>= props
)
528 // TODO create own map for this, it contains UNO_NAME_DISPLAY_NAME? or make property readable so ODF export can map it to a automatic style?
529 SfxItemPropertySet
const& rPropSet(*aSwMapProvider
.GetPropertySet(PROPERTY_MAP_CHAR_AUTO_STYLE
));
530 SfxItemPropertyMap
const& rMap(rPropSet
.getPropertyMap());
532 <RES_CHRATR_BEGIN
, RES_CHRATR_END
-1,
533 RES_TXTATR_CHARFMT
, RES_TXTATR_CHARFMT
,
534 RES_UNKNOWNATR_BEGIN
, RES_UNKNOWNATR_END
-1>
535 items( rPam
.GetDoc().GetAttrPool() );
537 for (beans::NamedValue
const& prop
: props
)
539 SfxItemPropertyMapEntry
const*const pEntry
=
540 rMap
.getByName(prop
.Name
);
543 throw beans::UnknownPropertyException(
544 "Unknown property: " + prop
.Name
);
546 if (pEntry
->nFlags
& beans::PropertyAttribute::READONLY
)
548 throw beans::PropertyVetoException(
549 "Property is read-only: " + prop
.Name
);
551 if (prop
.Name
== "CharStyleName")
553 lcl_setCharStyle(rPam
.GetDoc(), prop
.Value
, items
);
557 SfxItemPropertySet::setPropertyValue(*pEntry
, prop
.Value
, items
);
561 IStyleAccess
& rStyleAccess
= rPam
.GetDoc().GetIStyleAccess();
562 // Add it to the autostyle pool, needed by the ODT export.
563 pAutoStyle
= rStyleAccess
.getAutomaticStyle(items
, IStyleAccess::AUTO_STYLE_CHAR
);
565 else if (OUString styleName
; rValue
>>= styleName
)
567 IStyleAccess
& rStyleAccess
= rPam
.GetDoc().GetIStyleAccess();
568 pAutoStyle
= rStyleAccess
.getByName(styleName
, IStyleAccess::AUTO_STYLE_CHAR
);
572 SwFormatAutoFormat
item(RES_PARATR_LIST_AUTOFMT
);
573 // note: paragraph auto styles have ParaStyleName property for the parent style; character auto styles currently do not because there's a separate hint, but for this it would be a good way to add it in order to export it as style:parent-style-name, see XMLTextParagraphExport::Add()
574 item
.SetStyleHandle(pAutoStyle
);
575 pTextNd
->SetAttr(item
);
578 //PROPERTY_MAYBEVOID!
581 case FN_NUMBER_NEWSTART
:
584 if (!(rValue
>>= bVal
))
586 throw lang::IllegalArgumentException();
588 rPam
.GetDoc().SetNumRuleStart(*rPam
.GetPoint(), bVal
);
591 case FN_UNO_NUM_RULES
:
592 SwUnoCursorHelper::setNumberingProperty(rValue
, rPam
);
594 case RES_PARATR_DROP
:
596 if (MID_DROPCAP_CHAR_STYLE_NAME
== rEntry
.nMemberId
)
598 lcl_setDropcapCharStyle(rPam
, rItemSet
, rValue
);
606 case RES_TXTATR_CJK_RUBY
:
608 if (MID_RUBY_CHARSTYLE
== rEntry
.nMemberId
)
610 lcl_setRubyCharstyle(rItemSet
, rValue
);
620 if (MID_PAGEDESC_PAGEDESCNAME
== rEntry
.nMemberId
)
622 SwUnoCursorHelper::SetPageDesc(
623 rValue
, rPam
.GetDoc(), rItemSet
);
638 SwUnoCursorHelper::GetCurTextFormatColl(SwPaM
& rPaM
, const bool bConditional
)
640 static constexpr sal_Int32 nMaxLookup
= 1000;
641 SwFormatColl
*pFormat
= nullptr;
643 SwPaM
*pTmpCursor
= &rPaM
;
646 const SwNodeOffset nSttNd
= pTmpCursor
->Start()->GetNodeIndex();
647 const SwNodeOffset nEndNd
= pTmpCursor
->End()->GetNodeIndex();
649 if( nEndNd
- nSttNd
>= SwNodeOffset(nMaxLookup
) )
655 const SwNodes
& rNds
= rPaM
.GetDoc().GetNodes();
656 for( SwNodeOffset n
= nSttNd
; n
<= nEndNd
; ++n
)
658 SwTextNode
const*const pNd
= rNds
[ n
]->GetTextNode();
661 SwFormatColl
*const pNdFormat
= bConditional
662 ? pNd
->GetFormatColl() : &pNd
->GetAnyFormatColl();
667 else if( pFormat
!= pNdFormat
)
675 pTmpCursor
= pTmpCursor
->GetNext();
676 } while ( pTmpCursor
!= &rPaM
);
677 return bError
? nullptr : pFormat
;
680 SwUnoCursor
& SwXTextCursor::GetCursor()
681 { return *m_pUnoCursor
; }
683 SwPaM
const* SwXTextCursor::GetPaM() const
684 { return m_pUnoCursor
.get(); }
686 SwPaM
* SwXTextCursor::GetPaM()
687 { return m_pUnoCursor
.get(); }
689 SwDoc
const* SwXTextCursor::GetDoc() const
690 { return m_pUnoCursor
? &m_pUnoCursor
->GetDoc() : nullptr; }
692 SwDoc
* SwXTextCursor::GetDoc()
693 { return m_pUnoCursor
? &m_pUnoCursor
->GetDoc() : nullptr; }
695 SwXTextCursor::SwXTextCursor(
697 uno::Reference
< text::XText
> xParent
,
698 const CursorType eType
,
699 const SwPosition
& rPos
,
700 SwPosition
const*const pMark
)
701 : m_rPropSet(*aSwMapProvider
.GetPropertySet(PROPERTY_MAP_TEXT_CURSOR
))
703 , m_xParentText(std::move(xParent
))
704 , m_pUnoCursor(rDoc
.CreateUnoCursor(rPos
))
708 m_pUnoCursor
->SetMark();
709 *m_pUnoCursor
->GetMark() = *pMark
;
713 SwXTextCursor::SwXTextCursor(uno::Reference
< text::XText
> xParent
,
714 SwPaM
const& rSourceCursor
, const CursorType eType
)
715 : m_rPropSet(*aSwMapProvider
.GetPropertySet(PROPERTY_MAP_TEXT_CURSOR
))
717 , m_xParentText(std::move(xParent
))
718 , m_pUnoCursor(rSourceCursor
.GetDoc().CreateUnoCursor(*rSourceCursor
.GetPoint()))
720 if (rSourceCursor
.HasMark())
722 m_pUnoCursor
->SetMark();
723 *m_pUnoCursor
->GetMark() = *rSourceCursor
.GetMark();
727 SwXTextCursor::~SwXTextCursor()
729 SolarMutexGuard g
; // #i105557#: call dtor with locked solar mutex
730 m_pUnoCursor
.reset(nullptr); // need to delete this with SolarMutex held
733 void SwXTextCursor::DeleteAndInsert(std::u16string_view aText
,
734 ::sw::DeleteAndInsertMode
const eMode
)
736 auto pUnoCursor
= static_cast<SwCursor
*>(m_pUnoCursor
.get());
741 SwDoc
& rDoc
= pUnoCursor
->GetDoc();
742 UnoActionContext
aAction(&rDoc
);
743 const sal_Int32 nTextLen
= aText
.size();
744 rDoc
.GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT
, nullptr);
745 auto pCurrent
= pUnoCursor
;
748 if (pCurrent
->HasMark())
750 rDoc
.getIDocumentContentOperations().DeleteAndJoin(*pCurrent
,
751 // is it "delete" or "replace"?
752 (nTextLen
!= 0 || eMode
& ::sw::DeleteAndInsertMode::ForceReplace
) ? SwDeleteFlags::ArtificialSelection
: SwDeleteFlags::Default
);
756 // Store node and content indexes prior to insertion: to select the inserted text,
757 // we need to account for possible surrogate pairs, combining characters, etc.; it
758 // is easier to just restore the correct position from the indexes.
759 const auto start
= pCurrent
->Start();
760 const auto nodeIndex
= start
->GetNodeIndex();
761 const auto contentIndex
= start
->GetContentIndex();
763 SwUnoCursorHelper::DocInsertStringSplitCR(
764 rDoc
, SwPaM(*start
, pCurrent
), aText
, bool(eMode
& ::sw::DeleteAndInsertMode::ForceExpandHints
)));
765 OSL_ENSURE( bSuccess
, "Doc->Insert(Str) failed." );
768 pCurrent
->GetPoint()->Assign(nodeIndex
, contentIndex
);
770 pCurrent
= pCurrent
->GetNext();
771 } while (pCurrent
!= pUnoCursor
);
772 rDoc
.GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT
, nullptr);
777 enum ForceIntoMetaMode
{ META_CHECK_BOTH
, META_INIT_START
, META_INIT_END
};
779 enum ForceIntoContentControlMode
781 CONTENT_CONTROL_CHECK_BOTH
,
782 CONTENT_CONTROL_INIT_START
,
783 CONTENT_CONTROL_INIT_END
788 lcl_ForceIntoMeta(SwPaM
& rCursor
,
789 uno::Reference
<text::XText
> const & xParentText
,
790 const enum ForceIntoMetaMode eMode
)
792 bool bRet( true ); // means not forced in META_CHECK_BOTH
793 SwXMeta
const * const pXMeta( dynamic_cast<SwXMeta
*>(xParentText
.get()) );
794 OSL_ENSURE(pXMeta
, "no parent?");
796 throw uno::RuntimeException();
797 SwTextNode
* pTextNode
;
800 const bool bSuccess( pXMeta
->SetContentRange(pTextNode
, nStart
, nEnd
) );
801 OSL_ENSURE(bSuccess
, "no pam?");
803 throw uno::RuntimeException();
804 // force the cursor back into the meta if it has moved outside
805 SwPosition
start(*pTextNode
, nStart
);
806 SwPosition
end(*pTextNode
, nEnd
);
809 case META_INIT_START
:
810 *rCursor
.GetPoint() = start
;
813 *rCursor
.GetPoint() = end
;
815 case META_CHECK_BOTH
:
816 if (*rCursor
.Start() < start
)
818 *rCursor
.Start() = std::move(start
);
821 if (*rCursor
.End() > end
)
823 *rCursor
.End() = std::move(end
);
833 bool lcl_ForceIntoContentControl(SwPaM
& rCursor
, const uno::Reference
<text::XText
>& xParentText
,
834 ForceIntoContentControlMode eMode
)
836 bool bRet
= true; // means not forced in CONTENT_CONTROL_CHECK_BOTH
837 auto pXContentControl
= dynamic_cast<SwXContentControl
*>(xParentText
.get());
838 if (!pXContentControl
)
840 SAL_WARN("sw.core", "lcl_ForceIntoContentControl: no parent text");
841 throw uno::RuntimeException();
844 SwTextNode
* pTextNode
;
847 bool bSuccess
= pXContentControl
->SetContentRange(pTextNode
, nStart
, nEnd
);
850 SAL_WARN("sw.core", "lcl_ForceIntoContentControl: SetContentRange() failed");
851 throw uno::RuntimeException();
854 // Force the cursor back into the content control if it has moved outside.
855 SwPosition
aStart(*pTextNode
, nStart
);
856 SwPosition
aEnd(*pTextNode
, nEnd
);
859 case CONTENT_CONTROL_INIT_START
:
860 *rCursor
.GetPoint() = aStart
;
863 case CONTENT_CONTROL_INIT_END
:
864 *rCursor
.GetPoint() = aEnd
;
867 case CONTENT_CONTROL_CHECK_BOTH
:
868 if (*rCursor
.Start() < aStart
)
870 *rCursor
.Start() = std::move(aStart
);
874 if (*rCursor
.End() > aEnd
)
876 *rCursor
.End() = std::move(aEnd
);
886 bool SwXTextCursor::IsAtEndOfMeta() const
888 if (CursorType::Meta
== m_eType
)
890 sw::UnoCursorPointer
pCursor( m_pUnoCursor
);
891 SwXMeta
const*const pXMeta(
892 dynamic_cast<SwXMeta
*>(m_xParentText
.get()) );
893 OSL_ENSURE(pXMeta
, "no meta?");
894 if (pCursor
&& pXMeta
)
896 SwTextNode
* pTextNode
;
900 pXMeta
->SetContentRange(pTextNode
, nStart
, nEnd
) );
901 OSL_ENSURE(bSuccess
, "no pam?");
904 const SwPosition
end(*pTextNode
, nEnd
);
905 if ( (*pCursor
->GetPoint() == end
)
906 || (*pCursor
->GetMark() == end
))
916 bool SwXTextCursor::IsAtEndOfContentControl() const
918 if (CursorType::ContentControl
== m_eType
)
920 sw::UnoCursorPointer
pCursor( m_pUnoCursor
);
921 auto pXContentControl(
922 dynamic_cast<SwXContentControl
*>(m_xParentText
.get()) );
923 if (!pXContentControl
)
925 SAL_WARN("sw.core", "SwXTextCursor::IsAtEndOfContentControl: no content control");
927 if (pCursor
&& pXContentControl
)
929 SwTextNode
* pTextNode
;
933 pXContentControl
->SetContentRange(pTextNode
, nStart
, nEnd
) );
936 SAL_WARN("sw.core", "SwXTextCursor::IsAtEndOfContentControl: no pam");
940 const SwPosition
end(*pTextNode
, nEnd
);
941 if ( (*pCursor
->GetPoint() == end
)
942 || (*pCursor
->GetMark() == end
))
952 OUString
SwXTextCursor::getImplementationName()
954 return u
"SwXTextCursor"_ustr
;
957 sal_Bool SAL_CALL
SwXTextCursor::supportsService(const OUString
& rServiceName
)
959 return cppu::supportsService(this, rServiceName
);
962 uno::Sequence
< OUString
> SAL_CALL
963 SwXTextCursor::getSupportedServiceNames()
966 u
"com.sun.star.text.TextCursor"_ustr
,
967 u
"com.sun.star.style.CharacterProperties"_ustr
,
968 u
"com.sun.star.style.CharacterPropertiesAsian"_ustr
,
969 u
"com.sun.star.style.CharacterPropertiesComplex"_ustr
,
970 u
"com.sun.star.style.ParagraphProperties"_ustr
,
971 u
"com.sun.star.style.ParagraphPropertiesAsian"_ustr
,
972 u
"com.sun.star.style.ParagraphPropertiesComplex"_ustr
,
973 u
"com.sun.star.text.TextSortable"_ustr
977 void SAL_CALL
SwXTextCursor::collapseToStart()
979 SolarMutexGuard aGuard
;
981 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
983 if (rUnoCursor
.HasMark())
985 if (*rUnoCursor
.GetPoint() > *rUnoCursor
.GetMark())
987 rUnoCursor
.Exchange();
989 rUnoCursor
.DeleteMark();
993 void SAL_CALL
SwXTextCursor::collapseToEnd()
995 SolarMutexGuard aGuard
;
997 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
999 if (rUnoCursor
.HasMark())
1001 if (*rUnoCursor
.GetPoint() < *rUnoCursor
.GetMark())
1003 rUnoCursor
.Exchange();
1005 rUnoCursor
.DeleteMark();
1009 sal_Bool SAL_CALL
SwXTextCursor::isCollapsed()
1011 SolarMutexGuard aGuard
;
1014 sw::UnoCursorPointer
pUnoCursor(m_pUnoCursor
);
1015 if(pUnoCursor
&& pUnoCursor
->GetMark())
1017 bRet
= (*pUnoCursor
->GetPoint() == *pUnoCursor
->GetMark());
1023 SwXTextCursor::goLeft(sal_Int16 nCount
, sal_Bool Expand
)
1025 SolarMutexGuard aGuard
;
1027 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1029 SwUnoCursorHelper::SelectPam(rUnoCursor
, Expand
);
1030 bool bRet
= rUnoCursor
.Left( nCount
);
1031 if (CursorType::Meta
== m_eType
)
1033 bRet
= lcl_ForceIntoMeta(rUnoCursor
, m_xParentText
,
1037 else if (m_eType
== CursorType::ContentControl
)
1039 bRet
= lcl_ForceIntoContentControl(rUnoCursor
, m_xParentText
, CONTENT_CONTROL_CHECK_BOTH
)
1046 SwXTextCursor::goRight(sal_Int16 nCount
, sal_Bool Expand
)
1048 SolarMutexGuard aGuard
;
1050 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1052 SwUnoCursorHelper::SelectPam(rUnoCursor
, Expand
);
1053 bool bRet
= rUnoCursor
.Right(nCount
);
1054 if (CursorType::Meta
== m_eType
)
1056 bRet
= lcl_ForceIntoMeta(rUnoCursor
, m_xParentText
,
1060 else if (m_eType
== CursorType::ContentControl
)
1062 bRet
= lcl_ForceIntoContentControl(rUnoCursor
, m_xParentText
, CONTENT_CONTROL_CHECK_BOTH
)
1069 SwXTextCursor::gotoStart(sal_Bool Expand
)
1071 SolarMutexGuard aGuard
;
1072 comphelper::ProfileZone
aZone("gotoStart");
1074 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1076 SwUnoCursorHelper::SelectPam(rUnoCursor
, Expand
);
1077 if (CursorType::Body
== m_eType
)
1079 rUnoCursor
.Move( fnMoveBackward
, GoInDoc
);
1080 //check, that the cursor is not in a table
1081 SwTableNode
* pTableNode
= rUnoCursor
.GetPointNode().FindTableNode();
1084 rUnoCursor
.GetPoint()->Assign( *pTableNode
->EndOfSectionNode() );
1085 SwContentNode
* pCNode
= SwNodes::GoNext(rUnoCursor
.GetPoint());
1086 pTableNode
= pCNode
? pCNode
->FindTableNode() : nullptr;
1088 SwStartNode
const*const pTmp
=
1089 rUnoCursor
.GetPointNode().StartOfSectionNode();
1090 if (pTmp
->IsSectionNode())
1092 SwSectionNode
const*const pSectionStartNode
=
1093 static_cast<SwSectionNode
const*>(pTmp
);
1094 if (pSectionStartNode
->GetSection().IsHiddenFlag())
1096 SwNodes::GoNextSection(
1097 rUnoCursor
.GetPoint(), true, false);
1101 else if ( (CursorType::Frame
== m_eType
)
1102 || (CursorType::TableText
== m_eType
)
1103 || (CursorType::Header
== m_eType
)
1104 || (CursorType::Footer
== m_eType
)
1105 || (CursorType::Footnote
== m_eType
)
1106 || (CursorType::Redline
== m_eType
))
1108 rUnoCursor
.MoveSection(GoCurrSection
, fnSectionStart
);
1110 else if (CursorType::Meta
== m_eType
)
1112 lcl_ForceIntoMeta(rUnoCursor
, m_xParentText
, META_INIT_START
);
1114 else if (m_eType
== CursorType::ContentControl
)
1116 lcl_ForceIntoContentControl(rUnoCursor
, m_xParentText
, CONTENT_CONTROL_INIT_START
);
1121 SwXTextCursor::gotoEnd(sal_Bool Expand
)
1123 SolarMutexGuard aGuard
;
1124 comphelper::ProfileZone
aZone("gotoEnd");
1126 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1128 SwUnoCursorHelper::SelectPam(rUnoCursor
, Expand
);
1129 if (CursorType::Body
== m_eType
)
1131 rUnoCursor
.Move( fnMoveForward
, GoInDoc
);
1133 else if ( (CursorType::Frame
== m_eType
)
1134 || (CursorType::TableText
== m_eType
)
1135 || (CursorType::Header
== m_eType
)
1136 || (CursorType::Footer
== m_eType
)
1137 || (CursorType::Footnote
== m_eType
)
1138 || (CursorType::Redline
== m_eType
))
1140 rUnoCursor
.MoveSection( GoCurrSection
, fnSectionEnd
);
1142 else if (CursorType::Meta
== m_eType
)
1144 lcl_ForceIntoMeta(rUnoCursor
, m_xParentText
, META_INIT_END
);
1146 else if (m_eType
== CursorType::ContentControl
)
1148 lcl_ForceIntoContentControl(rUnoCursor
, m_xParentText
, CONTENT_CONTROL_INIT_END
);
1153 SwXTextCursor::gotoRange(
1154 const uno::Reference
< text::XTextRange
> & xRange
, sal_Bool bExpand
)
1156 SolarMutexGuard aGuard
;
1159 throw uno::RuntimeException();
1161 SwXTextRange
* pRange
= dynamic_cast<SwXTextRange
*>(xRange
.get());
1162 OTextCursorHelper
* pCursor
= dynamic_cast<OTextCursorHelper
*>(xRange
.get());
1163 if (!pRange
&& !pCursor
)
1165 throw uno::RuntimeException();
1168 gotoRangeImpl(pRange
, pCursor
, bExpand
);
1172 SwXTextCursor::gotoRangeImpl(
1173 SwXTextRange
* pRange
,
1174 OTextCursorHelper
* pCursor
,
1177 DBG_TESTSOLARMUTEX();
1178 assert((pRange
|| pCursor
) && "one of these parameters must be non-null");
1180 SwUnoCursor
& rOwnCursor( GetCursorOrThrow() );
1182 SwPaM
aPam(GetDoc()->GetNodes());
1183 const SwPaM
* pPam(nullptr);
1186 pPam
= pCursor
->GetPaM();
1190 if (pRange
->GetPositions(aPam
))
1198 throw uno::RuntimeException();
1202 SwStartNodeType eSearchNodeType
= SwNormalStartNode
;
1205 case CursorType::Frame
: eSearchNodeType
= SwFlyStartNode
; break;
1206 case CursorType::TableText
: eSearchNodeType
= SwTableBoxStartNode
; break;
1207 case CursorType::Footnote
: eSearchNodeType
= SwFootnoteStartNode
; break;
1208 case CursorType::Header
: eSearchNodeType
= SwHeaderStartNode
; break;
1209 case CursorType::Footer
: eSearchNodeType
= SwFooterStartNode
; break;
1210 //case CURSOR_INVALID:
1211 //case CursorType::Body:
1216 const SwStartNode
* pOwnStartNode
= rOwnCursor
.GetPointNode().FindStartNodeByType(eSearchNodeType
);
1217 while ( pOwnStartNode
!= nullptr
1218 && pOwnStartNode
->IsSectionNode())
1220 pOwnStartNode
= pOwnStartNode
->StartOfSectionNode();
1223 const SwStartNode
* pTmp
=
1224 pPam
->GetPointNode().FindStartNodeByType(eSearchNodeType
);
1225 while ( pTmp
!= nullptr
1226 && pTmp
->IsSectionNode() )
1228 pTmp
= pTmp
->StartOfSectionNode();
1231 if ( eSearchNodeType
== SwTableBoxStartNode
)
1233 if (!pOwnStartNode
|| !pTmp
)
1235 throw uno::RuntimeException();
1238 if ( pOwnStartNode
->FindTableNode() != pTmp
->FindTableNode() )
1240 throw uno::RuntimeException();
1245 if ( pOwnStartNode
!= pTmp
)
1247 throw uno::RuntimeException();
1252 if (CursorType::Meta
== m_eType
)
1254 SwPaM
CopyPam(*pPam
->GetMark(), *pPam
->GetPoint());
1255 const bool bNotForced( lcl_ForceIntoMeta(
1256 CopyPam
, m_xParentText
, META_CHECK_BOTH
) );
1259 throw uno::RuntimeException(
1260 u
"gotoRange: parameter range not contained in nesting"
1261 " text content for which this cursor was created"_ustr
,
1262 static_cast<text::XWordCursor
*>(this));
1265 else if (m_eType
== CursorType::ContentControl
)
1267 SwPaM
aPaM(*pPam
->GetMark(), *pPam
->GetPoint());
1268 if (!lcl_ForceIntoContentControl(aPaM
, m_xParentText
, CONTENT_CONTROL_CHECK_BOTH
))
1270 throw uno::RuntimeException(u
"gotoRange: xRange is out of bounds of the content control"_ustr
,
1271 static_cast<text::XWordCursor
*>(this));
1275 // selection has to be expanded here
1278 // cursor should include its previous range plus the given range
1279 const SwPosition
aOwnLeft(*rOwnCursor
.Start());
1280 const SwPosition
aOwnRight(*rOwnCursor
.End());
1281 SwPosition
const& rParamLeft
= *pPam
->Start();
1282 SwPosition
const& rParamRight
= *pPam
->End();
1284 // now there are four SwPositions,
1285 // two of them are going to be used, but which ones?
1286 if (aOwnRight
> rParamRight
)
1287 *rOwnCursor
.GetPoint() = aOwnRight
;
1289 *rOwnCursor
.GetPoint() = rParamRight
;
1290 rOwnCursor
.SetMark();
1291 if (aOwnLeft
< rParamLeft
)
1292 *rOwnCursor
.GetMark() = aOwnLeft
;
1294 *rOwnCursor
.GetMark() = rParamLeft
;
1298 // cursor should be the given range
1299 *rOwnCursor
.GetPoint() = *pPam
->GetPoint();
1300 if (pPam
->HasMark())
1302 rOwnCursor
.SetMark();
1303 *rOwnCursor
.GetMark() = *pPam
->GetMark();
1307 rOwnCursor
.DeleteMark();
1312 sal_Bool SAL_CALL
SwXTextCursor::isStartOfWord()
1314 SolarMutexGuard aGuard
;
1316 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1319 rUnoCursor
.IsStartWordWT( i18n::WordType::DICTIONARY_WORD
);
1323 sal_Bool SAL_CALL
SwXTextCursor::isEndOfWord()
1325 SolarMutexGuard aGuard
;
1327 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1330 rUnoCursor
.IsEndWordWT( i18n::WordType::DICTIONARY_WORD
);
1335 SwXTextCursor::gotoNextWord(sal_Bool Expand
)
1337 SolarMutexGuard aGuard
;
1339 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1341 // problems arise when a paragraph starts with something other than a word
1343 // remember old position to check if cursor has moved
1344 // since the called functions are sometimes a bit unreliable
1345 // in specific cases...
1346 SwPosition
*const pPoint
= rUnoCursor
.GetPoint();
1347 SwNode
*const pOldNode
= &pPoint
->GetNode();
1348 sal_Int32
const nOldIndex
= pPoint
->GetContentIndex();
1350 SwUnoCursorHelper::SelectPam(rUnoCursor
, Expand
);
1352 if (rUnoCursor
.GetPointContentNode() &&
1353 (pPoint
->GetContentIndex() == rUnoCursor
.GetPointContentNode()->Len()))
1355 rUnoCursor
.Right(1);
1360 rUnoCursor
.GoNextWordWT( i18n::WordType::DICTIONARY_WORD
);
1361 // if there is no next word within the current paragraph
1362 // try to go to the start of the next paragraph
1365 rUnoCursor
.MovePara(GoNextPara
, fnParaStart
);
1369 // return true if cursor has moved
1370 bRet
= (&pPoint
->GetNode() != pOldNode
) ||
1371 (pPoint
->GetContentIndex() != nOldIndex
);
1372 if (bRet
&& (CursorType::Meta
== m_eType
))
1374 bRet
= lcl_ForceIntoMeta(rUnoCursor
, m_xParentText
,
1377 else if (bRet
&& m_eType
== CursorType::ContentControl
)
1379 bRet
= lcl_ForceIntoContentControl(rUnoCursor
, m_xParentText
, CONTENT_CONTROL_CHECK_BOTH
);
1386 SwXTextCursor::gotoPreviousWord(sal_Bool Expand
)
1388 SolarMutexGuard aGuard
;
1390 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1392 // white spaces create problems on the paragraph start
1394 SwPosition
*const pPoint
= rUnoCursor
.GetPoint();
1395 SwNode
*const pOldNode
= &pPoint
->GetNode();
1396 sal_Int32
const nOldIndex
= pPoint
->GetContentIndex();
1398 SwUnoCursorHelper::SelectPam(rUnoCursor
, Expand
);
1399 // start of paragraph?
1400 if (pPoint
->GetContentIndex() == 0)
1406 rUnoCursor
.GoPrevWordWT( i18n::WordType::DICTIONARY_WORD
);
1407 if (pPoint
->GetContentIndex() == 0)
1413 // return true if cursor has moved
1414 bRet
= (&pPoint
->GetNode() != pOldNode
) ||
1415 (pPoint
->GetContentIndex() != nOldIndex
);
1416 if (bRet
&& (CursorType::Meta
== m_eType
))
1418 bRet
= lcl_ForceIntoMeta(rUnoCursor
, m_xParentText
,
1421 else if (bRet
&& m_eType
== CursorType::ContentControl
)
1423 bRet
= lcl_ForceIntoContentControl(rUnoCursor
, m_xParentText
, CONTENT_CONTROL_CHECK_BOTH
);
1430 SwXTextCursor::gotoEndOfWord(sal_Bool Expand
)
1432 SolarMutexGuard aGuard
;
1434 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1437 SwPosition
*const pPoint
= rUnoCursor
.GetPoint();
1438 SwNode
& rOldNode
= pPoint
->GetNode();
1439 sal_Int32
const nOldIndex
= pPoint
->GetContentIndex();
1441 const sal_Int16 nWordType
= i18n::WordType::DICTIONARY_WORD
;
1442 SwUnoCursorHelper::SelectPam(rUnoCursor
, Expand
);
1443 if (!rUnoCursor
.IsEndWordWT( nWordType
))
1445 rUnoCursor
.GoEndWordWT( nWordType
);
1448 // restore old cursor if we are not at the end of a word by now
1449 // otherwise use current one
1450 bRet
= rUnoCursor
.IsEndWordWT( nWordType
);
1453 pPoint
->Assign(rOldNode
, nOldIndex
);
1455 else if (CursorType::Meta
== m_eType
)
1457 bRet
= lcl_ForceIntoMeta(rUnoCursor
, m_xParentText
,
1460 else if (m_eType
== CursorType::ContentControl
)
1462 bRet
= lcl_ForceIntoContentControl(rUnoCursor
, m_xParentText
, CONTENT_CONTROL_CHECK_BOTH
);
1469 SwXTextCursor::gotoStartOfWord(sal_Bool Expand
)
1471 SolarMutexGuard aGuard
;
1473 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1476 SwPosition
*const pPoint
= rUnoCursor
.GetPoint();
1477 SwNode
& rOldNode
= pPoint
->GetNode();
1478 sal_Int32
const nOldIndex
= pPoint
->GetContentIndex();
1480 const sal_Int16 nWordType
= i18n::WordType::DICTIONARY_WORD
;
1481 SwUnoCursorHelper::SelectPam(rUnoCursor
, Expand
);
1482 if (!rUnoCursor
.IsStartWordWT( nWordType
))
1484 rUnoCursor
.GoStartWordWT( nWordType
);
1487 // restore old cursor if we are not at the start of a word by now
1488 // otherwise use current one
1489 bRet
= rUnoCursor
.IsStartWordWT( nWordType
);
1492 pPoint
->Assign(rOldNode
, nOldIndex
);
1494 else if (CursorType::Meta
== m_eType
)
1496 bRet
= lcl_ForceIntoMeta(rUnoCursor
, m_xParentText
,
1499 else if (m_eType
== CursorType::ContentControl
)
1501 bRet
= lcl_ForceIntoContentControl(rUnoCursor
, m_xParentText
, CONTENT_CONTROL_CHECK_BOTH
);
1508 SwXTextCursor::isStartOfSentence()
1510 SolarMutexGuard aGuard
;
1512 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1514 // start of paragraph?
1515 bool bRet
= rUnoCursor
.GetPoint()->GetContentIndex() == 0;
1516 // with mark ->no sentence start
1517 // (check if cursor is no selection, i.e. it does not have
1518 // a mark or else point and mark are identical)
1519 if (!bRet
&& (!rUnoCursor
.HasMark() ||
1520 *rUnoCursor
.GetPoint() == *rUnoCursor
.GetMark()))
1522 SwCursor
aCursor(*rUnoCursor
.GetPoint(),nullptr);
1523 SwPosition aOrigPos
= *aCursor
.GetPoint();
1524 aCursor
.GoSentence(SwCursor::START_SENT
);
1525 bRet
= aOrigPos
== *aCursor
.GetPoint();
1531 SwXTextCursor::isEndOfSentence()
1533 SolarMutexGuard aGuard
;
1535 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1537 // end of paragraph?
1538 bool bRet
= rUnoCursor
.GetPointContentNode() &&
1539 (rUnoCursor
.GetPoint()->GetContentIndex() == rUnoCursor
.GetPointContentNode()->Len());
1540 // with mark->no sentence end
1541 // (check if cursor is no selection, i.e. it does not have
1542 // a mark or else point and mark are identical)
1543 if (!bRet
&& (!rUnoCursor
.HasMark() ||
1544 *rUnoCursor
.GetPoint() == *rUnoCursor
.GetMark()))
1546 SwCursor
aCursor(*rUnoCursor
.GetPoint(), nullptr);
1547 SwPosition aOrigPos
= *aCursor
.GetPoint();
1548 aCursor
.GoSentence(SwCursor::END_SENT
);
1549 bRet
= aOrigPos
== *aCursor
.GetPoint();
1555 SwXTextCursor::gotoNextSentence(sal_Bool Expand
)
1557 SolarMutexGuard aGuard
;
1559 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1561 const bool bWasEOS
= isEndOfSentence();
1562 SwUnoCursorHelper::SelectPam(rUnoCursor
, Expand
);
1563 bool bRet
= rUnoCursor
.GoSentence(SwCursor::NEXT_SENT
);
1566 bRet
= rUnoCursor
.MovePara(GoNextPara
, fnParaStart
);
1569 // if at the end of the sentence (i.e. at the space after the '.')
1570 // advance to next word in order for GoSentence to work properly
1571 // next time and have isStartOfSentence return true after this call
1572 if (!rUnoCursor
.IsStartWordWT(css::i18n::WordType::ANYWORD_IGNOREWHITESPACES
))
1574 const bool bNextWord
= rUnoCursor
.GoNextWordWT(i18n::WordType::ANYWORD_IGNOREWHITESPACES
);
1575 if (bWasEOS
&& !bNextWord
)
1580 if (CursorType::Meta
== m_eType
)
1582 bRet
= lcl_ForceIntoMeta(rUnoCursor
, m_xParentText
,
1586 else if (m_eType
== CursorType::ContentControl
)
1588 bRet
= lcl_ForceIntoContentControl(rUnoCursor
, m_xParentText
, CONTENT_CONTROL_CHECK_BOTH
)
1595 SwXTextCursor::gotoPreviousSentence(sal_Bool Expand
)
1597 SolarMutexGuard aGuard
;
1599 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1601 SwUnoCursorHelper::SelectPam(rUnoCursor
, Expand
);
1602 bool bRet
= rUnoCursor
.GoSentence(SwCursor::PREV_SENT
);
1605 bRet
= rUnoCursor
.MovePara(GoPrevPara
, fnParaStart
);
1608 rUnoCursor
.MovePara(GoCurrPara
, fnParaEnd
);
1609 // at the end of a paragraph move to the sentence end again
1610 rUnoCursor
.GoSentence(SwCursor::PREV_SENT
);
1613 if (CursorType::Meta
== m_eType
)
1615 bRet
= lcl_ForceIntoMeta(rUnoCursor
, m_xParentText
,
1619 else if (m_eType
== CursorType::ContentControl
)
1621 bRet
= lcl_ForceIntoContentControl(rUnoCursor
, m_xParentText
, CONTENT_CONTROL_CHECK_BOTH
)
1628 SwXTextCursor::gotoStartOfSentence(sal_Bool Expand
)
1630 SolarMutexGuard aGuard
;
1632 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1634 SwUnoCursorHelper::SelectPam(rUnoCursor
, Expand
);
1635 // if we're at the para start then we won't move
1636 // but bRet is also true if GoSentence failed but
1637 // the start of the sentence is reached
1638 bool bRet
= SwUnoCursorHelper::IsStartOfPara(rUnoCursor
)
1639 || rUnoCursor
.GoSentence(SwCursor::START_SENT
)
1640 || SwUnoCursorHelper::IsStartOfPara(rUnoCursor
);
1641 if (CursorType::Meta
== m_eType
)
1643 bRet
= lcl_ForceIntoMeta(rUnoCursor
, m_xParentText
,
1647 else if (m_eType
== CursorType::ContentControl
)
1649 bRet
= lcl_ForceIntoContentControl(rUnoCursor
, m_xParentText
, CONTENT_CONTROL_CHECK_BOTH
)
1656 SwXTextCursor::gotoEndOfSentence(sal_Bool Expand
)
1658 SolarMutexGuard aGuard
;
1660 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1662 SwUnoCursorHelper::SelectPam(rUnoCursor
, Expand
);
1663 // bRet is true if GoSentence() succeeded or if the
1664 // MovePara() succeeded while the end of the para is
1665 // not reached already
1666 bool bAlreadyParaEnd
= SwUnoCursorHelper::IsEndOfPara(rUnoCursor
);
1667 bool bRet
= !bAlreadyParaEnd
1668 && (rUnoCursor
.GoSentence(SwCursor::END_SENT
)
1669 || rUnoCursor
.MovePara(GoCurrPara
, fnParaEnd
));
1670 if (CursorType::Meta
== m_eType
)
1672 bRet
= lcl_ForceIntoMeta(rUnoCursor
, m_xParentText
,
1676 else if (m_eType
== CursorType::ContentControl
)
1678 bRet
= lcl_ForceIntoContentControl(rUnoCursor
, m_xParentText
, CONTENT_CONTROL_CHECK_BOTH
)
1685 SwXTextCursor::isStartOfParagraph()
1687 SolarMutexGuard aGuard
;
1689 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1691 const bool bRet
= SwUnoCursorHelper::IsStartOfPara(rUnoCursor
);
1696 SwXTextCursor::isEndOfParagraph()
1698 SolarMutexGuard aGuard
;
1700 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1702 const bool bRet
= SwUnoCursorHelper::IsEndOfPara(rUnoCursor
);
1707 SwXTextCursor::gotoStartOfParagraph(sal_Bool Expand
)
1709 SolarMutexGuard aGuard
;
1711 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1713 if (CursorType::Meta
== m_eType
)
1717 SwUnoCursorHelper::SelectPam(rUnoCursor
, Expand
);
1718 bool bRet
= SwUnoCursorHelper::IsStartOfPara(rUnoCursor
);
1721 bRet
= rUnoCursor
.MovePara(GoCurrPara
, fnParaStart
);
1724 // since MovePara(GoCurrPara, fnParaStart) only returns false
1725 // if we were already at the start of the paragraph this function
1726 // should always complete successfully.
1727 OSL_ENSURE( bRet
, "gotoStartOfParagraph failed" );
1732 SwXTextCursor::gotoEndOfParagraph(sal_Bool Expand
)
1734 SolarMutexGuard aGuard
;
1736 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1738 if (CursorType::Meta
== m_eType
)
1742 SwUnoCursorHelper::SelectPam(rUnoCursor
, Expand
);
1743 bool bRet
= SwUnoCursorHelper::IsEndOfPara(rUnoCursor
);
1746 bRet
= rUnoCursor
.MovePara(GoCurrPara
, fnParaEnd
);
1749 // since MovePara(GoCurrPara, fnParaEnd) only returns false
1750 // if we were already at the end of the paragraph this function
1751 // should always complete successfully.
1752 OSL_ENSURE( bRet
, "gotoEndOfParagraph failed" );
1757 SwXTextCursor::gotoNextParagraph(sal_Bool Expand
)
1759 SolarMutexGuard aGuard
;
1761 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1763 if (CursorType::Meta
== m_eType
)
1767 SwUnoCursorHelper::SelectPam(rUnoCursor
, Expand
);
1768 const bool bRet
= rUnoCursor
.MovePara(GoNextPara
, fnParaStart
);
1773 SwXTextCursor::gotoPreviousParagraph(sal_Bool Expand
)
1775 SolarMutexGuard aGuard
;
1777 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1779 if (CursorType::Meta
== m_eType
)
1783 SwUnoCursorHelper::SelectPam(rUnoCursor
, Expand
);
1784 const bool bRet
= rUnoCursor
.MovePara(GoPrevPara
, fnParaStart
);
1788 uno::Reference
< text::XText
> SAL_CALL
1789 SwXTextCursor::getText()
1793 return m_xParentText
;
1796 uno::Reference
< text::XTextRange
> SAL_CALL
1797 SwXTextCursor::getStart()
1799 SolarMutexGuard aGuard
;
1801 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1803 uno::Reference
< text::XTextRange
> xRet
;
1804 SwPaM
aPam(*rUnoCursor
.Start());
1805 const uno::Reference
< text::XText
> xParent
= getText();
1806 if (CursorType::Meta
== m_eType
)
1808 // return cursor to prevent modifying SwXTextRange for META
1809 rtl::Reference
<SwXTextCursor
> pXCursor(
1810 new SwXTextCursor(rUnoCursor
.GetDoc(), xParent
, CursorType::Meta
,
1811 *rUnoCursor
.GetPoint()) );
1812 pXCursor
->gotoStart(false);
1813 xRet
= static_cast<text::XWordCursor
*>(pXCursor
.get());
1817 xRet
= new SwXTextRange(aPam
, xParent
);
1822 uno::Reference
< text::XTextRange
> SAL_CALL
1823 SwXTextCursor::getEnd()
1825 SolarMutexGuard aGuard
;
1827 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1829 uno::Reference
< text::XTextRange
> xRet
;
1830 SwPaM
aPam(*rUnoCursor
.End());
1831 const uno::Reference
< text::XText
> xParent
= getText();
1832 if (CursorType::Meta
== m_eType
)
1834 // return cursor to prevent modifying SwXTextRange for META
1835 rtl::Reference
<SwXTextCursor
> pXCursor(
1836 new SwXTextCursor(rUnoCursor
.GetDoc(), xParent
, CursorType::Meta
,
1837 *rUnoCursor
.GetPoint()) );
1838 pXCursor
->gotoEnd(false);
1839 xRet
= static_cast<text::XWordCursor
*>(pXCursor
.get());
1843 xRet
= new SwXTextRange(aPam
, xParent
);
1848 OUString SAL_CALL
SwXTextCursor::getString()
1850 SolarMutexGuard aGuard
;
1852 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1855 SwUnoCursorHelper::GetTextFromPam(rUnoCursor
, aText
);
1860 SwXTextCursor::setString(const OUString
& aString
)
1862 SolarMutexGuard aGuard
;
1864 GetCursorOrThrow(); // just to check if valid
1866 const bool bForceExpandHints( (CursorType::Meta
== m_eType
)
1867 && dynamic_cast<SwXMeta
&>(*m_xParentText
)
1868 .CheckForOwnMemberMeta(*GetPaM(), true) );
1869 DeleteAndInsert(aString
, bForceExpandHints
? ::sw::DeleteAndInsertMode::ForceExpandHints
: ::sw::DeleteAndInsertMode::Default
);
1872 uno::Any
SwUnoCursorHelper::GetPropertyValue(
1873 SwPaM
& rPaM
, const SfxItemPropertySet
& rPropSet
,
1874 std::u16string_view rPropertyName
)
1877 SfxItemPropertyMapEntry
const*const pEntry
=
1878 rPropSet
.getPropertyMap().getByName(rPropertyName
);
1882 throw beans::UnknownPropertyException(
1883 OUString::Concat("Unknown property: ") + rPropertyName
);
1886 beans::PropertyState eTemp
;
1887 const bool bDone
= SwUnoCursorHelper::getCursorPropertyValue(
1888 *pEntry
, rPaM
, &aAny
, eTemp
);
1893 RES_CHRATR_BEGIN
, RES_FRMATR_END
- 1,
1894 RES_UNKNOWNATR_CONTAINER
, RES_UNKNOWNATR_CONTAINER
>
1895 aSet(rPaM
.GetDoc().GetAttrPool());
1897 SwUnoCursorHelper::GetCursorAttr(rPaM
, aSet
);
1899 SfxItemPropertySet::getPropertyValue(*pEntry
, aSet
, aAny
);
1905 void SwUnoCursorHelper::SetPropertyValue(
1906 SwPaM
& rPaM
, const SfxItemPropertySet
& rPropSet
,
1907 const OUString
& rPropertyName
,
1908 const uno::Any
& rValue
,
1909 const SetAttrMode nAttrMode
)
1911 beans::PropertyValue aVal
{ comphelper::makePropertyValue(rPropertyName
, rValue
) };
1912 SetPropertyValues(rPaM
, rPropSet
, std::span
<beans::PropertyValue
>(&aVal
, 1), nAttrMode
);
1915 // FN_UNO_PARA_STYLE is known to set attributes for nodes, inside
1916 // SwUnoCursorHelper::SetTextFormatColl, instead of extending item set.
1917 // We need to get them from nodes in next call to GetCursorAttr.
1918 // The rest could cause similar problems in theory, so we just list them here.
1919 static bool propertyCausesSideEffectsInNodes(sal_uInt16 nWID
)
1921 return nWID
== FN_UNO_PARA_STYLE
||
1922 nWID
== FN_UNO_CHARFMT_SEQUENCE
||
1923 nWID
== FN_UNO_NUM_START_VALUE
||
1924 nWID
== FN_UNO_NUM_RULES
;
1927 void SwUnoCursorHelper::SetPropertyValues(
1928 SwPaM
& rPaM
, const SfxItemPropertySet
& rPropSet
,
1929 const uno::Sequence
< beans::PropertyValue
> &rPropertyValues
,
1930 const SetAttrMode nAttrMode
)
1932 SetPropertyValues(rPaM
, rPropSet
,
1933 std::span
<const beans::PropertyValue
>(rPropertyValues
.getConstArray(), rPropertyValues
.getLength()),
1937 void SwUnoCursorHelper::SetPropertyValues(
1938 SwPaM
& rPaM
, const SfxItemPropertySet
& rPropSet
,
1939 std::span
< const beans::PropertyValue
> aPropertyValues
,
1940 const SetAttrMode nAttrMode
)
1942 if (aPropertyValues
.empty())
1945 SwDoc
& rDoc
= rPaM
.GetDoc();
1946 OUString aUnknownExMsg
, aPropertyVetoExMsg
;
1948 // Build set of attributes we want to fetch
1949 WhichRangesContainer aRanges
;
1950 std::vector
<std::pair
<const SfxItemPropertyMapEntry
*, const uno::Any
&>> aSideEffectsEntries
;
1951 std::vector
<std::pair
<const SfxItemPropertyMapEntry
*, const uno::Any
&>> aEntries
;
1952 aEntries
.reserve(aPropertyValues
.size());
1953 for (const auto& rPropVal
: aPropertyValues
)
1955 const OUString
&rPropertyName
= rPropVal
.Name
;
1957 SfxItemPropertyMapEntry
const* pEntry
=
1958 rPropSet
.getPropertyMap().getByName(rPropertyName
);
1960 // Queue up any exceptions until the end ...
1963 aUnknownExMsg
+= "Unknown property: '" + rPropertyName
+ "' ";
1966 else if (pEntry
->nFlags
& beans::PropertyAttribute::READONLY
)
1968 aPropertyVetoExMsg
+= "Property is read-only: '" + rPropertyName
+ "' ";
1971 if (propertyCausesSideEffectsInNodes(pEntry
->nWID
))
1973 aSideEffectsEntries
.emplace_back(pEntry
, rPropVal
.Value
);
1977 aRanges
= aRanges
.MergeRange(pEntry
->nWID
, pEntry
->nWID
);
1978 aEntries
.emplace_back(pEntry
, rPropVal
.Value
);
1982 // Entries with side effects first, using dedicated one-element SfxItemSet for each
1983 for (const auto& [pEntry
, rValue
] : aSideEffectsEntries
)
1985 SfxItemSet
aItemSet(rDoc
.GetAttrPool(), pEntry
->nWID
, pEntry
->nWID
);
1986 // we need to get up-to-date item set from nodes
1987 SwUnoCursorHelper::GetCursorAttr(rPaM
, aItemSet
);
1988 // this can set some attributes in nodes' mpAttrSet
1989 if (!SwUnoCursorHelper::SetCursorPropertyValue(*pEntry
, rValue
, rPaM
, aItemSet
))
1990 SfxItemPropertySet::setPropertyValue(*pEntry
, rValue
, aItemSet
);
1991 SwUnoCursorHelper::SetCursorAttr(rPaM
, aItemSet
, nAttrMode
, false /*bTableMode*/);
1994 if (!aEntries
.empty())
1996 // Fetch, overwrite, and re-set the attributes from the core
1997 SfxItemSet
aItemSet(rDoc
.GetAttrPool(), std::move(aRanges
));
1998 // we need to get up-to-date item set from nodes
1999 SwUnoCursorHelper::GetCursorAttr(rPaM
, aItemSet
);
2001 for (const auto& [pEntry
, rValue
] : aEntries
)
2003 // this can set some attributes in nodes' mpAttrSet
2004 if (!SwUnoCursorHelper::SetCursorPropertyValue(*pEntry
, rValue
, rPaM
, aItemSet
))
2005 SfxItemPropertySet::setPropertyValue(*pEntry
, rValue
, aItemSet
);
2008 SwUnoCursorHelper::SetCursorAttr(rPaM
, aItemSet
, nAttrMode
, false /*bTableMode*/);
2011 if (!aUnknownExMsg
.isEmpty())
2012 throw beans::UnknownPropertyException(aUnknownExMsg
);
2013 if (!aPropertyVetoExMsg
.isEmpty())
2014 throw beans::PropertyVetoException(aPropertyVetoExMsg
);
2019 bool NotInRange(sal_uInt16 nWID
, sal_uInt16 nStart
, sal_uInt16 nEnd
)
2021 return nWID
< nStart
|| nWID
> nEnd
;
2025 uno::Sequence
< beans::PropertyState
>
2026 SwUnoCursorHelper::GetPropertyStates(
2027 SwPaM
& rPaM
, const SfxItemPropertySet
& rPropSet
,
2028 const uno::Sequence
< OUString
>& rPropertyNames
,
2029 const SwGetPropertyStatesCaller eCaller
)
2031 const OUString
* pNames
= rPropertyNames
.getConstArray();
2032 uno::Sequence
< beans::PropertyState
> aRet(rPropertyNames
.getLength());
2033 beans::PropertyState
* pStates
= aRet
.getArray();
2034 const SfxItemPropertyMap
&rMap
= rPropSet
.getPropertyMap();
2035 std::optional
<SfxItemSet
> oSet
;
2036 std::optional
<SfxItemSet
> oSetParent
;
2038 for (sal_Int32 i
= 0, nEnd
= rPropertyNames
.getLength(); i
< nEnd
; i
++)
2040 SfxItemPropertyMapEntry
const*const pEntry
=
2041 rMap
.getByName( pNames
[i
] );
2044 if (pNames
[i
] == UNO_NAME_IS_SKIP_HIDDEN_TEXT
||
2045 pNames
[i
] == UNO_NAME_IS_SKIP_PROTECTED_TEXT
||
2046 pNames
[i
] == UNO_NAME_NO_FORMAT_ATTR
)
2048 pStates
[i
] = beans::PropertyState_DEFAULT_VALUE
;
2051 else if (SW_PROPERTY_STATE_CALLER_SWX_TEXT_PORTION_TOLERANT
==
2054 //this values marks the element as unknown property
2055 pStates
[i
] = beans::PropertyState::PropertyState_MAKE_FIXED_SIZE
;
2060 throw beans::UnknownPropertyException(
2061 "Unknown property: " + pNames
[i
]);
2064 if (((SW_PROPERTY_STATE_CALLER_SWX_TEXT_PORTION
== eCaller
) ||
2065 (SW_PROPERTY_STATE_CALLER_SWX_TEXT_PORTION_TOLERANT
== eCaller
)) &&
2066 NotInRange(pEntry
->nWID
, FN_UNO_RANGE_BEGIN
, FN_UNO_RANGE_END
) &&
2067 NotInRange(pEntry
->nWID
, RES_CHRATR_BEGIN
, RES_TXTATR_END
) )
2069 pStates
[i
] = beans::PropertyState_DEFAULT_VALUE
;
2073 if ( pEntry
->nWID
>= FN_UNO_RANGE_BEGIN
&&
2074 pEntry
->nWID
<= FN_UNO_RANGE_END
)
2076 (void)SwUnoCursorHelper::getCursorPropertyValue(
2077 *pEntry
, rPaM
, nullptr, pStates
[i
] );
2085 case SW_PROPERTY_STATE_CALLER_SWX_TEXT_PORTION_TOLERANT
:
2086 case SW_PROPERTY_STATE_CALLER_SWX_TEXT_PORTION
:
2087 oSet
.emplace( rPaM
.GetDoc().GetAttrPool(),
2088 svl::Items
<RES_CHRATR_BEGIN
, RES_TXTATR_END
> );
2090 case SW_PROPERTY_STATE_CALLER_SINGLE_VALUE_ONLY
:
2091 oSet
.emplace( rPaM
.GetDoc().GetAttrPool(),
2092 pEntry
->nWID
, pEntry
->nWID
);
2096 rPaM
.GetDoc().GetAttrPool(),
2098 RES_CHRATR_BEGIN
, RES_FRMATR_END
- 1,
2099 RES_UNKNOWNATR_CONTAINER
,
2100 RES_UNKNOWNATR_CONTAINER
>);
2103 SwUnoCursorHelper::GetCursorAttr( rPaM
, *oSet
);
2106 pStates
[i
] = ( oSet
->Count() )
2107 ? SfxItemPropertySet::getPropertyState( *pEntry
, *oSet
)
2108 : beans::PropertyState_DEFAULT_VALUE
;
2110 //try again to find out if a value has been inherited
2111 if( beans::PropertyState_DIRECT_VALUE
== pStates
[i
] )
2115 oSetParent
.emplace(oSet
->CloneAsValue( false ));
2117 SwUnoCursorHelper::GetCursorAttr(
2118 rPaM
, *oSetParent
, true, false );
2121 pStates
[i
] = ( oSetParent
->Count() )
2122 ? SfxItemPropertySet::getPropertyState( *pEntry
, *oSetParent
)
2123 : beans::PropertyState_DEFAULT_VALUE
;
2131 beans::PropertyState
SwUnoCursorHelper::GetPropertyState(
2132 SwPaM
& rPaM
, const SfxItemPropertySet
& rPropSet
,
2133 const OUString
& rPropertyName
)
2135 uno::Sequence
< OUString
> aStrings
{ rPropertyName
};
2136 uno::Sequence
< beans::PropertyState
> aSeq
=
2137 GetPropertyStates(rPaM
, rPropSet
, aStrings
,
2138 SW_PROPERTY_STATE_CALLER_SINGLE_VALUE_ONLY
);
2143 lcl_SelectParaAndReset( SwPaM
&rPaM
, SwDoc
& rDoc
,
2144 o3tl::sorted_vector
<sal_uInt16
> const &rWhichIds
)
2146 // if we are resetting paragraph attributes, we need to select the full paragraph first
2147 SwPosition aStart
= *rPaM
.Start();
2148 SwPosition aEnd
= *rPaM
.End();
2149 auto pTemp ( rDoc
.CreateUnoCursor(aStart
) );
2150 if(!SwUnoCursorHelper::IsStartOfPara(*pTemp
))
2152 pTemp
->MovePara(GoCurrPara
, fnParaStart
);
2155 *pTemp
->GetPoint() = std::move(aEnd
);
2156 SwUnoCursorHelper::SelectPam(*pTemp
, true);
2157 if(!SwUnoCursorHelper::IsEndOfPara(*pTemp
))
2159 pTemp
->MovePara(GoCurrPara
, fnParaEnd
);
2161 rDoc
.ResetAttrs(*pTemp
, true, rWhichIds
);
2164 void SwUnoCursorHelper::SetPropertyToDefault(
2165 SwPaM
& rPaM
, const SfxItemPropertySet
& rPropSet
,
2166 std::u16string_view rPropertyName
)
2168 SwDoc
& rDoc
= rPaM
.GetDoc();
2169 SfxItemPropertyMapEntry
const*const pEntry
=
2170 rPropSet
.getPropertyMap().getByName(rPropertyName
);
2173 throw beans::UnknownPropertyException(
2174 OUString::Concat("Unknown property: ") + rPropertyName
);
2177 if (pEntry
->nFlags
& beans::PropertyAttribute::READONLY
)
2179 throw uno::RuntimeException(
2180 OUString::Concat("setPropertyToDefault: property is read-only: ")
2181 + rPropertyName
, nullptr);
2184 if (pEntry
->nWID
< RES_FRMATR_END
)
2186 const o3tl::sorted_vector
<sal_uInt16
> aWhichIds
{ pEntry
->nWID
};
2187 if (pEntry
->nWID
< RES_PARATR_BEGIN
)
2189 rDoc
.ResetAttrs(rPaM
, true, aWhichIds
);
2193 lcl_SelectParaAndReset ( rPaM
, rDoc
, aWhichIds
);
2198 SwUnoCursorHelper::resetCursorPropertyValue(*pEntry
, rPaM
);
2202 uno::Any
SwUnoCursorHelper::GetPropertyDefault(
2203 SwPaM
const & rPaM
, const SfxItemPropertySet
& rPropSet
,
2204 std::u16string_view rPropertyName
)
2206 SfxItemPropertyMapEntry
const*const pEntry
=
2207 rPropSet
.getPropertyMap().getByName(rPropertyName
);
2210 throw beans::UnknownPropertyException(
2211 OUString::Concat("Unknown property: ") + rPropertyName
);
2215 if (pEntry
->nWID
< RES_FRMATR_END
)
2217 SwDoc
& rDoc
= rPaM
.GetDoc();
2218 const SfxPoolItem
& rDefItem
=
2219 rDoc
.GetAttrPool().GetUserOrPoolDefaultItem(pEntry
->nWID
);
2220 rDefItem
.QueryValue(aRet
, pEntry
->nMemberId
);
2225 uno::Reference
< beans::XPropertySetInfo
> SAL_CALL
2226 SwXTextCursor::getPropertySetInfo()
2230 static uno::Reference
< beans::XPropertySetInfo
> xRef
= [&]()
2232 static SfxItemPropertyMapEntry
const aCursorExtMap_Impl
[] =
2234 { UNO_NAME_IS_SKIP_HIDDEN_TEXT
, FN_SKIP_HIDDEN_TEXT
, cppu::UnoType
<bool>::get(), PROPERTY_NONE
, 0},
2235 { UNO_NAME_IS_SKIP_PROTECTED_TEXT
, FN_SKIP_PROTECTED_TEXT
, cppu::UnoType
<bool>::get(), PROPERTY_NONE
, 0},
2236 { UNO_NAME_NO_FORMAT_ATTR
, 0, cppu::UnoType
<bool>::get(), PROPERTY_NONE
, 0},
2238 const uno::Reference
< beans::XPropertySetInfo
> xInfo
=
2239 m_rPropSet
.getPropertySetInfo();
2240 // extend PropertySetInfo!
2241 const uno::Sequence
<beans::Property
> aPropSeq
= xInfo
->getProperties();
2242 return rtl::Reference
<SfxExtItemPropertySetInfo
>(new SfxExtItemPropertySetInfo(
2250 SwXTextCursor::setPropertyValue(
2251 const OUString
& rPropertyName
, const uno::Any
& rValue
)
2253 SolarMutexGuard aGuard
;
2255 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
2257 if (rPropertyName
== UNO_NAME_IS_SKIP_HIDDEN_TEXT
)
2260 if (!(rValue
>>= bSet
))
2262 throw lang::IllegalArgumentException();
2264 rUnoCursor
.SetSkipOverHiddenSections(bSet
);
2266 else if (rPropertyName
== UNO_NAME_IS_SKIP_PROTECTED_TEXT
)
2269 if (!(rValue
>>= bSet
))
2271 throw lang::IllegalArgumentException();
2273 rUnoCursor
.SetSkipOverProtectSections(bSet
);
2275 else if (rPropertyName
== UNO_NAME_NO_FORMAT_ATTR
)
2278 if (!(rValue
>>= bSet
))
2280 throw lang::IllegalArgumentException();
2284 m_nAttrMode
= SetAttrMode::NOFORMATATTR
;
2288 m_nAttrMode
= SetAttrMode::DEFAULT
;
2291 else if (rPropertyName
== "ParaAutoStyleDef")
2293 // Create an autostyle from passed definition (sequence of PropertyValue, same
2294 // as in XAutoStyleFamily::insertStyle), using the currently applied properties
2295 // from the paragraph to not lose their values when creating complex properties
2296 // like SvxULSpaceItem, when only part of the properties stored there is passed;
2297 // and apply it to the paragraph.
2298 uno::Sequence
<beans::PropertyValue
> def
;
2299 if (!(rValue
>>= def
))
2300 throw lang::IllegalArgumentException();
2302 // See SwUnoCursorHelper::SetPropertyValues
2304 auto pPropSet
= aSwMapProvider
.GetPropertySet(PROPERTY_MAP_PARA_AUTO_STYLE
);
2306 // Build set of attributes we want to fetch
2307 WhichRangesContainer aRanges
;
2308 for (auto& rPropVal
: def
)
2310 SfxItemPropertyMapEntry
const* pEntry
=
2311 pPropSet
->getPropertyMap().getByName(rPropVal
.Name
);
2313 continue; // PropValuesToAutoStyleItemSet ignores invalid names
2315 aRanges
= aRanges
.MergeRange(pEntry
->nWID
, pEntry
->nWID
);
2318 if (!aRanges
.empty())
2320 SwAttrSet
aAutoStyleItemSet(rUnoCursor
.GetDoc().GetAttrPool(), std::move(aRanges
));
2321 // we need to get up-to-date item set: this makes sure that the complex properties,
2322 // that are only partially defined by passed definition, do not lose the rest of
2323 // their already present data (which will become part of the autostyle, too).
2324 SwUnoCursorHelper::GetCursorAttr(rUnoCursor
, aAutoStyleItemSet
);
2325 // Set normal set ranges before putting into autostyle, to the same ranges
2326 // that are used for paragraph autostyle in SwXAutoStyleFamily::insertStyle
2327 aAutoStyleItemSet
.SetRanges(aTextNodeSetRange
);
2329 // Fill the prepared item set, containing current paragraph property values,
2330 // with the passed definition, and create the autostyle.
2331 auto pStyle
= PropValuesToAutoStyleItemSet(
2332 rUnoCursor
.GetDoc(), IStyleAccess::AUTO_STYLE_PARA
, def
, aAutoStyleItemSet
);
2334 SwFormatAutoFormat
aFormat(RES_AUTO_STYLE
);
2335 aFormat
.SetStyleHandle(pStyle
);
2336 SfxItemSet
rSet(rUnoCursor
.GetDoc().GetAttrPool(), RES_AUTO_STYLE
, RES_AUTO_STYLE
);
2338 SwUnoCursorHelper::SetCursorAttr(rUnoCursor
, rSet
, m_nAttrMode
);
2343 SwUnoCursorHelper::SetPropertyValue(rUnoCursor
,
2344 m_rPropSet
, rPropertyName
, rValue
, m_nAttrMode
);
2349 SwXTextCursor::getPropertyValue(const OUString
& rPropertyName
)
2351 SolarMutexGuard aGuard
;
2353 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
2356 if (rPropertyName
== UNO_NAME_IS_SKIP_HIDDEN_TEXT
)
2358 const bool bSet
= rUnoCursor
.IsSkipOverHiddenSections();
2361 else if (rPropertyName
== UNO_NAME_IS_SKIP_PROTECTED_TEXT
)
2363 const bool bSet
= rUnoCursor
.IsSkipOverProtectSections();
2368 aAny
= SwUnoCursorHelper::GetPropertyValue(rUnoCursor
,
2369 m_rPropSet
, rPropertyName
);
2375 SwXTextCursor::addPropertyChangeListener(
2376 const OUString
& /*rPropertyName*/,
2377 const uno::Reference
< beans::XPropertyChangeListener
>& /*xListener*/)
2379 OSL_FAIL("SwXTextCursor::addPropertyChangeListener(): not implemented");
2383 SwXTextCursor::removePropertyChangeListener(
2384 const OUString
& /*rPropertyName*/,
2385 const uno::Reference
< beans::XPropertyChangeListener
>& /*xListener*/)
2387 OSL_FAIL("SwXTextCursor::removePropertyChangeListener(): not implemented");
2391 SwXTextCursor::addVetoableChangeListener(
2392 const OUString
& /*rPropertyName*/,
2393 const uno::Reference
< beans::XVetoableChangeListener
>& /*xListener*/)
2395 OSL_FAIL("SwXTextCursor::addVetoableChangeListener(): not implemented");
2399 SwXTextCursor::removeVetoableChangeListener(
2400 const OUString
& /*rPropertyName*/,
2401 const uno::Reference
< beans::XVetoableChangeListener
>& /*xListener*/)
2403 OSL_FAIL("SwXTextCursor::removeVetoableChangeListener(): not implemented");
2406 beans::PropertyState SAL_CALL
2407 SwXTextCursor::getPropertyState(const OUString
& rPropertyName
)
2409 SolarMutexGuard aGuard
;
2411 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
2413 const beans::PropertyState eRet
= SwUnoCursorHelper::GetPropertyState(
2414 rUnoCursor
, m_rPropSet
, rPropertyName
);
2418 uno::Sequence
< beans::PropertyState
> SAL_CALL
2419 SwXTextCursor::getPropertyStates(
2420 const uno::Sequence
< OUString
>& rPropertyNames
)
2422 SolarMutexGuard aGuard
;
2424 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
2426 return SwUnoCursorHelper::GetPropertyStates(
2427 rUnoCursor
, m_rPropSet
, rPropertyNames
);
2431 SwXTextCursor::setPropertyToDefault(const OUString
& rPropertyName
)
2433 // forward: need no solar mutex here
2434 uno::Sequence
< OUString
> aSequence ( &rPropertyName
, 1 );
2435 setPropertiesToDefault ( aSequence
);
2439 SwXTextCursor::getPropertyDefault(const OUString
& rPropertyName
)
2441 // forward: need no solar mutex here
2442 const uno::Sequence
< OUString
> aSequence ( &rPropertyName
, 1 );
2443 return getPropertyDefaults ( aSequence
).getConstArray()[0];
2446 void SAL_CALL
SwXTextCursor::setPropertyValues(
2447 const uno::Sequence
< OUString
>& aPropertyNames
,
2448 const uno::Sequence
< uno::Any
>& aValues
)
2450 if( aValues
.getLength() != aPropertyNames
.getLength() )
2452 OSL_FAIL( "mis-matched property value sequences" );
2453 throw lang::IllegalArgumentException();
2456 SolarMutexGuard aGuard
;
2458 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
2460 // a little lame to have to copy into this.
2461 uno::Sequence
< beans::PropertyValue
> aPropertyValues( aValues
.getLength() );
2462 auto aPropertyValuesRange
= asNonConstRange(aPropertyValues
);
2463 for ( sal_Int32 i
= 0; i
< aPropertyNames
.getLength(); i
++ )
2465 if ( aPropertyNames
[ i
] == UNO_NAME_IS_SKIP_HIDDEN_TEXT
||
2466 aPropertyNames
[ i
] == UNO_NAME_IS_SKIP_PROTECTED_TEXT
)
2468 // the behaviour of these is hard to model in a group
2469 OSL_FAIL("invalid property name for batch setting");
2470 throw lang::IllegalArgumentException();
2472 aPropertyValuesRange
[ i
].Name
= aPropertyNames
[ i
];
2473 aPropertyValuesRange
[ i
].Value
= aValues
[ i
];
2477 SwUnoCursorHelper::SetPropertyValues( rUnoCursor
, m_rPropSet
, aPropertyValues
);
2479 catch (const css::beans::UnknownPropertyException
& e
)
2481 uno::Any
a(cppu::getCaughtException());
2482 throw lang::WrappedTargetException(
2483 "wrapped Exception " + e
.Message
,
2484 uno::Reference
<uno::XInterface
>(), a
);
2488 uno::Sequence
< uno::Any
> SAL_CALL
2489 SwXTextCursor::getPropertyValues( const uno::Sequence
< OUString
>& aPropertyNames
)
2491 // a banal implementation for now
2492 uno::Sequence
< uno::Any
> aValues( aPropertyNames
.getLength() );
2493 std::transform(aPropertyNames
.begin(), aPropertyNames
.end(), aValues
.getArray(),
2494 [this](const OUString
& rName
) -> uno::Any
{ return getPropertyValue( rName
); });
2498 void SAL_CALL
SwXTextCursor::addPropertiesChangeListener(
2499 const uno::Sequence
< OUString
>& /* aPropertyNames */,
2500 const uno::Reference
< css::beans::XPropertiesChangeListener
>& /* xListener */ )
2502 OSL_FAIL("SwXTextCursor::addPropertiesChangeListener(): not implemented");
2504 void SAL_CALL
SwXTextCursor::removePropertiesChangeListener(
2505 const uno::Reference
< css::beans::XPropertiesChangeListener
>& /* xListener */ )
2507 OSL_FAIL("SwXTextCursor::removePropertiesChangeListener(): not implemented");
2510 void SAL_CALL
SwXTextCursor::firePropertiesChangeEvent(
2511 const uno::Sequence
< OUString
>& /* aPropertyNames */,
2512 const uno::Reference
< css::beans::XPropertiesChangeListener
>& /* xListener */ )
2514 OSL_FAIL("SwXTextCursor::firePropertiesChangeEvent(): not implemented");
2517 // para specific attribute ranges
2518 static sal_uInt16 g_ParaResetableSetRange
[] = {
2519 RES_FRMATR_BEGIN
, RES_FRMATR_END
-1,
2520 RES_PARATR_BEGIN
, RES_PARATR_END
-1,
2521 RES_PARATR_LIST_BEGIN
, RES_PARATR_LIST_END
-1,
2522 RES_UNKNOWNATR_BEGIN
, RES_UNKNOWNATR_END
-1,
2526 // selection specific attribute ranges
2527 static sal_uInt16 g_ResetableSetRange
[] = {
2528 RES_CHRATR_BEGIN
, RES_CHRATR_END
-1,
2529 RES_TXTATR_INETFMT
, RES_TXTATR_INETFMT
,
2530 RES_TXTATR_CHARFMT
, RES_TXTATR_CHARFMT
,
2531 RES_TXTATR_CJK_RUBY
, RES_TXTATR_CJK_RUBY
,
2532 RES_TXTATR_UNKNOWN_CONTAINER
, RES_TXTATR_UNKNOWN_CONTAINER
,
2537 lcl_EnumerateIds(sal_uInt16
const* pIdRange
, o3tl::sorted_vector
<sal_uInt16
> &rWhichIds
)
2541 const sal_uInt16 nStart
= *pIdRange
++;
2542 const sal_uInt16 nEnd
= *pIdRange
++;
2543 for (sal_uInt16 nId
= nStart
+ 1; nId
<= nEnd
; ++nId
)
2545 rWhichIds
.insert( nId
);
2551 SwXTextCursor::setAllPropertiesToDefault()
2553 SolarMutexGuard aGuard
;
2555 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
2557 o3tl::sorted_vector
<sal_uInt16
> aParaWhichIds
;
2558 o3tl::sorted_vector
<sal_uInt16
> aWhichIds
;
2559 lcl_EnumerateIds(g_ParaResetableSetRange
, aParaWhichIds
);
2560 lcl_EnumerateIds(g_ResetableSetRange
, aWhichIds
);
2561 if (!aParaWhichIds
.empty())
2563 lcl_SelectParaAndReset(rUnoCursor
, rUnoCursor
.GetDoc(),
2566 if (!aWhichIds
.empty())
2568 rUnoCursor
.GetDoc().ResetAttrs(rUnoCursor
, true, aWhichIds
);
2573 SwXTextCursor::setPropertiesToDefault(
2574 const uno::Sequence
< OUString
>& rPropertyNames
)
2576 SolarMutexGuard aGuard
;
2578 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
2580 if ( !rPropertyNames
.hasElements() )
2583 SwDoc
& rDoc
= rUnoCursor
.GetDoc();
2584 o3tl::sorted_vector
<sal_uInt16
> aWhichIds
;
2585 o3tl::sorted_vector
<sal_uInt16
> aParaWhichIds
;
2586 for (const OUString
& rName
: rPropertyNames
)
2588 SfxItemPropertyMapEntry
const*const pEntry
=
2589 m_rPropSet
.getPropertyMap().getByName( rName
);
2592 if (rName
== UNO_NAME_IS_SKIP_HIDDEN_TEXT
||
2593 rName
== UNO_NAME_IS_SKIP_PROTECTED_TEXT
)
2597 throw beans::UnknownPropertyException(
2598 "Unknown property: " + rName
,
2601 if (pEntry
->nFlags
& beans::PropertyAttribute::READONLY
)
2603 throw uno::RuntimeException(
2604 "setPropertiesToDefault: property is read-only: " + rName
,
2608 if (pEntry
->nWID
< RES_FRMATR_END
)
2610 if (pEntry
->nWID
< RES_PARATR_BEGIN
)
2612 aWhichIds
.insert( pEntry
->nWID
);
2616 aParaWhichIds
.insert( pEntry
->nWID
);
2619 else if (pEntry
->nWID
== FN_UNO_NUM_START_VALUE
)
2621 SwUnoCursorHelper::resetCursorPropertyValue(*pEntry
, rUnoCursor
);
2625 if (!aParaWhichIds
.empty())
2627 lcl_SelectParaAndReset(rUnoCursor
, rDoc
, aParaWhichIds
);
2629 if (!aWhichIds
.empty())
2631 rDoc
.ResetAttrs(rUnoCursor
, true, aWhichIds
);
2635 uno::Sequence
< uno::Any
> SAL_CALL
2636 SwXTextCursor::getPropertyDefaults(
2637 const uno::Sequence
< OUString
>& rPropertyNames
)
2639 SolarMutexGuard aGuard
;
2641 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
2643 const sal_Int32 nCount
= rPropertyNames
.getLength();
2644 uno::Sequence
< uno::Any
> aRet(nCount
);
2647 SwDoc
& rDoc
= rUnoCursor
.GetDoc();
2648 const OUString
*pNames
= rPropertyNames
.getConstArray();
2649 uno::Any
*pAny
= aRet
.getArray();
2650 for (sal_Int32 i
= 0; i
< nCount
; i
++)
2652 SfxItemPropertyMapEntry
const*const pEntry
=
2653 m_rPropSet
.getPropertyMap().getByName( pNames
[i
] );
2656 if (pNames
[i
] == UNO_NAME_IS_SKIP_HIDDEN_TEXT
||
2657 pNames
[i
] == UNO_NAME_IS_SKIP_PROTECTED_TEXT
||
2658 pNames
[i
] == UNO_NAME_NO_FORMAT_ATTR
)
2662 throw beans::UnknownPropertyException(
2663 "Unknown property: " + pNames
[i
]);
2665 if (pEntry
->nWID
< RES_FRMATR_END
)
2667 const SfxPoolItem
& rDefItem
=
2668 rDoc
.GetAttrPool().GetUserOrPoolDefaultItem(pEntry
->nWID
);
2669 rDefItem
.QueryValue(pAny
[i
], pEntry
->nMemberId
);
2676 void SAL_CALL
SwXTextCursor::invalidateMarkings(::sal_Int32 nType
)
2678 SolarMutexGuard aGuard
;
2680 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
2682 SwNode
& node
= rUnoCursor
.GetPointNode();
2684 SwTextNode
* txtNode
= node
.GetTextNode();
2686 if (txtNode
== nullptr) return;
2688 if ( text::TextMarkupType::SPELLCHECK
== nType
)
2690 txtNode
->SetWrongDirty(sw::WrongState::TODO
);
2691 txtNode
->ClearWrong();
2693 else if( text::TextMarkupType::PROOFREADING
== nType
)
2695 txtNode
->SetGrammarCheckDirty(true);
2696 txtNode
->ClearGrammarCheck();
2698 else if ( text::TextMarkupType::SMARTTAG
== nType
)
2700 txtNode
->SetSmartTagDirty(true);
2701 txtNode
->ClearSmartTags();
2705 SwFormatColl
* fmtColl
=txtNode
->GetFormatColl();
2707 if (fmtColl
== nullptr) return;
2709 txtNode
->CallSwClientNotify(SwFormatChangeHint(nullptr, fmtColl
));
2713 SwXTextCursor::makeRedline(
2714 const OUString
& rRedlineType
,
2715 const uno::Sequence
< beans::PropertyValue
>& rRedlineProperties
)
2717 SolarMutexGuard aGuard
;
2719 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
2721 SwUnoCursorHelper::makeRedline(rUnoCursor
, rRedlineType
, rRedlineProperties
);
2724 void SAL_CALL
SwXTextCursor::insertDocumentFromURL(const OUString
& rURL
,
2725 const uno::Sequence
< beans::PropertyValue
>& rOptions
)
2727 SolarMutexGuard aGuard
;
2729 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
2731 SwUnoCursorHelper::InsertFile(&rUnoCursor
, rURL
, rOptions
);
2734 uno::Sequence
< beans::PropertyValue
>
2735 SwUnoCursorHelper::CreateSortDescriptor(const bool bFromTable
)
2737 uno::Sequence
< beans::PropertyValue
> aRet(5);
2738 beans::PropertyValue
* pArray
= aRet
.getArray();
2741 aVal
<<= bFromTable
;
2742 pArray
[0] = beans::PropertyValue(u
"IsSortInTable"_ustr
, -1, aVal
,
2743 beans::PropertyState_DIRECT_VALUE
);
2746 pArray
[1] = beans::PropertyValue(u
"Delimiter"_ustr
, -1, aVal
,
2747 beans::PropertyState_DIRECT_VALUE
);
2750 pArray
[2] = beans::PropertyValue(u
"IsSortColumns"_ustr
, -1, aVal
,
2751 beans::PropertyState_DIRECT_VALUE
);
2753 aVal
<<= sal_Int32(3);
2754 pArray
[3] = beans::PropertyValue(u
"MaxSortFieldsCount"_ustr
, -1, aVal
,
2755 beans::PropertyState_DIRECT_VALUE
);
2757 lang::Locale
aLang( SvtSysLocale().GetLanguageTag().getLocale());
2758 // get collator algorithm to be used for the locale
2759 uno::Sequence
< OUString
> aSeq(
2760 GetAppCollator().listCollatorAlgorithms( aLang
) );
2761 const bool bHasElements
= aSeq
.hasElements();
2762 OSL_ENSURE( bHasElements
, "list of collator algorithms is empty!");
2766 aCollAlg
= aSeq
.getConstArray()[0];
2769 uno::Sequence
< table::TableSortField
> aFields
2771 // Field, IsAscending, IsCaseSensitive, FieldType, CollatorLocale, CollatorAlgorithm
2772 { 1, true, false, table::TableSortFieldType_ALPHANUMERIC
, aLang
, aCollAlg
},
2773 { 1, true, false, table::TableSortFieldType_ALPHANUMERIC
, aLang
, aCollAlg
},
2774 { 1, true, false, table::TableSortFieldType_ALPHANUMERIC
, aLang
, aCollAlg
}
2778 pArray
[4] = beans::PropertyValue(u
"SortFields"_ustr
, -1, aVal
,
2779 beans::PropertyState_DIRECT_VALUE
);
2784 uno::Sequence
< beans::PropertyValue
> SAL_CALL
2785 SwXTextCursor::createSortDescriptor()
2787 SolarMutexGuard aGuard
;
2789 return SwUnoCursorHelper::CreateSortDescriptor(false);
2792 bool SwUnoCursorHelper::ConvertSortProperties(
2793 const uno::Sequence
< beans::PropertyValue
>& rDescriptor
,
2794 SwSortOptions
& rSortOpt
)
2798 rSortOpt
.bTable
= false;
2799 rSortOpt
.cDeli
= ' ';
2800 rSortOpt
.eDirection
= SwSortDirection::Columns
; //!! UI text may be contrary though !!
2803 aKey1
.nColumnId
= USHRT_MAX
;
2804 aKey1
.bIsNumeric
= true;
2805 aKey1
.eSortOrder
= SwSortOrder::Ascending
;
2808 aKey2
.nColumnId
= USHRT_MAX
;
2809 aKey2
.bIsNumeric
= true;
2810 aKey2
.eSortOrder
= SwSortOrder::Ascending
;
2813 aKey3
.nColumnId
= USHRT_MAX
;
2814 aKey3
.bIsNumeric
= true;
2815 aKey3
.eSortOrder
= SwSortOrder::Ascending
;
2816 SwSortKey
* aKeys
[3] = {&aKey1
, &aKey2
, &aKey3
};
2818 bool bOldSortdescriptor(false);
2819 bool bNewSortdescriptor(false);
2821 for (const beans::PropertyValue
& rProperty
: rDescriptor
)
2823 uno::Any
aValue( rProperty
.Value
);
2824 const OUString
& rPropName
= rProperty
.Name
;
2826 // old and new sortdescriptor
2827 if ( rPropName
== "IsSortInTable" )
2829 if (auto b
= o3tl::tryAccess
<bool>(aValue
))
2831 rSortOpt
.bTable
= *b
;
2838 else if ( rPropName
== "Delimiter" )
2842 if (aValue
>>= uChar
)
2844 rSortOpt
.cDeli
= uChar
;
2846 else if (aValue
>>= nChar
)
2848 // For compatibility with BASIC, also accept an ANY containing
2849 // an UNSIGNED SHORT:
2850 rSortOpt
.cDeli
= nChar
;
2857 // old sortdescriptor
2858 else if ( rPropName
== "SortColumns" )
2860 bOldSortdescriptor
= true;
2862 if (aValue
>>= bTemp
)
2864 rSortOpt
.eDirection
= bTemp
? SwSortDirection::Columns
: SwSortDirection::Rows
;
2871 else if ( rPropName
== "IsCaseSensitive" )
2873 bOldSortdescriptor
= true;
2875 if (aValue
>>= bTemp
)
2877 rSortOpt
.bIgnoreCase
= !bTemp
;
2884 else if ( rPropName
== "CollatorLocale" )
2886 bOldSortdescriptor
= true;
2887 lang::Locale aLocale
;
2888 if (aValue
>>= aLocale
)
2890 rSortOpt
.nLanguage
= LanguageTag::convertToLanguageType( aLocale
);
2897 else if (rPropName
.startsWith("CollatorAlgorithm") &&
2898 rPropName
.getLength() == 18 &&
2899 (rPropName
[17] >= '0' && rPropName
[17] <= '9'))
2901 bOldSortdescriptor
= true;
2902 sal_uInt16 nIndex
= rPropName
[17];
2905 if ((aValue
>>= aText
) && nIndex
< 3)
2907 aKeys
[nIndex
]->sSortType
= aText
;
2914 else if (rPropName
.startsWith("SortRowOrColumnNo") &&
2915 rPropName
.getLength() == 18 &&
2916 (rPropName
[17] >= '0' && rPropName
[17] <= '9'))
2918 bOldSortdescriptor
= true;
2919 sal_uInt16 nIndex
= rPropName
[17];
2921 sal_Int16 nCol
= -1;
2922 if (aValue
.getValueType() == ::cppu::UnoType
<sal_Int16
>::get()
2929 aKeys
[nIndex
]->nColumnId
= nCol
;
2936 else if (rPropName
.startsWith("IsSortNumeric") &&
2937 rPropName
.getLength() == 14 &&
2938 (rPropName
[13] >= '0' && rPropName
[13] <= '9'))
2940 bOldSortdescriptor
= true;
2941 sal_uInt16 nIndex
= rPropName
[13];
2942 nIndex
= nIndex
- '0';
2943 std::optional
<const bool> bTemp
= o3tl::tryAccess
<bool>(aValue
);
2944 if (bTemp
.has_value() && nIndex
< 3)
2946 aKeys
[nIndex
]->bIsNumeric
= *bTemp
;
2953 else if (rPropName
.startsWith("IsSortAscending") &&
2954 rPropName
.getLength() == 16 &&
2955 (rPropName
[15] >= '0' && rPropName
[15] <= '9'))
2957 bOldSortdescriptor
= true;
2958 sal_uInt16 nIndex
= rPropName
[15];
2960 std::optional
<const bool> bTemp
= o3tl::tryAccess
<bool>(aValue
);
2961 if (bTemp
.has_value() && nIndex
< 3)
2963 aKeys
[nIndex
]->eSortOrder
= (*bTemp
)
2964 ? SwSortOrder::Ascending
: SwSortOrder::Descending
;
2971 // new sortdescriptor
2972 else if ( rPropName
== "IsSortColumns" )
2974 bNewSortdescriptor
= true;
2975 if (auto bTemp
= o3tl::tryAccess
<bool>(aValue
))
2977 rSortOpt
.eDirection
= *bTemp
? SwSortDirection::Columns
: SwSortDirection::Rows
;
2984 else if ( rPropName
== "SortFields" )
2986 bNewSortdescriptor
= true;
2987 uno::Sequence
< table::TableSortField
> aFields
;
2988 if (aValue
>>= aFields
)
2990 sal_Int32
nCount(aFields
.getLength());
2993 table::TableSortField
* pFields
= aFields
.getArray();
2994 for (sal_Int32 i
= 0; i
< nCount
; ++i
)
2996 rSortOpt
.bIgnoreCase
= !pFields
[i
].IsCaseSensitive
;
2997 rSortOpt
.nLanguage
=
2998 LanguageTag::convertToLanguageType( pFields
[i
].CollatorLocale
);
2999 aKeys
[i
]->sSortType
= pFields
[i
].CollatorAlgorithm
;
3000 aKeys
[i
]->nColumnId
=
3001 o3tl::narrowing
<sal_uInt16
>(pFields
[i
].Field
);
3002 aKeys
[i
]->bIsNumeric
= (pFields
[i
].FieldType
==
3003 table::TableSortFieldType_NUMERIC
);
3004 aKeys
[i
]->eSortOrder
= (pFields
[i
].IsAscending
)
3005 ? SwSortOrder::Ascending
: SwSortOrder::Descending
;
3020 if (bNewSortdescriptor
&& bOldSortdescriptor
)
3022 OSL_FAIL("someone tried to set the old deprecated and "
3023 "the new sortdescriptor");
3027 if (aKey1
.nColumnId
!= USHRT_MAX
)
3029 rSortOpt
.aKeys
.push_back(aKey1
);
3031 if (aKey2
.nColumnId
!= USHRT_MAX
)
3033 rSortOpt
.aKeys
.push_back(aKey2
);
3035 if (aKey3
.nColumnId
!= USHRT_MAX
)
3037 rSortOpt
.aKeys
.push_back(aKey3
);
3040 return bRet
&& !rSortOpt
.aKeys
.empty();
3044 SwXTextCursor::sort(const uno::Sequence
< beans::PropertyValue
>& rDescriptor
)
3046 SolarMutexGuard aGuard
;
3048 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
3050 if (!rUnoCursor
.HasMark())
3053 SwSortOptions aSortOpt
;
3054 if (!SwUnoCursorHelper::ConvertSortProperties(rDescriptor
, aSortOpt
))
3056 throw uno::RuntimeException(u
"Bad sort properties"_ustr
);
3058 UnoActionContext
aContext( &rUnoCursor
.GetDoc() );
3060 SwPosition
& rStart
= *rUnoCursor
.Start();
3061 SwPosition
& rEnd
= *rUnoCursor
.End();
3063 SwNodeIndex
aPrevIdx( rStart
.GetNode(), -1 );
3064 const SwNodeOffset nOffset
= rEnd
.GetNodeIndex() - rStart
.GetNodeIndex();
3065 const sal_Int32 nCntStt
= rStart
.GetContentIndex();
3067 rUnoCursor
.GetDoc().SortText(rUnoCursor
, aSortOpt
);
3070 rUnoCursor
.DeleteMark();
3071 rUnoCursor
.GetPoint()->Assign( aPrevIdx
.GetNode(), SwNodeOffset(1) );
3072 SwContentNode
*const pCNd
= rUnoCursor
.GetPointContentNode();
3073 sal_Int32 nLen
= pCNd
->Len();
3078 rUnoCursor
.GetPoint()->SetContent( nLen
);
3079 rUnoCursor
.SetMark();
3081 rUnoCursor
.GetPoint()->Adjust(nOffset
);
3082 SwContentNode
*const pCNd2
= rUnoCursor
.GetPointContentNode();
3083 rUnoCursor
.GetPoint()->SetContent( pCNd2
->Len() );
3087 uno::Reference
< container::XEnumeration
> SAL_CALL
3088 SwXTextCursor::createContentEnumeration(const OUString
& rServiceName
)
3091 if (rServiceName
!= "com.sun.star.text.TextContent")
3092 throw uno::RuntimeException();
3093 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
3094 return SwXParaFrameEnumeration::Create(rUnoCursor
, PARAFRAME_PORTION_TEXTRANGE
);
3097 uno::Reference
< container::XEnumeration
> SAL_CALL
3098 SwXTextCursor::createEnumeration()
3102 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
3104 SwXText
* pParentText
= dynamic_cast<SwXText
*>(m_xParentText
.get());
3105 OSL_ENSURE(pParentText
, "parent is not a SwXText");
3108 throw uno::RuntimeException();
3111 auto pNewCursor(rUnoCursor
.GetDoc().CreateUnoCursor(*rUnoCursor
.GetPoint()) );
3112 if (rUnoCursor
.HasMark())
3114 pNewCursor
->SetMark();
3115 *pNewCursor
->GetMark() = *rUnoCursor
.GetMark();
3117 const CursorType eSetType
= (CursorType::TableText
== m_eType
)
3118 ? CursorType::SelectionInTable
: CursorType::Selection
;
3119 return SwXParagraphEnumeration::Create(pParentText
, pNewCursor
, eSetType
);
3123 SwXTextCursor::getElementType()
3125 return cppu::UnoType
<text::XTextRange
>::get();
3128 sal_Bool SAL_CALL
SwXTextCursor::hasElements()
3133 uno::Sequence
< OUString
> SAL_CALL
3134 SwXTextCursor::getAvailableServiceNames()
3136 uno::Sequence
<OUString
> aRet
{ u
"com.sun.star.text.TextContent"_ustr
};
3140 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */