Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sw / source / core / unocore / unocrsrhelper.cxx
blob831cffd5ac1d81cf18084e81bff3665e44bbe921
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <unocrsrhelper.hxx>
22 #include <map>
23 #include <algorithm>
24 #include <memory>
26 #include <com/sun/star/beans/NamedValue.hpp>
27 #include <com/sun/star/beans/PropertyAttribute.hpp>
28 #include <com/sun/star/beans/PropertyState.hpp>
29 #include <com/sun/star/embed/ElementModes.hpp>
30 #include <com/sun/star/embed/XStorage.hpp>
31 #include <com/sun/star/io/IOException.hpp>
32 #include <com/sun/star/text/XTextSection.hpp>
33 #include <com/sun/star/lang/XSingleServiceFactory.hpp>
35 #include <svx/unoshape.hxx>
37 #include <cmdid.h>
38 #include <hintids.hxx>
39 #include <unotextrange.hxx>
40 #include <unodraw.hxx>
41 #include <unofootnote.hxx>
42 #include <unobookmark.hxx>
43 #include <unomap.hxx>
44 #include <unorefmark.hxx>
45 #include <unoidx.hxx>
46 #include <unofield.hxx>
47 #include <unotbl.hxx>
48 #include <unosett.hxx>
49 #include <unoframe.hxx>
50 #include <unocrsr.hxx>
51 #include <doc.hxx>
52 #include <IDocumentUndoRedo.hxx>
53 #include <IDocumentRedlineAccess.hxx>
54 #include <IDocumentLayoutAccess.hxx>
55 #include <fmtftn.hxx>
56 #include <charfmt.hxx>
57 #include <pagedesc.hxx>
58 #include <docstyle.hxx>
59 #include <ndtxt.hxx>
60 #include <docsh.hxx>
61 #include <section.hxx>
62 #include <shellio.hxx>
63 #include <edimp.hxx>
64 #include <swundo.hxx>
65 #include <cntfrm.hxx>
66 #include <pagefrm.hxx>
67 #include <svl/eitem.hxx>
68 #include <svl/lngmisc.hxx>
69 #include <swtable.hxx>
70 #include <tox.hxx>
71 #include <doctxm.hxx>
72 #include <fchrfmt.hxx>
73 #include <editeng/editids.hrc>
74 #include <editeng/flstitem.hxx>
75 #include <editeng/prntitem.hxx>
76 #include <vcl/metric.hxx>
77 #include <svtools/ctrltool.hxx>
78 #include <sfx2/docfilt.hxx>
79 #include <sfx2/docfile.hxx>
80 #include <sfx2/fcontnr.hxx>
81 #include <svl/stritem.hxx>
82 #include <SwStyleNameMapper.hxx>
83 #include <redline.hxx>
84 #include <numrule.hxx>
85 #include <comphelper/storagehelper.hxx>
86 #include <unotools/mediadescriptor.hxx>
87 #include <comphelper/sequenceashashmap.hxx>
88 #include <SwNodeNum.hxx>
89 #include <fmtmeta.hxx>
90 #include <txtfld.hxx>
91 #include <unoparagraph.hxx>
92 #include <poolfmt.hxx>
93 #include <paratr.hxx>
94 #include <sal/log.hxx>
96 using namespace ::com::sun::star;
97 using namespace ::com::sun::star::uno;
98 using namespace ::com::sun::star::beans;
99 using namespace ::com::sun::star::text;
100 using namespace ::com::sun::star::table;
101 using namespace ::com::sun::star::container;
102 using namespace ::com::sun::star::lang;
104 namespace SwUnoCursorHelper
107 static SwPaM* lcl_createPamCopy(const SwPaM& rPam)
109 SwPaM *const pRet = new SwPaM(*rPam.GetPoint());
110 ::sw::DeepCopyPaM(rPam, *pRet);
111 return pRet;
114 void GetSelectableFromAny(uno::Reference<uno::XInterface> const& xIfc,
115 SwDoc & rTargetDoc,
116 SwPaM *& o_rpPaM, std::pair<OUString, FlyCntType> & o_rFrame,
117 OUString & o_rTableName, SwUnoTableCursor const*& o_rpTableCursor,
118 ::sw::mark::IMark const*& o_rpMark,
119 std::vector<SdrObject *> & o_rSdrObjects)
121 uno::Reference<drawing::XShapes> const xShapes(xIfc, UNO_QUERY);
122 if (xShapes.is())
124 sal_Int32 nShapes(xShapes->getCount());
125 for (sal_Int32 i = 0; i < nShapes; ++i)
127 uno::Reference<lang::XUnoTunnel> xShape;
128 xShapes->getByIndex(i) >>= xShape;
129 if (xShape.is())
131 SvxShape *const pSvxShape(
132 comphelper::getFromUnoTunnel<SvxShape>(xShape));
133 if (pSvxShape)
135 SdrObject *const pSdrObject = pSvxShape->GetSdrObject();
136 if (pSdrObject)
137 { // hmm... needs view to verify it's in right doc...
138 o_rSdrObjects.push_back(pSdrObject);
143 return;
146 uno::Reference<lang::XUnoTunnel> const xTunnel(xIfc, UNO_QUERY);
148 SwXShape *const pShape(comphelper::getFromUnoTunnel<SwXShape>(xTunnel));
149 if (pShape)
151 uno::Reference<uno::XAggregation> const xAgg(
152 pShape->GetAggregationInterface());
153 if (xAgg.is())
155 SvxShape *const pSvxShape(
156 comphelper::getFromUnoTunnel<SvxShape>(xTunnel));
157 if (pSvxShape)
159 SdrObject *const pSdrObject = pSvxShape->GetSdrObject();
160 if (pSdrObject)
161 { // hmm... needs view to verify it's in right doc...
162 o_rSdrObjects.push_back(pSdrObject);
166 return;
169 OTextCursorHelper *const pCursor(
170 dynamic_cast<OTextCursorHelper*>(xIfc.get()));
171 if (pCursor)
173 if (pCursor->GetDoc() == &rTargetDoc)
175 o_rpPaM = lcl_createPamCopy(*pCursor->GetPaM());
177 return;
180 SwXTextRanges* const pRanges = dynamic_cast<SwXTextRanges*>(xIfc.get());
181 if (pRanges)
183 SwUnoCursor const* pUnoCursor = pRanges->GetCursor();
184 if (pUnoCursor && &pUnoCursor->GetDoc() == &rTargetDoc)
186 o_rpPaM = lcl_createPamCopy(*pUnoCursor);
188 return;
191 // check these before Range to prevent misinterpretation of text frames
192 // and cells also implement XTextRange
193 SwXFrame *const pFrame = dynamic_cast<SwXFrame*>(xIfc.get());
194 if (pFrame)
196 const SwFrameFormat *const pFrameFormat(pFrame->GetFrameFormat());
197 if (pFrameFormat && pFrameFormat->GetDoc() == &rTargetDoc)
199 o_rFrame = std::make_pair(pFrameFormat->GetName(), pFrame->GetFlyCntType());
201 return;
204 SwXTextTable *const pTextTable = dynamic_cast<SwXTextTable*>(xIfc.get());
205 if (pTextTable)
207 SwFrameFormat *const pFrameFormat(pTextTable->GetFrameFormat());
208 if (pFrameFormat && pFrameFormat->GetDoc() == &rTargetDoc)
210 o_rTableName = pFrameFormat->GetName();
212 return;
215 SwXCell *const pCell = dynamic_cast<SwXCell*>(xIfc.get());
216 if (pCell)
218 SwFrameFormat *const pFrameFormat(pCell->GetFrameFormat());
219 if (pFrameFormat && pFrameFormat->GetDoc() == &rTargetDoc)
221 SwTableBox * pBox = pCell->GetTableBox();
222 SwTable *const pTable = SwTable::FindTable(pFrameFormat);
223 // ??? what's the benefit of setting pBox in this convoluted way?
224 pBox = pCell->FindBox(pTable, pBox);
225 if (pBox)
227 SwPaM aPam(*pBox->GetSttNd());
228 aPam.Move(fnMoveForward, GoInNode);
229 o_rpPaM = lcl_createPamCopy(aPam);
232 return;
235 uno::Reference<text::XTextRange> const xTextRange(xTunnel, UNO_QUERY);
236 if (xTextRange.is())
238 SwUnoInternalPaM aPam(rTargetDoc);
239 if (::sw::XTextRangeToSwPaM(aPam, xTextRange))
241 o_rpPaM = lcl_createPamCopy(aPam);
243 return;
246 SwXCellRange *const pCellRange = dynamic_cast<SwXCellRange*>(xIfc.get());
247 if (pCellRange)
249 SwUnoCursor const*const pUnoCursor(pCellRange->GetTableCursor());
250 if (pUnoCursor && &pUnoCursor->GetDoc() == &rTargetDoc)
252 // probably can't copy it to o_rpPaM for this since it's
253 // a SwTableCursor
254 o_rpTableCursor = dynamic_cast<SwUnoTableCursor const*>(pUnoCursor);
256 return;
259 ::sw::mark::IMark const*const pMark =
260 SwXBookmark::GetBookmarkInDoc(& rTargetDoc, xIfc);
261 if (pMark)
263 o_rpMark = pMark;
264 return;
268 uno::Reference<text::XTextContent>
269 GetNestedTextContent(SwTextNode const & rTextNode, sal_Int32 const nIndex,
270 bool const bParent)
272 // these should be unambiguous because of the dummy character
273 auto const eMode( bParent
274 ? ::sw::GetTextAttrMode::Parent : ::sw::GetTextAttrMode::Expand );
275 SwTextAttr *const pMetaTextAttr =
276 rTextNode.GetTextAttrAt(nIndex, RES_TXTATR_META, eMode);
277 SwTextAttr *const pMetaFieldTextAttr =
278 rTextNode.GetTextAttrAt(nIndex, RES_TXTATR_METAFIELD, eMode);
279 // which is innermost?
280 SwTextAttr *const pTextAttr = pMetaTextAttr
281 ? (pMetaFieldTextAttr
282 ? ((pMetaFieldTextAttr->GetStart() >
283 pMetaTextAttr->GetStart())
284 ? pMetaFieldTextAttr : pMetaTextAttr)
285 : pMetaTextAttr)
286 : pMetaFieldTextAttr;
287 uno::Reference<XTextContent> xRet;
288 if (pTextAttr)
290 ::sw::Meta *const pMeta(
291 static_cast<SwFormatMeta &>(pTextAttr->GetAttr()).GetMeta());
292 assert(pMeta);
293 xRet.set(pMeta->MakeUnoObject(), uno::UNO_QUERY);
295 return xRet;
298 static uno::Any GetParaListAutoFormat(SwTextNode const& rNode)
300 SwFormatAutoFormat const*const pFormat(
301 rNode.GetSwAttrSet().GetItem<SwFormatAutoFormat>(RES_PARATR_LIST_AUTOFMT, false));
302 if (!pFormat)
304 return uno::Any();
306 const auto pSet(pFormat->GetStyleHandle());
307 if (!pSet)
308 return {};
309 SfxItemPropertySet const& rPropSet(*aSwMapProvider.GetPropertySet(PROPERTY_MAP_CHAR_AUTO_STYLE));
310 SfxItemPropertyMap const& rMap(rPropSet.getPropertyMap());
311 std::vector<beans::NamedValue> props;
312 // have to iterate the map, not the item set?
313 for (auto const pEntry : rMap.getPropertyEntries())
315 if (rPropSet.getPropertyState(*pEntry, *pSet) == PropertyState_DIRECT_VALUE)
317 Any value;
318 rPropSet.getPropertyValue(*pEntry, *pSet, value);
319 props.emplace_back(pEntry->aName, value);
322 return uno::Any(comphelper::containerToSequence(props));
325 // Read the special properties of the cursor
326 bool getCursorPropertyValue(const SfxItemPropertyMapEntry& rEntry
327 , SwPaM& rPam
328 , Any *pAny
329 , PropertyState& eState
330 , const SwTextNode* pNode )
332 PropertyState eNewState = PropertyState_DIRECT_VALUE;
333 bool bDone = true;
334 switch(rEntry.nWID)
336 case FN_UNO_PARA_CONT_PREV_SUBTREE:
337 if (pAny)
339 const SwTextNode * pTmpNode = pNode;
341 if (!pTmpNode)
342 pTmpNode = rPam.GetPointNode().GetTextNode();
344 bool bRet = false;
346 if ( pTmpNode &&
347 pTmpNode->GetNum() &&
348 pTmpNode->GetNum()->IsContinueingPreviousSubTree() )
350 bRet = true;
353 *pAny <<= bRet;
355 break;
356 case FN_UNO_PARA_NUM_STRING:
357 if (pAny)
359 const SwTextNode * pTmpNode = pNode;
361 if (!pTmpNode)
362 pTmpNode = rPam.GetPointNode().GetTextNode();
364 OUString sRet;
365 if ( pTmpNode && pTmpNode->GetNum() )
367 sRet = pTmpNode->GetNumString();
370 *pAny <<= sRet;
372 break;
373 case RES_PARATR_OUTLINELEVEL:
374 if (pAny)
376 const SwTextNode * pTmpNode = pNode;
378 if (!pTmpNode)
379 pTmpNode = rPam.GetPointNode().GetTextNode();
381 sal_Int16 nRet = -1;
382 if ( pTmpNode )
383 nRet = sal::static_int_cast< sal_Int16 >( pTmpNode->GetAttrOutlineLevel() );
385 *pAny <<= nRet;
387 break;
388 case FN_UNO_PARA_CONDITIONAL_STYLE_NAME:
389 case FN_UNO_PARA_STYLE :
391 SwFormatColl* pFormat = nullptr;
392 if(pNode)
393 pFormat = FN_UNO_PARA_CONDITIONAL_STYLE_NAME == rEntry.nWID
394 ? pNode->GetFormatColl() : &pNode->GetAnyFormatColl();
395 else
397 pFormat = SwUnoCursorHelper::GetCurTextFormatColl(rPam,
398 FN_UNO_PARA_CONDITIONAL_STYLE_NAME == rEntry.nWID);
400 if(pFormat)
402 if( pAny )
404 OUString sVal;
405 SwStyleNameMapper::FillProgName(pFormat->GetName(), sVal, SwGetPoolIdFromName::TxtColl );
406 *pAny <<= sVal;
409 else
410 eNewState = PropertyState_AMBIGUOUS_VALUE;
412 break;
413 case FN_UNO_PAGE_STYLE :
415 OUString sVal;
416 GetCurPageStyle(rPam, sVal);
417 if( pAny )
418 *pAny <<= sVal;
419 if(sVal.isEmpty())
420 eNewState = PropertyState_AMBIGUOUS_VALUE;
422 break;
423 case FN_UNO_NUM_START_VALUE :
424 if( pAny )
426 sal_Int16 nValue = IsNodeNumStart(rPam, eNewState);
427 *pAny <<= nValue;
429 break;
430 case FN_UNO_NUM_LEVEL :
431 case FN_UNO_IS_NUMBER :
432 // #i91601#
433 case FN_UNO_LIST_ID:
434 case FN_NUMBER_NEWSTART:
435 case FN_UNO_PARA_NUM_AUTO_FORMAT:
437 if (!pAny)
439 break;
441 // a multi selection is not considered
442 const SwTextNode* pTextNd = rPam.GetPointNode().GetTextNode();
443 if ( pTextNd && pTextNd->IsInList() )
445 switch (rEntry.nWID)
447 case FN_UNO_NUM_LEVEL:
449 *pAny <<= static_cast<sal_Int16>(pTextNd->GetActualListLevel());
450 break;
452 case FN_UNO_IS_NUMBER:
454 *pAny <<= pTextNd->IsCountedInList();
455 break;
457 // #i91601#
458 case FN_UNO_LIST_ID:
460 *pAny <<= pTextNd->GetListId();
461 break;
463 case FN_NUMBER_NEWSTART:
465 *pAny <<= pTextNd->IsListRestart();
466 break;
468 case FN_UNO_PARA_NUM_AUTO_FORMAT:
470 *pAny = GetParaListAutoFormat(*pTextNd);
471 break;
473 default:
474 assert(false);
477 else
479 eNewState = PropertyState_DEFAULT_VALUE;
481 // #i30838# set default values for default properties
482 switch (rEntry.nWID)
484 case FN_UNO_NUM_LEVEL:
486 *pAny <<= static_cast<sal_Int16>( 0 );
487 break;
489 case FN_UNO_IS_NUMBER:
491 *pAny <<= false;
492 break;
494 // #i91601#
495 case FN_UNO_LIST_ID:
497 *pAny <<= OUString();
498 break;
500 case FN_NUMBER_NEWSTART:
502 *pAny <<= false;
503 break;
505 case FN_UNO_PARA_NUM_AUTO_FORMAT:
507 break; // void
509 default:
510 assert(false);
513 //PROPERTY_MAYBEVOID!
515 break;
516 case FN_UNO_NUM_RULES :
517 if( pAny )
518 getNumberingProperty(rPam, eNewState, pAny);
519 else
521 if( !SwDoc::GetNumRuleAtPos( *rPam.GetPoint() ) )
522 eNewState = PropertyState_DEFAULT_VALUE;
524 break;
525 case FN_UNO_DOCUMENT_INDEX_MARK:
527 std::vector<SwTextAttr *> marks;
528 if (rPam.GetPointNode().IsTextNode())
530 marks = rPam.GetPointNode().GetTextNode()->GetTextAttrsAt(
531 rPam.GetPoint()->GetContentIndex(), RES_TXTATR_TOXMARK);
533 if (!marks.empty())
535 if( pAny )
536 { // hmm... can only return 1 here
537 SwTOXMark & rMark =
538 static_cast<SwTOXMark &>((*marks.begin())->GetAttr());
539 const uno::Reference< text::XDocumentIndexMark > xRef =
540 SwXDocumentIndexMark::CreateXDocumentIndexMark(
541 rPam.GetDoc(), &rMark);
542 (*pAny) <<= xRef;
545 else
546 //also here - indistinguishable
547 eNewState = PropertyState_DEFAULT_VALUE;
549 break;
550 case FN_UNO_DOCUMENT_INDEX:
552 SwTOXBase* pBase = SwDoc::GetCurTOX(
553 *rPam.Start() );
554 if( pBase )
556 if( pAny )
558 const uno::Reference< text::XDocumentIndex > xRef =
559 SwXDocumentIndex::CreateXDocumentIndex(rPam.GetDoc(),
560 static_cast<SwTOXBaseSection *>(pBase));
561 (*pAny) <<= xRef;
564 else
565 eNewState = PropertyState_DEFAULT_VALUE;
567 break;
568 case FN_UNO_TEXT_FIELD:
570 const SwPosition *pPos = rPam.Start();
571 const SwTextNode *pTextNd =
572 rPam.GetDoc().GetNodes()[pPos->GetNodeIndex()]->GetTextNode();
573 const SwTextAttr* pTextAttr = pTextNd
574 ? pTextNd->GetFieldTextAttrAt(pPos->GetContentIndex(), ::sw::GetTextAttrMode::Default)
575 : nullptr;
576 if ( pTextAttr != nullptr )
578 if( pAny )
580 uno::Reference<text::XTextField> const xField(
581 SwXTextField::CreateXTextField(&rPam.GetDoc(),
582 &pTextAttr->GetFormatField()));
583 *pAny <<= xField;
586 else
587 eNewState = PropertyState_DEFAULT_VALUE;
589 break;
590 case FN_UNO_TEXT_TABLE:
591 case FN_UNO_CELL:
593 SwStartNode* pSttNode = rPam.GetPointNode().StartOfSectionNode();
594 SwStartNodeType eType = pSttNode->GetStartNodeType();
595 if(SwTableBoxStartNode == eType)
597 if( pAny )
599 const SwTableNode* pTableNode = pSttNode->FindTableNode();
600 SwFrameFormat* pTableFormat = pTableNode->GetTable().GetFrameFormat();
601 //SwTable& rTable = static_cast<SwTableNode*>(pSttNode)->GetTable();
602 if(FN_UNO_TEXT_TABLE == rEntry.nWID)
604 uno::Reference< XTextTable > xTable = SwXTextTables::GetObject(*pTableFormat);
605 *pAny <<= xTable;
607 else
609 SwTableBox* pBox = pSttNode->GetTableBox();
610 uno::Reference< XCell > xCell = SwXCell::CreateXCell(pTableFormat, pBox);
611 *pAny <<= xCell;
615 else
616 eNewState = PropertyState_DEFAULT_VALUE;
618 break;
619 case FN_UNO_TEXT_FRAME:
621 SwStartNode* pSttNode = rPam.GetPointNode().StartOfSectionNode();
622 SwStartNodeType eType = pSttNode->GetStartNodeType();
624 SwFrameFormat* pFormat;
625 if(eType == SwFlyStartNode && nullptr != (pFormat = pSttNode->GetFlyFormat()))
627 // Create a wrapper only for text frames, not for graphic or OLE nodes.
628 if (pAny && !rPam.GetPointNode().IsNoTextNode())
630 uno::Reference<XTextFrame> const xFrame(
631 SwXTextFrame::CreateXTextFrame(*pFormat->GetDoc(), pFormat));
632 (*pAny) <<= xFrame;
635 else
636 eNewState = PropertyState_DEFAULT_VALUE;
638 break;
639 case FN_UNO_TEXT_SECTION:
641 SwSection* pSect = SwDoc::GetCurrSection(*rPam.GetPoint());
642 if(pSect)
644 if( pAny )
646 uno::Reference< XTextSection > xSect = SwXTextSections::GetObject( *pSect->GetFormat() );
647 *pAny <<= xSect;
650 else
651 eNewState = PropertyState_DEFAULT_VALUE;
653 break;
654 case FN_UNO_TEXT_PARAGRAPH:
656 SwTextNode* pTextNode = rPam.GetPoint()->GetNode().GetTextNode();
657 if (pTextNode)
659 if (pAny)
661 uno::Reference<text::XTextContent> xParagraph = SwXParagraph::CreateXParagraph(pTextNode->GetDoc(), pTextNode);
662 *pAny <<= xParagraph;
665 else
666 eNewState = PropertyState_DEFAULT_VALUE;
668 break;
669 case FN_UNO_SORTED_TEXT_ID:
671 if( pAny )
673 sal_Int32 nIndex = -1;
674 SwTextNode* pTextNode = rPam.GetPoint()->GetNode().GetTextNode();
675 if ( pTextNode )
676 nIndex = pTextNode->GetIndex().get();
677 *pAny <<= nIndex;
680 break;
681 case FN_UNO_ENDNOTE:
682 case FN_UNO_FOOTNOTE:
684 SwTextAttr *const pTextAttr = rPam.GetPointNode().IsTextNode() ?
685 rPam.GetPointNode().GetTextNode()->GetTextAttrForCharAt(
686 rPam.GetPoint()->GetContentIndex(), RES_TXTATR_FTN) : nullptr;
687 if(pTextAttr)
689 const SwFormatFootnote& rFootnote = pTextAttr->GetFootnote();
690 if(rFootnote.IsEndNote() == (FN_UNO_ENDNOTE == rEntry.nWID))
692 if( pAny )
694 const uno::Reference< text::XFootnote > xFootnote =
695 SwXFootnote::CreateXFootnote(rPam.GetDoc(),
696 &const_cast<SwFormatFootnote&>(rFootnote));
697 *pAny <<= xFootnote;
700 else
701 eNewState = PropertyState_DEFAULT_VALUE;
703 else
704 eNewState = PropertyState_DEFAULT_VALUE;
706 break;
707 case FN_UNO_REFERENCE_MARK:
709 std::vector<SwTextAttr *> marks;
710 if (rPam.GetPointNode().IsTextNode())
712 marks = rPam.GetPointNode().GetTextNode()->GetTextAttrsAt(
713 rPam.GetPoint()->GetContentIndex(), RES_TXTATR_REFMARK);
715 if (!marks.empty())
717 if( pAny )
718 { // hmm... can only return 1 here
719 const SwFormatRefMark& rRef = (*marks.begin())->GetRefMark();
720 uno::Reference<XTextContent> const xRef =
721 SwXReferenceMark::CreateXReferenceMark(rPam.GetDoc(),
722 const_cast<SwFormatRefMark*>(&rRef));
723 *pAny <<= xRef;
726 else
727 eNewState = PropertyState_DEFAULT_VALUE;
729 break;
730 case FN_UNO_NESTED_TEXT_CONTENT:
732 uno::Reference<XTextContent> const xRet(rPam.GetPointNode().IsTextNode()
733 ? GetNestedTextContent(*rPam.GetPointNode().GetTextNode(),
734 rPam.GetPoint()->GetContentIndex(), false)
735 : nullptr);
736 if (xRet.is())
738 if (pAny)
740 (*pAny) <<= xRet;
743 else
745 eNewState = PropertyState_DEFAULT_VALUE;
748 break;
749 case FN_UNO_CHARFMT_SEQUENCE:
752 SwTextNode *const pTextNode = rPam.GetPointNode().GetTextNode();
753 if (&rPam.GetPointNode() == &rPam.GetMarkNode()
754 && pTextNode && pTextNode->GetpSwpHints())
756 sal_Int32 nPaMStart = rPam.Start()->GetContentIndex();
757 sal_Int32 nPaMEnd = rPam.End()->GetContentIndex();
758 Sequence< OUString> aCharStyles;
759 SwpHints* pHints = pTextNode->GetpSwpHints();
760 for( size_t nAttr = 0; nAttr < pHints->Count(); ++nAttr )
762 SwTextAttr* pAttr = pHints->Get( nAttr );
763 if(pAttr->Which() != RES_TXTATR_CHARFMT)
764 continue;
765 const sal_Int32 nAttrStart = pAttr->GetStart();
766 const sal_Int32 nAttrEnd = *pAttr->GetEnd();
767 //check if the attribute touches the selection
768 if( ( nAttrEnd > nPaMStart && nAttrStart < nPaMEnd ) ||
769 ( !nAttrStart && !nAttrEnd && !nPaMStart && !nPaMEnd ) )
771 //check for overlapping
772 if(nAttrStart > nPaMStart ||
773 nAttrEnd < nPaMEnd)
775 aCharStyles.realloc(0);
776 break;
778 else
780 //now the attribute should start before or at the selection
781 //and it should end at the end of the selection or behind
782 OSL_ENSURE(nAttrStart <= nPaMStart && nAttrEnd >=nPaMEnd,
783 "attribute overlaps or is outside");
784 //now the name of the style has to be added to the sequence
785 aCharStyles.realloc(aCharStyles.getLength() + 1);
786 OSL_ENSURE(pAttr->GetCharFormat().GetCharFormat(), "no character format set");
787 aCharStyles.getArray()[aCharStyles.getLength() - 1] =
788 SwStyleNameMapper::GetProgName(
789 pAttr->GetCharFormat().GetCharFormat()->GetName(), SwGetPoolIdFromName::ChrFmt);
794 eNewState =
795 aCharStyles.hasElements() ?
796 PropertyState_DIRECT_VALUE : PropertyState_DEFAULT_VALUE;
797 if(pAny)
798 (*pAny) <<= aCharStyles;
800 else
801 eNewState = PropertyState_DEFAULT_VALUE;
803 break;
804 case RES_TXTATR_CHARFMT:
805 // no break here!
806 default: bDone = false;
808 if( bDone )
809 eState = eNewState;
810 return bDone;
813 sal_Int16 IsNodeNumStart(SwPaM const & rPam, PropertyState& eState)
815 const SwTextNode* pTextNd = rPam.GetPointNode().GetTextNode();
816 // correction: check, if restart value is set at the text node and use
817 // new method <SwTextNode::GetAttrListRestartValue()> to retrieve the value
818 if ( pTextNd && pTextNd->GetNumRule() && pTextNd->IsListRestart() &&
819 pTextNd->HasAttrListRestartValue() )
821 eState = PropertyState_DIRECT_VALUE;
822 sal_Int16 nTmp = sal::static_int_cast< sal_Int16 >(pTextNd->GetAttrListRestartValue());
823 return nTmp;
825 eState = PropertyState_DEFAULT_VALUE;
826 return -1;
829 void setNumberingProperty(const Any& rValue, SwPaM& rPam)
831 uno::Reference<XIndexReplace> xIndexReplace;
832 if(rValue >>= xIndexReplace)
834 auto pSwNum = dynamic_cast<SwXNumberingRules*>(xIndexReplace.get());
835 if(pSwNum)
837 SwDoc& rDoc = rPam.GetDoc();
838 if(pSwNum->GetNumRule())
840 SwNumRule aRule(*pSwNum->GetNumRule());
841 const OUString* pNewCharStyles = pSwNum->GetNewCharStyleNames();
842 const OUString* pBulletFontNames = pSwNum->GetBulletFontNames();
843 for(sal_uInt16 i = 0; i < MAXLEVEL; i++)
845 SwNumFormat aFormat(aRule.Get( i ));
846 if (!pNewCharStyles[i].isEmpty() &&
847 !SwXNumberingRules::isInvalidStyle(pNewCharStyles[i]) &&
848 (!aFormat.GetCharFormat() || pNewCharStyles[i] != aFormat.GetCharFormat()->GetName()))
850 if (pNewCharStyles[i].isEmpty())
852 // FIXME
853 // Is something missing/wrong here?
854 // if condition is always false due to outer check!
855 aFormat.SetCharFormat(nullptr);
857 else
860 // get CharStyle and set the rule
861 const size_t nChCount = rDoc.GetCharFormats()->size();
862 SwCharFormat* pCharFormat = nullptr;
863 for(size_t nCharFormat = 0; nCharFormat < nChCount; ++nCharFormat)
865 SwCharFormat& rChFormat = *((*(rDoc.GetCharFormats()))[nCharFormat]);
866 if(rChFormat.GetName() == pNewCharStyles[i])
868 pCharFormat = &rChFormat;
869 break;
873 if(!pCharFormat)
875 SfxStyleSheetBasePool* pPool = rDoc.GetDocShell()->GetStyleSheetPool();
876 SfxStyleSheetBase* pBase;
877 pBase = pPool->Find(pNewCharStyles[i], SfxStyleFamily::Char);
878 // shall it really be created?
879 if(!pBase)
880 pBase = &pPool->Make(pNewCharStyles[i], SfxStyleFamily::Page);
881 pCharFormat = static_cast<SwDocStyleSheet*>(pBase)->GetCharFormat();
883 if(pCharFormat)
884 aFormat.SetCharFormat(pCharFormat);
887 //Now again for fonts
889 !pBulletFontNames[i].isEmpty() &&
890 !SwXNumberingRules::isInvalidStyle(pBulletFontNames[i]) &&
891 (!aFormat.GetBulletFont() || aFormat.GetBulletFont()->GetFamilyName() != pBulletFontNames[i])
894 const SvxFontListItem* pFontListItem =
895 static_cast<const SvxFontListItem* >(rDoc.GetDocShell()
896 ->GetItem( SID_ATTR_CHAR_FONTLIST ));
897 const FontList* pList = pFontListItem->GetFontList();
899 FontMetric aFontMetric = pList->Get(
900 pBulletFontNames[i],WEIGHT_NORMAL, ITALIC_NONE);
901 vcl::Font aFont(aFontMetric);
902 aFormat.SetBulletFont(&aFont);
904 aRule.Set( i, aFormat );
906 UnoActionContext aAction(&rDoc);
908 if( rPam.GetNext() != &rPam ) // Multiple selection?
910 rDoc.GetIDocumentUndoRedo().StartUndo( SwUndoId::START, nullptr );
911 SwPamRanges aRangeArr( rPam );
912 SwPaM aPam( *rPam.GetPoint() );
913 for ( size_t n = 0; n < aRangeArr.Count(); ++n )
915 // no start of a new list
916 rDoc.SetNumRule( aRangeArr.SetPam( n, aPam ), aRule, false );
918 rDoc.GetIDocumentUndoRedo().EndUndo( SwUndoId::END, nullptr );
920 else
922 // no start of a new list
923 rDoc.SetNumRule( rPam, aRule, false );
927 else if(!pSwNum->GetCreatedNumRuleName().isEmpty())
929 UnoActionContext aAction( &rDoc );
930 SwNumRule* pRule = rDoc.FindNumRulePtr( pSwNum->GetCreatedNumRuleName() );
931 if ( !pRule )
932 throw RuntimeException();
933 // no start of a new list
934 rDoc.SetNumRule( rPam, *pRule, false );
936 else
938 // #i103817#
939 // outline numbering
940 UnoActionContext aAction(&rDoc);
941 SwNumRule* pRule = rDoc.GetOutlineNumRule();
942 if(!pRule)
943 throw RuntimeException();
944 rDoc.SetNumRule( rPam, *pRule, false );
948 else if ( rValue.getValueType() == cppu::UnoType<void>::get() )
950 rPam.GetDoc().DelNumRules(rPam);
954 void getNumberingProperty(SwPaM& rPam, PropertyState& eState, Any * pAny )
956 const SwNumRule* pNumRule = SwDoc::GetNumRuleAtPos( *rPam.GetPoint() );
957 if(pNumRule)
959 uno::Reference< XIndexReplace > xNum = new SwXNumberingRules(*pNumRule);
960 if ( pAny )
961 *pAny <<= xNum;
962 eState = PropertyState_DIRECT_VALUE;
964 else
965 eState = PropertyState_DEFAULT_VALUE;
968 void GetCurPageStyle(SwPaM const & rPaM, OUString &rString)
970 if (!rPaM.GetPointContentNode())
971 return; // TODO: is there an easy way to get it for tables/sections?
972 SwRootFrame* pLayout = rPaM.GetDoc().getIDocumentLayoutAccess().GetCurrentLayout();
973 // Consider the position inside the content node, since the node may span over multiple pages
974 // with different page styles.
975 SwContentFrame* pFrame = rPaM.GetPointContentNode()->getLayoutFrame(pLayout, rPaM.GetPoint());
976 if(pFrame)
978 const SwPageFrame* pPage = pFrame->FindPageFrame();
979 if(pPage)
981 SwStyleNameMapper::FillProgName(pPage->GetPageDesc()->GetName(),
982 rString, SwGetPoolIdFromName::PageDesc);
987 // reset special properties of the cursor
988 void resetCursorPropertyValue(const SfxItemPropertyMapEntry& rEntry, SwPaM& rPam)
990 SwDoc& rDoc = rPam.GetDoc();
991 switch(rEntry.nWID)
993 case FN_UNO_PARA_STYLE :
994 break;
995 case FN_UNO_PAGE_STYLE :
996 break;
997 case FN_UNO_NUM_START_VALUE :
999 UnoActionContext aAction(&rDoc);
1001 if( rPam.GetNext() != &rPam ) // Multiple selection?
1003 rDoc.GetIDocumentUndoRedo().StartUndo( SwUndoId::START, nullptr );
1004 SwPamRanges aRangeArr( rPam );
1005 SwPaM aPam( *rPam.GetPoint() );
1006 for( size_t n = 0; n < aRangeArr.Count(); ++n )
1007 rDoc.SetNodeNumStart( *aRangeArr.SetPam( n, aPam ).GetPoint(), 1 );
1008 rDoc.GetIDocumentUndoRedo().EndUndo( SwUndoId::END, nullptr );
1010 else
1011 rDoc.SetNodeNumStart( *rPam.GetPoint(), 0 );
1014 break;
1015 case FN_UNO_NUM_LEVEL :
1016 break;
1017 case FN_UNO_NUM_RULES:
1018 break;
1019 case FN_UNO_CHARFMT_SEQUENCE:
1021 rDoc.ResetAttrs(rPam, true, { RES_TXTATR_CHARFMT });
1023 break;
1027 void InsertFile(SwUnoCursor* pUnoCursor, const OUString& rURL,
1028 const uno::Sequence< beans::PropertyValue >& rOptions)
1030 if (SwTextNode const*const pTextNode = pUnoCursor->GetPoint()->GetNode().GetTextNode())
1032 // TODO: check meta field here too in case it ever grows a 2nd char
1033 if (pTextNode->GetTextAttrAt(pUnoCursor->GetPoint()->GetContentIndex(),
1034 RES_TXTATR_INPUTFIELD, ::sw::GetTextAttrMode::Parent))
1036 throw uno::RuntimeException("cannot insert file inside input field");
1039 if (pTextNode->GetTextAttrAt(pUnoCursor->GetPoint()->GetContentIndex(),
1040 RES_TXTATR_CONTENTCONTROL, ::sw::GetTextAttrMode::Parent))
1042 throw uno::RuntimeException("cannot insert file inside content controls");
1046 std::unique_ptr<SfxMedium> pMed;
1047 SwDoc& rDoc = pUnoCursor->GetDoc();
1048 SwDocShell* pDocSh = rDoc.GetDocShell();
1049 utl::MediaDescriptor aMediaDescriptor( rOptions );
1050 OUString sFileName = rURL;
1051 OUString sFilterName, sFilterOptions, sPassword, sBaseURL;
1052 uno::Reference < io::XStream > xStream;
1053 uno::Reference < io::XInputStream > xInputStream;
1055 if( sFileName.isEmpty() )
1056 aMediaDescriptor[utl::MediaDescriptor::PROP_URL] >>= sFileName;
1057 if( sFileName.isEmpty() )
1058 aMediaDescriptor[utl::MediaDescriptor::PROP_FILENAME] >>= sFileName;
1059 aMediaDescriptor[utl::MediaDescriptor::PROP_INPUTSTREAM] >>= xInputStream;
1060 aMediaDescriptor[utl::MediaDescriptor::PROP_STREAM] >>= xStream;
1061 aMediaDescriptor[utl::MediaDescriptor::PROP_INPUTSTREAM] >>= xInputStream;
1062 aMediaDescriptor[utl::MediaDescriptor::PROP_FILTERNAME] >>= sFilterName;
1063 aMediaDescriptor[utl::MediaDescriptor::PROP_FILTEROPTIONS] >>= sFilterOptions;
1064 aMediaDescriptor[utl::MediaDescriptor::PROP_PASSWORD] >>= sPassword;
1065 aMediaDescriptor[utl::MediaDescriptor::PROP_DOCUMENTBASEURL ] >>= sBaseURL;
1066 if ( !xInputStream.is() && xStream.is() )
1067 xInputStream = xStream->getInputStream();
1069 if(!pDocSh || (sFileName.isEmpty() && !xInputStream.is()))
1070 return;
1072 SfxObjectFactory& rFact = pDocSh->GetFactory();
1073 std::shared_ptr<const SfxFilter> pFilter = rFact.GetFilterContainer()->GetFilter4FilterName( sFilterName );
1074 uno::Reference < embed::XStorage > xReadStorage;
1075 if( xInputStream.is() )
1077 uno::Sequence< uno::Any > aArgs{ uno::Any(xInputStream),
1078 uno::Any(embed::ElementModes::READ) };
1081 xReadStorage.set( ::comphelper::OStorageHelper::GetStorageFactory()->createInstanceWithArguments( aArgs ),
1082 uno::UNO_QUERY );
1084 catch( const io::IOException&) {}
1086 if ( !pFilter )
1088 if( xInputStream.is() && !xReadStorage.is())
1090 pMed.reset(new SfxMedium);
1091 pMed->setStreamToLoadFrom(xInputStream, true );
1093 else
1094 pMed.reset(xReadStorage.is() ?
1095 new SfxMedium(xReadStorage, sBaseURL ) :
1096 new SfxMedium(sFileName, StreamMode::READ ));
1097 if( !sBaseURL.isEmpty() )
1098 pMed->GetItemSet()->Put( SfxStringItem( SID_DOC_BASEURL, sBaseURL ) );
1100 SfxFilterMatcher aMatcher( rFact.GetFilterContainer()->GetName() );
1101 ErrCode nErr = aMatcher.GuessFilter(*pMed, pFilter, SfxFilterFlags::NONE);
1102 if ( nErr || !pFilter)
1103 return;
1104 pMed->SetFilter( pFilter );
1106 else
1108 if( xInputStream.is() && !xReadStorage.is())
1110 pMed.reset(new SfxMedium);
1111 pMed->setStreamToLoadFrom(xInputStream, true );
1112 pMed->SetFilter( pFilter );
1114 else
1116 if( xReadStorage.is() )
1118 pMed.reset(new SfxMedium(xReadStorage, sBaseURL ));
1119 pMed->SetFilter( pFilter );
1121 else
1122 pMed.reset(new SfxMedium(sFileName, StreamMode::READ, pFilter, nullptr));
1124 if(!sFilterOptions.isEmpty())
1125 pMed->GetItemSet()->Put( SfxStringItem( SID_FILE_FILTEROPTIONS, sFilterOptions ) );
1126 if(!sBaseURL.isEmpty())
1127 pMed->GetItemSet()->Put( SfxStringItem( SID_DOC_BASEURL, sBaseURL ) );
1130 // this sourcecode is not responsible for the lifetime of the shell, SfxObjectShellLock should not be used
1131 SfxObjectShellRef aRef( pDocSh );
1133 pMed->Download(); // if necessary: start the download
1134 if( !(aRef.is() && 1 < aRef->GetRefCount()) ) // Ref still valid?
1135 return;
1137 SwReaderPtr pRdr;
1138 SfxItemSet* pSet = pMed->GetItemSet();
1139 pSet->Put(SfxBoolItem(FN_API_CALL, true));
1140 if(!sPassword.isEmpty())
1141 pSet->Put(SfxStringItem(SID_PASSWORD, sPassword));
1142 Reader *pRead = pDocSh->StartConvertFrom( *pMed, pRdr, nullptr, pUnoCursor);
1143 if( !pRead )
1144 return;
1146 UnoActionContext aContext(&rDoc);
1148 if(pUnoCursor->HasMark())
1149 rDoc.getIDocumentContentOperations().DeleteAndJoin(*pUnoCursor);
1151 SwNodeIndex aSave( pUnoCursor->GetPoint()->GetNode(), -1 );
1152 sal_Int32 nContent = pUnoCursor->GetPoint()->GetContentIndex();
1154 ErrCode nErrno = pRdr->Read( *pRead ); // and paste the document
1156 if(!nErrno)
1158 ++aSave;
1159 pUnoCursor->SetMark();
1160 pUnoCursor->GetMark()->Assign( aSave );
1162 SwContentNode* pCntNode = aSave.GetNode().GetContentNode();
1163 if( !pCntNode )
1164 nContent = 0;
1165 pUnoCursor->GetMark()->SetContent( nContent );
1169 // insert text and scan for CR characters in order to insert
1170 // paragraph breaks at those positions by calling SplitNode
1171 bool DocInsertStringSplitCR(
1172 SwDoc &rDoc,
1173 const SwPaM &rNewCursor,
1174 std::u16string_view rText,
1175 const bool bForceExpandHints )
1177 bool bOK = true;
1179 for (size_t i = 0; i < rText.size(); ++i)
1181 sal_Unicode const ch(rText[i]);
1182 if (linguistic::IsControlChar(ch)
1183 && ch != '\r' && ch != '\n' && ch != '\t')
1185 SAL_WARN("sw.uno", "DocInsertStringSplitCR: refusing to insert control character " << int(ch));
1186 return false;
1190 const SwInsertFlags nInsertFlags =
1191 bForceExpandHints
1192 ? ( SwInsertFlags::FORCEHINTEXPAND | SwInsertFlags::EMPTYEXPAND)
1193 : SwInsertFlags::EMPTYEXPAND;
1195 // grouping done in InsertString is intended for typing, not API calls
1196 ::sw::GroupUndoGuard const undoGuard(rDoc.GetIDocumentUndoRedo());
1197 SwTextNode* const pTextNd =
1198 rNewCursor.GetPoint()->GetNode().GetTextNode();
1199 if (!pTextNd)
1201 SAL_INFO("sw.uno", "DocInsertStringSplitCR: need a text node");
1202 return false;
1204 OUString aText;
1205 sal_Int32 nStartIdx = 0;
1206 const sal_Int32 nMaxLength = COMPLETE_STRING - pTextNd->GetText().getLength();
1208 size_t nIdx = rText.find( '\r', nStartIdx );
1209 if( ( nIdx == std::u16string_view::npos && nMaxLength < sal_Int32(rText.size()) ) ||
1210 ( nIdx != std::u16string_view::npos && nMaxLength < sal_Int32(nIdx) ) )
1212 nIdx = nMaxLength;
1214 while (nIdx != std::u16string_view::npos )
1216 OSL_ENSURE( sal_Int32(nIdx) - nStartIdx >= 0, "index negative!" );
1217 aText = rText.substr( nStartIdx, nIdx - nStartIdx );
1218 if (!aText.isEmpty() &&
1219 !rDoc.getIDocumentContentOperations().InsertString( rNewCursor, aText, nInsertFlags ))
1221 OSL_FAIL( "Doc->Insert(Str) failed." );
1222 bOK = false;
1224 if (!rDoc.getIDocumentContentOperations().SplitNode( *rNewCursor.GetPoint(), false ) )
1226 OSL_FAIL( "SplitNode failed" );
1227 bOK = false;
1229 nStartIdx = nIdx + 1;
1230 nIdx = rText.find( '\r', nStartIdx );
1232 aText = rText.substr( nStartIdx );
1233 if (!aText.isEmpty() &&
1234 !rDoc.getIDocumentContentOperations().InsertString( rNewCursor, aText, nInsertFlags ))
1236 OSL_FAIL( "Doc->Insert(Str) failed." );
1237 bOK = false;
1240 return bOK;
1243 void makeRedline( SwPaM const & rPaM,
1244 std::u16string_view rRedlineType,
1245 const uno::Sequence< beans::PropertyValue >& rRedlineProperties )
1247 IDocumentRedlineAccess& rRedlineAccess = rPaM.GetDoc().getIDocumentRedlineAccess();
1249 RedlineType eType;
1250 if ( rRedlineType == u"Insert" )
1251 eType = RedlineType::Insert;
1252 else if ( rRedlineType == u"Delete" )
1253 eType = RedlineType::Delete;
1254 else if ( rRedlineType == u"Format" )
1255 eType = RedlineType::Format;
1256 else if ( rRedlineType == u"TextTable" )
1257 eType = RedlineType::Table;
1258 else if ( rRedlineType == u"ParagraphFormat" )
1259 eType = RedlineType::ParagraphFormat;
1260 else
1261 throw lang::IllegalArgumentException();
1263 //todo: what about REDLINE_FMTCOLL?
1264 std::size_t nAuthor = 0;
1265 OUString sAuthor;
1266 OUString sComment;
1267 ::util::DateTime aStamp;
1268 uno::Sequence< beans::PropertyValue > aRevertProperties;
1269 bool bIsMoved = false;
1270 bool bFoundComment = false;
1271 bool bFoundStamp = false;
1272 bool bFoundRevertProperties = false;
1273 for (const css::beans::PropertyValue & rProp : rRedlineProperties )
1275 if (rProp.Name == "RedlineAuthor")
1277 if( rProp.Value >>= sAuthor )
1278 nAuthor = rRedlineAccess.InsertRedlineAuthor(sAuthor);
1280 else if (rProp.Name == "RedlineComment")
1281 bFoundComment = rProp.Value >>= sComment;
1282 else if (rProp.Name == "RedlineDateTime")
1283 bFoundStamp = rProp.Value >>= aStamp;
1284 else if (rProp.Name == "RedlineRevertProperties")
1285 bFoundRevertProperties = rProp.Value >>= aRevertProperties;
1286 else if (rProp.Name == "RedlineMoved")
1287 rProp.Value >>= bIsMoved;
1290 SwRedlineData aRedlineData( eType, nAuthor );
1291 if( bFoundComment )
1292 aRedlineData.SetComment( sComment );
1293 if( bFoundStamp )
1294 aRedlineData.SetTimeStamp( DateTime( aStamp));
1296 std::unique_ptr<SwRedlineExtraData_FormatColl> xRedlineExtraData;
1298 // Read the 'Redline Revert Properties' from the parameters
1299 // Check if the value exists
1300 if ( bFoundRevertProperties )
1302 int nMap = 0;
1303 // Make sure that paragraph format gets its own map, otherwise e.g. fill attributes are not preserved.
1304 if (eType == RedlineType::ParagraphFormat)
1306 nMap = PROPERTY_MAP_PARAGRAPH;
1307 if (!aRevertProperties.hasElements())
1309 // to reject the paragraph style change, use standard style
1310 xRedlineExtraData.reset(new SwRedlineExtraData_FormatColl( "", RES_POOLCOLL_STANDARD, nullptr ));
1313 else
1314 nMap = PROPERTY_MAP_TEXTPORTION_EXTENSIONS;
1315 SfxItemPropertySet const& rPropSet = *aSwMapProvider.GetPropertySet(nMap);
1317 // Check if there are any properties
1318 if (aRevertProperties.hasElements())
1320 SwDoc& rDoc = rPaM.GetDoc();
1322 // Build set of attributes we want to fetch
1323 WhichRangesContainer aWhichPairs;
1324 std::vector<SfxItemPropertyMapEntry const*> aEntries;
1325 std::vector<uno::Any> aValues;
1326 aEntries.reserve(aRevertProperties.getLength());
1327 sal_uInt16 nStyleId = USHRT_MAX;
1328 sal_uInt16 nNumId = USHRT_MAX;
1329 for (const auto& rRevertProperty : std::as_const(aRevertProperties))
1331 const OUString &rPropertyName = rRevertProperty.Name;
1332 SfxItemPropertyMapEntry const* pEntry = rPropSet.getPropertyMap().getByName(rPropertyName);
1334 if (!pEntry)
1336 // unknown property
1337 break;
1339 else if (pEntry->nFlags & beans::PropertyAttribute::READONLY)
1341 break;
1343 else if (rPropertyName == "NumberingRules")
1345 aWhichPairs = aWhichPairs.MergeRange(RES_PARATR_NUMRULE, RES_PARATR_NUMRULE);
1346 nNumId = aEntries.size();
1348 else
1350 aWhichPairs = aWhichPairs.MergeRange(pEntry->nWID, pEntry->nWID);
1351 if (rPropertyName == "ParaStyleName")
1352 nStyleId = aEntries.size();
1354 aEntries.push_back(pEntry);
1355 aValues.push_back(rRevertProperty.Value);
1358 if (!aWhichPairs.empty())
1360 sal_uInt16 nStylePoolId = USHRT_MAX;
1361 OUString sParaStyleName, sUIStyle;
1362 SfxItemSet aItemSet(rDoc.GetAttrPool(), std::move(aWhichPairs));
1364 for (size_t i = 0; i < aEntries.size(); ++i)
1366 const uno::Any &rValue = aValues[i];
1367 if (i == nNumId)
1369 uno::Reference<container::XNamed> xNumberingRules;
1370 rValue >>= xNumberingRules;
1371 if (xNumberingRules.is())
1373 aItemSet.Put( SwNumRuleItem( xNumberingRules->getName() ));
1374 // keep it during export
1375 SwNumRule* pRule = rDoc.FindNumRulePtr(
1376 xNumberingRules->getName());
1377 if (pRule)
1378 pRule->SetUsedByRedline(true);
1381 else
1383 SfxItemPropertyMapEntry const*const pEntry = aEntries[i];
1384 rPropSet.setPropertyValue(*pEntry, rValue, aItemSet);
1385 if (i == nStyleId)
1386 rValue >>= sParaStyleName;
1390 if (eType == RedlineType::ParagraphFormat && sParaStyleName.isEmpty())
1391 nStylePoolId = RES_POOLCOLL_STANDARD;
1393 // tdf#149747 Get UI style name from programmatic style name
1394 SwStyleNameMapper::FillUIName(sParaStyleName, sUIStyle,
1395 SwGetPoolIdFromName::TxtColl);
1396 xRedlineExtraData.reset(new SwRedlineExtraData_FormatColl(
1397 sUIStyle.isEmpty() ? sParaStyleName : sUIStyle, nStylePoolId, &aItemSet));
1399 else if (eType == RedlineType::ParagraphFormat)
1400 xRedlineExtraData.reset(new SwRedlineExtraData_FormatColl( "", RES_POOLCOLL_STANDARD, nullptr ));
1404 SwRangeRedline* pRedline = new SwRangeRedline( aRedlineData, rPaM );
1406 // set IsMoved bit of the redline to show and handle moved text
1407 if( bIsMoved )
1408 pRedline->SetMoved();
1410 RedlineFlags nPrevMode = rRedlineAccess.GetRedlineFlags( );
1411 // xRedlineExtraData is copied here
1412 pRedline->SetExtraData( xRedlineExtraData.get() );
1414 rRedlineAccess.SetRedlineFlags_intern(RedlineFlags::On);
1415 auto const result(rRedlineAccess.AppendRedline(pRedline, false));
1416 rRedlineAccess.SetRedlineFlags_intern( nPrevMode );
1417 if (IDocumentRedlineAccess::AppendResult::IGNORED == result)
1418 throw lang::IllegalArgumentException();
1421 void makeTableRowRedline( SwTableLine& rTableLine,
1422 std::u16string_view rRedlineType,
1423 const uno::Sequence< beans::PropertyValue >& rRedlineProperties )
1425 SwDoc* pDoc = rTableLine.GetFrameFormat()->GetDoc();
1426 IDocumentRedlineAccess* pRedlineAccess = &pDoc->getIDocumentRedlineAccess();
1428 RedlineType eType;
1429 if ( rRedlineType == u"TableRowInsert" )
1431 eType = RedlineType::TableRowInsert;
1433 else if ( rRedlineType == u"TableRowDelete" )
1435 eType = RedlineType::TableRowDelete;
1437 else
1439 throw lang::IllegalArgumentException();
1442 // set table row property "HasTextChangesOnly" to false
1443 // to handle tracked deletion or insertion of the table row on the UI
1444 const SvxPrintItem *pHasTextChangesOnlyProp =
1445 rTableLine.GetFrameFormat()->GetAttrSet().GetItem<SvxPrintItem>(RES_PRINT);
1446 if ( !pHasTextChangesOnlyProp || pHasTextChangesOnlyProp->GetValue() )
1448 SvxPrintItem aSetTracking(RES_PRINT, false);
1449 SwNodeIndex aInsPos( *(rTableLine.GetTabBoxes()[0]->GetSttNd()), 1 );
1450 // as a workaround for the rows without text content,
1451 // add a redline with invisible text CH_TXT_TRACKED_DUMMY_CHAR
1452 if ( rTableLine.IsEmpty() )
1454 SwPaM aPaM(aInsPos);
1455 pDoc->getIDocumentContentOperations().InsertString( aPaM,
1456 OUStringChar(CH_TXT_TRACKED_DUMMY_CHAR) );
1457 aPaM.SetMark();
1458 aPaM.GetMark()->SetContent(0);
1459 makeRedline(aPaM, RedlineType::TableRowInsert == eType
1460 ? u"Insert"
1461 : u"Delete", rRedlineProperties);
1463 SwCursor aCursor( SwPosition(aInsPos), nullptr );
1464 pDoc->SetRowNotTracked( aCursor, aSetTracking );
1467 comphelper::SequenceAsHashMap aPropMap( rRedlineProperties );
1468 std::size_t nAuthor = 0;
1469 OUString sAuthor;
1470 if( aPropMap.getValue("RedlineAuthor") >>= sAuthor )
1471 nAuthor = pRedlineAccess->InsertRedlineAuthor(sAuthor);
1473 OUString sComment;
1474 SwRedlineData aRedlineData( eType, nAuthor );
1475 if( aPropMap.getValue("RedlineComment") >>= sComment )
1476 aRedlineData.SetComment( sComment );
1478 ::util::DateTime aStamp;
1479 if( aPropMap.getValue("RedlineDateTime") >>= aStamp )
1481 aRedlineData.SetTimeStamp(
1482 DateTime( Date( aStamp.Day, aStamp.Month, aStamp.Year ), tools::Time( aStamp.Hours, aStamp.Minutes, aStamp.Seconds ) ) );
1485 SwTableRowRedline* pRedline = new SwTableRowRedline( aRedlineData, rTableLine );
1486 RedlineFlags nPrevMode = pRedlineAccess->GetRedlineFlags( );
1487 pRedline->SetExtraData( nullptr );
1489 pRedlineAccess->SetRedlineFlags_intern(RedlineFlags::On);
1490 bool bRet = pRedlineAccess->AppendTableRowRedline( pRedline );
1491 pRedlineAccess->SetRedlineFlags_intern( nPrevMode );
1492 if( !bRet )
1493 throw lang::IllegalArgumentException();
1496 void makeTableCellRedline( SwTableBox& rTableBox,
1497 std::u16string_view rRedlineType,
1498 const uno::Sequence< beans::PropertyValue >& rRedlineProperties )
1500 SwDoc* pDoc = rTableBox.GetFrameFormat()->GetDoc();
1501 IDocumentRedlineAccess* pRedlineAccess = &pDoc->getIDocumentRedlineAccess();
1503 RedlineType eType;
1504 if ( rRedlineType == u"TableCellInsert" )
1506 eType = RedlineType::TableCellInsert;
1508 else if ( rRedlineType == u"TableCellDelete" )
1510 eType = RedlineType::TableCellDelete;
1512 else
1514 throw lang::IllegalArgumentException();
1517 // set table row property "HasTextChangesOnly" to false
1518 // to handle tracked deletion or insertion of the table row on the UI
1519 const SvxPrintItem *pHasTextChangesOnlyProp =
1520 rTableBox.GetFrameFormat()->GetAttrSet().GetItem<SvxPrintItem>(RES_PRINT);
1521 if ( !pHasTextChangesOnlyProp || pHasTextChangesOnlyProp->GetValue() )
1523 SvxPrintItem aSetTracking(RES_PRINT, false);
1524 SwNodeIndex aInsPos( *rTableBox.GetSttNd(), 1 );
1525 // as a workaround for the cells without text content,
1526 // add a redline with invisible text CH_TXT_TRACKED_DUMMY_CHAR
1527 if ( rTableBox.IsEmpty() )
1529 SwPaM aPaM(aInsPos);
1530 pDoc->getIDocumentContentOperations().InsertString( aPaM,
1531 OUStringChar(CH_TXT_TRACKED_DUMMY_CHAR) );
1532 aPaM.SetMark();
1533 aPaM.GetMark()->SetContent(0);
1534 makeRedline(aPaM, RedlineType::TableCellInsert == eType
1535 ? u"Insert"
1536 : u"Delete", rRedlineProperties);
1538 SwCursor aCursor( SwPosition(aInsPos), nullptr );
1539 pDoc->SetBoxAttr( aCursor, aSetTracking );
1542 comphelper::SequenceAsHashMap aPropMap( rRedlineProperties );
1543 std::size_t nAuthor = 0;
1544 OUString sAuthor;
1545 if( aPropMap.getValue("RedlineAuthor") >>= sAuthor )
1546 nAuthor = pRedlineAccess->InsertRedlineAuthor(sAuthor);
1548 OUString sComment;
1549 SwRedlineData aRedlineData( eType, nAuthor );
1550 if( aPropMap.getValue("RedlineComment") >>= sComment )
1551 aRedlineData.SetComment( sComment );
1553 ::util::DateTime aStamp;
1554 if( aPropMap.getValue("RedlineDateTime") >>= aStamp )
1556 aRedlineData.SetTimeStamp(
1557 DateTime( Date( aStamp.Day, aStamp.Month, aStamp.Year ), tools::Time( aStamp.Hours, aStamp.Minutes, aStamp.Seconds ) ) );
1560 SwTableCellRedline* pRedline = new SwTableCellRedline( aRedlineData, rTableBox );
1561 RedlineFlags nPrevMode = pRedlineAccess->GetRedlineFlags( );
1562 pRedline->SetExtraData( nullptr );
1564 pRedlineAccess->SetRedlineFlags_intern(RedlineFlags::On);
1565 bool bRet = pRedlineAccess->AppendTableCellRedline( pRedline );
1566 pRedlineAccess->SetRedlineFlags_intern( nPrevMode );
1567 if( !bRet )
1568 throw lang::IllegalArgumentException();
1571 void SwAnyMapHelper::SetValue( sal_uInt16 nWhichId, sal_uInt16 nMemberId, const uno::Any& rAny )
1573 sal_uInt32 nKey = (nWhichId << 16) + nMemberId;
1574 m_Map[nKey] = rAny;
1577 bool SwAnyMapHelper::FillValue( sal_uInt16 nWhichId, sal_uInt16 nMemberId, const uno::Any*& pAny )
1579 bool bRet = false;
1580 sal_uInt32 nKey = (nWhichId << 16) + nMemberId;
1581 auto aIt = m_Map.find( nKey );
1582 if (aIt != m_Map.end())
1584 pAny = & aIt->second;
1585 bRet = true;
1587 return bRet;
1590 }//namespace SwUnoCursorHelper
1592 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */