Bug Summary

File:home/maarten/src/libreoffice/core/sw/inc/ring.hxx
Warning:line 85, column 19
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name unoobj.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /usr/include/libxml2 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D SW_DLLIMPLEMENTATION -D SWUI_DLL_NAME="libswuilo.so" -D SYSTEM_LIBXML -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/sw/source/core/inc -I /home/maarten/src/libreoffice/core/sw/source/filter/inc -I /home/maarten/src/libreoffice/core/sw/source/uibase/inc -I /home/maarten/src/libreoffice/core/sw/inc -I /home/maarten/src/libreoffice/core/workdir/SdiTarget/sw/sdi -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/sw/generated -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/oovbaapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/sw/source/core/unocore/unoobj.cxx

/home/maarten/src/libreoffice/core/sw/source/core/unocore/unoobj.cxx

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
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>
28#include <swtypes.hxx>
29#include <hintids.hxx>
30#include <cmdid.h>
31#include <unomid.h>
32#include <hints.hxx>
33#include <doc.hxx>
34#include <IDocumentUndoRedo.hxx>
35#include <istyleaccess.hxx>
36#include <ndtxt.hxx>
37#include <unocrsr.hxx>
38#include <unocrsrhelper.hxx>
39#include <swundo.hxx>
40#include <rootfrm.hxx>
41#include <paratr.hxx>
42#include <pam.hxx>
43#include <shellio.hxx>
44#include <fmtruby.hxx>
45#include <docsh.hxx>
46#include <docstyle.hxx>
47#include <fmtpdsc.hxx>
48#include <pagedesc.hxx>
49#include <edimp.hxx>
50#include <fchrfmt.hxx>
51#include <fmtautofmt.hxx>
52#include <unotextrange.hxx>
53#include <unotextcursor.hxx>
54#include <unomap.hxx>
55#include <unoprnms.hxx>
56#include <unometa.hxx>
57#include <unotext.hxx>
58#include <com/sun/star/text/TextMarkupType.hpp>
59#include <vcl/svapp.hxx>
60#include <unotools/syslocale.hxx>
61#include <i18nlangtag/languagetag.hxx>
62#include <SwStyleNameMapper.hxx>
63#include <sortopt.hxx>
64#include <com/sun/star/beans/PropertyAttribute.hpp>
65#include <com/sun/star/beans/NamedValue.hpp>
66#include <com/sun/star/i18n/WordType.hpp>
67#include <memory>
68#include <unoparaframeenum.hxx>
69#include <unoparagraph.hxx>
70#include <iodetect.hxx>
71#include <comphelper/servicehelper.hxx>
72#include <comphelper/profilezone.hxx>
73
74using namespace ::com::sun::star;
75
76// Helper classes
77SwUnoInternalPaM::SwUnoInternalPaM(SwDoc& rDoc) :
78 SwPaM(rDoc.GetNodes())
79{
80}
81
82SwUnoInternalPaM::~SwUnoInternalPaM()
83{
84 while( GetNext() != this)
1
Assuming the condition is true
2
Loop condition is true. Entering loop body
4
Calling 'SwPaM::GetNext'
85 {
86 delete GetNext();
3
Memory is released
87 }
88}
89
90SwUnoInternalPaM& SwUnoInternalPaM::operator=(const SwPaM& rPaM)
91{
92 const SwPaM* pTmp = &rPaM;
93 *GetPoint() = *rPaM.GetPoint();
94 if(rPaM.HasMark())
95 {
96 SetMark();
97 *GetMark() = *rPaM.GetMark();
98 }
99 else
100 DeleteMark();
101 while(&rPaM != (pTmp = pTmp->GetNext()))
102 {
103 if(pTmp->HasMark())
104 new SwPaM(*pTmp->GetMark(), *pTmp->GetPoint(), this);
105 else
106 new SwPaM(*pTmp->GetPoint(), this);
107 }
108 return *this;
109}
110
111void SwUnoCursorHelper::SelectPam(SwPaM & rPam, const bool bExpand)
112{
113 if (bExpand)
114 {
115 if (!rPam.HasMark())
116 {
117 rPam.SetMark();
118 }
119 }
120 else if (rPam.HasMark())
121 {
122 rPam.DeleteMark();
123 }
124}
125
126void SwUnoCursorHelper::GetTextFromPam(SwPaM & rPam, OUString & rBuffer,
127 SwRootFrame const*const pLayout)
128{
129 if (!rPam.HasMark())
130 {
131 return;
132 }
133 SvMemoryStream aStream;
134#ifdef OSL_BIGENDIAN
135 aStream.SetEndian( SvStreamEndian::BIG );
136#else
137 aStream.SetEndian( SvStreamEndian::LITTLE );
138#endif
139 WriterRef xWrt;
140 // TODO/MBA: looks like a BaseURL doesn't make sense here
141 SwReaderWriter::GetWriter( FILTER_TEXT_DLG"TEXT_DLG", OUString(), xWrt );
142 if( !xWrt.is() )
143 return;
144
145 SwWriter aWriter( aStream, rPam );
146 xWrt->m_bASCII_NoLastLineEnd = true;
147 xWrt->m_bExportParagraphNumbering = false;
148 SwAsciiOptions aOpt = xWrt->GetAsciiOptions();
149 aOpt.SetCharSet( RTL_TEXTENCODING_UNICODE(((rtl_TextEncoding) 0xFFFF)) );
150 xWrt->SetAsciiOptions( aOpt );
151 xWrt->m_bUCS2_WithStartChar = false;
152 // #i68522#
153 const bool bOldShowProgress = xWrt->m_bShowProgress;
154 xWrt->m_bShowProgress = false;
155 xWrt->m_bHideDeleteRedlines = pLayout && pLayout->IsHideRedlines();
156
157 if( ! aWriter.Write( xWrt ).IsError() )
158 {
159 const sal_uInt64 lUniLen = aStream.GetSize()/sizeof( sal_Unicode );
160 if (lUniLen < o3tl::make_unsigned(SAL_MAX_INT32((sal_Int32) 0x7FFFFFFF)-1))
161 {
162 aStream.WriteUInt16( '\0' );
163
164 aStream.Seek( 0 );
165 aStream.ResetError();
166
167 rtl_uString *pStr = rtl_uString_alloc(lUniLen);
168 aStream.ReadBytes(pStr->buffer, lUniLen * sizeof(sal_Unicode));
169 rBuffer = OUString(pStr, SAL_NO_ACQUIRE);
170 }
171 }
172 xWrt->m_bShowProgress = bOldShowProgress;
173
174}
175
176/// @throws lang::IllegalArgumentException
177/// @throws uno::RuntimeException
178static void
179lcl_setCharStyle(SwDoc& rDoc, const uno::Any & rValue, SfxItemSet & rSet)
180{
181 SwDocShell *const pDocSh = rDoc.GetDocShell();
182 if(!pDocSh)
183 return;
184
185 OUString uStyle;
186 if (!(rValue >>= uStyle))
187 {
188 throw lang::IllegalArgumentException();
189 }
190 OUString sStyle;
191 SwStyleNameMapper::FillUIName(uStyle, sStyle,
192 SwGetPoolIdFromName::ChrFmt);
193 SwDocStyleSheet *const pStyle = static_cast<SwDocStyleSheet*>(
194 pDocSh->GetStyleSheetPool()->Find(sStyle, SfxStyleFamily::Char));
195 if (!pStyle)
196 {
197 throw lang::IllegalArgumentException();
198 }
199 const SwFormatCharFormat aFormat(pStyle->GetCharFormat());
200 rSet.Put(aFormat);
201};
202
203/// @throws lang::IllegalArgumentException
204static void
205lcl_setAutoStyle(IStyleAccess & rStyleAccess, const uno::Any & rValue,
206 SfxItemSet & rSet, const bool bPara)
207{
208 OUString uStyle;
209 if (!(rValue >>= uStyle))
210 {
211 throw lang::IllegalArgumentException();
212 }
213 std::shared_ptr<SfxItemSet> pStyle = bPara ?
214 rStyleAccess.getByName(uStyle, IStyleAccess::AUTO_STYLE_PARA ):
215 rStyleAccess.getByName(uStyle, IStyleAccess::AUTO_STYLE_CHAR );
216 if(!pStyle)
217 {
218 throw lang::IllegalArgumentException();
219 }
220
221 SwFormatAutoFormat aFormat( bPara
222 ? sal::static_int_cast< sal_uInt16 >(RES_AUTO_STYLE)
223 : sal::static_int_cast< sal_uInt16 >(RES_TXTATR_AUTOFMT) );
224 aFormat.SetStyleHandle( pStyle );
225 rSet.Put(aFormat);
226};
227
228void
229SwUnoCursorHelper::SetTextFormatColl(const uno::Any & rAny, SwPaM & rPaM)
230{
231 SwDoc& rDoc = rPaM.GetDoc();
232 SwDocShell *const pDocSh = rDoc.GetDocShell();
233 if(!pDocSh)
234 return;
235 OUString uStyle;
236 rAny >>= uStyle;
237 OUString sStyle;
238 SwStyleNameMapper::FillUIName(uStyle, sStyle,
239 SwGetPoolIdFromName::TxtColl );
240 SwDocStyleSheet *const pStyle = static_cast<SwDocStyleSheet*>(
241 pDocSh->GetStyleSheetPool()->Find(sStyle, SfxStyleFamily::Para));
242 if (!pStyle)
243 {
244 throw lang::IllegalArgumentException();
245 }
246
247 SwTextFormatColl *const pLocal = pStyle->GetCollection();
248 UnoActionContext aAction(&rDoc);
249 rDoc.GetIDocumentUndoRedo().StartUndo( SwUndoId::START, nullptr );
250 SwPaM *pTmpCursor = &rPaM;
251 do {
252 rDoc.SetTextFormatColl(*pTmpCursor, pLocal);
253 pTmpCursor = pTmpCursor->GetNext();
254 } while ( pTmpCursor != &rPaM );
255 rDoc.GetIDocumentUndoRedo().EndUndo( SwUndoId::END, nullptr );
256}
257
258bool
259SwUnoCursorHelper::SetPageDesc(
260 const uno::Any& rValue, SwDoc & rDoc, SfxItemSet & rSet)
261{
262 OUString uDescName;
263 if (!(rValue >>= uDescName))
264 {
265 return false;
266 }
267 std::unique_ptr<SwFormatPageDesc> pNewDesc;
268 const SfxPoolItem* pItem;
269 if(SfxItemState::SET == rSet.GetItemState( RES_PAGEDESC, true, &pItem ) )
270 {
271 pNewDesc.reset(new SwFormatPageDesc(
272 *static_cast<const SwFormatPageDesc*>(pItem)));
273 }
274 if (!pNewDesc)
275 {
276 pNewDesc.reset(new SwFormatPageDesc());
277 }
278 OUString sDescName;
279 SwStyleNameMapper::FillUIName(uDescName, sDescName,
280 SwGetPoolIdFromName::PageDesc);
281 if (!pNewDesc->GetPageDesc() ||
282 (pNewDesc->GetPageDesc()->GetName() != sDescName))
283 {
284 bool bPut = false;
285 if (!sDescName.isEmpty())
286 {
287 SwPageDesc *const pPageDesc = SwPageDesc::GetByName(rDoc, sDescName);
288 if (!pPageDesc)
289 {
290 throw lang::IllegalArgumentException();
291 }
292 pNewDesc->RegisterToPageDesc(*pPageDesc);
293 bPut = true;
294 }
295 if(!bPut)
296 {
297 rSet.ClearItem(RES_BREAK);
298 rSet.Put(SwFormatPageDesc());
299 }
300 else
301 {
302 rSet.Put(*pNewDesc);
303 }
304 }
305 return true;
306}
307
308static void
309lcl_SetNodeNumStart(SwPaM & rCursor, uno::Any const& rValue)
310{
311 sal_Int16 nTmp = 1;
312 rValue >>= nTmp;
313 sal_uInt16 nStt = (nTmp < 0 ? USHRT_MAX(32767 *2 +1) : static_cast<sal_uInt16>(nTmp));
314 SwDoc& rDoc = rCursor.GetDoc();
315 UnoActionContext aAction(&rDoc);
316
317 if( rCursor.GetNext() != &rCursor ) // MultiSelection?
318 {
319 rDoc.GetIDocumentUndoRedo().StartUndo( SwUndoId::START, nullptr );
320 SwPamRanges aRangeArr( rCursor );
321 SwPaM aPam( *rCursor.GetPoint() );
322 for( size_t n = 0; n < aRangeArr.Count(); ++n )
323 {
324 rDoc.SetNumRuleStart(*aRangeArr.SetPam( n, aPam ).GetPoint());
325 rDoc.SetNodeNumStart(*aRangeArr.SetPam( n, aPam ).GetPoint(),
326 nStt );
327 }
328 rDoc.GetIDocumentUndoRedo().EndUndo( SwUndoId::END, nullptr );
329 }
330 else
331 {
332 rDoc.SetNumRuleStart( *rCursor.GetPoint());
333 rDoc.SetNodeNumStart( *rCursor.GetPoint(), nStt );
334 }
335}
336
337static bool
338lcl_setCharFormatSequence(SwPaM & rPam, uno::Any const& rValue)
339{
340 uno::Sequence<OUString> aCharStyles;
341 if (!(rValue >>= aCharStyles))
342 {
343 return false;
344 }
345
346 for (sal_Int32 nStyle = 0; nStyle < aCharStyles.getLength(); nStyle++)
347 {
348 uno::Any aStyle;
349 rPam.GetDoc().GetIDocumentUndoRedo().StartUndo(SwUndoId::START, nullptr);
350 aStyle <<= aCharStyles.getConstArray()[nStyle];
351 // create a local set and apply each format directly
352 SfxItemSet aSet(rPam.GetDoc().GetAttrPool(),
353 svl::Items<RES_TXTATR_CHARFMT, RES_TXTATR_CHARFMT>{});
354 lcl_setCharStyle(rPam.GetDoc(), aStyle, aSet);
355 // the first style should replace the current attributes,
356 // all other have to be added
357 SwUnoCursorHelper::SetCursorAttr(rPam, aSet, nStyle
358 ? SetAttrMode::DONTREPLACE
359 : SetAttrMode::DEFAULT);
360 rPam.GetDoc().GetIDocumentUndoRedo().EndUndo(SwUndoId::START, nullptr);
361 }
362 return true;
363}
364
365static void
366lcl_setDropcapCharStyle(SwPaM const & rPam, SfxItemSet & rItemSet,
367 uno::Any const& rValue)
368{
369 OUString uStyle;
370 if (!(rValue >>= uStyle))
371 {
372 throw lang::IllegalArgumentException();
373 }
374 OUString sStyle;
375 SwStyleNameMapper::FillUIName(uStyle, sStyle,
376 SwGetPoolIdFromName::ChrFmt);
377 SwDoc& rDoc = rPam.GetDoc();
378 //default character style must not be set as default format
379 SwDocStyleSheet *const pStyle = static_cast<SwDocStyleSheet*>(
380 rDoc.GetDocShell()
381 ->GetStyleSheetPool()->Find(sStyle, SfxStyleFamily::Char));
382 if (!pStyle || pStyle->GetCharFormat() == rDoc.GetDfltCharFormat())
383 {
384 throw lang::IllegalArgumentException();
385 }
386 std::unique_ptr<SwFormatDrop> pDrop;
387 SfxPoolItem const* pItem(nullptr);
388 if (SfxItemState::SET ==
389 rItemSet.GetItemState(RES_PARATR_DROP, true, &pItem))
390 {
391 pDrop.reset(new SwFormatDrop(*static_cast<const SwFormatDrop*>(pItem)));
392 }
393 if (!pDrop)
394 {
395 pDrop.reset(new SwFormatDrop);
396 }
397 const rtl::Reference<SwDocStyleSheet> xStyle(new SwDocStyleSheet(*pStyle));
398 pDrop->SetCharFormat(xStyle->GetCharFormat());
399 rItemSet.Put(*pDrop);
400}
401
402static void
403lcl_setRubyCharstyle(SfxItemSet & rItemSet, uno::Any const& rValue)
404{
405 OUString sTmp;
406 if (!(rValue >>= sTmp))
407 {
408 throw lang::IllegalArgumentException();
409 }
410
411 std::unique_ptr<SwFormatRuby> pRuby;
412 const SfxPoolItem* pItem;
413 if (SfxItemState::SET ==
414 rItemSet.GetItemState(RES_TXTATR_CJK_RUBY, true, &pItem))
415 {
416 pRuby.reset(new SwFormatRuby(*static_cast<const SwFormatRuby*>(pItem)));
417 }
418 if (!pRuby)
419 {
420 pRuby.reset(new SwFormatRuby(OUString()));
421 }
422 OUString sStyle;
423 SwStyleNameMapper::FillUIName(sTmp, sStyle,
424 SwGetPoolIdFromName::ChrFmt);
425 pRuby->SetCharFormatName(sStyle);
426 pRuby->SetCharFormatId(0);
427 if (!sStyle.isEmpty())
428 {
429 const sal_uInt16 nId = SwStyleNameMapper::GetPoolIdFromUIName(
430 sStyle, SwGetPoolIdFromName::ChrFmt);
431 pRuby->SetCharFormatId(nId);
432 }
433 rItemSet.Put(*pRuby);
434}
435
436bool
437SwUnoCursorHelper::SetCursorPropertyValue(
438 SfxItemPropertySimpleEntry const& rEntry, const uno::Any& rValue,
439 SwPaM & rPam, SfxItemSet & rItemSet)
440{
441 if (!(rEntry.nFlags & beans::PropertyAttribute::MAYBEVOID) &&
442 (rValue.getValueType() == cppu::UnoType<void>::get()))
443 {
444 return false;
445 }
446 bool bRet = true;
447 switch (rEntry.nWID)
448 {
449 case RES_TXTATR_CHARFMT:
450 lcl_setCharStyle(rPam.GetDoc(), rValue, rItemSet);
451 break;
452 case RES_TXTATR_AUTOFMT:
453 lcl_setAutoStyle(rPam.GetDoc().GetIStyleAccess(),
454 rValue, rItemSet, false);
455 break;
456 case FN_UNO_CHARFMT_SEQUENCE((20000 + 2200) + 94):
457 lcl_setCharFormatSequence(rPam, rValue);
458 break;
459 case FN_UNO_PARA_STYLE((20000 + 2200) + 9) :
460 SwUnoCursorHelper::SetTextFormatColl(rValue, rPam);
461 break;
462 case RES_AUTO_STYLE:
463 lcl_setAutoStyle(rPam.GetDoc().GetIStyleAccess(),
464 rValue, rItemSet, true);
465 break;
466 case FN_UNO_PAGE_STYLE((20000 + 2200) + 10):
467 //FIXME nothing here?
468 break;
469 case FN_UNO_NUM_START_VALUE((20000 + 2200) + 13):
470 lcl_SetNodeNumStart( rPam, rValue );
471 break;
472 case FN_UNO_NUM_LEVEL((20000 + 2200) + 14):
473 // #i91601#
474 case FN_UNO_LIST_ID((20000 + 2200) + 107):
475 case FN_UNO_IS_NUMBER((20000 + 2200) + 69):
476 case FN_UNO_PARA_NUM_AUTO_FORMAT((20000 + 2200) + 11):
477 {
478 // multi selection is not considered
479 SwTextNode *const pTextNd = rPam.GetNode().GetTextNode();
480 if (!pTextNd)
481 {
482 throw lang::IllegalArgumentException();
483 }
484 if (FN_UNO_NUM_LEVEL((20000 + 2200) + 14) == rEntry.nWID)
485 {
486 sal_Int16 nLevel = 0;
487 if (rValue >>= nLevel)
488 {
489 if (nLevel < 0 || MAXLEVEL <= nLevel)
490 {
491 throw lang::IllegalArgumentException(
492 "invalid NumberingLevel", nullptr, 0);
493 }
494 pTextNd->SetAttrListLevel(nLevel);
495 }
496 }
497 // #i91601#
498 else if (FN_UNO_LIST_ID((20000 + 2200) + 107) == rEntry.nWID)
499 {
500 OUString sListId;
501 if (rValue >>= sListId)
502 {
503 pTextNd->SetListId( sListId );
504 }
505 }
506 else if (FN_UNO_IS_NUMBER((20000 + 2200) + 69) == rEntry.nWID)
507 {
508 bool bIsNumber(false);
509 if ((rValue >>= bIsNumber) && !bIsNumber)
510 {
511 pTextNd->SetCountedInList( false );
512 }
513 }
514 else if (FN_UNO_PARA_NUM_AUTO_FORMAT((20000 + 2200) + 11) == rEntry.nWID)
515 {
516 uno::Sequence<beans::NamedValue> props;
517 if (rValue >>= props)
518 {
519 // 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?
520 SfxItemPropertySet const& rPropSet(*aSwMapProvider.GetPropertySet(PROPERTY_MAP_CHAR_AUTO_STYLE94));
521 SfxItemPropertyMap const& rMap(rPropSet.getPropertyMap());
522 SfxItemSet items( rPam.GetDoc().GetAttrPool(),
523 svl::Items<RES_CHRATR_BEGIN, RES_CHRATR_END-1,
524 RES_TXTATR_CHARFMT, RES_TXTATR_CHARFMT,
525 RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1>{} );
526
527 for (beans::NamedValue const & prop : std::as_const(props))
528 {
529 SfxItemPropertySimpleEntry const*const pEntry =
530 rMap.getByName(prop.Name);
531 if (!pEntry)
532 {
533 if (prop.Name == "CharStyleName")
534 {
535 lcl_setCharStyle(rPam.GetDoc(), prop.Value, items);
536 continue;
537 }
538 throw beans::UnknownPropertyException(
539 "Unknown property: " + prop.Name);
540 }
541 if (pEntry->nFlags & beans::PropertyAttribute::READONLY)
542 {
543 throw beans::PropertyVetoException(
544 "Property is read-only: " + prop.Name);
545 }
546 rPropSet.setPropertyValue(*pEntry, prop.Value, items);
547 }
548
549 SwFormatAutoFormat item(RES_PARATR_LIST_AUTOFMT);
550 // TODO: for ODF export we'd need to add it to the autostyle pool
551 // 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()
552 item.SetStyleHandle(std::make_shared<SfxItemSet>(items));
553 pTextNd->SetAttr(item);
554 }
555 }
556 //PROPERTY_MAYBEVOID!
557 }
558 break;
559 case FN_NUMBER_NEWSTART((20000 + 1600) + 138):
560 {
561 bool bVal = false;
562 if (!(rValue >>= bVal))
563 {
564 throw lang::IllegalArgumentException();
565 }
566 rPam.GetDoc().SetNumRuleStart(*rPam.GetPoint(), bVal);
567 }
568 break;
569 case FN_UNO_NUM_RULES((20000 + 2200) + 15):
570 SwUnoCursorHelper::setNumberingProperty(rValue, rPam);
571 break;
572 case RES_PARATR_DROP:
573 {
574 if (MID_DROPCAP_CHAR_STYLE_NAME2 == rEntry.nMemberId)
575 {
576 lcl_setDropcapCharStyle(rPam, rItemSet, rValue);
577 }
578 else
579 {
580 bRet = false;
581 }
582 }
583 break;
584 case RES_TXTATR_CJK_RUBY:
585 {
586 if (MID_RUBY_CHARSTYLE2 == rEntry.nMemberId)
587 {
588 lcl_setRubyCharstyle(rItemSet, rValue);
589 }
590 else
591 {
592 bRet = false;
593 }
594 }
595 break;
596 case RES_PAGEDESC:
597 {
598 if (MID_PAGEDESC_PAGEDESCNAME0 == rEntry.nMemberId)
599 {
600 SwUnoCursorHelper::SetPageDesc(
601 rValue, rPam.GetDoc(), rItemSet);
602 }
603 else
604 {
605 bRet = false;
606 }
607 }
608 break;
609 default:
610 bRet = false;
611 }
612 return bRet;
613}
614
615SwFormatColl *
616SwUnoCursorHelper::GetCurTextFormatColl(SwPaM & rPaM, const bool bConditional)
617{
618 static const sal_uLong nMaxLookup = 1000;
619 SwFormatColl *pFormat = nullptr;
620 bool bError = false;
621 SwPaM *pTmpCursor = &rPaM;
622 do
623 {
624 const sal_uLong nSttNd = pTmpCursor->Start()->nNode.GetIndex();
625 const sal_uLong nEndNd = pTmpCursor->End()->nNode.GetIndex();
626
627 if( nEndNd - nSttNd >= nMaxLookup )
628 {
629 pFormat = nullptr;
630 break;
631 }
632
633 const SwNodes& rNds = rPaM.GetDoc().GetNodes();
634 for( sal_uLong n = nSttNd; n <= nEndNd; ++n )
635 {
636 SwTextNode const*const pNd = rNds[ n ]->GetTextNode();
637 if( pNd )
638 {
639 SwFormatColl *const pNdFormat = bConditional
640 ? pNd->GetFormatColl() : &pNd->GetAnyFormatColl();
641 if( !pFormat )
642 {
643 pFormat = pNdFormat;
644 }
645 else if( pFormat != pNdFormat )
646 {
647 bError = true;
648 break;
649 }
650 }
651 }
652
653 pTmpCursor = pTmpCursor->GetNext();
654 } while ( pTmpCursor != &rPaM );
655 return bError ? nullptr : pFormat;
656}
657
658class SwXTextCursor::Impl
659{
660
661public:
662 const SfxItemPropertySet & m_rPropSet;
663 const CursorType m_eType;
664 const uno::Reference< text::XText > m_xParentText;
665 sw::UnoCursorPointer m_pUnoCursor;
666
667 Impl( SwDoc & rDoc,
668 const CursorType eType,
669 uno::Reference<text::XText> const & xParent,
670 SwPosition const& rPoint, SwPosition const*const pMark)
671 : m_rPropSet(*aSwMapProvider.GetPropertySet(PROPERTY_MAP_TEXT_CURSOR0))
672 , m_eType(eType)
673 , m_xParentText(xParent)
674 , m_pUnoCursor(rDoc.CreateUnoCursor(rPoint))
675 {
676 if (pMark)
677 {
678 m_pUnoCursor->SetMark();
679 *m_pUnoCursor->GetMark() = *pMark;
680 }
681 }
682
683 SwUnoCursor& GetCursorOrThrow() {
684 if(!m_pUnoCursor)
685 throw uno::RuntimeException("SwXTextCursor: disposed or invalid", nullptr);
686 return *m_pUnoCursor;
687 }
688};
689
690SwUnoCursor& SwXTextCursor::GetCursor()
691 { return *m_pImpl->m_pUnoCursor; }
692
693SwPaM const* SwXTextCursor::GetPaM() const
694 { return m_pImpl->m_pUnoCursor.get(); }
695
696SwPaM* SwXTextCursor::GetPaM()
697 { return m_pImpl->m_pUnoCursor.get(); }
698
699SwDoc const* SwXTextCursor::GetDoc() const
700 { return m_pImpl->m_pUnoCursor ? &m_pImpl->m_pUnoCursor->GetDoc() : nullptr; }
701
702SwDoc* SwXTextCursor::GetDoc()
703 { return m_pImpl->m_pUnoCursor ? &m_pImpl->m_pUnoCursor->GetDoc() : nullptr; }
704
705SwXTextCursor::SwXTextCursor(
706 SwDoc & rDoc,
707 uno::Reference< text::XText > const& xParent,
708 const CursorType eType,
709 const SwPosition& rPos,
710 SwPosition const*const pMark)
711 : m_pImpl( new Impl(rDoc, eType, xParent, rPos, pMark) )
712{
713}
714
715SwXTextCursor::SwXTextCursor(uno::Reference< text::XText > const& xParent,
716 SwPaM const& rSourceCursor, const CursorType eType)
717 : m_pImpl( new Impl(rSourceCursor.GetDoc(), eType,
718 xParent, *rSourceCursor.GetPoint(),
719 rSourceCursor.HasMark() ? rSourceCursor.GetMark() : nullptr) )
720{
721}
722
723SwXTextCursor::~SwXTextCursor()
724{
725}
726
727void SwXTextCursor::DeleteAndInsert(const OUString& rText,
728 const bool bForceExpandHints)
729{
730 auto pUnoCursor = static_cast<SwCursor*>(m_pImpl->m_pUnoCursor.get());
731 if (!pUnoCursor)
732 return;
733
734 // Start/EndAction
735 SwDoc& rDoc = pUnoCursor->GetDoc();
736 UnoActionContext aAction(&rDoc);
737 const sal_Int32 nTextLen = rText.getLength();
738 rDoc.GetIDocumentUndoRedo().StartUndo(SwUndoId::INSERT, nullptr);
739 auto pCurrent = pUnoCursor;
740 do
741 {
742 if (pCurrent->HasMark())
743 {
744 rDoc.getIDocumentContentOperations().DeleteAndJoin(*pCurrent);
745 }
746 if(nTextLen)
747 {
748 const bool bSuccess(
749 SwUnoCursorHelper::DocInsertStringSplitCR(
750 rDoc, *pCurrent, rText, bForceExpandHints ) );
751 OSL_ENSURE( bSuccess, "Doc->Insert(Str) failed." )do { if (true && (!(bSuccess))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/unocore/unoobj.cxx"
":" "751" ": "), "%s", "Doc->Insert(Str) failed."); } } while
(false)
;
752
753 SwUnoCursorHelper::SelectPam(*pUnoCursor, true);
754 pCurrent->Left(rText.getLength());
755 }
756 pCurrent = pCurrent->GetNext();
757 } while (pCurrent != pUnoCursor);
758 rDoc.GetIDocumentUndoRedo().EndUndo(SwUndoId::INSERT, nullptr);
759}
760
761namespace {
762
763enum ForceIntoMetaMode { META_CHECK_BOTH, META_INIT_START, META_INIT_END };
764
765}
766
767static bool
768lcl_ForceIntoMeta(SwPaM & rCursor,
769 uno::Reference<text::XText> const & xParentText,
770 const enum ForceIntoMetaMode eMode)
771{
772 bool bRet( true ); // means not forced in META_CHECK_BOTH
773 SwXMeta const * const pXMeta( dynamic_cast<SwXMeta*>(xParentText.get()) );
774 OSL_ENSURE(pXMeta, "no parent?")do { if (true && (!(pXMeta))) { sal_detail_logFormat(
(SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/unocore/unoobj.cxx"
":" "774" ": "), "%s", "no parent?"); } } while (false)
;
775 if (!pXMeta)
776 throw uno::RuntimeException();
777 SwTextNode * pTextNode;
778 sal_Int32 nStart;
779 sal_Int32 nEnd;
780 const bool bSuccess( pXMeta->SetContentRange(pTextNode, nStart, nEnd) );
781 OSL_ENSURE(bSuccess, "no pam?")do { if (true && (!(bSuccess))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/unocore/unoobj.cxx"
":" "781" ": "), "%s", "no pam?"); } } while (false)
;
782 if (!bSuccess)
783 throw uno::RuntimeException();
784 // force the cursor back into the meta if it has moved outside
785 SwPosition start(*pTextNode, nStart);
786 SwPosition end(*pTextNode, nEnd);
787 switch (eMode)
788 {
789 case META_INIT_START:
790 *rCursor.GetPoint() = start;
791 break;
792 case META_INIT_END:
793 *rCursor.GetPoint() = end;
794 break;
795 case META_CHECK_BOTH:
796 if (*rCursor.Start() < start)
797 {
798 *rCursor.Start() = start;
799 bRet = false;
800 }
801 if (*rCursor.End() > end)
802 {
803 *rCursor.End() = end;
804 bRet = false;
805 }
806 break;
807 }
808 return bRet;
809}
810
811bool SwXTextCursor::IsAtEndOfMeta() const
812{
813 if (CursorType::Meta == m_pImpl->m_eType)
814 {
815 auto pCursor( m_pImpl->m_pUnoCursor );
816 SwXMeta const*const pXMeta(
817 dynamic_cast<SwXMeta*>(m_pImpl->m_xParentText.get()) );
818 OSL_ENSURE(pXMeta, "no meta?")do { if (true && (!(pXMeta))) { sal_detail_logFormat(
(SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/unocore/unoobj.cxx"
":" "818" ": "), "%s", "no meta?"); } } while (false)
;
819 if (pCursor && pXMeta)
820 {
821 SwTextNode * pTextNode;
822 sal_Int32 nStart;
823 sal_Int32 nEnd;
824 const bool bSuccess(
825 pXMeta->SetContentRange(pTextNode, nStart, nEnd) );
826 OSL_ENSURE(bSuccess, "no pam?")do { if (true && (!(bSuccess))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/unocore/unoobj.cxx"
":" "826" ": "), "%s", "no pam?"); } } while (false)
;
827 if (bSuccess)
828 {
829 const SwPosition end(*pTextNode, nEnd);
830 if ( (*pCursor->GetPoint() == end)
831 || (*pCursor->GetMark() == end))
832 {
833 return true;
834 }
835 }
836 }
837 }
838 return false;
839}
840
841OUString SwXTextCursor::getImplementationName()
842{
843 return "SwXTextCursor";
844}
845
846sal_Bool SAL_CALL SwXTextCursor::supportsService(const OUString& rServiceName)
847{
848 return cppu::supportsService(this, rServiceName);
849}
850
851uno::Sequence< OUString > SAL_CALL
852SwXTextCursor::getSupportedServiceNames()
853{
854 return {
855 "com.sun.star.text.TextCursor",
856 "com.sun.star.style.CharacterProperties",
857 "com.sun.star.style.CharacterPropertiesAsian",
858 "com.sun.star.style.CharacterPropertiesComplex",
859 "com.sun.star.style.ParagraphProperties",
860 "com.sun.star.style.ParagraphPropertiesAsian",
861 "com.sun.star.style.ParagraphPropertiesComplex",
862 "com.sun.star.text.TextSortable"
863 };
864}
865
866namespace
867{
868 class theSwXTextCursorUnoTunnelId : public rtl::Static< UnoTunnelIdInit, theSwXTextCursorUnoTunnelId > {};
869}
870
871const uno::Sequence< sal_Int8 > & SwXTextCursor::getUnoTunnelId()
872{
873 return theSwXTextCursorUnoTunnelId::get().getSeq();
874}
875
876sal_Int64 SAL_CALL
877SwXTextCursor::getSomething(const uno::Sequence< sal_Int8 >& rId)
878{
879 const sal_Int64 nRet( ::sw::UnoTunnelImpl<SwXTextCursor>(rId, this) );
880 return nRet ? nRet : OTextCursorHelper::getSomething(rId);
881}
882
883void SAL_CALL SwXTextCursor::collapseToStart()
884{
885 SolarMutexGuard aGuard;
886
887 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
888
889 if (rUnoCursor.HasMark())
890 {
891 if (*rUnoCursor.GetPoint() > *rUnoCursor.GetMark())
892 {
893 rUnoCursor.Exchange();
894 }
895 rUnoCursor.DeleteMark();
896 }
897}
898
899void SAL_CALL SwXTextCursor::collapseToEnd()
900{
901 SolarMutexGuard aGuard;
902
903 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
904
905 if (rUnoCursor.HasMark())
906 {
907 if (*rUnoCursor.GetPoint() < *rUnoCursor.GetMark())
908 {
909 rUnoCursor.Exchange();
910 }
911 rUnoCursor.DeleteMark();
912 }
913}
914
915sal_Bool SAL_CALL SwXTextCursor::isCollapsed()
916{
917 SolarMutexGuard aGuard;
918
919 bool bRet = true;
920 auto pUnoCursor(m_pImpl->m_pUnoCursor);
921 if(pUnoCursor && pUnoCursor->GetMark())
922 {
923 bRet = (*pUnoCursor->GetPoint() == *pUnoCursor->GetMark());
924 }
925 return bRet;
926}
927
928sal_Bool SAL_CALL
929SwXTextCursor::goLeft(sal_Int16 nCount, sal_Bool Expand)
930{
931 SolarMutexGuard aGuard;
932
933 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
934
935 SwUnoCursorHelper::SelectPam(rUnoCursor, Expand);
936 bool bRet = rUnoCursor.Left( nCount);
937 if (CursorType::Meta == m_pImpl->m_eType)
938 {
939 bRet = lcl_ForceIntoMeta(rUnoCursor, m_pImpl->m_xParentText,
940 META_CHECK_BOTH)
941 && bRet;
942 }
943 return bRet;
944}
945
946sal_Bool SAL_CALL
947SwXTextCursor::goRight(sal_Int16 nCount, sal_Bool Expand)
948{
949 SolarMutexGuard aGuard;
950
951 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
952
953 SwUnoCursorHelper::SelectPam(rUnoCursor, Expand);
954 bool bRet = rUnoCursor.Right(nCount);
955 if (CursorType::Meta == m_pImpl->m_eType)
956 {
957 bRet = lcl_ForceIntoMeta(rUnoCursor, m_pImpl->m_xParentText,
958 META_CHECK_BOTH)
959 && bRet;
960 }
961 return bRet;
962}
963
964void SAL_CALL
965SwXTextCursor::gotoStart(sal_Bool Expand)
966{
967 SolarMutexGuard aGuard;
968 comphelper::ProfileZone aZone("gotoStart");
969
970 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
971
972 SwUnoCursorHelper::SelectPam(rUnoCursor, Expand);
973 if (CursorType::Body == m_pImpl->m_eType)
974 {
975 rUnoCursor.Move( fnMoveBackward, GoInDoc );
976 //check, that the cursor is not in a table
977 SwTableNode * pTableNode = rUnoCursor.GetNode().FindTableNode();
978 SwContentNode * pCNode = nullptr;
979 while (pTableNode)
980 {
981 rUnoCursor.GetPoint()->nNode = *pTableNode->EndOfSectionNode();
982 pCNode = GetDoc()->GetNodes().GoNext(&rUnoCursor.GetPoint()->nNode);
983 pTableNode = pCNode ? pCNode->FindTableNode() : nullptr;
984 }
985 if (pCNode)
986 {
987 rUnoCursor.GetPoint()->nContent.Assign(pCNode, 0);
988 }
989 SwStartNode const*const pTmp =
990 rUnoCursor.GetNode().StartOfSectionNode();
991 if (pTmp->IsSectionNode())
992 {
993 SwSectionNode const*const pSectionStartNode =
994 static_cast<SwSectionNode const*>(pTmp);
995 if (pSectionStartNode->GetSection().IsHiddenFlag())
996 {
997 pCNode = GetDoc()->GetNodes().GoNextSection(
998 &rUnoCursor.GetPoint()->nNode, true, false);
999 if (pCNode)
1000 {
1001 rUnoCursor.GetPoint()->nContent.Assign(pCNode, 0);
1002 }
1003 }
1004 }
1005 }
1006 else if ( (CursorType::Frame == m_pImpl->m_eType)
1007 || (CursorType::TableText == m_pImpl->m_eType)
1008 || (CursorType::Header == m_pImpl->m_eType)
1009 || (CursorType::Footer == m_pImpl->m_eType)
1010 || (CursorType::Footnote== m_pImpl->m_eType)
1011 || (CursorType::Redline == m_pImpl->m_eType))
1012 {
1013 rUnoCursor.MoveSection(GoCurrSection, fnSectionStart);
1014 }
1015 else if (CursorType::Meta == m_pImpl->m_eType)
1016 {
1017 lcl_ForceIntoMeta(rUnoCursor, m_pImpl->m_xParentText, META_INIT_START);
1018 }
1019}
1020
1021void SAL_CALL
1022SwXTextCursor::gotoEnd(sal_Bool Expand)
1023{
1024 SolarMutexGuard aGuard;
1025 comphelper::ProfileZone aZone("gotoEnd");
1026
1027 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
1028
1029 SwUnoCursorHelper::SelectPam(rUnoCursor, Expand);
1030 if (CursorType::Body == m_pImpl->m_eType)
1031 {
1032 rUnoCursor.Move( fnMoveForward, GoInDoc );
1033 }
1034 else if ( (CursorType::Frame == m_pImpl->m_eType)
1035 || (CursorType::TableText == m_pImpl->m_eType)
1036 || (CursorType::Header == m_pImpl->m_eType)
1037 || (CursorType::Footer == m_pImpl->m_eType)
1038 || (CursorType::Footnote== m_pImpl->m_eType)
1039 || (CursorType::Redline == m_pImpl->m_eType))
1040 {
1041 rUnoCursor.MoveSection( GoCurrSection, fnSectionEnd);
1042 }
1043 else if (CursorType::Meta == m_pImpl->m_eType)
1044 {
1045 lcl_ForceIntoMeta(rUnoCursor, m_pImpl->m_xParentText, META_INIT_END);
1046 }
1047}
1048
1049void SAL_CALL
1050SwXTextCursor::gotoRange(
1051 const uno::Reference< text::XTextRange > & xRange, sal_Bool bExpand)
1052{
1053 SolarMutexGuard aGuard;
1054
1055 if (!xRange.is())
1056 {
1057 throw uno::RuntimeException();
1058 }
1059
1060 SwUnoCursor & rOwnCursor( m_pImpl->GetCursorOrThrow() );
1061
1062 uno::Reference<lang::XUnoTunnel> xRangeTunnel( xRange, uno::UNO_QUERY);
1063 SwXTextRange* pRange = nullptr;
1064 OTextCursorHelper* pCursor = nullptr;
1065 if(xRangeTunnel.is())
1066 {
1067 pRange = ::sw::UnoTunnelGetImplementation<SwXTextRange>(xRangeTunnel);
1068 pCursor =
1069 ::sw::UnoTunnelGetImplementation<OTextCursorHelper>(xRangeTunnel);
1070 }
1071
1072 if (!pRange && !pCursor)
1073 {
1074 throw uno::RuntimeException();
1075 }
1076
1077 SwPaM aPam(GetDoc()->GetNodes());
1078 const SwPaM * pPam(nullptr);
1079 if (pCursor)
1080 {
1081 pPam = pCursor->GetPaM();
1082 }
1083 else if (pRange)
1084 {
1085 if (pRange->GetPositions(aPam))
1086 {
1087 pPam = & aPam;
1088 }
1089 }
1090
1091 if (!pPam)
1092 {
1093 throw uno::RuntimeException();
1094 }
1095
1096 {
1097 SwStartNodeType eSearchNodeType = SwNormalStartNode;
1098 switch (m_pImpl->m_eType)
1099 {
1100 case CursorType::Frame: eSearchNodeType = SwFlyStartNode; break;
1101 case CursorType::TableText: eSearchNodeType = SwTableBoxStartNode; break;
1102 case CursorType::Footnote: eSearchNodeType = SwFootnoteStartNode; break;
1103 case CursorType::Header: eSearchNodeType = SwHeaderStartNode; break;
1104 case CursorType::Footer: eSearchNodeType = SwFooterStartNode; break;
1105 //case CURSOR_INVALID:
1106 //case CursorType::Body:
1107 default:
1108 ;
1109 }
1110
1111 const SwStartNode* pOwnStartNode = rOwnCursor.GetNode().FindSttNodeByType(eSearchNodeType);
1112 while ( pOwnStartNode != nullptr
1113 && pOwnStartNode->IsSectionNode())
1114 {
1115 pOwnStartNode = pOwnStartNode->StartOfSectionNode();
1116 }
1117
1118 const SwStartNode* pTmp =
1119 pPam->GetNode().FindSttNodeByType(eSearchNodeType);
1120 while ( pTmp != nullptr
1121 && pTmp->IsSectionNode() )
1122 {
1123 pTmp = pTmp->StartOfSectionNode();
1124 }
1125
1126 if ( eSearchNodeType == SwTableBoxStartNode )
1127 {
1128 if (!pOwnStartNode || !pTmp)
1129 {
1130 throw uno::RuntimeException();
1131 }
1132
1133 if ( pOwnStartNode->FindTableNode() != pTmp->FindTableNode() )
1134 {
1135 throw uno::RuntimeException();
1136 }
1137 }
1138 else
1139 {
1140 if ( pOwnStartNode != pTmp )
1141 {
1142 throw uno::RuntimeException();
1143 }
1144 }
1145 }
1146
1147 if (CursorType::Meta == m_pImpl->m_eType)
1148 {
1149 SwPaM CopyPam(*pPam->GetMark(), *pPam->GetPoint());
1150 const bool bNotForced( lcl_ForceIntoMeta(
1151 CopyPam, m_pImpl->m_xParentText, META_CHECK_BOTH) );
1152 if (!bNotForced)
1153 {
1154 throw uno::RuntimeException(
1155 "gotoRange: parameter range not contained in nesting"
1156 " text content for which this cursor was created",
1157 static_cast<text::XWordCursor*>(this));
1158 }
1159 }
1160
1161 // selection has to be expanded here
1162 if(bExpand)
1163 {
1164 // cursor should include its previous range plus the given range
1165 const SwPosition aOwnLeft(*rOwnCursor.Start());
1166 const SwPosition aOwnRight(*rOwnCursor.End());
1167 SwPosition const& rParamLeft = *pPam->Start();
1168 SwPosition const& rParamRight = *pPam->End();
1169
1170 // now there are four SwPositions,
1171 // two of them are going to be used, but which ones?
1172 if (aOwnRight > rParamRight)
1173 *rOwnCursor.GetPoint() = aOwnRight;
1174 else
1175 *rOwnCursor.GetPoint() = rParamRight;
1176 rOwnCursor.SetMark();
1177 if (aOwnLeft < rParamLeft)
1178 *rOwnCursor.GetMark() = aOwnLeft;
1179 else
1180 *rOwnCursor.GetMark() = rParamLeft;
1181 }
1182 else
1183 {
1184 // cursor should be the given range
1185 *rOwnCursor.GetPoint() = *pPam->GetPoint();
1186 if (pPam->HasMark())
1187 {
1188 rOwnCursor.SetMark();
1189 *rOwnCursor.GetMark() = *pPam->GetMark();
1190 }
1191 else
1192 {
1193 rOwnCursor.DeleteMark();
1194 }
1195 }
1196}
1197
1198sal_Bool SAL_CALL SwXTextCursor::isStartOfWord()
1199{
1200 SolarMutexGuard aGuard;
1201
1202 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
1203
1204 const bool bRet =
1205 rUnoCursor.IsStartWordWT( i18n::WordType::DICTIONARY_WORD );
1206 return bRet;
1207}
1208
1209sal_Bool SAL_CALL SwXTextCursor::isEndOfWord()
1210{
1211 SolarMutexGuard aGuard;
1212
1213 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
1214
1215 const bool bRet =
1216 rUnoCursor.IsEndWordWT( i18n::WordType::DICTIONARY_WORD );
1217 return bRet;
1218}
1219
1220sal_Bool SAL_CALL
1221SwXTextCursor::gotoNextWord(sal_Bool Expand)
1222{
1223 SolarMutexGuard aGuard;
1224
1225 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
1226
1227 // problems arise when a paragraph starts with something other than a word
1228 bool bRet = false;
1229 // remember old position to check if cursor has moved
1230 // since the called functions are sometimes a bit unreliable
1231 // in specific cases...
1232 SwPosition *const pPoint = rUnoCursor.GetPoint();
1233 SwNode *const pOldNode = &pPoint->nNode.GetNode();
1234 sal_Int32 const nOldIndex = pPoint->nContent.GetIndex();
1235
1236 SwUnoCursorHelper::SelectPam(rUnoCursor, Expand);
1237 // end of paragraph
1238 if (rUnoCursor.GetContentNode() &&
1239 (pPoint->nContent == rUnoCursor.GetContentNode()->Len()))
1240 {
1241 rUnoCursor.Right(1);
1242 }
1243 else
1244 {
1245 const bool bTmp =
1246 rUnoCursor.GoNextWordWT( i18n::WordType::DICTIONARY_WORD );
1247 // if there is no next word within the current paragraph
1248 // try to go to the start of the next paragraph
1249 if (!bTmp)
1250 {
1251 rUnoCursor.MovePara(GoNextPara, fnParaStart);
1252 }
1253 }
1254
1255 // return true if cursor has moved
1256 bRet = (&pPoint->nNode.GetNode() != pOldNode) ||
1257 (pPoint->nContent.GetIndex() != nOldIndex);
1258 if (bRet && (CursorType::Meta == m_pImpl->m_eType))
1259 {
1260 bRet = lcl_ForceIntoMeta(rUnoCursor, m_pImpl->m_xParentText,
1261 META_CHECK_BOTH);
1262 }
1263
1264 return bRet;
1265}
1266
1267sal_Bool SAL_CALL
1268SwXTextCursor::gotoPreviousWord(sal_Bool Expand)
1269{
1270 SolarMutexGuard aGuard;
1271
1272 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
1273
1274 // white spaces create problems on the paragraph start
1275 bool bRet = false;
1276 SwPosition *const pPoint = rUnoCursor.GetPoint();
1277 SwNode *const pOldNode = &pPoint->nNode.GetNode();
1278 sal_Int32 const nOldIndex = pPoint->nContent.GetIndex();
1279
1280 SwUnoCursorHelper::SelectPam(rUnoCursor, Expand);
1281 // start of paragraph?
1282 if (pPoint->nContent == 0)
1283 {
1284 rUnoCursor.Left(1);
1285 }
1286 else
1287 {
1288 rUnoCursor.GoPrevWordWT( i18n::WordType::DICTIONARY_WORD );
1289 if (pPoint->nContent == 0)
1290 {
1291 rUnoCursor.Left(1);
1292 }
1293 }
1294
1295 // return true if cursor has moved
1296 bRet = (&pPoint->nNode.GetNode() != pOldNode) ||
1297 (pPoint->nContent.GetIndex() != nOldIndex);
1298 if (bRet && (CursorType::Meta == m_pImpl->m_eType))
1299 {
1300 bRet = lcl_ForceIntoMeta(rUnoCursor, m_pImpl->m_xParentText,
1301 META_CHECK_BOTH);
1302 }
1303
1304 return bRet;
1305}
1306
1307sal_Bool SAL_CALL
1308SwXTextCursor::gotoEndOfWord(sal_Bool Expand)
1309{
1310 SolarMutexGuard aGuard;
1311
1312 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
1313
1314 bool bRet = false;
1315 SwPosition *const pPoint = rUnoCursor.GetPoint();
1316 SwNode & rOldNode = pPoint->nNode.GetNode();
1317 sal_Int32 const nOldIndex = pPoint->nContent.GetIndex();
1318
1319 const sal_Int16 nWordType = i18n::WordType::DICTIONARY_WORD;
1320 SwUnoCursorHelper::SelectPam(rUnoCursor, Expand);
1321 if (!rUnoCursor.IsEndWordWT( nWordType ))
1322 {
1323 rUnoCursor.GoEndWordWT( nWordType );
1324 }
1325
1326 // restore old cursor if we are not at the end of a word by now
1327 // otherwise use current one
1328 bRet = rUnoCursor.IsEndWordWT( nWordType );
1329 if (!bRet)
1330 {
1331 pPoint->nNode = rOldNode;
1332 pPoint->nContent = nOldIndex;
1333 }
1334 else if (CursorType::Meta == m_pImpl->m_eType)
1335 {
1336 bRet = lcl_ForceIntoMeta(rUnoCursor, m_pImpl->m_xParentText,
1337 META_CHECK_BOTH);
1338 }
1339
1340 return bRet;
1341}
1342
1343sal_Bool SAL_CALL
1344SwXTextCursor::gotoStartOfWord(sal_Bool Expand)
1345{
1346 SolarMutexGuard aGuard;
1347
1348 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
1349
1350 bool bRet = false;
1351 SwPosition *const pPoint = rUnoCursor.GetPoint();
1352 SwNode & rOldNode = pPoint->nNode.GetNode();
1353 sal_Int32 const nOldIndex = pPoint->nContent.GetIndex();
1354
1355 const sal_Int16 nWordType = i18n::WordType::DICTIONARY_WORD;
1356 SwUnoCursorHelper::SelectPam(rUnoCursor, Expand);
1357 if (!rUnoCursor.IsStartWordWT( nWordType ))
1358 {
1359 rUnoCursor.GoStartWordWT( nWordType );
1360 }
1361
1362 // restore old cursor if we are not at the start of a word by now
1363 // otherwise use current one
1364 bRet = rUnoCursor.IsStartWordWT( nWordType );
1365 if (!bRet)
1366 {
1367 pPoint->nNode = rOldNode;
1368 pPoint->nContent = nOldIndex;
1369 }
1370 else if (CursorType::Meta == m_pImpl->m_eType)
1371 {
1372 bRet = lcl_ForceIntoMeta(rUnoCursor, m_pImpl->m_xParentText,
1373 META_CHECK_BOTH);
1374 }
1375
1376 return bRet;
1377}
1378
1379sal_Bool SAL_CALL
1380SwXTextCursor::isStartOfSentence()
1381{
1382 SolarMutexGuard aGuard;
1383
1384 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
1385
1386 // start of paragraph?
1387 bool bRet = rUnoCursor.GetPoint()->nContent == 0;
1388 // with mark ->no sentence start
1389 // (check if cursor is no selection, i.e. it does not have
1390 // a mark or else point and mark are identical)
1391 if (!bRet && (!rUnoCursor.HasMark() ||
1392 *rUnoCursor.GetPoint() == *rUnoCursor.GetMark()))
1393 {
1394 SwCursor aCursor(*rUnoCursor.GetPoint(),nullptr);
1395 SwPosition aOrigPos = *aCursor.GetPoint();
1396 aCursor.GoSentence(SwCursor::START_SENT );
1397 bRet = aOrigPos == *aCursor.GetPoint();
1398 }
1399 return bRet;
1400}
1401
1402sal_Bool SAL_CALL
1403SwXTextCursor::isEndOfSentence()
1404{
1405 SolarMutexGuard aGuard;
1406
1407 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
1408
1409 // end of paragraph?
1410 bool bRet = rUnoCursor.GetContentNode() &&
1411 (rUnoCursor.GetPoint()->nContent == rUnoCursor.GetContentNode()->Len());
1412 // with mark->no sentence end
1413 // (check if cursor is no selection, i.e. it does not have
1414 // a mark or else point and mark are identical)
1415 if (!bRet && (!rUnoCursor.HasMark() ||
1416 *rUnoCursor.GetPoint() == *rUnoCursor.GetMark()))
1417 {
1418 SwCursor aCursor(*rUnoCursor.GetPoint(), nullptr);
1419 SwPosition aOrigPos = *aCursor.GetPoint();
1420 aCursor.GoSentence(SwCursor::END_SENT);
1421 bRet = aOrigPos == *aCursor.GetPoint();
1422 }
1423 return bRet;
1424}
1425
1426sal_Bool SAL_CALL
1427SwXTextCursor::gotoNextSentence(sal_Bool Expand)
1428{
1429 SolarMutexGuard aGuard;
1430
1431 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
1432
1433 const bool bWasEOS = isEndOfSentence();
1434 SwUnoCursorHelper::SelectPam(rUnoCursor, Expand);
1435 bool bRet = rUnoCursor.GoSentence(SwCursor::NEXT_SENT);
1436 if (!bRet)
1437 {
1438 bRet = rUnoCursor.MovePara(GoNextPara, fnParaStart);
1439 }
1440
1441 // if at the end of the sentence (i.e. at the space after the '.')
1442 // advance to next word in order for GoSentence to work properly
1443 // next time and have isStartOfSentence return true after this call
1444 if (!rUnoCursor.IsStartWordWT(css::i18n::WordType::ANYWORD_IGNOREWHITESPACES))
1445 {
1446 const bool bNextWord = rUnoCursor.GoNextWordWT(i18n::WordType::ANYWORD_IGNOREWHITESPACES);
1447 if (bWasEOS && !bNextWord)
1448 {
1449 bRet = false;
1450 }
1451 }
1452 if (CursorType::Meta == m_pImpl->m_eType)
1453 {
1454 bRet = lcl_ForceIntoMeta(rUnoCursor, m_pImpl->m_xParentText,
1455 META_CHECK_BOTH)
1456 && bRet;
1457 }
1458 return bRet;
1459}
1460
1461sal_Bool SAL_CALL
1462SwXTextCursor::gotoPreviousSentence(sal_Bool Expand)
1463{
1464 SolarMutexGuard aGuard;
1465
1466 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
1467
1468 SwUnoCursorHelper::SelectPam(rUnoCursor, Expand);
1469 bool bRet = rUnoCursor.GoSentence(SwCursor::PREV_SENT);
1470 if (!bRet)
1471 {
1472 bRet = rUnoCursor.MovePara(GoPrevPara, fnParaStart);
1473 if (bRet)
1474 {
1475 rUnoCursor.MovePara(GoCurrPara, fnParaEnd);
1476 // at the end of a paragraph move to the sentence end again
1477 rUnoCursor.GoSentence(SwCursor::PREV_SENT);
1478 }
1479 }
1480 if (CursorType::Meta == m_pImpl->m_eType)
1481 {
1482 bRet = lcl_ForceIntoMeta(rUnoCursor, m_pImpl->m_xParentText,
1483 META_CHECK_BOTH)
1484 && bRet;
1485 }
1486 return bRet;
1487}
1488
1489sal_Bool SAL_CALL
1490SwXTextCursor::gotoStartOfSentence(sal_Bool Expand)
1491{
1492 SolarMutexGuard aGuard;
1493
1494 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
1495
1496 SwUnoCursorHelper::SelectPam(rUnoCursor, Expand);
1497 // if we're at the para start then we won't move
1498 // but bRet is also true if GoSentence failed but
1499 // the start of the sentence is reached
1500 bool bRet = SwUnoCursorHelper::IsStartOfPara(rUnoCursor)
1501 || rUnoCursor.GoSentence(SwCursor::START_SENT)
1502 || SwUnoCursorHelper::IsStartOfPara(rUnoCursor);
1503 if (CursorType::Meta == m_pImpl->m_eType)
1504 {
1505 bRet = lcl_ForceIntoMeta(rUnoCursor, m_pImpl->m_xParentText,
1506 META_CHECK_BOTH)
1507 && bRet;
1508 }
1509 return bRet;
1510}
1511
1512sal_Bool SAL_CALL
1513SwXTextCursor::gotoEndOfSentence(sal_Bool Expand)
1514{
1515 SolarMutexGuard aGuard;
1516
1517 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
1518
1519 SwUnoCursorHelper::SelectPam(rUnoCursor, Expand);
1520 // bRet is true if GoSentence() succeeded or if the
1521 // MovePara() succeeded while the end of the para is
1522 // not reached already
1523 bool bAlreadyParaEnd = SwUnoCursorHelper::IsEndOfPara(rUnoCursor);
1524 bool bRet = !bAlreadyParaEnd
1525 && (rUnoCursor.GoSentence(SwCursor::END_SENT)
1526 || rUnoCursor.MovePara(GoCurrPara, fnParaEnd));
1527 if (CursorType::Meta == m_pImpl->m_eType)
1528 {
1529 bRet = lcl_ForceIntoMeta(rUnoCursor, m_pImpl->m_xParentText,
1530 META_CHECK_BOTH)
1531 && bRet;
1532 }
1533 return bRet;
1534}
1535
1536sal_Bool SAL_CALL
1537SwXTextCursor::isStartOfParagraph()
1538{
1539 SolarMutexGuard aGuard;
1540
1541 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
1542
1543 const bool bRet = SwUnoCursorHelper::IsStartOfPara(rUnoCursor);
1544 return bRet;
1545}
1546
1547sal_Bool SAL_CALL
1548SwXTextCursor::isEndOfParagraph()
1549{
1550 SolarMutexGuard aGuard;
1551
1552 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
1553
1554 const bool bRet = SwUnoCursorHelper::IsEndOfPara(rUnoCursor);
1555 return bRet;
1556}
1557
1558sal_Bool SAL_CALL
1559SwXTextCursor::gotoStartOfParagraph(sal_Bool Expand)
1560{
1561 SolarMutexGuard aGuard;
1562
1563 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
1564
1565 if (CursorType::Meta == m_pImpl->m_eType)
1566 {
1567 return false;
1568 }
1569 SwUnoCursorHelper::SelectPam(rUnoCursor, Expand);
1570 bool bRet = SwUnoCursorHelper::IsStartOfPara(rUnoCursor);
1571 if (!bRet)
1572 {
1573 bRet = rUnoCursor.MovePara(GoCurrPara, fnParaStart);
1574 }
1575
1576 // since MovePara(GoCurrPara, fnParaStart) only returns false
1577 // if we were already at the start of the paragraph this function
1578 // should always complete successfully.
1579 OSL_ENSURE( bRet, "gotoStartOfParagraph failed" )do { if (true && (!(bRet))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/unocore/unoobj.cxx"
":" "1579" ": "), "%s", "gotoStartOfParagraph failed"); } } while
(false)
;
1580 return bRet;
1581}
1582
1583sal_Bool SAL_CALL
1584SwXTextCursor::gotoEndOfParagraph(sal_Bool Expand)
1585{
1586 SolarMutexGuard aGuard;
1587
1588 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
1589
1590 if (CursorType::Meta == m_pImpl->m_eType)
1591 {
1592 return false;
1593 }
1594 SwUnoCursorHelper::SelectPam(rUnoCursor, Expand);
1595 bool bRet = SwUnoCursorHelper::IsEndOfPara(rUnoCursor);
1596 if (!bRet)
1597 {
1598 bRet = rUnoCursor.MovePara(GoCurrPara, fnParaEnd);
1599 }
1600
1601 // since MovePara(GoCurrPara, fnParaEnd) only returns false
1602 // if we were already at the end of the paragraph this function
1603 // should always complete successfully.
1604 OSL_ENSURE( bRet, "gotoEndOfParagraph failed" )do { if (true && (!(bRet))) { sal_detail_logFormat((SAL_DETAIL_LOG_LEVEL_WARN
), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/unocore/unoobj.cxx"
":" "1604" ": "), "%s", "gotoEndOfParagraph failed"); } } while
(false)
;
1605 return bRet;
1606}
1607
1608sal_Bool SAL_CALL
1609SwXTextCursor::gotoNextParagraph(sal_Bool Expand)
1610{
1611 SolarMutexGuard aGuard;
1612
1613 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
1614
1615 if (CursorType::Meta == m_pImpl->m_eType)
1616 {
1617 return false;
1618 }
1619 SwUnoCursorHelper::SelectPam(rUnoCursor, Expand);
1620 const bool bRet = rUnoCursor.MovePara(GoNextPara, fnParaStart);
1621 return bRet;
1622}
1623
1624sal_Bool SAL_CALL
1625SwXTextCursor::gotoPreviousParagraph(sal_Bool Expand)
1626{
1627 SolarMutexGuard aGuard;
1628
1629 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
1630
1631 if (CursorType::Meta == m_pImpl->m_eType)
1632 {
1633 return false;
1634 }
1635 SwUnoCursorHelper::SelectPam(rUnoCursor, Expand);
1636 const bool bRet = rUnoCursor.MovePara(GoPrevPara, fnParaStart);
1637 return bRet;
1638}
1639
1640uno::Reference< text::XText > SAL_CALL
1641SwXTextCursor::getText()
1642{
1643 SolarMutexGuard g;
1644
1645 return m_pImpl->m_xParentText;
1646}
1647
1648uno::Reference< text::XTextRange > SAL_CALL
1649SwXTextCursor::getStart()
1650{
1651 SolarMutexGuard aGuard;
1652
1653 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
1654
1655 uno::Reference< text::XTextRange > xRet;
1656 SwPaM aPam(*rUnoCursor.Start());
1657 const uno::Reference< text::XText > xParent = getText();
1658 if (CursorType::Meta == m_pImpl->m_eType)
1659 {
1660 // return cursor to prevent modifying SwXTextRange for META
1661 SwXTextCursor * const pXCursor(
1662 new SwXTextCursor(rUnoCursor.GetDoc(), xParent, CursorType::Meta,
1663 *rUnoCursor.GetPoint()) );
1664 pXCursor->gotoStart(false);
1665 xRet = static_cast<text::XWordCursor*>(pXCursor);
1666 }
1667 else
1668 {
1669 xRet = new SwXTextRange(aPam, xParent);
1670 }
1671 return xRet;
1672}
1673
1674uno::Reference< text::XTextRange > SAL_CALL
1675SwXTextCursor::getEnd()
1676{
1677 SolarMutexGuard aGuard;
1678
1679 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
1680
1681 uno::Reference< text::XTextRange > xRet;
1682 SwPaM aPam(*rUnoCursor.End());
1683 const uno::Reference< text::XText > xParent = getText();
1684 if (CursorType::Meta == m_pImpl->m_eType)
1685 {
1686 // return cursor to prevent modifying SwXTextRange for META
1687 SwXTextCursor * const pXCursor(
1688 new SwXTextCursor(rUnoCursor.GetDoc(), xParent, CursorType::Meta,
1689 *rUnoCursor.GetPoint()) );
1690 pXCursor->gotoEnd(false);
1691 xRet = static_cast<text::XWordCursor*>(pXCursor);
1692 }
1693 else
1694 {
1695 xRet = new SwXTextRange(aPam, xParent);
1696 }
1697 return xRet;
1698}
1699
1700OUString SAL_CALL SwXTextCursor::getString()
1701{
1702 SolarMutexGuard aGuard;
1703
1704 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
1705
1706 OUString aText;
1707 SwUnoCursorHelper::GetTextFromPam(rUnoCursor, aText);
1708 return aText;
1709}
1710
1711void SAL_CALL
1712SwXTextCursor::setString(const OUString& aString)
1713{
1714 SolarMutexGuard aGuard;
1715
1716 m_pImpl->GetCursorOrThrow(); // just to check if valid
1717
1718 const bool bForceExpandHints( (CursorType::Meta == m_pImpl->m_eType)
1719 && dynamic_cast<SwXMeta&>(*m_pImpl->m_xParentText)
1720 .CheckForOwnMemberMeta(*GetPaM(), true) );
1721 DeleteAndInsert(aString, bForceExpandHints);
1722}
1723
1724uno::Any SwUnoCursorHelper::GetPropertyValue(
1725 SwPaM& rPaM, const SfxItemPropertySet& rPropSet,
1726 const OUString& rPropertyName)
1727{
1728 uno::Any aAny;
1729 SfxItemPropertySimpleEntry const*const pEntry =
1730 rPropSet.getPropertyMap().getByName(rPropertyName);
1731
1732 if (!pEntry)
1733 {
1734 throw beans::UnknownPropertyException(
1735 "Unknown property: " + rPropertyName,
1736 static_cast<cppu::OWeakObject *>(nullptr));
1737 }
1738
1739 beans::PropertyState eTemp;
1740 const bool bDone = SwUnoCursorHelper::getCursorPropertyValue(
1741 *pEntry, rPaM, &aAny, eTemp );
1742
1743 if (!bDone)
1744 {
1745 SfxItemSet aSet(
1746 rPaM.GetDoc().GetAttrPool(),
1747 svl::Items<
1748 RES_CHRATR_BEGIN, RES_FRMATR_END - 1,
1749 RES_UNKNOWNATR_CONTAINER, RES_UNKNOWNATR_CONTAINER>{});
1750 SwUnoCursorHelper::GetCursorAttr(rPaM, aSet);
1751
1752 rPropSet.getPropertyValue(*pEntry, aSet, aAny);
1753 }
1754
1755 return aAny;
1756}
1757
1758void SwUnoCursorHelper::SetPropertyValue(
1759 SwPaM& rPaM, const SfxItemPropertySet& rPropSet,
1760 const OUString& rPropertyName,
1761 const uno::Any& rValue,
1762 const SetAttrMode nAttrMode)
1763{
1764 uno::Sequence< beans::PropertyValue > aValues(1);
1765 aValues[0].Name = rPropertyName;
1766 aValues[0].Value = rValue;
1767 SetPropertyValues(rPaM, rPropSet, aValues, nAttrMode);
1768}
1769
1770// FN_UNO_PARA_STYLE is known to set attributes for nodes, inside
1771// SwUnoCursorHelper::SetTextFormatColl, instead of extending item set.
1772// We need to get them from nodes in next call to GetCursorAttr.
1773// The rest could cause similar problems in theory, so we just list them here.
1774static bool propertyCausesSideEffectsInNodes(sal_uInt16 nWID)
1775{
1776 return nWID == FN_UNO_PARA_STYLE((20000 + 2200) + 9) ||
1777 nWID == FN_UNO_CHARFMT_SEQUENCE((20000 + 2200) + 94) ||
1778 nWID == FN_UNO_NUM_START_VALUE((20000 + 2200) + 13) ||
1779 nWID == FN_UNO_NUM_RULES((20000 + 2200) + 15);
1780}
1781
1782void SwUnoCursorHelper::SetPropertyValues(
1783 SwPaM& rPaM, const SfxItemPropertySet& rPropSet,
1784 const uno::Sequence< beans::PropertyValue > &rPropertyValues,
1785 const SetAttrMode nAttrMode)
1786{
1787 if (!rPropertyValues.hasElements())
1788 return;
1789
1790 SwDoc& rDoc = rPaM.GetDoc();
1791 OUString aUnknownExMsg, aPropertyVetoExMsg;
1792
1793 // Build set of attributes we want to fetch
1794 const sal_uInt16 zero = 0;
1795 SfxItemSet aItemSet(rDoc.GetAttrPool(), &zero);
1796 std::vector<std::pair<const SfxItemPropertySimpleEntry*, const uno::Any&>> aEntries;
1797 aEntries.reserve(rPropertyValues.getLength());
1798 for (const auto& rPropVal : rPropertyValues)
1799 {
1800 const OUString &rPropertyName = rPropVal.Name;
1801
1802 SfxItemPropertySimpleEntry const* pEntry =
1803 rPropSet.getPropertyMap().getByName(rPropertyName);
1804
1805 // Queue up any exceptions until the end ...
1806 if (!pEntry)
1807 {
1808 aUnknownExMsg += "Unknown property: '" + rPropertyName + "' ";
1809 continue;
1810 }
1811 else if (pEntry->nFlags & beans::PropertyAttribute::READONLY)
1812 {
1813 aPropertyVetoExMsg += "Property is read-only: '" + rPropertyName + "' ";
1814 continue;
1815 }
1816 aItemSet.MergeRange(pEntry->nWID, pEntry->nWID);
1817 aEntries.emplace_back(pEntry, rPropVal.Value);
1818 }
1819
1820 if (!aEntries.empty())
1821 {
1822 // Fetch, overwrite, and re-set the attributes from the core
1823
1824 bool bPreviousPropertyCausesSideEffectsInNodes = false;
1825 for (size_t i = 0; i < aEntries.size(); ++i)
1826 {
1827 SfxItemPropertySimpleEntry const*const pEntry = aEntries[i].first;
1828 bool bPropertyCausesSideEffectsInNodes =
1829 propertyCausesSideEffectsInNodes(pEntry->nWID);
1830
1831 // we need to get up-to-date item set from nodes
1832 if (i == 0 || bPreviousPropertyCausesSideEffectsInNodes)
1833 {
1834 aItemSet.ClearItem();
1835 SwUnoCursorHelper::GetCursorAttr(rPaM, aItemSet);
1836 }
1837
1838 const uno::Any &rValue = aEntries[i].second;
1839 // this can set some attributes in nodes' mpAttrSet
1840 if (!SwUnoCursorHelper::SetCursorPropertyValue(*pEntry, rValue, rPaM, aItemSet))
1841 rPropSet.setPropertyValue(*pEntry, rValue, aItemSet);
1842
1843 if (i + 1 == aEntries.size() || bPropertyCausesSideEffectsInNodes)
1844 SwUnoCursorHelper::SetCursorAttr(rPaM, aItemSet, nAttrMode, false/*bTableMode*/);
1845
1846 bPreviousPropertyCausesSideEffectsInNodes = bPropertyCausesSideEffectsInNodes;
1847 }
1848 }
1849
1850 if (!aUnknownExMsg.isEmpty())
1851 throw beans::UnknownPropertyException(aUnknownExMsg, static_cast<cppu::OWeakObject *>(nullptr));
1852 if (!aPropertyVetoExMsg.isEmpty())
1853 throw beans::PropertyVetoException(aPropertyVetoExMsg, static_cast<cppu::OWeakObject *>(nullptr));
1854}
1855
1856namespace
1857{
1858 bool NotInRange(sal_uInt16 nWID, sal_uInt16 nStart, sal_uInt16 nEnd)
1859 {
1860 return nWID < nStart || nWID > nEnd;
1861 }
1862}
1863
1864uno::Sequence< beans::PropertyState >
1865SwUnoCursorHelper::GetPropertyStates(
1866 SwPaM& rPaM, const SfxItemPropertySet& rPropSet,
1867 const uno::Sequence< OUString >& rPropertyNames,
1868 const SwGetPropertyStatesCaller eCaller)
1869{
1870 const OUString* pNames = rPropertyNames.getConstArray();
1871 uno::Sequence< beans::PropertyState > aRet(rPropertyNames.getLength());
1872 beans::PropertyState* pStates = aRet.getArray();
1873 const SfxItemPropertyMap &rMap = rPropSet.getPropertyMap();
1874 std::unique_ptr<SfxItemSet> pSet;
1875 std::unique_ptr<SfxItemSet> pSetParent;
1876
1877 for (sal_Int32 i = 0, nEnd = rPropertyNames.getLength(); i < nEnd; i++)
1878 {
1879 SfxItemPropertySimpleEntry const*const pEntry =
1880 rMap.getByName( pNames[i] );
1881 if(!pEntry)
1882 {
1883 if (pNames[i] == UNO_NAME_IS_SKIP_HIDDEN_TEXT"IsSkipHiddenText" ||
1884 pNames[i] == UNO_NAME_IS_SKIP_PROTECTED_TEXT"IsSkipProtectedText")
1885 {
1886 pStates[i] = beans::PropertyState_DEFAULT_VALUE;
1887 continue;
1888 }
1889 else if (SW_PROPERTY_STATE_CALLER_SWX_TEXT_PORTION_TOLERANT ==
1890 eCaller)
1891 {
1892 //this values marks the element as unknown property
1893 pStates[i] = beans::PropertyState::PropertyState_MAKE_FIXED_SIZE;
1894 continue;
1895 }
1896 else
1897 {
1898 throw beans::UnknownPropertyException(
1899 "Unknown property: " + pNames[i],
1900 static_cast<cppu::OWeakObject *>(nullptr));
1901 }
1902 }
1903 if (((SW_PROPERTY_STATE_CALLER_SWX_TEXT_PORTION == eCaller) ||
1904 (SW_PROPERTY_STATE_CALLER_SWX_TEXT_PORTION_TOLERANT == eCaller)) &&
1905 NotInRange(pEntry->nWID, FN_UNO_RANGE_BEGIN(20000 + 1600), FN_UNO_RANGE_END((20000 + 2400) + 199)) &&
1906 NotInRange(pEntry->nWID, RES_CHRATR_BEGIN, RES_TXTATR_END) )
1907 {
1908 pStates[i] = beans::PropertyState_DEFAULT_VALUE;
1909 }
1910 else
1911 {
1912 if ( pEntry->nWID >= FN_UNO_RANGE_BEGIN(20000 + 1600) &&
1913 pEntry->nWID <= FN_UNO_RANGE_END((20000 + 2400) + 199) )
1914 {
1915 (void)SwUnoCursorHelper::getCursorPropertyValue(
1916 *pEntry, rPaM, nullptr, pStates[i] );
1917 }
1918 else
1919 {
1920 if (!pSet)
1921 {
1922 switch ( eCaller )
1923 {
1924 case SW_PROPERTY_STATE_CALLER_SWX_TEXT_PORTION_TOLERANT:
1925 case SW_PROPERTY_STATE_CALLER_SWX_TEXT_PORTION:
1926 pSet.reset(
1927 new SfxItemSet( rPaM.GetDoc().GetAttrPool(),
1928 svl::Items<RES_CHRATR_BEGIN, RES_TXTATR_END>{} ));
1929 break;
1930 case SW_PROPERTY_STATE_CALLER_SINGLE_VALUE_ONLY:
1931 pSet.reset(
1932 new SfxItemSet( rPaM.GetDoc().GetAttrPool(),
1933 {{pEntry->nWID, pEntry->nWID}} ));
1934 break;
1935 default:
1936 pSet.reset( new SfxItemSet(
1937 rPaM.GetDoc().GetAttrPool(),
1938 svl::Items<
1939 RES_CHRATR_BEGIN, RES_FRMATR_END - 1,
1940 RES_UNKNOWNATR_CONTAINER,
1941 RES_UNKNOWNATR_CONTAINER>{}));
1942 }
1943 // #i63870#
1944 SwUnoCursorHelper::GetCursorAttr( rPaM, *pSet );
1945 }
1946
1947 pStates[i] = ( pSet->Count() )
1948 ? rPropSet.getPropertyState( *pEntry, *pSet )
1949 : beans::PropertyState_DEFAULT_VALUE;
1950
1951 //try again to find out if a value has been inherited
1952 if( beans::PropertyState_DIRECT_VALUE == pStates[i] )
1953 {
1954 if (!pSetParent)
1955 {
1956 pSetParent = pSet->Clone( false );
1957 // #i63870#
1958 SwUnoCursorHelper::GetCursorAttr(
1959 rPaM, *pSetParent, true, false );
1960 }
1961
1962 pStates[i] = ( pSetParent->Count() )
1963 ? rPropSet.getPropertyState( *pEntry, *pSetParent )
1964 : beans::PropertyState_DEFAULT_VALUE;
1965 }
1966 }
1967 }
1968 }
1969 return aRet;
1970}
1971
1972beans::PropertyState SwUnoCursorHelper::GetPropertyState(
1973 SwPaM& rPaM, const SfxItemPropertySet& rPropSet,
1974 const OUString& rPropertyName)
1975{
1976 uno::Sequence< OUString > aStrings { rPropertyName };
1977 uno::Sequence< beans::PropertyState > aSeq =
1978 GetPropertyStates(rPaM, rPropSet, aStrings,
1979 SW_PROPERTY_STATE_CALLER_SINGLE_VALUE_ONLY );
1980 return aSeq[0];
1981}
1982
1983static void
1984lcl_SelectParaAndReset( SwPaM &rPaM, SwDoc & rDoc,
1985 std::set<sal_uInt16> const &rWhichIds )
1986{
1987 // if we are resetting paragraph attributes, we need to select the full paragraph first
1988 SwPosition aStart = *rPaM.Start();
1989 SwPosition aEnd = *rPaM.End();
1990 auto pTemp ( rDoc.CreateUnoCursor(aStart) );
1991 if(!SwUnoCursorHelper::IsStartOfPara(*pTemp))
1992 {
1993 pTemp->MovePara(GoCurrPara, fnParaStart);
1994 }
1995 pTemp->SetMark();
1996 *pTemp->GetPoint() = aEnd;
1997 SwUnoCursorHelper::SelectPam(*pTemp, true);
1998 if(!SwUnoCursorHelper::IsEndOfPara(*pTemp))
1999 {
2000 pTemp->MovePara(GoCurrPara, fnParaEnd);
2001 }
2002 rDoc.ResetAttrs(*pTemp, true, rWhichIds);
2003}
2004
2005void SwUnoCursorHelper::SetPropertyToDefault(
2006 SwPaM& rPaM, const SfxItemPropertySet& rPropSet,
2007 const OUString& rPropertyName)
2008{
2009 SwDoc& rDoc = rPaM.GetDoc();
2010 SfxItemPropertySimpleEntry const*const pEntry =
2011 rPropSet.getPropertyMap().getByName(rPropertyName);
2012 if (!pEntry)
2013 {
2014 throw beans::UnknownPropertyException(
2015 "Unknown property: " + rPropertyName,
2016 static_cast<cppu::OWeakObject *>(nullptr));
2017 }
2018
2019 if (pEntry->nFlags & beans::PropertyAttribute::READONLY)
2020 {
2021 throw uno::RuntimeException(
2022 "setPropertyToDefault: property is read-only: "
2023 + rPropertyName, nullptr);
2024 }
2025
2026 if (pEntry->nWID < RES_FRMATR_END)
2027 {
2028 std::set<sal_uInt16> aWhichIds;
2029 aWhichIds.insert( pEntry->nWID );
2030 if (pEntry->nWID < RES_PARATR_BEGIN)
2031 {
2032 rDoc.ResetAttrs(rPaM, true, aWhichIds);
2033 }
2034 else
2035 {
2036 lcl_SelectParaAndReset ( rPaM, rDoc, aWhichIds );
2037 }
2038 }
2039 else
2040 {
2041 SwUnoCursorHelper::resetCursorPropertyValue(*pEntry, rPaM);
2042 }
2043}
2044
2045uno::Any SwUnoCursorHelper::GetPropertyDefault(
2046 SwPaM const & rPaM, const SfxItemPropertySet& rPropSet,
2047 const OUString& rPropertyName)
2048{
2049 SfxItemPropertySimpleEntry const*const pEntry =
2050 rPropSet.getPropertyMap().getByName(rPropertyName);
2051 if (!pEntry)
2052 {
2053 throw beans::UnknownPropertyException(
2054 "Unknown property: " + rPropertyName, static_cast<cppu::OWeakObject *>(nullptr));
2055 }
2056
2057 uno::Any aRet;
2058 if (pEntry->nWID < RES_FRMATR_END)
2059 {
2060 SwDoc& rDoc = rPaM.GetDoc();
2061 const SfxPoolItem& rDefItem =
2062 rDoc.GetAttrPool().GetDefaultItem(pEntry->nWID);
2063 rDefItem.QueryValue(aRet, pEntry->nMemberId);
2064 }
2065 return aRet;
2066}
2067
2068uno::Reference< beans::XPropertySetInfo > SAL_CALL
2069SwXTextCursor::getPropertySetInfo()
2070{
2071 SolarMutexGuard g;
2072
2073 static uno::Reference< beans::XPropertySetInfo > xRef = [&]()
2074 {
2075 static SfxItemPropertyMapEntry const aCursorExtMap_Impl[] =
2076 {
2077 { u"" UNO_NAME_IS_SKIP_HIDDEN_TEXT"IsSkipHiddenText", FN_SKIP_HIDDEN_TEXT((20000 + 2200) + 72), cppu::UnoType<bool>::get(), PROPERTY_NONE0, 0},
2078 { u"" UNO_NAME_IS_SKIP_PROTECTED_TEXT"IsSkipProtectedText", FN_SKIP_PROTECTED_TEXT((20000 + 2200) + 73), cppu::UnoType<bool>::get(), PROPERTY_NONE0, 0},
2079 { u"", 0, css::uno::Type(), 0, 0 }
2080 };
2081 const uno::Reference< beans::XPropertySetInfo > xInfo =
2082 m_pImpl->m_rPropSet.getPropertySetInfo();
2083 // extend PropertySetInfo!
2084 const uno::Sequence<beans::Property> aPropSeq = xInfo->getProperties();
2085 return new SfxExtItemPropertySetInfo(
2086 aCursorExtMap_Impl,
2087 aPropSeq );
2088 }();
2089 return xRef;
2090}
2091
2092void SAL_CALL
2093SwXTextCursor::setPropertyValue(
2094 const OUString& rPropertyName, const uno::Any& rValue)
2095{
2096 SolarMutexGuard aGuard;
2097
2098 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
2099
2100 if (rPropertyName == UNO_NAME_IS_SKIP_HIDDEN_TEXT"IsSkipHiddenText")
2101 {
2102 bool bSet(false);
2103 if (!(rValue >>= bSet))
2104 {
2105 throw lang::IllegalArgumentException();
2106 }
2107 rUnoCursor.SetSkipOverHiddenSections(bSet);
2108 }
2109 else if (rPropertyName == UNO_NAME_IS_SKIP_PROTECTED_TEXT"IsSkipProtectedText")
2110 {
2111 bool bSet(false);
2112 if (!(rValue >>= bSet))
2113 {
2114 throw lang::IllegalArgumentException();
2115 }
2116 rUnoCursor.SetSkipOverProtectSections(bSet);
2117 }
2118 else
2119 {
2120 SwUnoCursorHelper::SetPropertyValue(rUnoCursor,
2121 m_pImpl->m_rPropSet, rPropertyName, rValue);
2122 }
2123}
2124
2125uno::Any SAL_CALL
2126SwXTextCursor::getPropertyValue(const OUString& rPropertyName)
2127{
2128 SolarMutexGuard aGuard;
2129
2130 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
2131
2132 uno::Any aAny;
2133 if (rPropertyName == UNO_NAME_IS_SKIP_HIDDEN_TEXT"IsSkipHiddenText")
2134 {
2135 const bool bSet = rUnoCursor.IsSkipOverHiddenSections();
2136 aAny <<= bSet;
2137 }
2138 else if (rPropertyName == UNO_NAME_IS_SKIP_PROTECTED_TEXT"IsSkipProtectedText")
2139 {
2140 const bool bSet = rUnoCursor.IsSkipOverProtectSections();
2141 aAny <<= bSet;
2142 }
2143 else
2144 {
2145 aAny = SwUnoCursorHelper::GetPropertyValue(rUnoCursor,
2146 m_pImpl->m_rPropSet, rPropertyName);
2147 }
2148 return aAny;
2149}
2150
2151void SAL_CALL
2152SwXTextCursor::addPropertyChangeListener(
2153 const OUString& /*rPropertyName*/,
2154 const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/)
2155{
2156 OSL_FAIL("SwXTextCursor::addPropertyChangeListener(): not implemented")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/unocore/unoobj.cxx"
":" "2156" ": "), "%s", "SwXTextCursor::addPropertyChangeListener(): not implemented"
); } } while (false)
;
2157}
2158
2159void SAL_CALL
2160SwXTextCursor::removePropertyChangeListener(
2161 const OUString& /*rPropertyName*/,
2162 const uno::Reference< beans::XPropertyChangeListener >& /*xListener*/)
2163{
2164 OSL_FAIL("SwXTextCursor::removePropertyChangeListener(): not implemented")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/unocore/unoobj.cxx"
":" "2164" ": "), "%s", "SwXTextCursor::removePropertyChangeListener(): not implemented"
); } } while (false)
;
2165}
2166
2167void SAL_CALL
2168SwXTextCursor::addVetoableChangeListener(
2169 const OUString& /*rPropertyName*/,
2170 const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/)
2171{
2172 OSL_FAIL("SwXTextCursor::addVetoableChangeListener(): not implemented")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/unocore/unoobj.cxx"
":" "2172" ": "), "%s", "SwXTextCursor::addVetoableChangeListener(): not implemented"
); } } while (false)
;
2173}
2174
2175void SAL_CALL
2176SwXTextCursor::removeVetoableChangeListener(
2177 const OUString& /*rPropertyName*/,
2178 const uno::Reference< beans::XVetoableChangeListener >& /*xListener*/)
2179{
2180 OSL_FAIL("SwXTextCursor::removeVetoableChangeListener(): not implemented")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/unocore/unoobj.cxx"
":" "2180" ": "), "%s", "SwXTextCursor::removeVetoableChangeListener(): not implemented"
); } } while (false)
;
2181}
2182
2183beans::PropertyState SAL_CALL
2184SwXTextCursor::getPropertyState(const OUString& rPropertyName)
2185{
2186 SolarMutexGuard aGuard;
2187
2188 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
2189
2190 const beans::PropertyState eRet = SwUnoCursorHelper::GetPropertyState(
2191 rUnoCursor, m_pImpl->m_rPropSet, rPropertyName);
2192 return eRet;
2193}
2194
2195uno::Sequence< beans::PropertyState > SAL_CALL
2196SwXTextCursor::getPropertyStates(
2197 const uno::Sequence< OUString >& rPropertyNames)
2198{
2199 SolarMutexGuard aGuard;
2200
2201 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
2202
2203 return SwUnoCursorHelper::GetPropertyStates(
2204 rUnoCursor, m_pImpl->m_rPropSet, rPropertyNames);
2205}
2206
2207void SAL_CALL
2208SwXTextCursor::setPropertyToDefault(const OUString& rPropertyName)
2209{
2210 // forward: need no solar mutex here
2211 uno::Sequence < OUString > aSequence ( &rPropertyName, 1 );
2212 setPropertiesToDefault ( aSequence );
2213}
2214
2215uno::Any SAL_CALL
2216SwXTextCursor::getPropertyDefault(const OUString& rPropertyName)
2217{
2218 // forward: need no solar mutex here
2219 const uno::Sequence < OUString > aSequence ( &rPropertyName, 1 );
2220 return getPropertyDefaults ( aSequence ).getConstArray()[0];
2221}
2222
2223void SAL_CALL SwXTextCursor::setPropertyValues(
2224 const uno::Sequence< OUString >& aPropertyNames,
2225 const uno::Sequence< uno::Any >& aValues )
2226{
2227 if( aValues.getLength() != aPropertyNames.getLength() )
2228 {
2229 OSL_FAIL( "mis-matched property value sequences" )do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/unocore/unoobj.cxx"
":" "2229" ": "), "%s", "mis-matched property value sequences"
); } } while (false)
;
2230 throw lang::IllegalArgumentException();
2231 }
2232
2233 SolarMutexGuard aGuard;
2234
2235 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
2236
2237 // a little lame to have to copy into this.
2238 uno::Sequence< beans::PropertyValue > aPropertyValues( aValues.getLength() );
2239 for ( sal_Int32 i = 0; i < aPropertyNames.getLength(); i++ )
2240 {
2241 if ( aPropertyNames[ i ] == UNO_NAME_IS_SKIP_HIDDEN_TEXT"IsSkipHiddenText" ||
2242 aPropertyNames[ i ] == UNO_NAME_IS_SKIP_PROTECTED_TEXT"IsSkipProtectedText" )
2243 {
2244 // the behaviour of these is hard to model in a group
2245 OSL_FAIL("invalid property name for batch setting")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/unocore/unoobj.cxx"
":" "2245" ": "), "%s", "invalid property name for batch setting"
); } } while (false)
;
2246 throw lang::IllegalArgumentException();
2247 }
2248 aPropertyValues[ i ].Name = aPropertyNames[ i ];
2249 aPropertyValues[ i ].Value = aValues[ i ];
2250 }
2251 try
2252 {
2253 SwUnoCursorHelper::SetPropertyValues( rUnoCursor, m_pImpl->m_rPropSet, aPropertyValues );
2254 }
2255 catch (const css::beans::UnknownPropertyException& e)
2256 {
2257 uno::Any a(cppu::getCaughtException());
2258 throw lang::WrappedTargetException(
2259 "wrapped Exception " + e.Message,
2260 uno::Reference<uno::XInterface>(), a);
2261 }
2262}
2263
2264uno::Sequence< uno::Any > SAL_CALL
2265SwXTextCursor::getPropertyValues( const uno::Sequence< OUString >& aPropertyNames )
2266{
2267 // a banal implementation for now
2268 uno::Sequence< uno::Any > aValues( aPropertyNames.getLength() );
2269 std::transform(aPropertyNames.begin(), aPropertyNames.end(), aValues.begin(),
2270 [this](const OUString& rName) -> uno::Any { return getPropertyValue( rName ); });
2271 return aValues;
2272}
2273
2274void SAL_CALL SwXTextCursor::addPropertiesChangeListener(
2275 const uno::Sequence< OUString >& /* aPropertyNames */,
2276 const uno::Reference< css::beans::XPropertiesChangeListener >& /* xListener */ )
2277{
2278 OSL_FAIL("SwXTextCursor::addPropertiesChangeListener(): not implemented")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/unocore/unoobj.cxx"
":" "2278" ": "), "%s", "SwXTextCursor::addPropertiesChangeListener(): not implemented"
); } } while (false)
;
2279}
2280void SAL_CALL SwXTextCursor::removePropertiesChangeListener(
2281 const uno::Reference< css::beans::XPropertiesChangeListener >& /* xListener */ )
2282{
2283 OSL_FAIL("SwXTextCursor::removePropertiesChangeListener(): not implemented")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/unocore/unoobj.cxx"
":" "2283" ": "), "%s", "SwXTextCursor::removePropertiesChangeListener(): not implemented"
); } } while (false)
;
2284}
2285
2286void SAL_CALL SwXTextCursor::firePropertiesChangeEvent(
2287 const uno::Sequence< OUString >& /* aPropertyNames */,
2288 const uno::Reference< css::beans::XPropertiesChangeListener >& /* xListener */ )
2289{
2290 OSL_FAIL("SwXTextCursor::firePropertiesChangeEvent(): not implemented")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/unocore/unoobj.cxx"
":" "2290" ": "), "%s", "SwXTextCursor::firePropertiesChangeEvent(): not implemented"
); } } while (false)
;
2291}
2292
2293// para specific attribute ranges
2294static sal_uInt16 g_ParaResetableSetRange[] = {
2295 RES_FRMATR_BEGIN, RES_FRMATR_END-1,
2296 RES_PARATR_BEGIN, RES_PARATR_END-1,
2297 RES_PARATR_LIST_BEGIN, RES_PARATR_LIST_END-1,
2298 RES_UNKNOWNATR_BEGIN, RES_UNKNOWNATR_END-1,
2299 0
2300};
2301
2302// selection specific attribute ranges
2303static sal_uInt16 g_ResetableSetRange[] = {
2304 RES_CHRATR_BEGIN, RES_CHRATR_END-1,
2305 RES_TXTATR_INETFMT, RES_TXTATR_INETFMT,
2306 RES_TXTATR_CHARFMT, RES_TXTATR_CHARFMT,
2307 RES_TXTATR_CJK_RUBY, RES_TXTATR_CJK_RUBY,
2308 RES_TXTATR_UNKNOWN_CONTAINER, RES_TXTATR_UNKNOWN_CONTAINER,
2309 0
2310};
2311
2312static void
2313lcl_EnumerateIds(sal_uInt16 const* pIdRange, std::set<sal_uInt16> &rWhichIds)
2314{
2315 while (*pIdRange)
2316 {
2317 const sal_uInt16 nStart = *pIdRange++;
2318 const sal_uInt16 nEnd = *pIdRange++;
2319 for (sal_uInt16 nId = nStart + 1; nId <= nEnd; ++nId)
2320 {
2321 rWhichIds.insert( rWhichIds.end(), nId );
2322 }
2323 }
2324}
2325
2326void SAL_CALL
2327SwXTextCursor::setAllPropertiesToDefault()
2328{
2329 SolarMutexGuard aGuard;
2330
2331 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
2332
2333 std::set<sal_uInt16> aParaWhichIds;
2334 std::set<sal_uInt16> aWhichIds;
2335 lcl_EnumerateIds(g_ParaResetableSetRange, aParaWhichIds);
2336 lcl_EnumerateIds(g_ResetableSetRange, aWhichIds);
2337 if (!aParaWhichIds.empty())
2338 {
2339 lcl_SelectParaAndReset(rUnoCursor, rUnoCursor.GetDoc(),
2340 aParaWhichIds);
2341 }
2342 if (!aWhichIds.empty())
2343 {
2344 rUnoCursor.GetDoc().ResetAttrs(rUnoCursor, true, aWhichIds);
2345 }
2346}
2347
2348void SAL_CALL
2349SwXTextCursor::setPropertiesToDefault(
2350 const uno::Sequence< OUString >& rPropertyNames)
2351{
2352 SolarMutexGuard aGuard;
2353
2354 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
2355
2356 if ( !rPropertyNames.hasElements() )
2357 return;
2358
2359 SwDoc& rDoc = rUnoCursor.GetDoc();
2360 std::set<sal_uInt16> aWhichIds;
2361 std::set<sal_uInt16> aParaWhichIds;
2362 for (const OUString& rName : rPropertyNames)
2363 {
2364 SfxItemPropertySimpleEntry const*const pEntry =
2365 m_pImpl->m_rPropSet.getPropertyMap().getByName( rName );
2366 if (!pEntry)
2367 {
2368 if (rName == UNO_NAME_IS_SKIP_HIDDEN_TEXT"IsSkipHiddenText" ||
2369 rName == UNO_NAME_IS_SKIP_PROTECTED_TEXT"IsSkipProtectedText")
2370 {
2371 continue;
2372 }
2373 throw beans::UnknownPropertyException(
2374 "Unknown property: " + rName,
2375 static_cast<cppu::OWeakObject *>(this));
2376 }
2377 if (pEntry->nFlags & beans::PropertyAttribute::READONLY)
2378 {
2379 throw uno::RuntimeException(
2380 "setPropertiesToDefault: property is read-only: " + rName,
2381 static_cast<cppu::OWeakObject *>(this));
2382 }
2383
2384 if (pEntry->nWID < RES_FRMATR_END)
2385 {
2386 if (pEntry->nWID < RES_PARATR_BEGIN)
2387 {
2388 aWhichIds.insert( pEntry->nWID );
2389 }
2390 else
2391 {
2392 aParaWhichIds.insert( pEntry->nWID );
2393 }
2394 }
2395 else if (pEntry->nWID == FN_UNO_NUM_START_VALUE((20000 + 2200) + 13))
2396 {
2397 SwUnoCursorHelper::resetCursorPropertyValue(*pEntry, rUnoCursor);
2398 }
2399 }
2400
2401 if (!aParaWhichIds.empty())
2402 {
2403 lcl_SelectParaAndReset(rUnoCursor, rDoc, aParaWhichIds);
2404 }
2405 if (!aWhichIds.empty())
2406 {
2407 rDoc.ResetAttrs(rUnoCursor, true, aWhichIds);
2408 }
2409}
2410
2411uno::Sequence< uno::Any > SAL_CALL
2412SwXTextCursor::getPropertyDefaults(
2413 const uno::Sequence< OUString >& rPropertyNames)
2414{
2415 SolarMutexGuard aGuard;
2416
2417 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
2418
2419 const sal_Int32 nCount = rPropertyNames.getLength();
2420 uno::Sequence< uno::Any > aRet(nCount);
2421 if ( nCount )
2422 {
2423 SwDoc& rDoc = rUnoCursor.GetDoc();
2424 const OUString *pNames = rPropertyNames.getConstArray();
2425 uno::Any *pAny = aRet.getArray();
2426 for (sal_Int32 i = 0; i < nCount; i++)
2427 {
2428 SfxItemPropertySimpleEntry const*const pEntry =
2429 m_pImpl->m_rPropSet.getPropertyMap().getByName( pNames[i] );
2430 if (!pEntry)
2431 {
2432 if (pNames[i] == UNO_NAME_IS_SKIP_HIDDEN_TEXT"IsSkipHiddenText" ||
2433 pNames[i] == UNO_NAME_IS_SKIP_PROTECTED_TEXT"IsSkipProtectedText")
2434 {
2435 continue;
2436 }
2437 throw beans::UnknownPropertyException(
2438 "Unknown property: " + pNames[i],
2439 static_cast<cppu::OWeakObject *>(nullptr));
2440 }
2441 if (pEntry->nWID < RES_FRMATR_END)
2442 {
2443 const SfxPoolItem& rDefItem =
2444 rDoc.GetAttrPool().GetDefaultItem(pEntry->nWID);
2445 rDefItem.QueryValue(pAny[i], pEntry->nMemberId);
2446 }
2447 }
2448 }
2449 return aRet;
2450}
2451
2452void SAL_CALL SwXTextCursor::invalidateMarkings(::sal_Int32 nType)
2453{
2454 SolarMutexGuard aGuard;
2455
2456 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
2457
2458 SwNode& node = rUnoCursor.GetNode();
2459
2460 SwTextNode* txtNode = node.GetTextNode();
2461
2462 if (txtNode == nullptr) return;
2463
2464 if ( text::TextMarkupType::SPELLCHECK == nType )
2465 {
2466 txtNode->SetWrongDirty(SwTextNode::WrongState::TODO);
2467 txtNode->SetWrong(nullptr);
2468 }
2469 else if( text::TextMarkupType::PROOFREADING == nType )
2470 {
2471 txtNode->SetGrammarCheckDirty(true);
2472 txtNode->SetGrammarCheck(nullptr);
2473 }
2474 else if ( text::TextMarkupType::SMARTTAG == nType )
2475 {
2476 txtNode->SetSmartTagDirty(true);
2477 txtNode->SetSmartTags(nullptr);
2478 }
2479 else return;
2480
2481 SwFormatColl* fmtColl=txtNode->GetFormatColl();
2482
2483 if (fmtColl == nullptr) return;
2484
2485 SwFormatChg aNew( fmtColl );
2486 txtNode->NotifyClients( nullptr, &aNew );
2487}
2488
2489void SAL_CALL
2490SwXTextCursor::makeRedline(
2491 const OUString& rRedlineType,
2492 const uno::Sequence< beans::PropertyValue >& rRedlineProperties)
2493{
2494 SolarMutexGuard aGuard;
2495
2496 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
2497
2498 SwUnoCursorHelper::makeRedline(rUnoCursor, rRedlineType, rRedlineProperties);
2499}
2500
2501void SAL_CALL SwXTextCursor::insertDocumentFromURL(const OUString& rURL,
2502 const uno::Sequence< beans::PropertyValue >& rOptions)
2503{
2504 SolarMutexGuard aGuard;
2505
2506 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
2507
2508 SwUnoCursorHelper::InsertFile(&rUnoCursor, rURL, rOptions);
2509}
2510
2511uno::Sequence< beans::PropertyValue >
2512SwUnoCursorHelper::CreateSortDescriptor(const bool bFromTable)
2513{
2514 uno::Sequence< beans::PropertyValue > aRet(5);
2515 beans::PropertyValue* pArray = aRet.getArray();
2516
2517 uno::Any aVal;
2518 aVal <<= bFromTable;
2519 pArray[0] = beans::PropertyValue("IsSortInTable", -1, aVal,
2520 beans::PropertyState_DIRECT_VALUE);
2521
2522 aVal <<= u' ';
2523 pArray[1] = beans::PropertyValue("Delimiter", -1, aVal,
2524 beans::PropertyState_DIRECT_VALUE);
2525
2526 aVal <<= false;
2527 pArray[2] = beans::PropertyValue("IsSortColumns", -1, aVal,
2528 beans::PropertyState_DIRECT_VALUE);
2529
2530 aVal <<= sal_Int32(3);
2531 pArray[3] = beans::PropertyValue("MaxSortFieldsCount", -1, aVal,
2532 beans::PropertyState_DIRECT_VALUE);
2533
2534 uno::Sequence< table::TableSortField > aFields(3);
2535 table::TableSortField* pFields = aFields.getArray();
2536
2537 lang::Locale aLang( SvtSysLocale().GetLanguageTag().getLocale());
2538 // get collator algorithm to be used for the locale
2539 uno::Sequence< OUString > aSeq(
2540 GetAppCollator().listCollatorAlgorithms( aLang ) );
2541 const bool bHasElements = aSeq.hasElements();
2542 OSL_ENSURE( bHasElements, "list of collator algorithms is empty!")do { if (true && (!(bHasElements))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/unocore/unoobj.cxx"
":" "2542" ": "), "%s", "list of collator algorithms is empty!"
); } } while (false)
;
2543 OUString aCollAlg;
2544 if (bHasElements)
2545 {
2546 aCollAlg = aSeq.getConstArray()[0];
2547 }
2548
2549 pFields[0].Field = 1;
2550 pFields[0].IsAscending = true;
2551 pFields[0].IsCaseSensitive = false;
2552 pFields[0].FieldType = table::TableSortFieldType_ALPHANUMERIC;
2553 pFields[0].CollatorLocale = aLang;
2554 pFields[0].CollatorAlgorithm = aCollAlg;
2555
2556 pFields[1].Field = 1;
2557 pFields[1].IsAscending = true;
2558 pFields[1].IsCaseSensitive = false;
2559 pFields[1].FieldType = table::TableSortFieldType_ALPHANUMERIC;
2560 pFields[1].CollatorLocale = aLang;
2561 pFields[1].CollatorAlgorithm = aCollAlg;
2562
2563 pFields[2].Field = 1;
2564 pFields[2].IsAscending = true;
2565 pFields[2].IsCaseSensitive = false;
2566 pFields[2].FieldType = table::TableSortFieldType_ALPHANUMERIC;
2567 pFields[2].CollatorLocale = aLang;
2568 pFields[2].CollatorAlgorithm = aCollAlg;
2569
2570 aVal <<= aFields;
2571 pArray[4] = beans::PropertyValue("SortFields", -1, aVal,
2572 beans::PropertyState_DIRECT_VALUE);
2573
2574 return aRet;
2575}
2576
2577uno::Sequence< beans::PropertyValue > SAL_CALL
2578SwXTextCursor::createSortDescriptor()
2579{
2580 SolarMutexGuard aGuard;
2581
2582 return SwUnoCursorHelper::CreateSortDescriptor(false);
2583}
2584
2585bool SwUnoCursorHelper::ConvertSortProperties(
2586 const uno::Sequence< beans::PropertyValue >& rDescriptor,
2587 SwSortOptions& rSortOpt)
2588{
2589 bool bRet = true;
2590
2591 rSortOpt.bTable = false;
2592 rSortOpt.cDeli = ' ';
2593 rSortOpt.eDirection = SwSortDirection::Columns; //!! UI text may be contrary though !!
2594
2595 std::unique_ptr<SwSortKey> pKey1(new SwSortKey);
2596 pKey1->nColumnId = USHRT_MAX(32767 *2 +1);
2597 pKey1->bIsNumeric = true;
2598 pKey1->eSortOrder = SwSortOrder::Ascending;
2599
2600 std::unique_ptr<SwSortKey> pKey2(new SwSortKey);
2601 pKey2->nColumnId = USHRT_MAX(32767 *2 +1);
2602 pKey2->bIsNumeric = true;
2603 pKey2->eSortOrder = SwSortOrder::Ascending;
2604
2605 std::unique_ptr<SwSortKey> pKey3(new SwSortKey);
2606 pKey3->nColumnId = USHRT_MAX(32767 *2 +1);
2607 pKey3->bIsNumeric = true;
2608 pKey3->eSortOrder = SwSortOrder::Ascending;
2609 SwSortKey* aKeys[3] = {pKey1.get(), pKey2.get(), pKey3.get()};
2610
2611 bool bOldSortdescriptor(false);
2612 bool bNewSortdescriptor(false);
2613
2614 for (const beans::PropertyValue& rProperty : rDescriptor)
2615 {
2616 uno::Any aValue( rProperty.Value );
2617 const OUString& rPropName = rProperty.Name;
2618
2619 // old and new sortdescriptor
2620 if ( rPropName == "IsSortInTable" )
2621 {
2622 if (auto b = o3tl::tryAccess<bool>(aValue))
2623 {
2624 rSortOpt.bTable = *b;
2625 }
2626 else
2627 {
2628 bRet = false;
2629 }
2630 }
2631 else if ( rPropName == "Delimiter" )
2632 {
2633 sal_Unicode uChar;
2634 sal_uInt16 nChar;
2635 if (aValue >>= uChar)
2636 {
2637 rSortOpt.cDeli = uChar;
2638 }
2639 else if (aValue >>= nChar)
2640 {
2641 // For compatibility with BASIC, also accept an ANY containing
2642 // an UNSIGNED SHORT:
2643 rSortOpt.cDeli = nChar;
2644 }
2645 else
2646 {
2647 bRet = false;
2648 }
2649 }
2650 // old sortdescriptor
2651 else if ( rPropName == "SortColumns" )
2652 {
2653 bOldSortdescriptor = true;
2654 bool bTemp(false);
2655 if (aValue >>= bTemp)
2656 {
2657 rSortOpt.eDirection = bTemp ? SwSortDirection::Columns : SwSortDirection::Rows;
2658 }
2659 else
2660 {
2661 bRet = false;
2662 }
2663 }
2664 else if ( rPropName == "IsCaseSensitive" )
2665 {
2666 bOldSortdescriptor = true;
2667 bool bTemp(false);
2668 if (aValue >>= bTemp)
2669 {
2670 rSortOpt.bIgnoreCase = !bTemp;
2671 }
2672 else
2673 {
2674 bRet = false;
2675 }
2676 }
2677 else if ( rPropName == "CollatorLocale" )
2678 {
2679 bOldSortdescriptor = true;
2680 lang::Locale aLocale;
2681 if (aValue >>= aLocale)
2682 {
2683 rSortOpt.nLanguage = LanguageTag::convertToLanguageType( aLocale);
2684 }
2685 else
2686 {
2687 bRet = false;
2688 }
2689 }
2690 else if (rPropName.startsWith("CollatorAlgorithm") &&
2691 rPropName.getLength() == 18 &&
2692 (rPropName[17] >= '0' && rPropName[17] <= '9'))
2693 {
2694 bOldSortdescriptor = true;
2695 sal_uInt16 nIndex = rPropName[17];
2696 nIndex -= '0';
2697 OUString aText;
2698 if ((aValue >>= aText) && nIndex < 3)
2699 {
2700 aKeys[nIndex]->sSortType = aText;
2701 }
2702 else
2703 {
2704 bRet = false;
2705 }
2706 }
2707 else if (rPropName.startsWith("SortRowOrColumnNo") &&
2708 rPropName.getLength() == 18 &&
2709 (rPropName[17] >= '0' && rPropName[17] <= '9'))
2710 {
2711 bOldSortdescriptor = true;
2712 sal_uInt16 nIndex = rPropName[17];
2713 nIndex -= '0';
2714 sal_Int16 nCol = -1;
2715 if (aValue.getValueType() == ::cppu::UnoType<sal_Int16>::get()
2716 && nIndex < 3)
2717 {
2718 aValue >>= nCol;
2719 }
2720 if (nCol >= 0)
2721 {
2722 aKeys[nIndex]->nColumnId = nCol;
2723 }
2724 else
2725 {
2726 bRet = false;
2727 }
2728 }
2729 else if (rPropName.startsWith("IsSortNumeric") &&
2730 rPropName.getLength() == 14 &&
2731 (rPropName[13] >= '0' && rPropName[13] <= '9'))
2732 {
2733 bOldSortdescriptor = true;
2734 sal_uInt16 nIndex = rPropName[13];
2735 nIndex = nIndex - '0';
2736 auto bTemp = o3tl::tryAccess<bool>(aValue);
2737 if (bTemp && nIndex < 3)
2738 {
2739 aKeys[nIndex]->bIsNumeric = *bTemp;
2740 }
2741 else
2742 {
2743 bRet = false;
2744 }
2745 }
2746 else if (rPropName.startsWith("IsSortAscending") &&
2747 rPropName.getLength() == 16 &&
2748 (rPropName[15] >= '0' && rPropName[15] <= '9'))
2749 {
2750 bOldSortdescriptor = true;
2751 sal_uInt16 nIndex = rPropName[15];
2752 nIndex -= '0';
2753 auto bTemp = o3tl::tryAccess<bool>(aValue);
2754 if (bTemp && nIndex < 3)
2755 {
2756 aKeys[nIndex]->eSortOrder = (*bTemp)
2757 ? SwSortOrder::Ascending : SwSortOrder::Descending;
2758 }
2759 else
2760 {
2761 bRet = false;
2762 }
2763 }
2764 // new sortdescriptor
2765 else if ( rPropName == "IsSortColumns" )
2766 {
2767 bNewSortdescriptor = true;
2768 if (auto bTemp = o3tl::tryAccess<bool>(aValue))
2769 {
2770 rSortOpt.eDirection = *bTemp ? SwSortDirection::Columns : SwSortDirection::Rows;
2771 }
2772 else
2773 {
2774 bRet = false;
2775 }
2776 }
2777 else if ( rPropName == "SortFields" )
2778 {
2779 bNewSortdescriptor = true;
2780 uno::Sequence < table::TableSortField > aFields;
2781 if (aValue >>= aFields)
2782 {
2783 sal_Int32 nCount(aFields.getLength());
2784 if (nCount <= 3)
2785 {
2786 table::TableSortField* pFields = aFields.getArray();
2787 for (sal_Int32 i = 0; i < nCount; ++i)
2788 {
2789 rSortOpt.bIgnoreCase = !pFields[i].IsCaseSensitive;
2790 rSortOpt.nLanguage =
2791 LanguageTag::convertToLanguageType( pFields[i].CollatorLocale );
2792 aKeys[i]->sSortType = pFields[i].CollatorAlgorithm;
2793 aKeys[i]->nColumnId =
2794 static_cast<sal_uInt16>(pFields[i].Field);
2795 aKeys[i]->bIsNumeric = (pFields[i].FieldType ==
2796 table::TableSortFieldType_NUMERIC);
2797 aKeys[i]->eSortOrder = (pFields[i].IsAscending)
2798 ? SwSortOrder::Ascending : SwSortOrder::Descending;
2799 }
2800 }
2801 else
2802 {
2803 bRet = false;
2804 }
2805 }
2806 else
2807 {
2808 bRet = false;
2809 }
2810 }
2811 }
2812
2813 if (bNewSortdescriptor && bOldSortdescriptor)
2814 {
2815 OSL_FAIL("someone tried to set the old deprecated and "do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/unocore/unoobj.cxx"
":" "2816" ": "), "%s", "someone tried to set the old deprecated and "
"the new sortdescriptor"); } } while (false)
2816 "the new sortdescriptor")do { if (true && (((sal_Bool)1))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/unocore/unoobj.cxx"
":" "2816" ": "), "%s", "someone tried to set the old deprecated and "
"the new sortdescriptor"); } } while (false)
;
2817 bRet = false;
2818 }
2819
2820 if (pKey1->nColumnId != USHRT_MAX(32767 *2 +1))
2821 {
2822 rSortOpt.aKeys.push_back(std::move(pKey1));
2823 }
2824 if (pKey2->nColumnId != USHRT_MAX(32767 *2 +1))
2825 {
2826 rSortOpt.aKeys.push_back(std::move(pKey2));
2827 }
2828 if (pKey3->nColumnId != USHRT_MAX(32767 *2 +1))
2829 {
2830 rSortOpt.aKeys.push_back(std::move(pKey3));
2831 }
2832
2833 return bRet && !rSortOpt.aKeys.empty();
2834}
2835
2836void SAL_CALL
2837SwXTextCursor::sort(const uno::Sequence< beans::PropertyValue >& rDescriptor)
2838{
2839 SolarMutexGuard aGuard;
2840
2841 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
2842
2843 if (!rUnoCursor.HasMark())
2844 return;
2845
2846 SwSortOptions aSortOpt;
2847 if (!SwUnoCursorHelper::ConvertSortProperties(rDescriptor, aSortOpt))
2848 {
2849 throw uno::RuntimeException("Bad sort properties");
2850 }
2851 UnoActionContext aContext( &rUnoCursor.GetDoc() );
2852
2853 SwPosition & rStart = *rUnoCursor.Start();
2854 SwPosition & rEnd = *rUnoCursor.End();
2855
2856 SwNodeIndex aPrevIdx( rStart.nNode, -1 );
2857 const sal_uLong nOffset = rEnd.nNode.GetIndex() - rStart.nNode.GetIndex();
2858 const sal_Int32 nCntStt = rStart.nContent.GetIndex();
2859
2860 rUnoCursor.GetDoc().SortText(rUnoCursor, aSortOpt);
2861
2862 // update selection
2863 rUnoCursor.DeleteMark();
2864 rUnoCursor.GetPoint()->nNode.Assign( aPrevIdx.GetNode(), +1 );
2865 SwContentNode *const pCNd = rUnoCursor.GetContentNode();
2866 sal_Int32 nLen = pCNd->Len();
2867 if (nLen > nCntStt)
2868 {
2869 nLen = nCntStt;
2870 }
2871 rUnoCursor.GetPoint()->nContent.Assign(pCNd, nLen );
2872 rUnoCursor.SetMark();
2873
2874 rUnoCursor.GetPoint()->nNode += nOffset;
2875 SwContentNode *const pCNd2 = rUnoCursor.GetContentNode();
2876 rUnoCursor.GetPoint()->nContent.Assign( pCNd2, pCNd2->Len() );
2877
2878}
2879
2880uno::Reference< container::XEnumeration > SAL_CALL
2881SwXTextCursor::createContentEnumeration(const OUString& rServiceName)
2882{
2883 SolarMutexGuard g;
2884 if (rServiceName != "com.sun.star.text.TextContent")
2885 throw uno::RuntimeException();
2886 SwUnoCursor& rUnoCursor( m_pImpl->GetCursorOrThrow() );
2887 return SwXParaFrameEnumeration::Create(rUnoCursor, PARAFRAME_PORTION_TEXTRANGE);
2888}
2889
2890uno::Reference< container::XEnumeration > SAL_CALL
2891SwXTextCursor::createEnumeration()
2892{
2893 SolarMutexGuard g;
2894
2895 SwUnoCursor & rUnoCursor( m_pImpl->GetCursorOrThrow() );
2896
2897 SwXText* pParentText = comphelper::getUnoTunnelImplementation<SwXText>(m_pImpl->m_xParentText);
2898 OSL_ENSURE(pParentText, "parent is not a SwXText")do { if (true && (!(pParentText))) { sal_detail_logFormat
((SAL_DETAIL_LOG_LEVEL_WARN), ("legacy.osl"), ("/home/maarten/src/libreoffice/core/sw/source/core/unocore/unoobj.cxx"
":" "2898" ": "), "%s", "parent is not a SwXText"); } } while
(false)
;
2899 if (!pParentText)
2900 {
2901 throw uno::RuntimeException();
2902 }
2903
2904 auto pNewCursor(rUnoCursor.GetDoc().CreateUnoCursor(*rUnoCursor.GetPoint()) );
2905 if (rUnoCursor.HasMark())
2906 {
2907 pNewCursor->SetMark();
2908 *pNewCursor->GetMark() = *rUnoCursor.GetMark();
2909 }
2910 const CursorType eSetType = (CursorType::TableText == m_pImpl->m_eType)
2911 ? CursorType::SelectionInTable : CursorType::Selection;
2912 SwTableNode const*const pStartNode( (CursorType::TableText == m_pImpl->m_eType)
2913 ? rUnoCursor.GetPoint()->nNode.GetNode().FindTableNode()
2914 : nullptr);
2915 SwTable const*const pTable(
2916 pStartNode ? & pStartNode->GetTable() : nullptr );
2917 return SwXParagraphEnumeration::Create(pParentText, pNewCursor, eSetType, pStartNode, pTable);
2918}
2919
2920uno::Type SAL_CALL
2921SwXTextCursor::getElementType()
2922{
2923 return cppu::UnoType<text::XTextRange>::get();
2924}
2925
2926sal_Bool SAL_CALL SwXTextCursor::hasElements()
2927{
2928 return true;
2929}
2930
2931uno::Sequence< OUString > SAL_CALL
2932SwXTextCursor::getAvailableServiceNames()
2933{
2934 uno::Sequence<OUString> aRet { "com.sun.star.text.TextContent" };
2935 return aRet;
2936}
2937
2938IMPLEMENT_FORWARD_REFCOUNT( SwXTextCursor,SwXTextCursor_Base )void SwXTextCursor::acquire() throw() { SwXTextCursor_Base::acquire
(); } void SwXTextCursor::release() throw() { SwXTextCursor_Base
::release(); }
2939
2940uno::Any SAL_CALL
2941SwXTextCursor::queryInterface(const uno::Type& rType)
2942{
2943 return (rType == cppu::UnoType<lang::XUnoTunnel>::get())
2944 ? OTextCursorHelper::queryInterface(rType)
2945 : SwXTextCursor_Base::queryInterface(rType);
2946}
2947
2948/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/sw/inc/pam.hxx

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19#ifndef INCLUDED_SW_INC_PAM_HXX
20#define INCLUDED_SW_INC_PAM_HXX
21
22#include <sal/types.h>
23#include "ring.hxx"
24#include "index.hxx"
25#include "ndindex.hxx"
26#include "swdllapi.h"
27
28#include <iostream>
29
30class SwDoc;
31class SwPaM;
32class Point;
33
34/// Marks a position in the document model.
35struct SAL_WARN_UNUSED__attribute__((warn_unused)) SW_DLLPUBLIC__attribute__ ((visibility("default"))) SwPosition
36{
37 SwNodeIndex nNode;
38 SwIndex nContent;
39
40 SwPosition( const SwNodeIndex &rNode, const SwIndex &rContent );
41 explicit SwPosition( const SwNodeIndex &rNode );
42 explicit SwPosition( const SwNode& rNode );
43 explicit SwPosition( SwContentNode& rNode, const sal_Int32 nOffset = 0 );
44
45 /**
46 Returns the document this position is in.
47
48 @return the document this position is in.
49 */
50 SwDoc& GetDoc() const;
51
52 bool operator < (const SwPosition &) const;
53 bool operator > (const SwPosition &) const;
54 bool operator <=(const SwPosition &) const;
55 bool operator >=(const SwPosition &) const;
56 bool operator ==(const SwPosition &) const;
57 bool operator !=(const SwPosition &) const;
58 void dumpAsXml(xmlTextWriterPtr pWriter) const;
59};
60
61SW_DLLPUBLIC__attribute__ ((visibility("default"))) std::ostream &operator <<(std::ostream& s, const SwPosition& position);
62
63// Result of comparing positions.
64enum class SwComparePosition {
65 Before, ///< Pos1 before Pos2.
66 Behind, ///< Pos1 behind Pos2.
67 Inside, ///< Pos1 completely contained in Pos2.
68 Outside, ///< Pos2 completely contained in Pos1.
69 Equal, ///< Pos1 is as large as Pos2.
70 OverlapBefore, ///< Pos1 overlaps Pos2 at the beginning.
71 OverlapBehind, ///< Pos1 overlaps Pos2 at the end.
72 CollideStart, ///< Pos1 start touches at Pos2 end.
73 CollideEnd ///< Pos1 end touches at Pos2 start.
74};
75
76template<typename T>
77SwComparePosition ComparePosition(
78 const T& rStt1, const T& rEnd1,
79 const T& rStt2, const T& rEnd2 )
80{
81 SwComparePosition nRet;
82 if( rStt1 < rStt2 )
83 {
84 if( rEnd1 > rStt2 )
85 {
86 if( rEnd1 >= rEnd2 )
87 nRet = SwComparePosition::Outside;
88 else
89 nRet = SwComparePosition::OverlapBefore;
90
91 }
92 else if( rEnd1 == rStt2 )
93 nRet = SwComparePosition::CollideEnd;
94 else
95 nRet = SwComparePosition::Before;
96 }
97 else if( rEnd2 > rStt1 )
98 {
99 if( rEnd2 >= rEnd1 )
100 {
101 if( rEnd2 == rEnd1 && rStt2 == rStt1 )
102 nRet = SwComparePosition::Equal;
103 else
104 nRet = SwComparePosition::Inside;
105 }
106 else
107 {
108 if (rStt1 == rStt2)
109 nRet = SwComparePosition::Outside;
110 else
111 nRet = SwComparePosition::OverlapBehind;
112 }
113 }
114 else if( rEnd2 == rStt1 )
115 nRet = SwComparePosition::CollideStart;
116 else
117 nRet = SwComparePosition::Behind;
118 return nRet;
119}
120
121/// SwPointAndMark / SwPaM
122struct SwMoveFnCollection;
123SW_DLLPUBLIC__attribute__ ((visibility("default"))) extern SwMoveFnCollection const & fnMoveForward; ///< SwPam::Move()/Find() default argument.
124SW_DLLPUBLIC__attribute__ ((visibility("default"))) extern SwMoveFnCollection const & fnMoveBackward;
125
126using SwGoInDoc = auto (*)(SwPaM& rPam, SwMoveFnCollection const & fnMove) -> bool;
127SW_DLLPUBLIC__attribute__ ((visibility("default"))) bool GoInDoc( SwPaM&, SwMoveFnCollection const &);
128bool GoInSection( SwPaM&, SwMoveFnCollection const &);
129SW_DLLPUBLIC__attribute__ ((visibility("default"))) bool GoInNode( SwPaM&, SwMoveFnCollection const &);
130SW_DLLPUBLIC__attribute__ ((visibility("default"))) bool GoInContent( SwPaM&, SwMoveFnCollection const &);
131bool GoInContentCells( SwPaM&, SwMoveFnCollection const &);
132bool GoInContentSkipHidden( SwPaM&, SwMoveFnCollection const &);
133bool GoInContentCellsSkipHidden( SwPaM&, SwMoveFnCollection const &);
134
135/// PaM is Point and Mark: a selection of the document model.
136class SAL_WARN_UNUSED__attribute__((warn_unused)) SW_DLLPUBLIC__attribute__ ((visibility("default"))) SwPaM : public sw::Ring<SwPaM>
137{
138 SwPosition m_Bound1;
139 SwPosition m_Bound2;
140 SwPosition * m_pPoint; ///< points at either m_Bound1 or m_Bound2
141 SwPosition * m_pMark; ///< points at either m_Bound1 or m_Bound2
142 bool m_bIsInFrontOfLabel;
143
144 SwPaM(SwPaM const& rPaM) = delete;
145
146public:
147 explicit SwPaM( const SwPosition& rPos, SwPaM* pRing = nullptr );
148 SwPaM( const SwPosition& rMk, const SwPosition& rPt, SwPaM* pRing = nullptr );
149 SwPaM( const SwNodeIndex& rMk, const SwNodeIndex& rPt,
150 long nMkOffset = 0, long nPtOffset = 0, SwPaM* pRing = nullptr );
151 SwPaM( const SwNode& rMk, const SwNode& rPt,
152 long nMkOffset = 0, long nPtOffset = 0, SwPaM* pRing = nullptr );
153 SwPaM( const SwNodeIndex& rMk, sal_Int32 nMkContent,
154 const SwNodeIndex& rPt, sal_Int32 nPtContent, SwPaM* pRing = nullptr );
155 SwPaM( const SwNode& rMk, sal_Int32 nMkContent,
156 const SwNode& rPt, sal_Int32 nPtContent, SwPaM* pRing = nullptr );
157 SwPaM( const SwNode& rNd, sal_Int32 nContent = 0, SwPaM* pRing = nullptr );
158 SwPaM( const SwNodeIndex& rNd, sal_Int32 nContent = 0, SwPaM* pRing = nullptr );
159 virtual ~SwPaM() override;
160
161 /// this takes a second parameter, which indicates the Ring that
162 /// the new PaM should be part of (may be null)
163 SwPaM(SwPaM const& rPaM, SwPaM * pRing);
164 /// @@@ semantic: no copy assignment for super class Ring.
165 SwPaM& operator=( const SwPaM & );
166
167 /// Movement of cursor.
168 bool Move( SwMoveFnCollection const & fnMove = fnMoveForward,
169 SwGoInDoc fnGo = GoInContent );
170
171 bool IsInFrontOfLabel() const { return m_bIsInFrontOfLabel; }
172 void SetInFrontOfLabel_( bool bNew ) { m_bIsInFrontOfLabel = bNew; }
173
174 /// Unless this is called, the getter method of Mark will return Point.
175 virtual void SetMark();
176
177 void DeleteMark()
178 {
179 if (m_pMark != m_pPoint)
180 {
181 /** clear the mark position; this helps if mark's SwIndex is
182 registered at some node, and that node is then deleted */
183 *m_pMark = SwPosition( SwNodeIndex( GetNode().GetNodes() ) );
184 m_pMark = m_pPoint;
185 }
186 }
187#ifdef DBG_UTIL
188 void Exchange();
189
190#else
191 void Exchange()
192 {
193 if (m_pPoint != m_pMark)
194 {
195 SwPosition *pTmp = m_pPoint;
196 m_pPoint = m_pMark;
197 m_pMark = pTmp;
198 }
199 }
200#endif
201
202 /** A PaM marks a selection if Point and Mark are distinct positions.
203 @return true if the PaM spans a selection
204 */
205 bool HasMark() const { return m_pPoint != m_pMark; }
206
207 const SwPosition *GetPoint() const { return m_pPoint; }
208 SwPosition *GetPoint() { return m_pPoint; }
209 const SwPosition *GetMark() const { return m_pMark; }
210 SwPosition *GetMark() { return m_pMark; }
211
212 const SwPosition *Start() const
213 { return (*m_pPoint) <= (*m_pMark) ? m_pPoint : m_pMark; }
214 SwPosition *Start()
215 { return (*m_pPoint) <= (*m_pMark) ? m_pPoint : m_pMark; }
216
217 const SwPosition *End() const
218 { return (*m_pPoint) > (*m_pMark) ? m_pPoint : m_pMark; }
219 SwPosition *End()
220 { return (*m_pPoint) > (*m_pMark) ? m_pPoint : m_pMark; }
221
222 /// @return current Node at Point/Mark
223 SwNode & GetNode ( bool bPoint = true ) const
224 {
225 return ( bPoint ? m_pPoint->nNode : m_pMark->nNode ).GetNode();
226 }
227
228 /// @return current ContentNode at Point/Mark
229 SwContentNode* GetContentNode( bool bPoint = true ) const
230 {
231 return GetNode(bPoint).GetContentNode();
232 }
233
234 /**
235 Normalizes PaM, i.e. sort point and mark.
236
237 @param bPointFirst true: If the point is behind the mark then swap.
238 false: If the mark is behind the point then swap.
239 */
240 void Normalize(bool bPointFirst = true);
241
242 /// @return the document (SwDoc) at which the PaM is registered
243 SwDoc& GetDoc() const { return m_pPoint->nNode.GetNode().GetDoc(); }
244
245 SwPosition& GetBound( bool bOne = true )
246 { return bOne ? m_Bound1 : m_Bound2; }
247 const SwPosition& GetBound( bool bOne = true ) const
248 { return bOne ? m_Bound1 : m_Bound2; }
249
250 /// Get number of page which contains cursor.
251 sal_uInt16 GetPageNum( bool bAtPoint = true, const Point* pLayPos = nullptr );
252
253 /** Is in something protected (readonly) or selection contains
254 something protected. */
255 bool HasReadonlySel( bool bFormView ) const;
256
257 bool ContainsPosition(const SwPosition & rPos) const
258 {
259 return *Start() <= rPos && rPos <= *End();
260 }
261
262 OUString GetText() const;
263 void InvalidatePaM();
264 SwPaM* GetNext()
265 { return GetNextInRing(); }
5
Calling 'Ring::GetNextInRing'
266 const SwPaM* GetNext() const
267 { return GetNextInRing(); }
268 SwPaM* GetPrev()
269 { return GetPrevInRing(); }
270 const SwPaM* GetPrev() const
271 { return GetPrevInRing(); }
272 bool IsMultiSelection() const
273 { return !unique(); }
274
275 void dumpAsXml(xmlTextWriterPtr pWriter) const;
276};
277
278SW_DLLPUBLIC__attribute__ ((visibility("default"))) std::ostream &operator <<(std::ostream& s, const SwPaM& pam);
279
280bool CheckNodesRange(const SwNodeIndex&, const SwNodeIndex&, bool bChkSection);
281
282#endif // INCLUDED_SW_INC_PAM_HXX
283
284/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/sw/inc/ring.hxx

1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19#ifndef INCLUDED_SW_INC_RING_HXX
20#define INCLUDED_SW_INC_RING_HXX
21
22#include <utility>
23#include <sal/types.h>
24#include <iterator>
25#include <type_traits>
26#include <boost/iterator/iterator_facade.hpp>
27#include <boost/intrusive/circular_list_algorithms.hpp>
28
29namespace sw
30{
31 template <typename value_type> class RingContainer;
32 template <typename value_type> class RingIterator;
33 /**
34 * An intrusive container class double linking the contained nodes
35 * @example sw/qa/core/uwriter.cxx
36 */
37 template <typename value_type>
38 class SAL_WARN_UNUSED__attribute__((warn_unused)) Ring
39 {
40 public:
41 typedef typename std::add_const<value_type>::type const_value_type;
42 typedef RingContainer<value_type> ring_container;
43 typedef RingContainer<const_value_type> const_ring_container;
44 virtual ~Ring() COVERITY_NOEXCEPT_FALSE
45 { unlink(); };
46 /** algo::unlink is buggy! don't call it directly! */
47 void unlink()
48 {
49 algo::unlink(this);
50 m_pNext = this; // don't leave pointers to old list behind!
51 m_pPrev = this;
52 }
53 /**
54 * Removes this item from its current ring container and adds it to
55 * another ring container. If the item was not alone in the original
56 * ring container, the other items in the ring will stay in the old
57 * ring container.
58 * Note: the newly created item will be inserted just before item pDestRing.
59 * @param pDestRing the container to add this item to
60 */
61 void MoveTo( value_type* pDestRing );
62 /** @return a stl-like container with begin()/end() for iteration */
63 ring_container GetRingContainer();
64 /** @return a stl-like container with begin()/end() for const iteration */
65 const_ring_container GetRingContainer() const;
66
67 protected:
68 /**
69 * Creates a new item in a ring container all by itself.
70 * Note: Ring instances can newer be outside a container. At most, they
71 * are alone in one.
72 */
73 Ring()
74 : m_pNext(this)
75 , m_pPrev(this)
76 { }
77 /**
78 * Creates a new item and add it to an existing ring container.
79 * Note: the newly created item will be inserted just before item pRing.
80 * @param pRing ring container to add the created item to
81 */
82 Ring( value_type* pRing );
83 /** @return the next item in the ring container */
84 value_type* GetNextInRing()
85 { return static_cast<value_type *>(m_pNext); }
6
Use of memory after it is freed
86 /** @return the previous item in the ring container */
87 value_type* GetPrevInRing()
88 { return static_cast<value_type *>(m_pPrev); }
89 /** @return the next item in the ring container */
90 const_value_type* GetNextInRing() const
91 { return static_cast<value_type *>(m_pNext); }
92 /** @return the previous item in the ring container */
93 const_value_type* GetPrevInRing() const
94 { return static_cast<value_type *>(m_pPrev); }
95 /** @return true if and only if this item is alone in its ring */
96 bool unique() const
97 { return algo::unique(static_cast< const_value_type* >(this)); }
98
99 private:
100 /** internal implementation class -- not for external use */
101 struct Ring_node_traits
102 {
103 typedef Ring node;
104 typedef Ring* node_ptr;
105 typedef const Ring* const_node_ptr;
106 static node_ptr get_next(const_node_ptr n) { return const_cast<node_ptr>(n)->m_pNext; };
107 static void set_next(node_ptr n, node_ptr next) { n->m_pNext = next; };
108 static node_ptr get_previous(const_node_ptr n) { return const_cast<node_ptr>(n)->m_pPrev; };
109 static void set_previous(node_ptr n, node_ptr previous) { n->m_pPrev = previous; };
110 };
111 friend ring_container;
112 friend const_ring_container;
113 friend typename ring_container::iterator;
114 friend typename ring_container::const_iterator;
115 friend typename const_ring_container::iterator;
116 friend typename const_ring_container::const_iterator;
117 friend class boost::iterator_core_access;
118 typedef boost::intrusive::circular_list_algorithms<Ring_node_traits> algo;
119 Ring* m_pNext;
120 Ring* m_pPrev;
121 };
122
123 template <typename value_type>
124 inline Ring<value_type>::Ring( value_type* pObj )
125 : m_pNext(this)
126 , m_pPrev(this)
127 {
128 if( pObj )
129 {
130 algo::link_before(pObj, this);
131 }
132 }
133
134 template <typename value_type>
135 inline void Ring<value_type>::MoveTo(value_type* pDestRing)
136 {
137 value_type* pThis = static_cast< value_type* >(this);
138 unlink();
139 // insert into "new"
140 if (pDestRing)
141 {
142 algo::link_before(pDestRing, pThis);
143 }
144 }
145
146 /**
147 * helper class that provides Svalue_typeL-style container iteration to the ring
148 */
149 template <typename value_type>
150 class SAL_WARN_UNUSED__attribute__((warn_unused)) RingContainer final
151 {
152 private:
153 /** the item in the ring where iteration starts */
154 value_type* m_pStart;
155 typedef typename std::remove_const<value_type>::type nonconst_value_type;
156
157 public:
158 RingContainer( value_type* pRing ) : m_pStart(pRing) {};
159 typedef RingIterator<value_type> iterator;
160 typedef RingIterator<const value_type> const_iterator;
161 /**
162 * iterator access
163 * @code
164 * for(SwPaM& rCurrentPaM : pPaM->GetRingContainer())
165 * do_stuff(rCurrentPaM); // this gets called on every SwPaM in the same ring as pPaM
166 * @endcode
167 */
168 iterator begin();
169 iterator end();
170 const_iterator begin() const;
171 const_iterator end() const;
172 /** @return the number of elements in the container */
173 size_t size() const
174 { return std::distance(begin(), end()); }
175 /**
176 * Merges two ring containers. All item from both ring containers will
177 * be in the same ring container in the end.
178 * Note: The items of this ring container will be inserted just before
179 * item pDestRing
180 * @param pDestRing the container to merge this container with
181 */
182 void merge( RingContainer< value_type > aDestRing )
183 {
184 // first check that we aren't merged already, swapping would
185 // actually un-merge in this case!
186 assert(m_pStart->m_pPrev != aDestRing.m_pStart)(static_cast <bool> (m_pStart->m_pPrev != aDestRing.
m_pStart) ? void (0) : __assert_fail ("m_pStart->m_pPrev != aDestRing.m_pStart"
, "/home/maarten/src/libreoffice/core/sw/inc/ring.hxx", 186, __extension__
__PRETTY_FUNCTION__))
;
187 assert(m_pStart != aDestRing.m_pStart->m_pPrev)(static_cast <bool> (m_pStart != aDestRing.m_pStart->
m_pPrev) ? void (0) : __assert_fail ("m_pStart != aDestRing.m_pStart->m_pPrev"
, "/home/maarten/src/libreoffice/core/sw/inc/ring.hxx", 187, __extension__
__PRETTY_FUNCTION__))
;
188 std::swap(m_pStart->m_pPrev->m_pNext, aDestRing.m_pStart->m_pPrev->m_pNext);
189 std::swap(m_pStart->m_pPrev, aDestRing.m_pStart->m_pPrev);
190 }
191 };
192
193 template <typename value_type>
194 class RingIterator final : public boost::iterator_facade<
195 RingIterator<value_type>
196 , value_type
197 , boost::forward_traversal_tag
198 >
199 {
200 private:
201 typedef typename std::remove_const<value_type>::type nonconst_value_type;
202 public:
203 RingIterator()
204 : m_pCurrent(nullptr)
205 , m_pStart(nullptr)
206 {}
207 explicit RingIterator(nonconst_value_type* pRing, bool bStart = true)
208 : m_pCurrent(nullptr)
209 , m_pStart(pRing)
210 {
211 if(!bStart)
212 m_pCurrent = m_pStart;
213 }
214
215 private:
216 friend class boost::iterator_core_access;
217 void increment()
218 { m_pCurrent = m_pCurrent ? m_pCurrent->GetNextInRing() : m_pStart->GetNextInRing(); }
219 bool equal(RingIterator const& other) const
220 {
221 // we never want to compare iterators from
222 // different rings or starting points
223 assert(m_pStart == other.m_pStart)(static_cast <bool> (m_pStart == other.m_pStart) ? void
(0) : __assert_fail ("m_pStart == other.m_pStart", "/home/maarten/src/libreoffice/core/sw/inc/ring.hxx"
, 223, __extension__ __PRETTY_FUNCTION__))
;
224 return m_pCurrent == other.m_pCurrent;
225 }
226 value_type& dereference() const
227 { return m_pCurrent ? *m_pCurrent : * m_pStart; }
228 /**
229 * value_type is:
230 * - pointing to the current item in the iteration in general
231 * - nullptr if on the first item (begin())
232 * - m_pStart when beyond the last item (end())
233 */
234 nonconst_value_type* m_pCurrent;
235 /** the first item of the iteration */
236 nonconst_value_type* m_pStart;
237 };
238
239 template <typename value_type>
240 inline typename Ring<value_type>::ring_container Ring<value_type>::GetRingContainer()
241 { return Ring<value_type>::ring_container(static_cast< value_type* >(this)); };
242
243 template <typename value_type>
244 inline typename Ring<value_type>::const_ring_container Ring<value_type>::GetRingContainer() const
245 { return Ring<value_type>::const_ring_container(static_cast< const_value_type* >(this)); };
246
247 template <typename value_type>
248 inline typename RingContainer<value_type>::iterator RingContainer<value_type>::begin()
249 { return RingContainer<value_type>::iterator(const_cast< nonconst_value_type* >(m_pStart)); };
250
251 template <typename value_type>
252 inline typename RingContainer<value_type>::iterator RingContainer<value_type>::end()
253 { return RingContainer<value_type>::iterator(const_cast< nonconst_value_type* >(m_pStart), false); };
254
255 template <typename value_type>
256 inline typename RingContainer<value_type>::const_iterator RingContainer<value_type>::begin() const
257 { return RingContainer<value_type>::const_iterator(const_cast< nonconst_value_type* >(m_pStart)); };
258
259 template <typename value_type>
260 inline typename RingContainer<value_type>::const_iterator RingContainer<value_type>::end() const
261 { return RingContainer<value_type>::const_iterator(const_cast< nonconst_value_type* >(m_pStart), false); };
262}
263#endif
264
265/* vim:set shiftwidth=4 softtabstop=4 expandtab: */