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>
42 #include <rootfrm.hxx>
45 #include <shellio.hxx>
47 #include <fmtruby.hxx>
49 #include <docstyle.hxx>
50 #include <fmtpdsc.hxx>
51 #include <pagedesc.hxx>
53 #include <fchrfmt.hxx>
54 #include <fmtautofmt.hxx>
55 #include <unotextrange.hxx>
56 #include <unotextcursor.hxx>
58 #include <unoprnms.hxx>
59 #include <unometa.hxx>
60 #include <unocontentcontrol.hxx>
61 #include <unotext.hxx>
62 #include <com/sun/star/text/TextMarkupType.hpp>
64 #include <vcl/svapp.hxx>
65 #include <unotools/syslocale.hxx>
66 #include <i18nlangtag/languagetag.hxx>
67 #include <SwStyleNameMapper.hxx>
68 #include <sortopt.hxx>
69 #include <com/sun/star/beans/PropertyAttribute.hpp>
70 #include <com/sun/star/beans/NamedValue.hpp>
71 #include <com/sun/star/i18n/WordType.hpp>
73 #include <unoparaframeenum.hxx>
74 #include <unoparagraph.hxx>
75 #include <iodetect.hxx>
76 #include <comphelper/propertyvalue.hxx>
77 #include <comphelper/servicehelper.hxx>
78 #include <comphelper/profilezone.hxx>
79 #include <comphelper/flagguard.hxx>
80 #include <swmodule.hxx>
82 using namespace ::com::sun::star
;
85 SwUnoInternalPaM::SwUnoInternalPaM(SwDoc
& rDoc
) :
86 SwPaM(rDoc
.GetNodes())
90 SwUnoInternalPaM::~SwUnoInternalPaM()
92 while( GetNext() != this)
94 // coverity[deref_arg] - the delete moves a new entry into GetNext()
99 SwUnoInternalPaM
& SwUnoInternalPaM::operator=(const SwPaM
& rPaM
)
101 const SwPaM
* pTmp
= &rPaM
;
102 *GetPoint() = *rPaM
.GetPoint();
106 *GetMark() = *rPaM
.GetMark();
110 while(&rPaM
!= (pTmp
= pTmp
->GetNext()))
113 new SwPaM(*pTmp
->GetMark(), *pTmp
->GetPoint(), this);
115 new SwPaM(*pTmp
->GetPoint(), this);
120 void SwUnoCursorHelper::SelectPam(SwPaM
& rPam
, const bool bExpand
)
129 else if (rPam
.HasMark())
135 void SwUnoCursorHelper::GetTextFromPam(SwPaM
& rPam
, OUString
& rBuffer
,
136 SwRootFrame
const*const pLayout
)
142 SvMemoryStream aStream
;
144 aStream
.SetEndian( SvStreamEndian::BIG
);
146 aStream
.SetEndian( SvStreamEndian::LITTLE
);
149 // TODO/MBA: looks like a BaseURL doesn't make sense here
150 SwReaderWriter::GetWriter( FILTER_TEXT_DLG
, OUString(), xWrt
);
154 SwWriter
aWriter( aStream
, rPam
);
155 xWrt
->m_bASCII_NoLastLineEnd
= true;
156 xWrt
->m_bExportParagraphNumbering
= false;
157 SwAsciiOptions aOpt
= xWrt
->GetAsciiOptions();
158 aOpt
.SetCharSet( RTL_TEXTENCODING_UNICODE
);
159 xWrt
->SetAsciiOptions( aOpt
);
160 xWrt
->m_bUCS2_WithStartChar
= false;
162 const bool bOldShowProgress
= xWrt
->m_bShowProgress
;
163 xWrt
->m_bShowProgress
= false;
164 xWrt
->m_bHideDeleteRedlines
= pLayout
&& pLayout
->IsHideRedlines();
165 // tdf#155951 SwWriter::Write calls EndAllAction, and that
166 // called SelectShell(), triggering selection change event, which
167 // resulted infinite recursion, if selectionChanged() calls
168 // XTextRange::getString() e.g. on the selected range.
169 ::comphelper::FlagRestorationGuard
g(g_bNoInterrupt
, true);
171 if( ! aWriter
.Write( xWrt
).IsError() )
173 const sal_uInt64 lUniLen
= aStream
.GetSize()/sizeof( sal_Unicode
);
174 if (lUniLen
< o3tl::make_unsigned(SAL_MAX_INT32
-1))
176 aStream
.WriteUInt16( '\0' );
179 aStream
.ResetError();
181 rtl_uString
*pStr
= rtl_uString_alloc(lUniLen
);
182 aStream
.ReadBytes(pStr
->buffer
, lUniLen
* sizeof(sal_Unicode
));
183 rBuffer
= OUString(pStr
, SAL_NO_ACQUIRE
);
186 xWrt
->m_bShowProgress
= bOldShowProgress
;
190 /// @throws lang::IllegalArgumentException
191 /// @throws uno::RuntimeException
193 lcl_setCharStyle(SwDoc
& rDoc
, const uno::Any
& rValue
, SfxItemSet
& rSet
)
195 SwDocShell
*const pDocSh
= rDoc
.GetDocShell();
200 if (!(rValue
>>= uStyle
))
202 throw lang::IllegalArgumentException();
205 SwStyleNameMapper::FillUIName(uStyle
, sStyle
,
206 SwGetPoolIdFromName::ChrFmt
);
207 SwDocStyleSheet
*const pStyle
= static_cast<SwDocStyleSheet
*>(
208 pDocSh
->GetStyleSheetPool()->Find(sStyle
, SfxStyleFamily::Char
));
211 throw lang::IllegalArgumentException();
213 const SwFormatCharFormat
aFormat(pStyle
->GetCharFormat());
217 /// @throws lang::IllegalArgumentException
219 lcl_setAutoStyle(IStyleAccess
& rStyleAccess
, const uno::Any
& rValue
,
220 SfxItemSet
& rSet
, const bool bPara
)
223 if (!(rValue
>>= uStyle
))
225 throw lang::IllegalArgumentException();
227 std::shared_ptr
<SfxItemSet
> pStyle
= bPara
?
228 rStyleAccess
.getByName(uStyle
, IStyleAccess::AUTO_STYLE_PARA
):
229 rStyleAccess
.getByName(uStyle
, IStyleAccess::AUTO_STYLE_CHAR
);
232 throw lang::IllegalArgumentException();
235 SwFormatAutoFormat
aFormat( bPara
236 ? sal::static_int_cast
< sal_uInt16
>(RES_AUTO_STYLE
)
237 : sal::static_int_cast
< sal_uInt16
>(RES_TXTATR_AUTOFMT
) );
238 aFormat
.SetStyleHandle( pStyle
);
243 SwUnoCursorHelper::SetTextFormatColl(const uno::Any
& rAny
, SwPaM
& rPaM
)
245 SwDoc
& rDoc
= rPaM
.GetDoc();
246 SwDocShell
*const pDocSh
= rDoc
.GetDocShell();
252 SwStyleNameMapper::FillUIName(uStyle
, sStyle
,
253 SwGetPoolIdFromName::TxtColl
);
254 SwDocStyleSheet
*const pStyle
= static_cast<SwDocStyleSheet
*>(
255 pDocSh
->GetStyleSheetPool()->Find(sStyle
, SfxStyleFamily::Para
));
258 throw lang::IllegalArgumentException();
261 SwTextFormatColl
*const pLocal
= pStyle
->GetCollection();
262 UnoActionContext
aAction(&rDoc
);
263 rDoc
.GetIDocumentUndoRedo().StartUndo( SwUndoId::START
, nullptr );
264 SwPaM
*pTmpCursor
= &rPaM
;
266 rDoc
.SetTextFormatColl(*pTmpCursor
, pLocal
);
267 pTmpCursor
= pTmpCursor
->GetNext();
268 } while ( pTmpCursor
!= &rPaM
);
269 rDoc
.GetIDocumentUndoRedo().EndUndo( SwUndoId::END
, nullptr );
273 SwUnoCursorHelper::SetPageDesc(
274 const uno::Any
& rValue
, SwDoc
& rDoc
, SfxItemSet
& rSet
)
277 if (!(rValue
>>= uDescName
))
281 std::unique_ptr
<SwFormatPageDesc
> pNewDesc
;
282 if(const SwFormatPageDesc
* pItem
= rSet
.GetItemIfSet( RES_PAGEDESC
))
284 pNewDesc
.reset(new SwFormatPageDesc(*pItem
));
288 pNewDesc
.reset(new SwFormatPageDesc());
291 SwStyleNameMapper::FillUIName(uDescName
, sDescName
,
292 SwGetPoolIdFromName::PageDesc
);
293 if (!pNewDesc
->GetPageDesc() ||
294 (pNewDesc
->GetPageDesc()->GetName() != sDescName
))
297 if (!sDescName
.isEmpty())
299 SwPageDesc
*const pPageDesc
= SwPageDesc::GetByName(rDoc
, sDescName
);
302 throw lang::IllegalArgumentException();
304 pNewDesc
->RegisterToPageDesc(*pPageDesc
);
309 rSet
.ClearItem(RES_BREAK
);
310 rSet
.Put(SwFormatPageDesc());
314 rSet
.Put(std::move(pNewDesc
));
321 lcl_SetNodeNumStart(SwPaM
& rCursor
, uno::Any
const& rValue
)
325 sal_uInt16 nStt
= (nTmp
< 0 ? USHRT_MAX
: o3tl::narrowing
<sal_uInt16
>(nTmp
));
326 SwDoc
& rDoc
= rCursor
.GetDoc();
327 UnoActionContext
aAction(&rDoc
);
329 if( rCursor
.GetNext() != &rCursor
) // MultiSelection?
331 rDoc
.GetIDocumentUndoRedo().StartUndo( SwUndoId::START
, nullptr );
332 SwPamRanges
aRangeArr( rCursor
);
333 SwPaM
aPam( *rCursor
.GetPoint() );
334 for( size_t n
= 0; n
< aRangeArr
.Count(); ++n
)
336 rDoc
.SetNumRuleStart(*aRangeArr
.SetPam( n
, aPam
).GetPoint());
337 rDoc
.SetNodeNumStart(*aRangeArr
.SetPam( n
, aPam
).GetPoint(),
340 rDoc
.GetIDocumentUndoRedo().EndUndo( SwUndoId::END
, nullptr );
344 rDoc
.SetNumRuleStart( *rCursor
.GetPoint());
345 rDoc
.SetNodeNumStart( *rCursor
.GetPoint(), nStt
);
350 lcl_setCharFormatSequence(SwPaM
& rPam
, uno::Any
const& rValue
)
352 uno::Sequence
<OUString
> aCharStyles
;
353 if (!(rValue
>>= aCharStyles
))
358 for (sal_Int32 nStyle
= 0; nStyle
< aCharStyles
.getLength(); nStyle
++)
361 rPam
.GetDoc().GetIDocumentUndoRedo().StartUndo(SwUndoId::START
, nullptr);
362 aStyle
<<= aCharStyles
.getConstArray()[nStyle
];
363 // create a local set and apply each format directly
364 SfxItemSetFixed
<RES_TXTATR_CHARFMT
, RES_TXTATR_CHARFMT
> aSet(rPam
.GetDoc().GetAttrPool());
365 lcl_setCharStyle(rPam
.GetDoc(), aStyle
, aSet
);
366 // the first style should replace the current attributes,
367 // all other have to be added
368 SwUnoCursorHelper::SetCursorAttr(rPam
, aSet
, nStyle
369 ? SetAttrMode::DONTREPLACE
370 : SetAttrMode::DEFAULT
);
371 rPam
.GetDoc().GetIDocumentUndoRedo().EndUndo(SwUndoId::START
, nullptr);
377 lcl_setDropcapCharStyle(SwPaM
const & rPam
, SfxItemSet
& rItemSet
,
378 uno::Any
const& rValue
)
381 if (!(rValue
>>= uStyle
))
383 throw lang::IllegalArgumentException();
386 SwStyleNameMapper::FillUIName(uStyle
, sStyle
,
387 SwGetPoolIdFromName::ChrFmt
);
388 SwDoc
& rDoc
= rPam
.GetDoc();
389 //default character style must not be set as default format
390 SwDocStyleSheet
*const pStyle
= static_cast<SwDocStyleSheet
*>(
392 ->GetStyleSheetPool()->Find(sStyle
, SfxStyleFamily::Char
));
393 if (!pStyle
|| pStyle
->GetCharFormat() == rDoc
.GetDfltCharFormat())
395 throw lang::IllegalArgumentException();
397 std::unique_ptr
<SwFormatDrop
> pDrop
;
398 if (const SwFormatDrop
* pItem
= rItemSet
.GetItemIfSet(RES_PARATR_DROP
))
400 pDrop
.reset(new SwFormatDrop(*pItem
));
404 pDrop
.reset(new SwFormatDrop
);
406 const rtl::Reference
<SwDocStyleSheet
> xStyle(new SwDocStyleSheet(*pStyle
));
407 pDrop
->SetCharFormat(xStyle
->GetCharFormat());
408 rItemSet
.Put(std::move(pDrop
));
412 lcl_setRubyCharstyle(SfxItemSet
& rItemSet
, uno::Any
const& rValue
)
415 if (!(rValue
>>= sTmp
))
417 throw lang::IllegalArgumentException();
420 std::unique_ptr
<SwFormatRuby
> pRuby
;
421 if (const SwFormatRuby
* pItem
= rItemSet
.GetItemIfSet(RES_TXTATR_CJK_RUBY
))
423 pRuby
.reset(new SwFormatRuby(*pItem
));
427 pRuby
.reset(new SwFormatRuby(OUString()));
430 SwStyleNameMapper::FillUIName(sTmp
, sStyle
,
431 SwGetPoolIdFromName::ChrFmt
);
432 pRuby
->SetCharFormatName(sStyle
);
433 pRuby
->SetCharFormatId(0);
434 if (!sStyle
.isEmpty())
436 const sal_uInt16 nId
= SwStyleNameMapper::GetPoolIdFromUIName(
437 sStyle
, SwGetPoolIdFromName::ChrFmt
);
438 pRuby
->SetCharFormatId(nId
);
440 rItemSet
.Put(std::move(pRuby
));
444 SwUnoCursorHelper::SetCursorPropertyValue(
445 SfxItemPropertyMapEntry
const& rEntry
, const uno::Any
& rValue
,
446 SwPaM
& rPam
, SfxItemSet
& rItemSet
)
448 if (!(rEntry
.nFlags
& beans::PropertyAttribute::MAYBEVOID
) &&
449 (rValue
.getValueType() == cppu::UnoType
<void>::get()))
456 case RES_TXTATR_CHARFMT
:
457 lcl_setCharStyle(rPam
.GetDoc(), rValue
, rItemSet
);
459 case RES_TXTATR_AUTOFMT
:
460 lcl_setAutoStyle(rPam
.GetDoc().GetIStyleAccess(),
461 rValue
, rItemSet
, false);
463 case FN_UNO_CHARFMT_SEQUENCE
:
464 lcl_setCharFormatSequence(rPam
, rValue
);
466 case FN_UNO_PARA_STYLE
:
467 SwUnoCursorHelper::SetTextFormatColl(rValue
, rPam
);
470 lcl_setAutoStyle(rPam
.GetDoc().GetIStyleAccess(),
471 rValue
, rItemSet
, true);
473 case FN_UNO_PAGE_STYLE
:
474 //FIXME nothing here?
476 case FN_UNO_NUM_START_VALUE
:
477 lcl_SetNodeNumStart( rPam
, rValue
);
479 case FN_UNO_NUM_LEVEL
:
482 case FN_UNO_IS_NUMBER
:
483 case FN_UNO_PARA_NUM_AUTO_FORMAT
:
485 // multi selection is not considered
486 SwTextNode
*const pTextNd
= rPam
.GetPointNode().GetTextNode();
489 throw lang::IllegalArgumentException();
491 if (FN_UNO_NUM_LEVEL
== rEntry
.nWID
)
493 sal_Int16 nLevel
= 0;
494 if (rValue
>>= nLevel
)
496 if (nLevel
< 0 || MAXLEVEL
<= nLevel
)
498 throw lang::IllegalArgumentException(
499 "invalid NumberingLevel", nullptr, 0);
501 pTextNd
->SetAttrListLevel(nLevel
);
505 else if (FN_UNO_LIST_ID
== rEntry
.nWID
)
508 if (rValue
>>= sListId
)
510 pTextNd
->SetListId( sListId
);
513 else if (FN_UNO_IS_NUMBER
== rEntry
.nWID
)
515 bool bIsNumber(false);
516 if ((rValue
>>= bIsNumber
) && !bIsNumber
)
518 pTextNd
->SetCountedInList( false );
521 else if (FN_UNO_PARA_NUM_AUTO_FORMAT
== rEntry
.nWID
)
523 std::shared_ptr
<SfxItemSet
> pAutoStyle
;
524 if (uno::Sequence
<beans::NamedValue
> props
; rValue
>>= props
)
526 // 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?
527 SfxItemPropertySet
const& rPropSet(*aSwMapProvider
.GetPropertySet(PROPERTY_MAP_CHAR_AUTO_STYLE
));
528 SfxItemPropertyMap
const& rMap(rPropSet
.getPropertyMap());
530 <RES_CHRATR_BEGIN
, RES_CHRATR_END
-1,
531 RES_TXTATR_CHARFMT
, RES_TXTATR_CHARFMT
,
532 RES_UNKNOWNATR_BEGIN
, RES_UNKNOWNATR_END
-1>
533 items( rPam
.GetDoc().GetAttrPool() );
535 for (beans::NamedValue
const & prop
: std::as_const(props
))
537 SfxItemPropertyMapEntry
const*const pEntry
=
538 rMap
.getByName(prop
.Name
);
541 if (prop
.Name
== "CharStyleName")
543 lcl_setCharStyle(rPam
.GetDoc(), prop
.Value
, items
);
546 throw beans::UnknownPropertyException(
547 "Unknown property: " + prop
.Name
);
549 if (pEntry
->nFlags
& beans::PropertyAttribute::READONLY
)
551 throw beans::PropertyVetoException(
552 "Property is read-only: " + prop
.Name
);
554 rPropSet
.setPropertyValue(*pEntry
, prop
.Value
, items
);
557 IStyleAccess
& rStyleAccess
= rPam
.GetDoc().GetIStyleAccess();
558 // Add it to the autostyle pool, needed by the ODT export.
559 pAutoStyle
= rStyleAccess
.getAutomaticStyle(items
, IStyleAccess::AUTO_STYLE_CHAR
);
561 else if (OUString styleName
; rValue
>>= styleName
)
563 IStyleAccess
& rStyleAccess
= rPam
.GetDoc().GetIStyleAccess();
564 pAutoStyle
= rStyleAccess
.getByName(styleName
, IStyleAccess::AUTO_STYLE_CHAR
);
568 SwFormatAutoFormat
item(RES_PARATR_LIST_AUTOFMT
);
569 // 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()
570 item
.SetStyleHandle(pAutoStyle
);
571 pTextNd
->SetAttr(item
);
574 //PROPERTY_MAYBEVOID!
577 case FN_NUMBER_NEWSTART
:
580 if (!(rValue
>>= bVal
))
582 throw lang::IllegalArgumentException();
584 rPam
.GetDoc().SetNumRuleStart(*rPam
.GetPoint(), bVal
);
587 case FN_UNO_NUM_RULES
:
588 SwUnoCursorHelper::setNumberingProperty(rValue
, rPam
);
590 case RES_PARATR_DROP
:
592 if (MID_DROPCAP_CHAR_STYLE_NAME
== rEntry
.nMemberId
)
594 lcl_setDropcapCharStyle(rPam
, rItemSet
, rValue
);
602 case RES_TXTATR_CJK_RUBY
:
604 if (MID_RUBY_CHARSTYLE
== rEntry
.nMemberId
)
606 lcl_setRubyCharstyle(rItemSet
, rValue
);
616 if (MID_PAGEDESC_PAGEDESCNAME
== rEntry
.nMemberId
)
618 SwUnoCursorHelper::SetPageDesc(
619 rValue
, rPam
.GetDoc(), rItemSet
);
634 SwUnoCursorHelper::GetCurTextFormatColl(SwPaM
& rPaM
, const bool bConditional
)
636 static const sal_uLong nMaxLookup
= 1000;
637 SwFormatColl
*pFormat
= nullptr;
639 SwPaM
*pTmpCursor
= &rPaM
;
642 const SwNodeOffset nSttNd
= pTmpCursor
->Start()->GetNodeIndex();
643 const SwNodeOffset nEndNd
= pTmpCursor
->End()->GetNodeIndex();
645 if( nEndNd
- nSttNd
>= SwNodeOffset(nMaxLookup
) )
651 const SwNodes
& rNds
= rPaM
.GetDoc().GetNodes();
652 for( SwNodeOffset n
= nSttNd
; n
<= nEndNd
; ++n
)
654 SwTextNode
const*const pNd
= rNds
[ n
]->GetTextNode();
657 SwFormatColl
*const pNdFormat
= bConditional
658 ? pNd
->GetFormatColl() : &pNd
->GetAnyFormatColl();
663 else if( pFormat
!= pNdFormat
)
671 pTmpCursor
= pTmpCursor
->GetNext();
672 } while ( pTmpCursor
!= &rPaM
);
673 return bError
? nullptr : pFormat
;
676 SwUnoCursor
& SwXTextCursor::GetCursor()
677 { return *m_pUnoCursor
; }
679 SwPaM
const* SwXTextCursor::GetPaM() const
680 { return m_pUnoCursor
.get(); }
682 SwPaM
* SwXTextCursor::GetPaM()
683 { return m_pUnoCursor
.get(); }
685 SwDoc
const* SwXTextCursor::GetDoc() const
686 { return m_pUnoCursor
? &m_pUnoCursor
->GetDoc() : nullptr; }
688 SwDoc
* SwXTextCursor::GetDoc()
689 { return m_pUnoCursor
? &m_pUnoCursor
->GetDoc() : nullptr; }
691 SwXTextCursor::SwXTextCursor(
693 uno::Reference
< text::XText
> xParent
,
694 const CursorType eType
,
695 const SwPosition
& rPos
,
696 SwPosition
const*const pMark
)
697 : m_rPropSet(*aSwMapProvider
.GetPropertySet(PROPERTY_MAP_TEXT_CURSOR
))
699 , m_xParentText(std::move(xParent
))
700 , m_pUnoCursor(rDoc
.CreateUnoCursor(rPos
))
704 m_pUnoCursor
->SetMark();
705 *m_pUnoCursor
->GetMark() = *pMark
;
709 SwXTextCursor::SwXTextCursor(uno::Reference
< text::XText
> xParent
,
710 SwPaM
const& rSourceCursor
, const CursorType eType
)
711 : m_rPropSet(*aSwMapProvider
.GetPropertySet(PROPERTY_MAP_TEXT_CURSOR
))
713 , m_xParentText(std::move(xParent
))
714 , m_pUnoCursor(rSourceCursor
.GetDoc().CreateUnoCursor(*rSourceCursor
.GetPoint()))
716 if (rSourceCursor
.HasMark())
718 m_pUnoCursor
->SetMark();
719 *m_pUnoCursor
->GetMark() = *rSourceCursor
.GetMark();
723 SwXTextCursor::~SwXTextCursor()
725 SolarMutexGuard g
; // #i105557#: call dtor with locked solar mutex
726 m_pUnoCursor
.reset(nullptr); // need to delete this with SolarMutex held
729 void SwXTextCursor::DeleteAndInsert(std::u16string_view aText
,
730 ::sw::DeleteAndInsertMode
const eMode
)
732 auto pUnoCursor
= static_cast<SwCursor
*>(m_pUnoCursor
.get());
737 SwDoc
& rDoc
= pUnoCursor
->GetDoc();
738 UnoActionContext
aAction(&rDoc
);
739 const sal_Int32 nTextLen
= aText
.size();
740 rDoc
.GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT
, nullptr);
741 auto pCurrent
= pUnoCursor
;
744 if (pCurrent
->HasMark())
746 rDoc
.getIDocumentContentOperations().DeleteAndJoin(*pCurrent
,
747 // is it "delete" or "replace"?
748 (nTextLen
!= 0 || eMode
& ::sw::DeleteAndInsertMode::ForceReplace
) ? SwDeleteFlags::ArtificialSelection
: SwDeleteFlags::Default
);
753 SwUnoCursorHelper::DocInsertStringSplitCR(
754 rDoc
, *pCurrent
, aText
, bool(eMode
& ::sw::DeleteAndInsertMode::ForceExpandHints
)));
755 OSL_ENSURE( bSuccess
, "Doc->Insert(Str) failed." );
757 SwUnoCursorHelper::SelectPam(*pUnoCursor
, true);
758 pCurrent
->Left(aText
.size());
760 pCurrent
= pCurrent
->GetNext();
761 } while (pCurrent
!= pUnoCursor
);
762 rDoc
.GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT
, nullptr);
767 enum ForceIntoMetaMode
{ META_CHECK_BOTH
, META_INIT_START
, META_INIT_END
};
769 enum ForceIntoContentControlMode
771 CONTENT_CONTROL_CHECK_BOTH
,
772 CONTENT_CONTROL_INIT_START
,
773 CONTENT_CONTROL_INIT_END
778 lcl_ForceIntoMeta(SwPaM
& rCursor
,
779 uno::Reference
<text::XText
> const & xParentText
,
780 const enum ForceIntoMetaMode eMode
)
782 bool bRet( true ); // means not forced in META_CHECK_BOTH
783 SwXMeta
const * const pXMeta( dynamic_cast<SwXMeta
*>(xParentText
.get()) );
784 OSL_ENSURE(pXMeta
, "no parent?");
786 throw uno::RuntimeException();
787 SwTextNode
* pTextNode
;
790 const bool bSuccess( pXMeta
->SetContentRange(pTextNode
, nStart
, nEnd
) );
791 OSL_ENSURE(bSuccess
, "no pam?");
793 throw uno::RuntimeException();
794 // force the cursor back into the meta if it has moved outside
795 SwPosition
start(*pTextNode
, nStart
);
796 SwPosition
end(*pTextNode
, nEnd
);
799 case META_INIT_START
:
800 *rCursor
.GetPoint() = start
;
803 *rCursor
.GetPoint() = end
;
805 case META_CHECK_BOTH
:
806 if (*rCursor
.Start() < start
)
808 *rCursor
.Start() = start
;
811 if (*rCursor
.End() > end
)
813 *rCursor
.End() = end
;
823 bool lcl_ForceIntoContentControl(SwPaM
& rCursor
, const uno::Reference
<text::XText
>& xParentText
,
824 ForceIntoContentControlMode eMode
)
826 bool bRet
= true; // means not forced in CONTENT_CONTROL_CHECK_BOTH
827 auto pXContentControl
= dynamic_cast<SwXContentControl
*>(xParentText
.get());
828 if (!pXContentControl
)
830 SAL_WARN("sw.core", "lcl_ForceIntoContentControl: no parent text");
831 throw uno::RuntimeException();
834 SwTextNode
* pTextNode
;
837 bool bSuccess
= pXContentControl
->SetContentRange(pTextNode
, nStart
, nEnd
);
840 SAL_WARN("sw.core", "lcl_ForceIntoContentControl: SetContentRange() failed");
841 throw uno::RuntimeException();
844 // Force the cursor back into the content control if it has moved outside.
845 SwPosition
aStart(*pTextNode
, nStart
);
846 SwPosition
aEnd(*pTextNode
, nEnd
);
849 case CONTENT_CONTROL_INIT_START
:
850 *rCursor
.GetPoint() = aStart
;
853 case CONTENT_CONTROL_INIT_END
:
854 *rCursor
.GetPoint() = aEnd
;
857 case CONTENT_CONTROL_CHECK_BOTH
:
858 if (*rCursor
.Start() < aStart
)
860 *rCursor
.Start() = aStart
;
864 if (*rCursor
.End() > aEnd
)
866 *rCursor
.End() = aEnd
;
876 bool SwXTextCursor::IsAtEndOfMeta() const
878 if (CursorType::Meta
== m_eType
)
880 auto pCursor( m_pUnoCursor
);
881 SwXMeta
const*const pXMeta(
882 dynamic_cast<SwXMeta
*>(m_xParentText
.get()) );
883 OSL_ENSURE(pXMeta
, "no meta?");
884 if (pCursor
&& pXMeta
)
886 SwTextNode
* pTextNode
;
890 pXMeta
->SetContentRange(pTextNode
, nStart
, nEnd
) );
891 OSL_ENSURE(bSuccess
, "no pam?");
894 const SwPosition
end(*pTextNode
, nEnd
);
895 if ( (*pCursor
->GetPoint() == end
)
896 || (*pCursor
->GetMark() == end
))
906 bool SwXTextCursor::IsAtEndOfContentControl() const
908 if (CursorType::ContentControl
== m_eType
)
910 auto pCursor( m_pUnoCursor
);
911 auto pXContentControl(
912 dynamic_cast<SwXContentControl
*>(m_xParentText
.get()) );
913 if (!pXContentControl
)
915 SAL_WARN("sw.core", "SwXTextCursor::IsAtEndOfContentControl: no content control");
917 if (pCursor
&& pXContentControl
)
919 SwTextNode
* pTextNode
;
923 pXContentControl
->SetContentRange(pTextNode
, nStart
, nEnd
) );
926 SAL_WARN("sw.core", "SwXTextCursor::IsAtEndOfContentControl: no pam");
930 const SwPosition
end(*pTextNode
, nEnd
);
931 if ( (*pCursor
->GetPoint() == end
)
932 || (*pCursor
->GetMark() == end
))
942 OUString
SwXTextCursor::getImplementationName()
944 return "SwXTextCursor";
947 sal_Bool SAL_CALL
SwXTextCursor::supportsService(const OUString
& rServiceName
)
949 return cppu::supportsService(this, rServiceName
);
952 uno::Sequence
< OUString
> SAL_CALL
953 SwXTextCursor::getSupportedServiceNames()
956 "com.sun.star.text.TextCursor",
957 "com.sun.star.style.CharacterProperties",
958 "com.sun.star.style.CharacterPropertiesAsian",
959 "com.sun.star.style.CharacterPropertiesComplex",
960 "com.sun.star.style.ParagraphProperties",
961 "com.sun.star.style.ParagraphPropertiesAsian",
962 "com.sun.star.style.ParagraphPropertiesComplex",
963 "com.sun.star.text.TextSortable"
967 void SAL_CALL
SwXTextCursor::collapseToStart()
969 SolarMutexGuard aGuard
;
971 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
973 if (rUnoCursor
.HasMark())
975 if (*rUnoCursor
.GetPoint() > *rUnoCursor
.GetMark())
977 rUnoCursor
.Exchange();
979 rUnoCursor
.DeleteMark();
983 void SAL_CALL
SwXTextCursor::collapseToEnd()
985 SolarMutexGuard aGuard
;
987 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
989 if (rUnoCursor
.HasMark())
991 if (*rUnoCursor
.GetPoint() < *rUnoCursor
.GetMark())
993 rUnoCursor
.Exchange();
995 rUnoCursor
.DeleteMark();
999 sal_Bool SAL_CALL
SwXTextCursor::isCollapsed()
1001 SolarMutexGuard aGuard
;
1004 auto pUnoCursor(m_pUnoCursor
);
1005 if(pUnoCursor
&& pUnoCursor
->GetMark())
1007 bRet
= (*pUnoCursor
->GetPoint() == *pUnoCursor
->GetMark());
1013 SwXTextCursor::goLeft(sal_Int16 nCount
, sal_Bool Expand
)
1015 SolarMutexGuard aGuard
;
1017 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1019 SwUnoCursorHelper::SelectPam(rUnoCursor
, Expand
);
1020 bool bRet
= rUnoCursor
.Left( nCount
);
1021 if (CursorType::Meta
== m_eType
)
1023 bRet
= lcl_ForceIntoMeta(rUnoCursor
, m_xParentText
,
1027 else if (m_eType
== CursorType::ContentControl
)
1029 bRet
= lcl_ForceIntoContentControl(rUnoCursor
, m_xParentText
, CONTENT_CONTROL_CHECK_BOTH
)
1036 SwXTextCursor::goRight(sal_Int16 nCount
, sal_Bool Expand
)
1038 SolarMutexGuard aGuard
;
1040 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1042 SwUnoCursorHelper::SelectPam(rUnoCursor
, Expand
);
1043 bool bRet
= rUnoCursor
.Right(nCount
);
1044 if (CursorType::Meta
== m_eType
)
1046 bRet
= lcl_ForceIntoMeta(rUnoCursor
, m_xParentText
,
1050 else if (m_eType
== CursorType::ContentControl
)
1052 bRet
= lcl_ForceIntoContentControl(rUnoCursor
, m_xParentText
, CONTENT_CONTROL_CHECK_BOTH
)
1059 SwXTextCursor::gotoStart(sal_Bool Expand
)
1061 SolarMutexGuard aGuard
;
1062 comphelper::ProfileZone
aZone("gotoStart");
1064 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1066 SwUnoCursorHelper::SelectPam(rUnoCursor
, Expand
);
1067 if (CursorType::Body
== m_eType
)
1069 rUnoCursor
.Move( fnMoveBackward
, GoInDoc
);
1070 //check, that the cursor is not in a table
1071 SwTableNode
* pTableNode
= rUnoCursor
.GetPointNode().FindTableNode();
1074 rUnoCursor
.GetPoint()->Assign( *pTableNode
->EndOfSectionNode() );
1075 SwContentNode
* pCNode
= GetDoc()->GetNodes().GoNext(rUnoCursor
.GetPoint());
1076 pTableNode
= pCNode
? pCNode
->FindTableNode() : nullptr;
1078 SwStartNode
const*const pTmp
=
1079 rUnoCursor
.GetPointNode().StartOfSectionNode();
1080 if (pTmp
->IsSectionNode())
1082 SwSectionNode
const*const pSectionStartNode
=
1083 static_cast<SwSectionNode
const*>(pTmp
);
1084 if (pSectionStartNode
->GetSection().IsHiddenFlag())
1086 GetDoc()->GetNodes().GoNextSection(
1087 rUnoCursor
.GetPoint(), true, false);
1091 else if ( (CursorType::Frame
== m_eType
)
1092 || (CursorType::TableText
== m_eType
)
1093 || (CursorType::Header
== m_eType
)
1094 || (CursorType::Footer
== m_eType
)
1095 || (CursorType::Footnote
== m_eType
)
1096 || (CursorType::Redline
== m_eType
))
1098 rUnoCursor
.MoveSection(GoCurrSection
, fnSectionStart
);
1100 else if (CursorType::Meta
== m_eType
)
1102 lcl_ForceIntoMeta(rUnoCursor
, m_xParentText
, META_INIT_START
);
1104 else if (m_eType
== CursorType::ContentControl
)
1106 lcl_ForceIntoContentControl(rUnoCursor
, m_xParentText
, CONTENT_CONTROL_INIT_START
);
1111 SwXTextCursor::gotoEnd(sal_Bool Expand
)
1113 SolarMutexGuard aGuard
;
1114 comphelper::ProfileZone
aZone("gotoEnd");
1116 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1118 SwUnoCursorHelper::SelectPam(rUnoCursor
, Expand
);
1119 if (CursorType::Body
== m_eType
)
1121 rUnoCursor
.Move( fnMoveForward
, GoInDoc
);
1123 else if ( (CursorType::Frame
== m_eType
)
1124 || (CursorType::TableText
== m_eType
)
1125 || (CursorType::Header
== m_eType
)
1126 || (CursorType::Footer
== m_eType
)
1127 || (CursorType::Footnote
== m_eType
)
1128 || (CursorType::Redline
== m_eType
))
1130 rUnoCursor
.MoveSection( GoCurrSection
, fnSectionEnd
);
1132 else if (CursorType::Meta
== m_eType
)
1134 lcl_ForceIntoMeta(rUnoCursor
, m_xParentText
, META_INIT_END
);
1136 else if (m_eType
== CursorType::ContentControl
)
1138 lcl_ForceIntoContentControl(rUnoCursor
, m_xParentText
, CONTENT_CONTROL_INIT_END
);
1143 SwXTextCursor::gotoRange(
1144 const uno::Reference
< text::XTextRange
> & xRange
, sal_Bool bExpand
)
1146 SolarMutexGuard aGuard
;
1150 throw uno::RuntimeException();
1153 SwUnoCursor
& rOwnCursor( GetCursorOrThrow() );
1155 SwXTextRange
* pRange
= dynamic_cast<SwXTextRange
*>(xRange
.get());
1156 OTextCursorHelper
* pCursor
= dynamic_cast<OTextCursorHelper
*>(xRange
.get());
1158 if (!pRange
&& !pCursor
)
1160 throw uno::RuntimeException();
1163 SwPaM
aPam(GetDoc()->GetNodes());
1164 const SwPaM
* pPam(nullptr);
1167 pPam
= pCursor
->GetPaM();
1171 if (pRange
->GetPositions(aPam
))
1179 throw uno::RuntimeException();
1183 SwStartNodeType eSearchNodeType
= SwNormalStartNode
;
1186 case CursorType::Frame
: eSearchNodeType
= SwFlyStartNode
; break;
1187 case CursorType::TableText
: eSearchNodeType
= SwTableBoxStartNode
; break;
1188 case CursorType::Footnote
: eSearchNodeType
= SwFootnoteStartNode
; break;
1189 case CursorType::Header
: eSearchNodeType
= SwHeaderStartNode
; break;
1190 case CursorType::Footer
: eSearchNodeType
= SwFooterStartNode
; break;
1191 //case CURSOR_INVALID:
1192 //case CursorType::Body:
1197 const SwStartNode
* pOwnStartNode
= rOwnCursor
.GetPointNode().FindSttNodeByType(eSearchNodeType
);
1198 while ( pOwnStartNode
!= nullptr
1199 && pOwnStartNode
->IsSectionNode())
1201 pOwnStartNode
= pOwnStartNode
->StartOfSectionNode();
1204 const SwStartNode
* pTmp
=
1205 pPam
->GetPointNode().FindSttNodeByType(eSearchNodeType
);
1206 while ( pTmp
!= nullptr
1207 && pTmp
->IsSectionNode() )
1209 pTmp
= pTmp
->StartOfSectionNode();
1212 if ( eSearchNodeType
== SwTableBoxStartNode
)
1214 if (!pOwnStartNode
|| !pTmp
)
1216 throw uno::RuntimeException();
1219 if ( pOwnStartNode
->FindTableNode() != pTmp
->FindTableNode() )
1221 throw uno::RuntimeException();
1226 if ( pOwnStartNode
!= pTmp
)
1228 throw uno::RuntimeException();
1233 if (CursorType::Meta
== m_eType
)
1235 SwPaM
CopyPam(*pPam
->GetMark(), *pPam
->GetPoint());
1236 const bool bNotForced( lcl_ForceIntoMeta(
1237 CopyPam
, m_xParentText
, META_CHECK_BOTH
) );
1240 throw uno::RuntimeException(
1241 "gotoRange: parameter range not contained in nesting"
1242 " text content for which this cursor was created",
1243 static_cast<text::XWordCursor
*>(this));
1246 else if (m_eType
== CursorType::ContentControl
)
1248 SwPaM
aPaM(*pPam
->GetMark(), *pPam
->GetPoint());
1249 if (!lcl_ForceIntoContentControl(aPaM
, m_xParentText
, CONTENT_CONTROL_CHECK_BOTH
))
1251 throw uno::RuntimeException("gotoRange: xRange is out of bounds of the content control",
1252 static_cast<text::XWordCursor
*>(this));
1256 // selection has to be expanded here
1259 // cursor should include its previous range plus the given range
1260 const SwPosition
aOwnLeft(*rOwnCursor
.Start());
1261 const SwPosition
aOwnRight(*rOwnCursor
.End());
1262 SwPosition
const& rParamLeft
= *pPam
->Start();
1263 SwPosition
const& rParamRight
= *pPam
->End();
1265 // now there are four SwPositions,
1266 // two of them are going to be used, but which ones?
1267 if (aOwnRight
> rParamRight
)
1268 *rOwnCursor
.GetPoint() = aOwnRight
;
1270 *rOwnCursor
.GetPoint() = rParamRight
;
1271 rOwnCursor
.SetMark();
1272 if (aOwnLeft
< rParamLeft
)
1273 *rOwnCursor
.GetMark() = aOwnLeft
;
1275 *rOwnCursor
.GetMark() = rParamLeft
;
1279 // cursor should be the given range
1280 *rOwnCursor
.GetPoint() = *pPam
->GetPoint();
1281 if (pPam
->HasMark())
1283 rOwnCursor
.SetMark();
1284 *rOwnCursor
.GetMark() = *pPam
->GetMark();
1288 rOwnCursor
.DeleteMark();
1293 sal_Bool SAL_CALL
SwXTextCursor::isStartOfWord()
1295 SolarMutexGuard aGuard
;
1297 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1300 rUnoCursor
.IsStartWordWT( i18n::WordType::DICTIONARY_WORD
);
1304 sal_Bool SAL_CALL
SwXTextCursor::isEndOfWord()
1306 SolarMutexGuard aGuard
;
1308 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1311 rUnoCursor
.IsEndWordWT( i18n::WordType::DICTIONARY_WORD
);
1316 SwXTextCursor::gotoNextWord(sal_Bool Expand
)
1318 SolarMutexGuard aGuard
;
1320 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1322 // problems arise when a paragraph starts with something other than a word
1324 // remember old position to check if cursor has moved
1325 // since the called functions are sometimes a bit unreliable
1326 // in specific cases...
1327 SwPosition
*const pPoint
= rUnoCursor
.GetPoint();
1328 SwNode
*const pOldNode
= &pPoint
->GetNode();
1329 sal_Int32
const nOldIndex
= pPoint
->GetContentIndex();
1331 SwUnoCursorHelper::SelectPam(rUnoCursor
, Expand
);
1333 if (rUnoCursor
.GetPointContentNode() &&
1334 (pPoint
->GetContentIndex() == rUnoCursor
.GetPointContentNode()->Len()))
1336 rUnoCursor
.Right(1);
1341 rUnoCursor
.GoNextWordWT( i18n::WordType::DICTIONARY_WORD
);
1342 // if there is no next word within the current paragraph
1343 // try to go to the start of the next paragraph
1346 rUnoCursor
.MovePara(GoNextPara
, fnParaStart
);
1350 // return true if cursor has moved
1351 bRet
= (&pPoint
->GetNode() != pOldNode
) ||
1352 (pPoint
->GetContentIndex() != nOldIndex
);
1353 if (bRet
&& (CursorType::Meta
== m_eType
))
1355 bRet
= lcl_ForceIntoMeta(rUnoCursor
, m_xParentText
,
1358 else if (bRet
&& m_eType
== CursorType::ContentControl
)
1360 bRet
= lcl_ForceIntoContentControl(rUnoCursor
, m_xParentText
, CONTENT_CONTROL_CHECK_BOTH
);
1367 SwXTextCursor::gotoPreviousWord(sal_Bool Expand
)
1369 SolarMutexGuard aGuard
;
1371 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1373 // white spaces create problems on the paragraph start
1375 SwPosition
*const pPoint
= rUnoCursor
.GetPoint();
1376 SwNode
*const pOldNode
= &pPoint
->GetNode();
1377 sal_Int32
const nOldIndex
= pPoint
->GetContentIndex();
1379 SwUnoCursorHelper::SelectPam(rUnoCursor
, Expand
);
1380 // start of paragraph?
1381 if (pPoint
->GetContentIndex() == 0)
1387 rUnoCursor
.GoPrevWordWT( i18n::WordType::DICTIONARY_WORD
);
1388 if (pPoint
->GetContentIndex() == 0)
1394 // return true if cursor has moved
1395 bRet
= (&pPoint
->GetNode() != pOldNode
) ||
1396 (pPoint
->GetContentIndex() != nOldIndex
);
1397 if (bRet
&& (CursorType::Meta
== m_eType
))
1399 bRet
= lcl_ForceIntoMeta(rUnoCursor
, m_xParentText
,
1402 else if (bRet
&& m_eType
== CursorType::ContentControl
)
1404 bRet
= lcl_ForceIntoContentControl(rUnoCursor
, m_xParentText
, CONTENT_CONTROL_CHECK_BOTH
);
1411 SwXTextCursor::gotoEndOfWord(sal_Bool Expand
)
1413 SolarMutexGuard aGuard
;
1415 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1418 SwPosition
*const pPoint
= rUnoCursor
.GetPoint();
1419 SwNode
& rOldNode
= pPoint
->GetNode();
1420 sal_Int32
const nOldIndex
= pPoint
->GetContentIndex();
1422 const sal_Int16 nWordType
= i18n::WordType::DICTIONARY_WORD
;
1423 SwUnoCursorHelper::SelectPam(rUnoCursor
, Expand
);
1424 if (!rUnoCursor
.IsEndWordWT( nWordType
))
1426 rUnoCursor
.GoEndWordWT( nWordType
);
1429 // restore old cursor if we are not at the end of a word by now
1430 // otherwise use current one
1431 bRet
= rUnoCursor
.IsEndWordWT( nWordType
);
1434 pPoint
->Assign(rOldNode
, nOldIndex
);
1436 else if (CursorType::Meta
== m_eType
)
1438 bRet
= lcl_ForceIntoMeta(rUnoCursor
, m_xParentText
,
1441 else if (m_eType
== CursorType::ContentControl
)
1443 bRet
= lcl_ForceIntoContentControl(rUnoCursor
, m_xParentText
, CONTENT_CONTROL_CHECK_BOTH
);
1450 SwXTextCursor::gotoStartOfWord(sal_Bool Expand
)
1452 SolarMutexGuard aGuard
;
1454 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1457 SwPosition
*const pPoint
= rUnoCursor
.GetPoint();
1458 SwNode
& rOldNode
= pPoint
->GetNode();
1459 sal_Int32
const nOldIndex
= pPoint
->GetContentIndex();
1461 const sal_Int16 nWordType
= i18n::WordType::DICTIONARY_WORD
;
1462 SwUnoCursorHelper::SelectPam(rUnoCursor
, Expand
);
1463 if (!rUnoCursor
.IsStartWordWT( nWordType
))
1465 rUnoCursor
.GoStartWordWT( nWordType
);
1468 // restore old cursor if we are not at the start of a word by now
1469 // otherwise use current one
1470 bRet
= rUnoCursor
.IsStartWordWT( nWordType
);
1473 pPoint
->Assign(rOldNode
, nOldIndex
);
1475 else if (CursorType::Meta
== m_eType
)
1477 bRet
= lcl_ForceIntoMeta(rUnoCursor
, m_xParentText
,
1480 else if (m_eType
== CursorType::ContentControl
)
1482 bRet
= lcl_ForceIntoContentControl(rUnoCursor
, m_xParentText
, CONTENT_CONTROL_CHECK_BOTH
);
1489 SwXTextCursor::isStartOfSentence()
1491 SolarMutexGuard aGuard
;
1493 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1495 // start of paragraph?
1496 bool bRet
= rUnoCursor
.GetPoint()->GetContentIndex() == 0;
1497 // with mark ->no sentence start
1498 // (check if cursor is no selection, i.e. it does not have
1499 // a mark or else point and mark are identical)
1500 if (!bRet
&& (!rUnoCursor
.HasMark() ||
1501 *rUnoCursor
.GetPoint() == *rUnoCursor
.GetMark()))
1503 SwCursor
aCursor(*rUnoCursor
.GetPoint(),nullptr);
1504 SwPosition aOrigPos
= *aCursor
.GetPoint();
1505 aCursor
.GoSentence(SwCursor::START_SENT
);
1506 bRet
= aOrigPos
== *aCursor
.GetPoint();
1512 SwXTextCursor::isEndOfSentence()
1514 SolarMutexGuard aGuard
;
1516 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1518 // end of paragraph?
1519 bool bRet
= rUnoCursor
.GetPointContentNode() &&
1520 (rUnoCursor
.GetPoint()->GetContentIndex() == rUnoCursor
.GetPointContentNode()->Len());
1521 // with mark->no sentence end
1522 // (check if cursor is no selection, i.e. it does not have
1523 // a mark or else point and mark are identical)
1524 if (!bRet
&& (!rUnoCursor
.HasMark() ||
1525 *rUnoCursor
.GetPoint() == *rUnoCursor
.GetMark()))
1527 SwCursor
aCursor(*rUnoCursor
.GetPoint(), nullptr);
1528 SwPosition aOrigPos
= *aCursor
.GetPoint();
1529 aCursor
.GoSentence(SwCursor::END_SENT
);
1530 bRet
= aOrigPos
== *aCursor
.GetPoint();
1536 SwXTextCursor::gotoNextSentence(sal_Bool Expand
)
1538 SolarMutexGuard aGuard
;
1540 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1542 const bool bWasEOS
= isEndOfSentence();
1543 SwUnoCursorHelper::SelectPam(rUnoCursor
, Expand
);
1544 bool bRet
= rUnoCursor
.GoSentence(SwCursor::NEXT_SENT
);
1547 bRet
= rUnoCursor
.MovePara(GoNextPara
, fnParaStart
);
1550 // if at the end of the sentence (i.e. at the space after the '.')
1551 // advance to next word in order for GoSentence to work properly
1552 // next time and have isStartOfSentence return true after this call
1553 if (!rUnoCursor
.IsStartWordWT(css::i18n::WordType::ANYWORD_IGNOREWHITESPACES
))
1555 const bool bNextWord
= rUnoCursor
.GoNextWordWT(i18n::WordType::ANYWORD_IGNOREWHITESPACES
);
1556 if (bWasEOS
&& !bNextWord
)
1561 if (CursorType::Meta
== m_eType
)
1563 bRet
= lcl_ForceIntoMeta(rUnoCursor
, m_xParentText
,
1567 else if (m_eType
== CursorType::ContentControl
)
1569 bRet
= lcl_ForceIntoContentControl(rUnoCursor
, m_xParentText
, CONTENT_CONTROL_CHECK_BOTH
)
1576 SwXTextCursor::gotoPreviousSentence(sal_Bool Expand
)
1578 SolarMutexGuard aGuard
;
1580 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1582 SwUnoCursorHelper::SelectPam(rUnoCursor
, Expand
);
1583 bool bRet
= rUnoCursor
.GoSentence(SwCursor::PREV_SENT
);
1586 bRet
= rUnoCursor
.MovePara(GoPrevPara
, fnParaStart
);
1589 rUnoCursor
.MovePara(GoCurrPara
, fnParaEnd
);
1590 // at the end of a paragraph move to the sentence end again
1591 rUnoCursor
.GoSentence(SwCursor::PREV_SENT
);
1594 if (CursorType::Meta
== m_eType
)
1596 bRet
= lcl_ForceIntoMeta(rUnoCursor
, m_xParentText
,
1600 else if (m_eType
== CursorType::ContentControl
)
1602 bRet
= lcl_ForceIntoContentControl(rUnoCursor
, m_xParentText
, CONTENT_CONTROL_CHECK_BOTH
)
1609 SwXTextCursor::gotoStartOfSentence(sal_Bool Expand
)
1611 SolarMutexGuard aGuard
;
1613 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1615 SwUnoCursorHelper::SelectPam(rUnoCursor
, Expand
);
1616 // if we're at the para start then we won't move
1617 // but bRet is also true if GoSentence failed but
1618 // the start of the sentence is reached
1619 bool bRet
= SwUnoCursorHelper::IsStartOfPara(rUnoCursor
)
1620 || rUnoCursor
.GoSentence(SwCursor::START_SENT
)
1621 || SwUnoCursorHelper::IsStartOfPara(rUnoCursor
);
1622 if (CursorType::Meta
== m_eType
)
1624 bRet
= lcl_ForceIntoMeta(rUnoCursor
, m_xParentText
,
1628 else if (m_eType
== CursorType::ContentControl
)
1630 bRet
= lcl_ForceIntoContentControl(rUnoCursor
, m_xParentText
, CONTENT_CONTROL_CHECK_BOTH
)
1637 SwXTextCursor::gotoEndOfSentence(sal_Bool Expand
)
1639 SolarMutexGuard aGuard
;
1641 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1643 SwUnoCursorHelper::SelectPam(rUnoCursor
, Expand
);
1644 // bRet is true if GoSentence() succeeded or if the
1645 // MovePara() succeeded while the end of the para is
1646 // not reached already
1647 bool bAlreadyParaEnd
= SwUnoCursorHelper::IsEndOfPara(rUnoCursor
);
1648 bool bRet
= !bAlreadyParaEnd
1649 && (rUnoCursor
.GoSentence(SwCursor::END_SENT
)
1650 || rUnoCursor
.MovePara(GoCurrPara
, fnParaEnd
));
1651 if (CursorType::Meta
== m_eType
)
1653 bRet
= lcl_ForceIntoMeta(rUnoCursor
, m_xParentText
,
1657 else if (m_eType
== CursorType::ContentControl
)
1659 bRet
= lcl_ForceIntoContentControl(rUnoCursor
, m_xParentText
, CONTENT_CONTROL_CHECK_BOTH
)
1666 SwXTextCursor::isStartOfParagraph()
1668 SolarMutexGuard aGuard
;
1670 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1672 const bool bRet
= SwUnoCursorHelper::IsStartOfPara(rUnoCursor
);
1677 SwXTextCursor::isEndOfParagraph()
1679 SolarMutexGuard aGuard
;
1681 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1683 const bool bRet
= SwUnoCursorHelper::IsEndOfPara(rUnoCursor
);
1688 SwXTextCursor::gotoStartOfParagraph(sal_Bool Expand
)
1690 SolarMutexGuard aGuard
;
1692 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1694 if (CursorType::Meta
== m_eType
)
1698 SwUnoCursorHelper::SelectPam(rUnoCursor
, Expand
);
1699 bool bRet
= SwUnoCursorHelper::IsStartOfPara(rUnoCursor
);
1702 bRet
= rUnoCursor
.MovePara(GoCurrPara
, fnParaStart
);
1705 // since MovePara(GoCurrPara, fnParaStart) only returns false
1706 // if we were already at the start of the paragraph this function
1707 // should always complete successfully.
1708 OSL_ENSURE( bRet
, "gotoStartOfParagraph failed" );
1713 SwXTextCursor::gotoEndOfParagraph(sal_Bool Expand
)
1715 SolarMutexGuard aGuard
;
1717 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1719 if (CursorType::Meta
== m_eType
)
1723 SwUnoCursorHelper::SelectPam(rUnoCursor
, Expand
);
1724 bool bRet
= SwUnoCursorHelper::IsEndOfPara(rUnoCursor
);
1727 bRet
= rUnoCursor
.MovePara(GoCurrPara
, fnParaEnd
);
1730 // since MovePara(GoCurrPara, fnParaEnd) only returns false
1731 // if we were already at the end of the paragraph this function
1732 // should always complete successfully.
1733 OSL_ENSURE( bRet
, "gotoEndOfParagraph failed" );
1738 SwXTextCursor::gotoNextParagraph(sal_Bool Expand
)
1740 SolarMutexGuard aGuard
;
1742 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1744 if (CursorType::Meta
== m_eType
)
1748 SwUnoCursorHelper::SelectPam(rUnoCursor
, Expand
);
1749 const bool bRet
= rUnoCursor
.MovePara(GoNextPara
, fnParaStart
);
1754 SwXTextCursor::gotoPreviousParagraph(sal_Bool Expand
)
1756 SolarMutexGuard aGuard
;
1758 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1760 if (CursorType::Meta
== m_eType
)
1764 SwUnoCursorHelper::SelectPam(rUnoCursor
, Expand
);
1765 const bool bRet
= rUnoCursor
.MovePara(GoPrevPara
, fnParaStart
);
1769 uno::Reference
< text::XText
> SAL_CALL
1770 SwXTextCursor::getText()
1774 return m_xParentText
;
1777 uno::Reference
< text::XTextRange
> SAL_CALL
1778 SwXTextCursor::getStart()
1780 SolarMutexGuard aGuard
;
1782 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1784 uno::Reference
< text::XTextRange
> xRet
;
1785 SwPaM
aPam(*rUnoCursor
.Start());
1786 const uno::Reference
< text::XText
> xParent
= getText();
1787 if (CursorType::Meta
== m_eType
)
1789 // return cursor to prevent modifying SwXTextRange for META
1790 rtl::Reference
<SwXTextCursor
> pXCursor(
1791 new SwXTextCursor(rUnoCursor
.GetDoc(), xParent
, CursorType::Meta
,
1792 *rUnoCursor
.GetPoint()) );
1793 pXCursor
->gotoStart(false);
1794 xRet
= static_cast<text::XWordCursor
*>(pXCursor
.get());
1798 xRet
= new SwXTextRange(aPam
, xParent
);
1803 uno::Reference
< text::XTextRange
> SAL_CALL
1804 SwXTextCursor::getEnd()
1806 SolarMutexGuard aGuard
;
1808 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1810 uno::Reference
< text::XTextRange
> xRet
;
1811 SwPaM
aPam(*rUnoCursor
.End());
1812 const uno::Reference
< text::XText
> xParent
= getText();
1813 if (CursorType::Meta
== m_eType
)
1815 // return cursor to prevent modifying SwXTextRange for META
1816 rtl::Reference
<SwXTextCursor
> pXCursor(
1817 new SwXTextCursor(rUnoCursor
.GetDoc(), xParent
, CursorType::Meta
,
1818 *rUnoCursor
.GetPoint()) );
1819 pXCursor
->gotoEnd(false);
1820 xRet
= static_cast<text::XWordCursor
*>(pXCursor
.get());
1824 xRet
= new SwXTextRange(aPam
, xParent
);
1829 OUString SAL_CALL
SwXTextCursor::getString()
1831 SolarMutexGuard aGuard
;
1833 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
1836 SwUnoCursorHelper::GetTextFromPam(rUnoCursor
, aText
);
1841 SwXTextCursor::setString(const OUString
& aString
)
1843 SolarMutexGuard aGuard
;
1845 GetCursorOrThrow(); // just to check if valid
1847 const bool bForceExpandHints( (CursorType::Meta
== m_eType
)
1848 && dynamic_cast<SwXMeta
&>(*m_xParentText
)
1849 .CheckForOwnMemberMeta(*GetPaM(), true) );
1850 DeleteAndInsert(aString
, bForceExpandHints
? ::sw::DeleteAndInsertMode::ForceExpandHints
: ::sw::DeleteAndInsertMode::Default
);
1853 uno::Any
SwUnoCursorHelper::GetPropertyValue(
1854 SwPaM
& rPaM
, const SfxItemPropertySet
& rPropSet
,
1855 std::u16string_view rPropertyName
)
1858 SfxItemPropertyMapEntry
const*const pEntry
=
1859 rPropSet
.getPropertyMap().getByName(rPropertyName
);
1863 throw beans::UnknownPropertyException(
1864 OUString::Concat("Unknown property: ") + rPropertyName
,
1865 static_cast<cppu::OWeakObject
*>(nullptr));
1868 beans::PropertyState eTemp
;
1869 const bool bDone
= SwUnoCursorHelper::getCursorPropertyValue(
1870 *pEntry
, rPaM
, &aAny
, eTemp
);
1875 RES_CHRATR_BEGIN
, RES_FRMATR_END
- 1,
1876 RES_UNKNOWNATR_CONTAINER
, RES_UNKNOWNATR_CONTAINER
>
1877 aSet(rPaM
.GetDoc().GetAttrPool());
1879 SwUnoCursorHelper::GetCursorAttr(rPaM
, aSet
);
1881 rPropSet
.getPropertyValue(*pEntry
, aSet
, aAny
);
1887 void SwUnoCursorHelper::SetPropertyValue(
1888 SwPaM
& rPaM
, const SfxItemPropertySet
& rPropSet
,
1889 const OUString
& rPropertyName
,
1890 const uno::Any
& rValue
,
1891 const SetAttrMode nAttrMode
)
1893 beans::PropertyValue aVal
{ comphelper::makePropertyValue(rPropertyName
, rValue
) };
1894 SetPropertyValues(rPaM
, rPropSet
, o3tl::span
<beans::PropertyValue
>(&aVal
, 1), nAttrMode
);
1897 // FN_UNO_PARA_STYLE is known to set attributes for nodes, inside
1898 // SwUnoCursorHelper::SetTextFormatColl, instead of extending item set.
1899 // We need to get them from nodes in next call to GetCursorAttr.
1900 // The rest could cause similar problems in theory, so we just list them here.
1901 static bool propertyCausesSideEffectsInNodes(sal_uInt16 nWID
)
1903 return nWID
== FN_UNO_PARA_STYLE
||
1904 nWID
== FN_UNO_CHARFMT_SEQUENCE
||
1905 nWID
== FN_UNO_NUM_START_VALUE
||
1906 nWID
== FN_UNO_NUM_RULES
;
1909 void SwUnoCursorHelper::SetPropertyValues(
1910 SwPaM
& rPaM
, const SfxItemPropertySet
& rPropSet
,
1911 const uno::Sequence
< beans::PropertyValue
> &rPropertyValues
,
1912 const SetAttrMode nAttrMode
)
1914 SetPropertyValues(rPaM
, rPropSet
,
1915 o3tl::span
<const beans::PropertyValue
>(rPropertyValues
.getConstArray(), rPropertyValues
.getLength()),
1919 void SwUnoCursorHelper::SetPropertyValues(
1920 SwPaM
& rPaM
, const SfxItemPropertySet
& rPropSet
,
1921 o3tl::span
< const beans::PropertyValue
> aPropertyValues
,
1922 const SetAttrMode nAttrMode
)
1924 if (aPropertyValues
.empty())
1927 SwDoc
& rDoc
= rPaM
.GetDoc();
1928 OUString aUnknownExMsg
, aPropertyVetoExMsg
;
1930 // Build set of attributes we want to fetch
1931 WhichRangesContainer aRanges
;
1932 std::vector
<std::pair
<const SfxItemPropertyMapEntry
*, const uno::Any
&>> aSideEffectsEntries
;
1933 std::vector
<std::pair
<const SfxItemPropertyMapEntry
*, const uno::Any
&>> aEntries
;
1934 aEntries
.reserve(aPropertyValues
.size());
1935 for (const auto& rPropVal
: aPropertyValues
)
1937 const OUString
&rPropertyName
= rPropVal
.Name
;
1939 SfxItemPropertyMapEntry
const* pEntry
=
1940 rPropSet
.getPropertyMap().getByName(rPropertyName
);
1942 // Queue up any exceptions until the end ...
1945 aUnknownExMsg
+= "Unknown property: '" + rPropertyName
+ "' ";
1948 else if (pEntry
->nFlags
& beans::PropertyAttribute::READONLY
)
1950 aPropertyVetoExMsg
+= "Property is read-only: '" + rPropertyName
+ "' ";
1953 if (propertyCausesSideEffectsInNodes(pEntry
->nWID
))
1955 aSideEffectsEntries
.emplace_back(pEntry
, rPropVal
.Value
);
1959 aRanges
= aRanges
.MergeRange(pEntry
->nWID
, pEntry
->nWID
);
1960 aEntries
.emplace_back(pEntry
, rPropVal
.Value
);
1964 // Entries with side effects first, using dedicated one-element SfxItemSet for each
1965 for (const auto& [pEntry
, rValue
] : aSideEffectsEntries
)
1967 SfxItemSet
aItemSet(rDoc
.GetAttrPool(), pEntry
->nWID
, pEntry
->nWID
);
1968 // we need to get up-to-date item set from nodes
1969 SwUnoCursorHelper::GetCursorAttr(rPaM
, aItemSet
);
1970 // this can set some attributes in nodes' mpAttrSet
1971 if (!SwUnoCursorHelper::SetCursorPropertyValue(*pEntry
, rValue
, rPaM
, aItemSet
))
1972 rPropSet
.setPropertyValue(*pEntry
, rValue
, aItemSet
);
1973 SwUnoCursorHelper::SetCursorAttr(rPaM
, aItemSet
, nAttrMode
, false /*bTableMode*/);
1976 if (!aEntries
.empty())
1978 // Fetch, overwrite, and re-set the attributes from the core
1979 SfxItemSet
aItemSet(rDoc
.GetAttrPool(), std::move(aRanges
));
1980 // we need to get up-to-date item set from nodes
1981 SwUnoCursorHelper::GetCursorAttr(rPaM
, aItemSet
);
1983 for (const auto& [pEntry
, rValue
] : aEntries
)
1985 // this can set some attributes in nodes' mpAttrSet
1986 if (!SwUnoCursorHelper::SetCursorPropertyValue(*pEntry
, rValue
, rPaM
, aItemSet
))
1987 rPropSet
.setPropertyValue(*pEntry
, rValue
, aItemSet
);
1990 SwUnoCursorHelper::SetCursorAttr(rPaM
, aItemSet
, nAttrMode
, false /*bTableMode*/);
1993 if (!aUnknownExMsg
.isEmpty())
1994 throw beans::UnknownPropertyException(aUnknownExMsg
, static_cast<cppu::OWeakObject
*>(nullptr));
1995 if (!aPropertyVetoExMsg
.isEmpty())
1996 throw beans::PropertyVetoException(aPropertyVetoExMsg
, static_cast<cppu::OWeakObject
*>(nullptr));
2001 bool NotInRange(sal_uInt16 nWID
, sal_uInt16 nStart
, sal_uInt16 nEnd
)
2003 return nWID
< nStart
|| nWID
> nEnd
;
2007 uno::Sequence
< beans::PropertyState
>
2008 SwUnoCursorHelper::GetPropertyStates(
2009 SwPaM
& rPaM
, const SfxItemPropertySet
& rPropSet
,
2010 const uno::Sequence
< OUString
>& rPropertyNames
,
2011 const SwGetPropertyStatesCaller eCaller
)
2013 const OUString
* pNames
= rPropertyNames
.getConstArray();
2014 uno::Sequence
< beans::PropertyState
> aRet(rPropertyNames
.getLength());
2015 beans::PropertyState
* pStates
= aRet
.getArray();
2016 const SfxItemPropertyMap
&rMap
= rPropSet
.getPropertyMap();
2017 std::optional
<SfxItemSet
> oSet
;
2018 std::optional
<SfxItemSet
> oSetParent
;
2020 for (sal_Int32 i
= 0, nEnd
= rPropertyNames
.getLength(); i
< nEnd
; i
++)
2022 SfxItemPropertyMapEntry
const*const pEntry
=
2023 rMap
.getByName( pNames
[i
] );
2026 if (pNames
[i
] == UNO_NAME_IS_SKIP_HIDDEN_TEXT
||
2027 pNames
[i
] == UNO_NAME_IS_SKIP_PROTECTED_TEXT
||
2028 pNames
[i
] == UNO_NAME_NO_FORMAT_ATTR
)
2030 pStates
[i
] = beans::PropertyState_DEFAULT_VALUE
;
2033 else if (SW_PROPERTY_STATE_CALLER_SWX_TEXT_PORTION_TOLERANT
==
2036 //this values marks the element as unknown property
2037 pStates
[i
] = beans::PropertyState::PropertyState_MAKE_FIXED_SIZE
;
2042 throw beans::UnknownPropertyException(
2043 "Unknown property: " + pNames
[i
],
2044 static_cast<cppu::OWeakObject
*>(nullptr));
2047 if (((SW_PROPERTY_STATE_CALLER_SWX_TEXT_PORTION
== eCaller
) ||
2048 (SW_PROPERTY_STATE_CALLER_SWX_TEXT_PORTION_TOLERANT
== eCaller
)) &&
2049 NotInRange(pEntry
->nWID
, FN_UNO_RANGE_BEGIN
, FN_UNO_RANGE_END
) &&
2050 NotInRange(pEntry
->nWID
, RES_CHRATR_BEGIN
, RES_TXTATR_END
) )
2052 pStates
[i
] = beans::PropertyState_DEFAULT_VALUE
;
2056 if ( pEntry
->nWID
>= FN_UNO_RANGE_BEGIN
&&
2057 pEntry
->nWID
<= FN_UNO_RANGE_END
)
2059 (void)SwUnoCursorHelper::getCursorPropertyValue(
2060 *pEntry
, rPaM
, nullptr, pStates
[i
] );
2068 case SW_PROPERTY_STATE_CALLER_SWX_TEXT_PORTION_TOLERANT
:
2069 case SW_PROPERTY_STATE_CALLER_SWX_TEXT_PORTION
:
2070 oSet
.emplace( rPaM
.GetDoc().GetAttrPool(),
2071 svl::Items
<RES_CHRATR_BEGIN
, RES_TXTATR_END
> );
2073 case SW_PROPERTY_STATE_CALLER_SINGLE_VALUE_ONLY
:
2074 oSet
.emplace( rPaM
.GetDoc().GetAttrPool(),
2075 pEntry
->nWID
, pEntry
->nWID
);
2079 rPaM
.GetDoc().GetAttrPool(),
2081 RES_CHRATR_BEGIN
, RES_FRMATR_END
- 1,
2082 RES_UNKNOWNATR_CONTAINER
,
2083 RES_UNKNOWNATR_CONTAINER
>);
2086 SwUnoCursorHelper::GetCursorAttr( rPaM
, *oSet
);
2089 pStates
[i
] = ( oSet
->Count() )
2090 ? rPropSet
.getPropertyState( *pEntry
, *oSet
)
2091 : beans::PropertyState_DEFAULT_VALUE
;
2093 //try again to find out if a value has been inherited
2094 if( beans::PropertyState_DIRECT_VALUE
== pStates
[i
] )
2098 oSetParent
.emplace(oSet
->CloneAsValue( false ));
2100 SwUnoCursorHelper::GetCursorAttr(
2101 rPaM
, *oSetParent
, true, false );
2104 pStates
[i
] = ( oSetParent
->Count() )
2105 ? rPropSet
.getPropertyState( *pEntry
, *oSetParent
)
2106 : beans::PropertyState_DEFAULT_VALUE
;
2114 beans::PropertyState
SwUnoCursorHelper::GetPropertyState(
2115 SwPaM
& rPaM
, const SfxItemPropertySet
& rPropSet
,
2116 const OUString
& rPropertyName
)
2118 uno::Sequence
< OUString
> aStrings
{ rPropertyName
};
2119 uno::Sequence
< beans::PropertyState
> aSeq
=
2120 GetPropertyStates(rPaM
, rPropSet
, aStrings
,
2121 SW_PROPERTY_STATE_CALLER_SINGLE_VALUE_ONLY
);
2126 lcl_SelectParaAndReset( SwPaM
&rPaM
, SwDoc
& rDoc
,
2127 o3tl::sorted_vector
<sal_uInt16
> const &rWhichIds
)
2129 // if we are resetting paragraph attributes, we need to select the full paragraph first
2130 SwPosition aStart
= *rPaM
.Start();
2131 SwPosition aEnd
= *rPaM
.End();
2132 auto pTemp ( rDoc
.CreateUnoCursor(aStart
) );
2133 if(!SwUnoCursorHelper::IsStartOfPara(*pTemp
))
2135 pTemp
->MovePara(GoCurrPara
, fnParaStart
);
2138 *pTemp
->GetPoint() = aEnd
;
2139 SwUnoCursorHelper::SelectPam(*pTemp
, true);
2140 if(!SwUnoCursorHelper::IsEndOfPara(*pTemp
))
2142 pTemp
->MovePara(GoCurrPara
, fnParaEnd
);
2144 rDoc
.ResetAttrs(*pTemp
, true, rWhichIds
);
2147 void SwUnoCursorHelper::SetPropertyToDefault(
2148 SwPaM
& rPaM
, const SfxItemPropertySet
& rPropSet
,
2149 std::u16string_view rPropertyName
)
2151 SwDoc
& rDoc
= rPaM
.GetDoc();
2152 SfxItemPropertyMapEntry
const*const pEntry
=
2153 rPropSet
.getPropertyMap().getByName(rPropertyName
);
2156 throw beans::UnknownPropertyException(
2157 OUString::Concat("Unknown property: ") + rPropertyName
,
2158 static_cast<cppu::OWeakObject
*>(nullptr));
2161 if (pEntry
->nFlags
& beans::PropertyAttribute::READONLY
)
2163 throw uno::RuntimeException(
2164 OUString::Concat("setPropertyToDefault: property is read-only: ")
2165 + rPropertyName
, nullptr);
2168 if (pEntry
->nWID
< RES_FRMATR_END
)
2170 const o3tl::sorted_vector
<sal_uInt16
> aWhichIds
{ pEntry
->nWID
};
2171 if (pEntry
->nWID
< RES_PARATR_BEGIN
)
2173 rDoc
.ResetAttrs(rPaM
, true, aWhichIds
);
2177 lcl_SelectParaAndReset ( rPaM
, rDoc
, aWhichIds
);
2182 SwUnoCursorHelper::resetCursorPropertyValue(*pEntry
, rPaM
);
2186 uno::Any
SwUnoCursorHelper::GetPropertyDefault(
2187 SwPaM
const & rPaM
, const SfxItemPropertySet
& rPropSet
,
2188 std::u16string_view rPropertyName
)
2190 SfxItemPropertyMapEntry
const*const pEntry
=
2191 rPropSet
.getPropertyMap().getByName(rPropertyName
);
2194 throw beans::UnknownPropertyException(
2195 OUString::Concat("Unknown property: ") + rPropertyName
,
2196 static_cast<cppu::OWeakObject
*>(nullptr));
2200 if (pEntry
->nWID
< RES_FRMATR_END
)
2202 SwDoc
& rDoc
= rPaM
.GetDoc();
2203 const SfxPoolItem
& rDefItem
=
2204 rDoc
.GetAttrPool().GetDefaultItem(pEntry
->nWID
);
2205 rDefItem
.QueryValue(aRet
, pEntry
->nMemberId
);
2210 uno::Reference
< beans::XPropertySetInfo
> SAL_CALL
2211 SwXTextCursor::getPropertySetInfo()
2215 static uno::Reference
< beans::XPropertySetInfo
> xRef
= [&]()
2217 static SfxItemPropertyMapEntry
const aCursorExtMap_Impl
[] =
2219 { UNO_NAME_IS_SKIP_HIDDEN_TEXT
, FN_SKIP_HIDDEN_TEXT
, cppu::UnoType
<bool>::get(), PROPERTY_NONE
, 0},
2220 { UNO_NAME_IS_SKIP_PROTECTED_TEXT
, FN_SKIP_PROTECTED_TEXT
, cppu::UnoType
<bool>::get(), PROPERTY_NONE
, 0},
2221 { UNO_NAME_NO_FORMAT_ATTR
, 0, cppu::UnoType
<bool>::get(), PROPERTY_NONE
, 0},
2223 const uno::Reference
< beans::XPropertySetInfo
> xInfo
=
2224 m_rPropSet
.getPropertySetInfo();
2225 // extend PropertySetInfo!
2226 const uno::Sequence
<beans::Property
> aPropSeq
= xInfo
->getProperties();
2227 return rtl::Reference
<SfxExtItemPropertySetInfo
>(new SfxExtItemPropertySetInfo(
2235 SwXTextCursor::setPropertyValue(
2236 const OUString
& rPropertyName
, const uno::Any
& rValue
)
2238 SolarMutexGuard aGuard
;
2240 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
2242 if (rPropertyName
== UNO_NAME_IS_SKIP_HIDDEN_TEXT
)
2245 if (!(rValue
>>= bSet
))
2247 throw lang::IllegalArgumentException();
2249 rUnoCursor
.SetSkipOverHiddenSections(bSet
);
2251 else if (rPropertyName
== UNO_NAME_IS_SKIP_PROTECTED_TEXT
)
2254 if (!(rValue
>>= bSet
))
2256 throw lang::IllegalArgumentException();
2258 rUnoCursor
.SetSkipOverProtectSections(bSet
);
2260 else if (rPropertyName
== UNO_NAME_NO_FORMAT_ATTR
)
2263 if (!(rValue
>>= bSet
))
2265 throw lang::IllegalArgumentException();
2269 m_nAttrMode
= SetAttrMode::NOFORMATATTR
;
2273 m_nAttrMode
= SetAttrMode::DEFAULT
;
2276 else if (rPropertyName
== "ParaAutoStyleDef")
2278 // Create an autostyle from passed definition (sequence of PropertyValue, same
2279 // as in XAutoStyleFamily::insertStyle), using the currently applied properties
2280 // from the paragraph to not lose their values when creating complex properties
2281 // like SvxULSpaceItem, when only part of the properties stored there is passed;
2282 // and apply it to the paragraph.
2283 uno::Sequence
<beans::PropertyValue
> def
;
2284 if (!(rValue
>>= def
))
2285 throw lang::IllegalArgumentException();
2287 // See SwUnoCursorHelper::SetPropertyValues
2289 auto pPropSet
= aSwMapProvider
.GetPropertySet(PROPERTY_MAP_PARA_AUTO_STYLE
);
2291 // Build set of attributes we want to fetch
2292 WhichRangesContainer aRanges
;
2293 for (auto& rPropVal
: def
)
2295 SfxItemPropertyMapEntry
const* pEntry
=
2296 pPropSet
->getPropertyMap().getByName(rPropVal
.Name
);
2298 continue; // PropValuesToAutoStyleItemSet ignores invalid names
2300 aRanges
= aRanges
.MergeRange(pEntry
->nWID
, pEntry
->nWID
);
2303 if (!aRanges
.empty())
2305 SwAttrSet
aAutoStyleItemSet(rUnoCursor
.GetDoc().GetAttrPool(), std::move(aRanges
));
2306 // we need to get up-to-date item set: this makes sure that the complex properties,
2307 // that are only partially defined by passed definition, do not lose the rest of
2308 // their already present data (which will become part of the autostyle, too).
2309 SwUnoCursorHelper::GetCursorAttr(rUnoCursor
, aAutoStyleItemSet
);
2310 // Set normal set ranges before putting into autostyle, to the same ranges
2311 // that are used for paragraph autostyle in SwXAutoStyleFamily::insertStyle
2312 aAutoStyleItemSet
.SetRanges(aTextNodeSetRange
);
2314 // Fill the prepared item set, containing current paragraph property values,
2315 // with the passed definition, and create the autostyle.
2316 auto pStyle
= PropValuesToAutoStyleItemSet(
2317 rUnoCursor
.GetDoc(), IStyleAccess::AUTO_STYLE_PARA
, def
, aAutoStyleItemSet
);
2319 SwFormatAutoFormat
aFormat(RES_AUTO_STYLE
);
2320 aFormat
.SetStyleHandle(pStyle
);
2321 SfxItemSet
rSet(rUnoCursor
.GetDoc().GetAttrPool(), RES_AUTO_STYLE
, RES_AUTO_STYLE
);
2323 SwUnoCursorHelper::SetCursorAttr(rUnoCursor
, rSet
, m_nAttrMode
);
2328 SwUnoCursorHelper::SetPropertyValue(rUnoCursor
,
2329 m_rPropSet
, rPropertyName
, rValue
, m_nAttrMode
);
2334 SwXTextCursor::getPropertyValue(const OUString
& rPropertyName
)
2336 SolarMutexGuard aGuard
;
2338 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
2341 if (rPropertyName
== UNO_NAME_IS_SKIP_HIDDEN_TEXT
)
2343 const bool bSet
= rUnoCursor
.IsSkipOverHiddenSections();
2346 else if (rPropertyName
== UNO_NAME_IS_SKIP_PROTECTED_TEXT
)
2348 const bool bSet
= rUnoCursor
.IsSkipOverProtectSections();
2353 aAny
= SwUnoCursorHelper::GetPropertyValue(rUnoCursor
,
2354 m_rPropSet
, rPropertyName
);
2360 SwXTextCursor::addPropertyChangeListener(
2361 const OUString
& /*rPropertyName*/,
2362 const uno::Reference
< beans::XPropertyChangeListener
>& /*xListener*/)
2364 OSL_FAIL("SwXTextCursor::addPropertyChangeListener(): not implemented");
2368 SwXTextCursor::removePropertyChangeListener(
2369 const OUString
& /*rPropertyName*/,
2370 const uno::Reference
< beans::XPropertyChangeListener
>& /*xListener*/)
2372 OSL_FAIL("SwXTextCursor::removePropertyChangeListener(): not implemented");
2376 SwXTextCursor::addVetoableChangeListener(
2377 const OUString
& /*rPropertyName*/,
2378 const uno::Reference
< beans::XVetoableChangeListener
>& /*xListener*/)
2380 OSL_FAIL("SwXTextCursor::addVetoableChangeListener(): not implemented");
2384 SwXTextCursor::removeVetoableChangeListener(
2385 const OUString
& /*rPropertyName*/,
2386 const uno::Reference
< beans::XVetoableChangeListener
>& /*xListener*/)
2388 OSL_FAIL("SwXTextCursor::removeVetoableChangeListener(): not implemented");
2391 beans::PropertyState SAL_CALL
2392 SwXTextCursor::getPropertyState(const OUString
& rPropertyName
)
2394 SolarMutexGuard aGuard
;
2396 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
2398 const beans::PropertyState eRet
= SwUnoCursorHelper::GetPropertyState(
2399 rUnoCursor
, m_rPropSet
, rPropertyName
);
2403 uno::Sequence
< beans::PropertyState
> SAL_CALL
2404 SwXTextCursor::getPropertyStates(
2405 const uno::Sequence
< OUString
>& rPropertyNames
)
2407 SolarMutexGuard aGuard
;
2409 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
2411 return SwUnoCursorHelper::GetPropertyStates(
2412 rUnoCursor
, m_rPropSet
, rPropertyNames
);
2416 SwXTextCursor::setPropertyToDefault(const OUString
& rPropertyName
)
2418 // forward: need no solar mutex here
2419 uno::Sequence
< OUString
> aSequence ( &rPropertyName
, 1 );
2420 setPropertiesToDefault ( aSequence
);
2424 SwXTextCursor::getPropertyDefault(const OUString
& rPropertyName
)
2426 // forward: need no solar mutex here
2427 const uno::Sequence
< OUString
> aSequence ( &rPropertyName
, 1 );
2428 return getPropertyDefaults ( aSequence
).getConstArray()[0];
2431 void SAL_CALL
SwXTextCursor::setPropertyValues(
2432 const uno::Sequence
< OUString
>& aPropertyNames
,
2433 const uno::Sequence
< uno::Any
>& aValues
)
2435 if( aValues
.getLength() != aPropertyNames
.getLength() )
2437 OSL_FAIL( "mis-matched property value sequences" );
2438 throw lang::IllegalArgumentException();
2441 SolarMutexGuard aGuard
;
2443 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
2445 // a little lame to have to copy into this.
2446 uno::Sequence
< beans::PropertyValue
> aPropertyValues( aValues
.getLength() );
2447 auto aPropertyValuesRange
= asNonConstRange(aPropertyValues
);
2448 for ( sal_Int32 i
= 0; i
< aPropertyNames
.getLength(); i
++ )
2450 if ( aPropertyNames
[ i
] == UNO_NAME_IS_SKIP_HIDDEN_TEXT
||
2451 aPropertyNames
[ i
] == UNO_NAME_IS_SKIP_PROTECTED_TEXT
)
2453 // the behaviour of these is hard to model in a group
2454 OSL_FAIL("invalid property name for batch setting");
2455 throw lang::IllegalArgumentException();
2457 aPropertyValuesRange
[ i
].Name
= aPropertyNames
[ i
];
2458 aPropertyValuesRange
[ i
].Value
= aValues
[ i
];
2462 SwUnoCursorHelper::SetPropertyValues( rUnoCursor
, m_rPropSet
, aPropertyValues
);
2464 catch (const css::beans::UnknownPropertyException
& e
)
2466 uno::Any
a(cppu::getCaughtException());
2467 throw lang::WrappedTargetException(
2468 "wrapped Exception " + e
.Message
,
2469 uno::Reference
<uno::XInterface
>(), a
);
2473 uno::Sequence
< uno::Any
> SAL_CALL
2474 SwXTextCursor::getPropertyValues( const uno::Sequence
< OUString
>& aPropertyNames
)
2476 // a banal implementation for now
2477 uno::Sequence
< uno::Any
> aValues( aPropertyNames
.getLength() );
2478 std::transform(aPropertyNames
.begin(), aPropertyNames
.end(), aValues
.getArray(),
2479 [this](const OUString
& rName
) -> uno::Any
{ return getPropertyValue( rName
); });
2483 void SAL_CALL
SwXTextCursor::addPropertiesChangeListener(
2484 const uno::Sequence
< OUString
>& /* aPropertyNames */,
2485 const uno::Reference
< css::beans::XPropertiesChangeListener
>& /* xListener */ )
2487 OSL_FAIL("SwXTextCursor::addPropertiesChangeListener(): not implemented");
2489 void SAL_CALL
SwXTextCursor::removePropertiesChangeListener(
2490 const uno::Reference
< css::beans::XPropertiesChangeListener
>& /* xListener */ )
2492 OSL_FAIL("SwXTextCursor::removePropertiesChangeListener(): not implemented");
2495 void SAL_CALL
SwXTextCursor::firePropertiesChangeEvent(
2496 const uno::Sequence
< OUString
>& /* aPropertyNames */,
2497 const uno::Reference
< css::beans::XPropertiesChangeListener
>& /* xListener */ )
2499 OSL_FAIL("SwXTextCursor::firePropertiesChangeEvent(): not implemented");
2502 // para specific attribute ranges
2503 static sal_uInt16 g_ParaResetableSetRange
[] = {
2504 RES_FRMATR_BEGIN
, RES_FRMATR_END
-1,
2505 RES_PARATR_BEGIN
, RES_PARATR_END
-1,
2506 RES_PARATR_LIST_BEGIN
, RES_PARATR_LIST_END
-1,
2507 RES_UNKNOWNATR_BEGIN
, RES_UNKNOWNATR_END
-1,
2511 // selection specific attribute ranges
2512 static sal_uInt16 g_ResetableSetRange
[] = {
2513 RES_CHRATR_BEGIN
, RES_CHRATR_END
-1,
2514 RES_TXTATR_INETFMT
, RES_TXTATR_INETFMT
,
2515 RES_TXTATR_CHARFMT
, RES_TXTATR_CHARFMT
,
2516 RES_TXTATR_CJK_RUBY
, RES_TXTATR_CJK_RUBY
,
2517 RES_TXTATR_UNKNOWN_CONTAINER
, RES_TXTATR_UNKNOWN_CONTAINER
,
2522 lcl_EnumerateIds(sal_uInt16
const* pIdRange
, o3tl::sorted_vector
<sal_uInt16
> &rWhichIds
)
2526 const sal_uInt16 nStart
= *pIdRange
++;
2527 const sal_uInt16 nEnd
= *pIdRange
++;
2528 for (sal_uInt16 nId
= nStart
+ 1; nId
<= nEnd
; ++nId
)
2530 rWhichIds
.insert( nId
);
2536 SwXTextCursor::setAllPropertiesToDefault()
2538 SolarMutexGuard aGuard
;
2540 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
2542 o3tl::sorted_vector
<sal_uInt16
> aParaWhichIds
;
2543 o3tl::sorted_vector
<sal_uInt16
> aWhichIds
;
2544 lcl_EnumerateIds(g_ParaResetableSetRange
, aParaWhichIds
);
2545 lcl_EnumerateIds(g_ResetableSetRange
, aWhichIds
);
2546 if (!aParaWhichIds
.empty())
2548 lcl_SelectParaAndReset(rUnoCursor
, rUnoCursor
.GetDoc(),
2551 if (!aWhichIds
.empty())
2553 rUnoCursor
.GetDoc().ResetAttrs(rUnoCursor
, true, aWhichIds
);
2558 SwXTextCursor::setPropertiesToDefault(
2559 const uno::Sequence
< OUString
>& rPropertyNames
)
2561 SolarMutexGuard aGuard
;
2563 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
2565 if ( !rPropertyNames
.hasElements() )
2568 SwDoc
& rDoc
= rUnoCursor
.GetDoc();
2569 o3tl::sorted_vector
<sal_uInt16
> aWhichIds
;
2570 o3tl::sorted_vector
<sal_uInt16
> aParaWhichIds
;
2571 for (const OUString
& rName
: rPropertyNames
)
2573 SfxItemPropertyMapEntry
const*const pEntry
=
2574 m_rPropSet
.getPropertyMap().getByName( rName
);
2577 if (rName
== UNO_NAME_IS_SKIP_HIDDEN_TEXT
||
2578 rName
== UNO_NAME_IS_SKIP_PROTECTED_TEXT
)
2582 throw beans::UnknownPropertyException(
2583 "Unknown property: " + rName
,
2584 static_cast<cppu::OWeakObject
*>(this));
2586 if (pEntry
->nFlags
& beans::PropertyAttribute::READONLY
)
2588 throw uno::RuntimeException(
2589 "setPropertiesToDefault: property is read-only: " + rName
,
2590 static_cast<cppu::OWeakObject
*>(this));
2593 if (pEntry
->nWID
< RES_FRMATR_END
)
2595 if (pEntry
->nWID
< RES_PARATR_BEGIN
)
2597 aWhichIds
.insert( pEntry
->nWID
);
2601 aParaWhichIds
.insert( pEntry
->nWID
);
2604 else if (pEntry
->nWID
== FN_UNO_NUM_START_VALUE
)
2606 SwUnoCursorHelper::resetCursorPropertyValue(*pEntry
, rUnoCursor
);
2610 if (!aParaWhichIds
.empty())
2612 lcl_SelectParaAndReset(rUnoCursor
, rDoc
, aParaWhichIds
);
2614 if (!aWhichIds
.empty())
2616 rDoc
.ResetAttrs(rUnoCursor
, true, aWhichIds
);
2620 uno::Sequence
< uno::Any
> SAL_CALL
2621 SwXTextCursor::getPropertyDefaults(
2622 const uno::Sequence
< OUString
>& rPropertyNames
)
2624 SolarMutexGuard aGuard
;
2626 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
2628 const sal_Int32 nCount
= rPropertyNames
.getLength();
2629 uno::Sequence
< uno::Any
> aRet(nCount
);
2632 SwDoc
& rDoc
= rUnoCursor
.GetDoc();
2633 const OUString
*pNames
= rPropertyNames
.getConstArray();
2634 uno::Any
*pAny
= aRet
.getArray();
2635 for (sal_Int32 i
= 0; i
< nCount
; i
++)
2637 SfxItemPropertyMapEntry
const*const pEntry
=
2638 m_rPropSet
.getPropertyMap().getByName( pNames
[i
] );
2641 if (pNames
[i
] == UNO_NAME_IS_SKIP_HIDDEN_TEXT
||
2642 pNames
[i
] == UNO_NAME_IS_SKIP_PROTECTED_TEXT
||
2643 pNames
[i
] == UNO_NAME_NO_FORMAT_ATTR
)
2647 throw beans::UnknownPropertyException(
2648 "Unknown property: " + pNames
[i
],
2649 static_cast<cppu::OWeakObject
*>(nullptr));
2651 if (pEntry
->nWID
< RES_FRMATR_END
)
2653 const SfxPoolItem
& rDefItem
=
2654 rDoc
.GetAttrPool().GetDefaultItem(pEntry
->nWID
);
2655 rDefItem
.QueryValue(pAny
[i
], pEntry
->nMemberId
);
2662 void SAL_CALL
SwXTextCursor::invalidateMarkings(::sal_Int32 nType
)
2664 SolarMutexGuard aGuard
;
2666 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
2668 SwNode
& node
= rUnoCursor
.GetPointNode();
2670 SwTextNode
* txtNode
= node
.GetTextNode();
2672 if (txtNode
== nullptr) return;
2674 if ( text::TextMarkupType::SPELLCHECK
== nType
)
2676 txtNode
->SetWrongDirty(sw::WrongState::TODO
);
2677 txtNode
->ClearWrong();
2679 else if( text::TextMarkupType::PROOFREADING
== nType
)
2681 txtNode
->SetGrammarCheckDirty(true);
2682 txtNode
->ClearGrammarCheck();
2684 else if ( text::TextMarkupType::SMARTTAG
== nType
)
2686 txtNode
->SetSmartTagDirty(true);
2687 txtNode
->ClearSmartTags();
2691 SwFormatColl
* fmtColl
=txtNode
->GetFormatColl();
2693 if (fmtColl
== nullptr) return;
2695 SwFormatChg
aNew( fmtColl
);
2696 txtNode
->CallSwClientNotify(sw::LegacyModifyHint(nullptr, &aNew
));
2700 SwXTextCursor::makeRedline(
2701 const OUString
& rRedlineType
,
2702 const uno::Sequence
< beans::PropertyValue
>& rRedlineProperties
)
2704 SolarMutexGuard aGuard
;
2706 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
2708 SwUnoCursorHelper::makeRedline(rUnoCursor
, rRedlineType
, rRedlineProperties
);
2711 void SAL_CALL
SwXTextCursor::insertDocumentFromURL(const OUString
& rURL
,
2712 const uno::Sequence
< beans::PropertyValue
>& rOptions
)
2714 SolarMutexGuard aGuard
;
2716 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
2718 SwUnoCursorHelper::InsertFile(&rUnoCursor
, rURL
, rOptions
);
2721 uno::Sequence
< beans::PropertyValue
>
2722 SwUnoCursorHelper::CreateSortDescriptor(const bool bFromTable
)
2724 uno::Sequence
< beans::PropertyValue
> aRet(5);
2725 beans::PropertyValue
* pArray
= aRet
.getArray();
2728 aVal
<<= bFromTable
;
2729 pArray
[0] = beans::PropertyValue("IsSortInTable", -1, aVal
,
2730 beans::PropertyState_DIRECT_VALUE
);
2733 pArray
[1] = beans::PropertyValue("Delimiter", -1, aVal
,
2734 beans::PropertyState_DIRECT_VALUE
);
2737 pArray
[2] = beans::PropertyValue("IsSortColumns", -1, aVal
,
2738 beans::PropertyState_DIRECT_VALUE
);
2740 aVal
<<= sal_Int32(3);
2741 pArray
[3] = beans::PropertyValue("MaxSortFieldsCount", -1, aVal
,
2742 beans::PropertyState_DIRECT_VALUE
);
2744 lang::Locale
aLang( SvtSysLocale().GetLanguageTag().getLocale());
2745 // get collator algorithm to be used for the locale
2746 uno::Sequence
< OUString
> aSeq(
2747 GetAppCollator().listCollatorAlgorithms( aLang
) );
2748 const bool bHasElements
= aSeq
.hasElements();
2749 OSL_ENSURE( bHasElements
, "list of collator algorithms is empty!");
2753 aCollAlg
= aSeq
.getConstArray()[0];
2756 uno::Sequence
< table::TableSortField
> aFields
2758 // Field, IsAscending, IsCaseSensitive, FieldType, CollatorLocale, CollatorAlgorithm
2759 { 1, true, false, table::TableSortFieldType_ALPHANUMERIC
, aLang
, aCollAlg
},
2760 { 1, true, false, table::TableSortFieldType_ALPHANUMERIC
, aLang
, aCollAlg
},
2761 { 1, true, false, table::TableSortFieldType_ALPHANUMERIC
, aLang
, aCollAlg
}
2765 pArray
[4] = beans::PropertyValue("SortFields", -1, aVal
,
2766 beans::PropertyState_DIRECT_VALUE
);
2771 uno::Sequence
< beans::PropertyValue
> SAL_CALL
2772 SwXTextCursor::createSortDescriptor()
2774 SolarMutexGuard aGuard
;
2776 return SwUnoCursorHelper::CreateSortDescriptor(false);
2779 bool SwUnoCursorHelper::ConvertSortProperties(
2780 const uno::Sequence
< beans::PropertyValue
>& rDescriptor
,
2781 SwSortOptions
& rSortOpt
)
2785 rSortOpt
.bTable
= false;
2786 rSortOpt
.cDeli
= ' ';
2787 rSortOpt
.eDirection
= SwSortDirection::Columns
; //!! UI text may be contrary though !!
2790 aKey1
.nColumnId
= USHRT_MAX
;
2791 aKey1
.bIsNumeric
= true;
2792 aKey1
.eSortOrder
= SwSortOrder::Ascending
;
2795 aKey2
.nColumnId
= USHRT_MAX
;
2796 aKey2
.bIsNumeric
= true;
2797 aKey2
.eSortOrder
= SwSortOrder::Ascending
;
2800 aKey3
.nColumnId
= USHRT_MAX
;
2801 aKey3
.bIsNumeric
= true;
2802 aKey3
.eSortOrder
= SwSortOrder::Ascending
;
2803 SwSortKey
* aKeys
[3] = {&aKey1
, &aKey2
, &aKey3
};
2805 bool bOldSortdescriptor(false);
2806 bool bNewSortdescriptor(false);
2808 for (const beans::PropertyValue
& rProperty
: rDescriptor
)
2810 uno::Any
aValue( rProperty
.Value
);
2811 const OUString
& rPropName
= rProperty
.Name
;
2813 // old and new sortdescriptor
2814 if ( rPropName
== "IsSortInTable" )
2816 if (auto b
= o3tl::tryAccess
<bool>(aValue
))
2818 rSortOpt
.bTable
= *b
;
2825 else if ( rPropName
== "Delimiter" )
2829 if (aValue
>>= uChar
)
2831 rSortOpt
.cDeli
= uChar
;
2833 else if (aValue
>>= nChar
)
2835 // For compatibility with BASIC, also accept an ANY containing
2836 // an UNSIGNED SHORT:
2837 rSortOpt
.cDeli
= nChar
;
2844 // old sortdescriptor
2845 else if ( rPropName
== "SortColumns" )
2847 bOldSortdescriptor
= true;
2849 if (aValue
>>= bTemp
)
2851 rSortOpt
.eDirection
= bTemp
? SwSortDirection::Columns
: SwSortDirection::Rows
;
2858 else if ( rPropName
== "IsCaseSensitive" )
2860 bOldSortdescriptor
= true;
2862 if (aValue
>>= bTemp
)
2864 rSortOpt
.bIgnoreCase
= !bTemp
;
2871 else if ( rPropName
== "CollatorLocale" )
2873 bOldSortdescriptor
= true;
2874 lang::Locale aLocale
;
2875 if (aValue
>>= aLocale
)
2877 rSortOpt
.nLanguage
= LanguageTag::convertToLanguageType( aLocale
);
2884 else if (rPropName
.startsWith("CollatorAlgorithm") &&
2885 rPropName
.getLength() == 18 &&
2886 (rPropName
[17] >= '0' && rPropName
[17] <= '9'))
2888 bOldSortdescriptor
= true;
2889 sal_uInt16 nIndex
= rPropName
[17];
2892 if ((aValue
>>= aText
) && nIndex
< 3)
2894 aKeys
[nIndex
]->sSortType
= aText
;
2901 else if (rPropName
.startsWith("SortRowOrColumnNo") &&
2902 rPropName
.getLength() == 18 &&
2903 (rPropName
[17] >= '0' && rPropName
[17] <= '9'))
2905 bOldSortdescriptor
= true;
2906 sal_uInt16 nIndex
= rPropName
[17];
2908 sal_Int16 nCol
= -1;
2909 if (aValue
.getValueType() == ::cppu::UnoType
<sal_Int16
>::get()
2916 aKeys
[nIndex
]->nColumnId
= nCol
;
2923 else if (rPropName
.startsWith("IsSortNumeric") &&
2924 rPropName
.getLength() == 14 &&
2925 (rPropName
[13] >= '0' && rPropName
[13] <= '9'))
2927 bOldSortdescriptor
= true;
2928 sal_uInt16 nIndex
= rPropName
[13];
2929 nIndex
= nIndex
- '0';
2930 auto bTemp
= o3tl::tryAccess
<bool>(aValue
);
2931 if (bTemp
&& nIndex
< 3)
2933 aKeys
[nIndex
]->bIsNumeric
= *bTemp
;
2940 else if (rPropName
.startsWith("IsSortAscending") &&
2941 rPropName
.getLength() == 16 &&
2942 (rPropName
[15] >= '0' && rPropName
[15] <= '9'))
2944 bOldSortdescriptor
= true;
2945 sal_uInt16 nIndex
= rPropName
[15];
2947 auto bTemp
= o3tl::tryAccess
<bool>(aValue
);
2948 if (bTemp
&& nIndex
< 3)
2950 aKeys
[nIndex
]->eSortOrder
= (*bTemp
)
2951 ? SwSortOrder::Ascending
: SwSortOrder::Descending
;
2958 // new sortdescriptor
2959 else if ( rPropName
== "IsSortColumns" )
2961 bNewSortdescriptor
= true;
2962 if (auto bTemp
= o3tl::tryAccess
<bool>(aValue
))
2964 rSortOpt
.eDirection
= *bTemp
? SwSortDirection::Columns
: SwSortDirection::Rows
;
2971 else if ( rPropName
== "SortFields" )
2973 bNewSortdescriptor
= true;
2974 uno::Sequence
< table::TableSortField
> aFields
;
2975 if (aValue
>>= aFields
)
2977 sal_Int32
nCount(aFields
.getLength());
2980 table::TableSortField
* pFields
= aFields
.getArray();
2981 for (sal_Int32 i
= 0; i
< nCount
; ++i
)
2983 rSortOpt
.bIgnoreCase
= !pFields
[i
].IsCaseSensitive
;
2984 rSortOpt
.nLanguage
=
2985 LanguageTag::convertToLanguageType( pFields
[i
].CollatorLocale
);
2986 aKeys
[i
]->sSortType
= pFields
[i
].CollatorAlgorithm
;
2987 aKeys
[i
]->nColumnId
=
2988 o3tl::narrowing
<sal_uInt16
>(pFields
[i
].Field
);
2989 aKeys
[i
]->bIsNumeric
= (pFields
[i
].FieldType
==
2990 table::TableSortFieldType_NUMERIC
);
2991 aKeys
[i
]->eSortOrder
= (pFields
[i
].IsAscending
)
2992 ? SwSortOrder::Ascending
: SwSortOrder::Descending
;
3007 if (bNewSortdescriptor
&& bOldSortdescriptor
)
3009 OSL_FAIL("someone tried to set the old deprecated and "
3010 "the new sortdescriptor");
3014 if (aKey1
.nColumnId
!= USHRT_MAX
)
3016 rSortOpt
.aKeys
.push_back(aKey1
);
3018 if (aKey2
.nColumnId
!= USHRT_MAX
)
3020 rSortOpt
.aKeys
.push_back(aKey2
);
3022 if (aKey3
.nColumnId
!= USHRT_MAX
)
3024 rSortOpt
.aKeys
.push_back(aKey3
);
3027 return bRet
&& !rSortOpt
.aKeys
.empty();
3031 SwXTextCursor::sort(const uno::Sequence
< beans::PropertyValue
>& rDescriptor
)
3033 SolarMutexGuard aGuard
;
3035 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
3037 if (!rUnoCursor
.HasMark())
3040 SwSortOptions aSortOpt
;
3041 if (!SwUnoCursorHelper::ConvertSortProperties(rDescriptor
, aSortOpt
))
3043 throw uno::RuntimeException("Bad sort properties");
3045 UnoActionContext
aContext( &rUnoCursor
.GetDoc() );
3047 SwPosition
& rStart
= *rUnoCursor
.Start();
3048 SwPosition
& rEnd
= *rUnoCursor
.End();
3050 SwNodeIndex
aPrevIdx( rStart
.GetNode(), -1 );
3051 const SwNodeOffset nOffset
= rEnd
.GetNodeIndex() - rStart
.GetNodeIndex();
3052 const sal_Int32 nCntStt
= rStart
.GetContentIndex();
3054 rUnoCursor
.GetDoc().SortText(rUnoCursor
, aSortOpt
);
3057 rUnoCursor
.DeleteMark();
3058 rUnoCursor
.GetPoint()->Assign( aPrevIdx
.GetNode(), SwNodeOffset(1) );
3059 SwContentNode
*const pCNd
= rUnoCursor
.GetPointContentNode();
3060 sal_Int32 nLen
= pCNd
->Len();
3065 rUnoCursor
.GetPoint()->SetContent( nLen
);
3066 rUnoCursor
.SetMark();
3068 rUnoCursor
.GetPoint()->Adjust(nOffset
);
3069 SwContentNode
*const pCNd2
= rUnoCursor
.GetPointContentNode();
3070 rUnoCursor
.GetPoint()->SetContent( pCNd2
->Len() );
3074 uno::Reference
< container::XEnumeration
> SAL_CALL
3075 SwXTextCursor::createContentEnumeration(const OUString
& rServiceName
)
3078 if (rServiceName
!= "com.sun.star.text.TextContent")
3079 throw uno::RuntimeException();
3080 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
3081 return SwXParaFrameEnumeration::Create(rUnoCursor
, PARAFRAME_PORTION_TEXTRANGE
);
3084 uno::Reference
< container::XEnumeration
> SAL_CALL
3085 SwXTextCursor::createEnumeration()
3089 SwUnoCursor
& rUnoCursor( GetCursorOrThrow() );
3091 SwXText
* pParentText
= dynamic_cast<SwXText
*>(m_xParentText
.get());
3092 OSL_ENSURE(pParentText
, "parent is not a SwXText");
3095 throw uno::RuntimeException();
3098 auto pNewCursor(rUnoCursor
.GetDoc().CreateUnoCursor(*rUnoCursor
.GetPoint()) );
3099 if (rUnoCursor
.HasMark())
3101 pNewCursor
->SetMark();
3102 *pNewCursor
->GetMark() = *rUnoCursor
.GetMark();
3104 const CursorType eSetType
= (CursorType::TableText
== m_eType
)
3105 ? CursorType::SelectionInTable
: CursorType::Selection
;
3106 return SwXParagraphEnumeration::Create(pParentText
, pNewCursor
, eSetType
);
3110 SwXTextCursor::getElementType()
3112 return cppu::UnoType
<text::XTextRange
>::get();
3115 sal_Bool SAL_CALL
SwXTextCursor::hasElements()
3120 uno::Sequence
< OUString
> SAL_CALL
3121 SwXTextCursor::getAvailableServiceNames()
3123 uno::Sequence
<OUString
> aRet
{ "com.sun.star.text.TextContent" };
3127 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */