File: | home/maarten/src/libreoffice/core/sw/inc/ring.hxx |
Warning: | line 85, column 19 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | ||||
74 | using namespace ::com::sun::star; | |||
75 | ||||
76 | // Helper classes | |||
77 | SwUnoInternalPaM::SwUnoInternalPaM(SwDoc& rDoc) : | |||
78 | SwPaM(rDoc.GetNodes()) | |||
79 | { | |||
80 | } | |||
81 | ||||
82 | SwUnoInternalPaM::~SwUnoInternalPaM() | |||
83 | { | |||
84 | while( GetNext() != this) | |||
| ||||
85 | { | |||
86 | delete GetNext(); | |||
87 | } | |||
88 | } | |||
89 | ||||
90 | SwUnoInternalPaM& 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 | ||||
111 | void 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 | ||||
126 | void 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 | |||
178 | static void | |||
179 | lcl_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 | |||
204 | static void | |||
205 | lcl_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 | ||||
228 | void | |||
229 | SwUnoCursorHelper::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 | ||||
258 | bool | |||
259 | SwUnoCursorHelper::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 | ||||
308 | static void | |||
309 | lcl_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 | ||||
337 | static bool | |||
338 | lcl_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 | ||||
365 | static void | |||
366 | lcl_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 | ||||
402 | static void | |||
403 | lcl_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 | ||||
436 | bool | |||
437 | SwUnoCursorHelper::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 | ||||
615 | SwFormatColl * | |||
616 | SwUnoCursorHelper::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 | ||||
658 | class SwXTextCursor::Impl | |||
659 | { | |||
660 | ||||
661 | public: | |||
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 | ||||
690 | SwUnoCursor& SwXTextCursor::GetCursor() | |||
691 | { return *m_pImpl->m_pUnoCursor; } | |||
692 | ||||
693 | SwPaM const* SwXTextCursor::GetPaM() const | |||
694 | { return m_pImpl->m_pUnoCursor.get(); } | |||
695 | ||||
696 | SwPaM* SwXTextCursor::GetPaM() | |||
697 | { return m_pImpl->m_pUnoCursor.get(); } | |||
698 | ||||
699 | SwDoc const* SwXTextCursor::GetDoc() const | |||
700 | { return m_pImpl->m_pUnoCursor ? &m_pImpl->m_pUnoCursor->GetDoc() : nullptr; } | |||
701 | ||||
702 | SwDoc* SwXTextCursor::GetDoc() | |||
703 | { return m_pImpl->m_pUnoCursor ? &m_pImpl->m_pUnoCursor->GetDoc() : nullptr; } | |||
704 | ||||
705 | SwXTextCursor::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 | ||||
715 | SwXTextCursor::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 | ||||
723 | SwXTextCursor::~SwXTextCursor() | |||
724 | { | |||
725 | } | |||
726 | ||||
727 | void 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 | ||||
761 | namespace { | |||
762 | ||||
763 | enum ForceIntoMetaMode { META_CHECK_BOTH, META_INIT_START, META_INIT_END }; | |||
764 | ||||
765 | } | |||
766 | ||||
767 | static bool | |||
768 | lcl_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 | ||||
811 | bool 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 | ||||
841 | OUString SwXTextCursor::getImplementationName() | |||
842 | { | |||
843 | return "SwXTextCursor"; | |||
844 | } | |||
845 | ||||
846 | sal_Bool SAL_CALL SwXTextCursor::supportsService(const OUString& rServiceName) | |||
847 | { | |||
848 | return cppu::supportsService(this, rServiceName); | |||
849 | } | |||
850 | ||||
851 | uno::Sequence< OUString > SAL_CALL | |||
852 | SwXTextCursor::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 | ||||
866 | namespace | |||
867 | { | |||
868 | class theSwXTextCursorUnoTunnelId : public rtl::Static< UnoTunnelIdInit, theSwXTextCursorUnoTunnelId > {}; | |||
869 | } | |||
870 | ||||
871 | const uno::Sequence< sal_Int8 > & SwXTextCursor::getUnoTunnelId() | |||
872 | { | |||
873 | return theSwXTextCursorUnoTunnelId::get().getSeq(); | |||
874 | } | |||
875 | ||||
876 | sal_Int64 SAL_CALL | |||
877 | SwXTextCursor::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 | ||||
883 | void 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 | ||||
899 | void 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 | ||||
915 | sal_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 | ||||
928 | sal_Bool SAL_CALL | |||
929 | SwXTextCursor::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 | ||||
946 | sal_Bool SAL_CALL | |||
947 | SwXTextCursor::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 | ||||
964 | void SAL_CALL | |||
965 | SwXTextCursor::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 | ||||
1021 | void SAL_CALL | |||
1022 | SwXTextCursor::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 | ||||
1049 | void SAL_CALL | |||
1050 | SwXTextCursor::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 | ||||
1198 | sal_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 | ||||
1209 | sal_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 | ||||
1220 | sal_Bool SAL_CALL | |||
1221 | SwXTextCursor::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 | ||||
1267 | sal_Bool SAL_CALL | |||
1268 | SwXTextCursor::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 | ||||
1307 | sal_Bool SAL_CALL | |||
1308 | SwXTextCursor::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 | ||||
1343 | sal_Bool SAL_CALL | |||
1344 | SwXTextCursor::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 | ||||
1379 | sal_Bool SAL_CALL | |||
1380 | SwXTextCursor::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 | ||||
1402 | sal_Bool SAL_CALL | |||
1403 | SwXTextCursor::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 | ||||
1426 | sal_Bool SAL_CALL | |||
1427 | SwXTextCursor::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 | ||||
1461 | sal_Bool SAL_CALL | |||
1462 | SwXTextCursor::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 | ||||
1489 | sal_Bool SAL_CALL | |||
1490 | SwXTextCursor::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 | ||||
1512 | sal_Bool SAL_CALL | |||
1513 | SwXTextCursor::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 | ||||
1536 | sal_Bool SAL_CALL | |||
1537 | SwXTextCursor::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 | ||||
1547 | sal_Bool SAL_CALL | |||
1548 | SwXTextCursor::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 | ||||
1558 | sal_Bool SAL_CALL | |||
1559 | SwXTextCursor::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 | ||||
1583 | sal_Bool SAL_CALL | |||
1584 | SwXTextCursor::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 | ||||
1608 | sal_Bool SAL_CALL | |||
1609 | SwXTextCursor::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 | ||||
1624 | sal_Bool SAL_CALL | |||
1625 | SwXTextCursor::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 | ||||
1640 | uno::Reference< text::XText > SAL_CALL | |||
1641 | SwXTextCursor::getText() | |||
1642 | { | |||
1643 | SolarMutexGuard g; | |||
1644 | ||||
1645 | return m_pImpl->m_xParentText; | |||
1646 | } | |||
1647 | ||||
1648 | uno::Reference< text::XTextRange > SAL_CALL | |||
1649 | SwXTextCursor::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 | ||||
1674 | uno::Reference< text::XTextRange > SAL_CALL | |||
1675 | SwXTextCursor::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 | ||||
1700 | OUString 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 | ||||
1711 | void SAL_CALL | |||
1712 | SwXTextCursor::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 | ||||
1724 | uno::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 | ||||
1758 | void 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. | |||
1774 | static 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 | ||||
1782 | void 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 | ||||
1856 | namespace | |||
1857 | { | |||
1858 | bool NotInRange(sal_uInt16 nWID, sal_uInt16 nStart, sal_uInt16 nEnd) | |||
1859 | { | |||
1860 | return nWID < nStart || nWID > nEnd; | |||
1861 | } | |||
1862 | } | |||
1863 | ||||
1864 | uno::Sequence< beans::PropertyState > | |||
1865 | SwUnoCursorHelper::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 | ||||
1972 | beans::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 | ||||
1983 | static void | |||
1984 | lcl_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 | ||||
2005 | void 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 | ||||
2045 | uno::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 | ||||
2068 | uno::Reference< beans::XPropertySetInfo > SAL_CALL | |||
2069 | SwXTextCursor::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 | ||||
2092 | void SAL_CALL | |||
2093 | SwXTextCursor::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 | ||||
2125 | uno::Any SAL_CALL | |||
2126 | SwXTextCursor::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 | ||||
2151 | void SAL_CALL | |||
2152 | SwXTextCursor::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 | ||||
2159 | void SAL_CALL | |||
2160 | SwXTextCursor::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 | ||||
2167 | void SAL_CALL | |||
2168 | SwXTextCursor::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 | ||||
2175 | void SAL_CALL | |||
2176 | SwXTextCursor::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 | ||||
2183 | beans::PropertyState SAL_CALL | |||
2184 | SwXTextCursor::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 | ||||
2195 | uno::Sequence< beans::PropertyState > SAL_CALL | |||
2196 | SwXTextCursor::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 | ||||
2207 | void SAL_CALL | |||
2208 | SwXTextCursor::setPropertyToDefault(const OUString& rPropertyName) | |||
2209 | { | |||
2210 | // forward: need no solar mutex here | |||
2211 | uno::Sequence < OUString > aSequence ( &rPropertyName, 1 ); | |||
2212 | setPropertiesToDefault ( aSequence ); | |||
2213 | } | |||
2214 | ||||
2215 | uno::Any SAL_CALL | |||
2216 | SwXTextCursor::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 | ||||
2223 | void 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 | ||||
2264 | uno::Sequence< uno::Any > SAL_CALL | |||
2265 | SwXTextCursor::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 | ||||
2274 | void 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 | } | |||
2280 | void 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 | ||||
2286 | void 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 | |||
2294 | static 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 | |||
2303 | static 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 | ||||
2312 | static void | |||
2313 | lcl_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 | ||||
2326 | void SAL_CALL | |||
2327 | SwXTextCursor::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 | ||||
2348 | void SAL_CALL | |||
2349 | SwXTextCursor::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 | ||||
2411 | uno::Sequence< uno::Any > SAL_CALL | |||
2412 | SwXTextCursor::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 | ||||
2452 | void 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 | ||||
2489 | void SAL_CALL | |||
2490 | SwXTextCursor::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 | ||||
2501 | void 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 | ||||
2511 | uno::Sequence< beans::PropertyValue > | |||
2512 | SwUnoCursorHelper::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 | ||||
2577 | uno::Sequence< beans::PropertyValue > SAL_CALL | |||
2578 | SwXTextCursor::createSortDescriptor() | |||
2579 | { | |||
2580 | SolarMutexGuard aGuard; | |||
2581 | ||||
2582 | return SwUnoCursorHelper::CreateSortDescriptor(false); | |||
2583 | } | |||
2584 | ||||
2585 | bool 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 | ||||
2836 | void SAL_CALL | |||
2837 | SwXTextCursor::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 | ||||
2880 | uno::Reference< container::XEnumeration > SAL_CALL | |||
2881 | SwXTextCursor::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 | ||||
2890 | uno::Reference< container::XEnumeration > SAL_CALL | |||
2891 | SwXTextCursor::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 | ||||
2920 | uno::Type SAL_CALL | |||
2921 | SwXTextCursor::getElementType() | |||
2922 | { | |||
2923 | return cppu::UnoType<text::XTextRange>::get(); | |||
2924 | } | |||
2925 | ||||
2926 | sal_Bool SAL_CALL SwXTextCursor::hasElements() | |||
2927 | { | |||
2928 | return true; | |||
2929 | } | |||
2930 | ||||
2931 | uno::Sequence< OUString > SAL_CALL | |||
2932 | SwXTextCursor::getAvailableServiceNames() | |||
2933 | { | |||
2934 | uno::Sequence<OUString> aRet { "com.sun.star.text.TextContent" }; | |||
2935 | return aRet; | |||
2936 | } | |||
2937 | ||||
2938 | IMPLEMENT_FORWARD_REFCOUNT( SwXTextCursor,SwXTextCursor_Base )void SwXTextCursor::acquire() throw() { SwXTextCursor_Base::acquire (); } void SwXTextCursor::release() throw() { SwXTextCursor_Base ::release(); } | |||
2939 | ||||
2940 | uno::Any SAL_CALL | |||
2941 | SwXTextCursor::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: */ |
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 | |
30 | class SwDoc; |
31 | class SwPaM; |
32 | class Point; |
33 | |
34 | /// Marks a position in the document model. |
35 | struct 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 | |
61 | SW_DLLPUBLIC__attribute__ ((visibility("default"))) std::ostream &operator <<(std::ostream& s, const SwPosition& position); |
62 | |
63 | // Result of comparing positions. |
64 | enum 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 | |
76 | template<typename T> |
77 | SwComparePosition 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 |
122 | struct SwMoveFnCollection; |
123 | SW_DLLPUBLIC__attribute__ ((visibility("default"))) extern SwMoveFnCollection const & fnMoveForward; ///< SwPam::Move()/Find() default argument. |
124 | SW_DLLPUBLIC__attribute__ ((visibility("default"))) extern SwMoveFnCollection const & fnMoveBackward; |
125 | |
126 | using SwGoInDoc = auto (*)(SwPaM& rPam, SwMoveFnCollection const & fnMove) -> bool; |
127 | SW_DLLPUBLIC__attribute__ ((visibility("default"))) bool GoInDoc( SwPaM&, SwMoveFnCollection const &); |
128 | bool GoInSection( SwPaM&, SwMoveFnCollection const &); |
129 | SW_DLLPUBLIC__attribute__ ((visibility("default"))) bool GoInNode( SwPaM&, SwMoveFnCollection const &); |
130 | SW_DLLPUBLIC__attribute__ ((visibility("default"))) bool GoInContent( SwPaM&, SwMoveFnCollection const &); |
131 | bool GoInContentCells( SwPaM&, SwMoveFnCollection const &); |
132 | bool GoInContentSkipHidden( SwPaM&, SwMoveFnCollection const &); |
133 | bool GoInContentCellsSkipHidden( SwPaM&, SwMoveFnCollection const &); |
134 | |
135 | /// PaM is Point and Mark: a selection of the document model. |
136 | class 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 | |
146 | public: |
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(); } |
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 | |
278 | SW_DLLPUBLIC__attribute__ ((visibility("default"))) std::ostream &operator <<(std::ostream& s, const SwPaM& pam); |
279 | |
280 | bool CheckNodesRange(const SwNodeIndex&, const SwNodeIndex&, bool bChkSection); |
281 | |
282 | #endif // INCLUDED_SW_INC_PAM_HXX |
283 | |
284 | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |
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 | ||||
29 | namespace 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); } | |||
| ||||
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: */ |