1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <sal/config.h>
22 #include <sal/log.hxx>
23 #include <osl/diagnose.h>
27 #include <hintids.hxx>
30 #include <svl/cintitem.hxx>
31 #include <svl/stritem.hxx>
32 #include <fmtanchr.hxx>
34 #include <redline.hxx>
37 #include <IDocumentFieldsAccess.hxx>
38 #include <IDocumentRedlineAccess.hxx>
39 #include <IDocumentLayoutAccess.hxx>
40 #include <IDocumentMarkAccess.hxx>
43 #include <docufld.hxx>
47 #include <bookmark.hxx>
48 #include <fltshell.hxx>
49 #include <rdfhelper.hxx>
52 using namespace com::sun::star
;
54 static SwContentNode
* GetContentNode(SwDoc
& rDoc
, SwPosition
& rPos
, bool bNext
)
56 SwContentNode
* pCNd
= rPos
.GetNode().GetContentNode();
57 if(!pCNd
&& nullptr == (pCNd
= bNext
? rDoc
.GetNodes().GoNext(&rPos
)
58 : SwNodes::GoPrevious(&rPos
)))
60 pCNd
= bNext
? SwNodes::GoPrevious(&rPos
)
61 : rDoc
.GetNodes().GoNext(&rPos
);
62 OSL_ENSURE(pCNd
, "no ContentNode found");
67 static OUString
lcl_getTypePath(OUString
& rType
)
70 if (rType
.startsWith("urn:bails"))
73 aRet
= "tscp/bails.rdf";
78 // Stack entry for all text attributes
79 SwFltStackEntry::SwFltStackEntry(const SwPosition
& rStartPos
, std::unique_ptr
<SfxPoolItem
> pHt
)
82 , m_pAttr( std::move(pHt
) )
83 , m_isAnnotationOnEnd(false)
85 m_bOld
= false; // used for marking Attributes *before* skipping field results
86 m_bOpen
= true; // lock the attribute --> may first
87 m_bConsumedByField
= false;
90 SwFltStackEntry::~SwFltStackEntry()
92 // Although attribute got passed as pointer, it gets deleted here
95 void SwFltStackEntry::SetEndPos(const SwPosition
& rEndPos
)
97 // Release attribute and keep track of end
98 // Everything with sal_uInt16s, lest the inserting of new text at
99 // the cursor position moves the attribute's range
100 // That's not the desired behavior!
101 m_bOpen
= false; // release and remember END
102 m_aPtPos
.FromSwPosition(rEndPos
);
105 bool SwFltStackEntry::MakeRegion(SwDoc
& rDoc
, SwPaM
& rRegion
, RegionMode
const eCheck
,
106 const SwFltPosition
&rMkPos
, const SwFltPosition
&rPtPos
,
109 // does this range actually contain something?
110 // empty range is allowed if at start of empty paragraph
111 // fields are special: never have range, so leave them
112 SwNodeOffset nMk
= rMkPos
.m_nNode
.GetIndex() + 1;
113 const SwNodes
& rMkNodes
= rMkPos
.m_nNode
.GetNodes();
114 if (nMk
>= rMkNodes
.Count())
116 SwContentNode
*const pContentNode(rMkNodes
[nMk
]->GetContentNode());
117 if (rMkPos
== rPtPos
&&
118 ((0 != rPtPos
.m_nContent
) || (pContentNode
&& (0 != pContentNode
->Len())))
119 && ( RES_TXTATR_FIELD
!= nWhich
120 && RES_TXTATR_ANNOTATION
!= nWhich
121 && RES_TXTATR_INPUTFIELD
!= nWhich
))
125 // The content indices always apply to the node!
126 rRegion
.GetPoint()->Assign( rMkPos
.m_nNode
.GetIndex() + 1 );
127 SwContentNode
* pCNd
= GetContentNode(rDoc
, *rRegion
.GetPoint(), true);
129 SAL_WARN_IF(pCNd
->Len() < rMkPos
.m_nContent
, "sw.ww8",
130 "invalid content index " << rMkPos
.m_nContent
<< " but text node has only " << pCNd
->Len());
131 rRegion
.GetPoint()->SetContent( std::min
<sal_Int32
>(rMkPos
.m_nContent
, pCNd
->Len()) );
133 if (rMkPos
.m_nNode
!= rPtPos
.m_nNode
)
135 SwNodeOffset n
= rPtPos
.m_nNode
.GetIndex() + 1;
136 SwNodes
& rNodes
= rRegion
.GetPoint()->GetNodes();
137 if (n
>= rNodes
.Count())
139 rRegion
.GetPoint()->Assign(n
);
140 pCNd
= GetContentNode(rDoc
, *rRegion
.GetPoint(), false);
142 SAL_WARN_IF(pCNd
->Len() < rPtPos
.m_nContent
, "sw.ww8",
143 "invalid content index " << rPtPos
.m_nContent
<< " but text node has only " << pCNd
->Len());
144 rRegion
.GetPoint()->SetContent( std::min
<sal_Int32
>(rPtPos
.m_nContent
, pCNd
->Len()) );
145 OSL_ENSURE( CheckNodesRange( rRegion
.Start()->GetNode(),
146 rRegion
.End()->GetNode(), true ),
147 "attribute or similar crosses section-boundaries" );
149 if (eCheck
& RegionMode::CheckNodes
)
151 bRet
&= CheckNodesRange(rRegion
.Start()->GetNode(),
152 rRegion
.End()->GetNode(), true);
154 if (eCheck
& RegionMode::CheckFieldmark
)
156 bRet
&= !sw::mark::IsFieldmarkOverlap(rRegion
);
161 bool SwFltStackEntry::MakeRegion(SwDoc
& rDoc
, SwPaM
& rRegion
, RegionMode eCheck
) const
163 return MakeRegion(rDoc
, rRegion
, eCheck
, m_aMkPos
, m_aPtPos
, m_pAttr
->Which());
166 SwFltControlStack::SwFltControlStack(SwDoc
& rDo
, sal_uLong nFieldFl
)
167 : m_nFieldFlags(nFieldFl
), m_rDoc(rDo
), m_bIsEndStack(false)
171 SwFltControlStack::~SwFltControlStack()
173 OSL_ENSURE(m_Entries
.empty(), "There are still Attributes on the stack");
176 // MoveAttrs() is meant to address the following problem:
177 // When a field like "set variable" is set through the stack, the text
178 // is shifted by one \xff character, which makes all subsequent
179 // attribute positions invalid.
180 // After setting the attribute in the doc, MoveAttrs() needs to be
181 // called in order to push all attribute positions to the right in the
182 // same paragraph further out by one character.
183 void SwFltControlStack::MoveAttrs(const SwPosition
& rPos
, MoveAttrsMode eMode
)
185 SwNodeOffset nPosNd
= rPos
.GetNodeIndex();
186 sal_uInt16 nPosCt
= rPos
.GetContentIndex() - 1;
188 for (size_t i
= 0, nCnt
= m_Entries
.size(); i
< nCnt
; ++i
)
190 SwFltStackEntry
& rEntry
= *m_Entries
[i
];
192 (rEntry
.m_aMkPos
.m_nNode
.GetIndex()+1 == nPosNd
) &&
193 (rEntry
.m_aMkPos
.m_nContent
>= nPosCt
)
196 rEntry
.m_aMkPos
.m_nContent
++;
197 OSL_ENSURE( rEntry
.m_aMkPos
.m_nContent
198 <= m_rDoc
.GetNodes()[nPosNd
]->GetContentNode()->Len(),
199 "Attribute ends after end of line" );
202 (rEntry
.m_aPtPos
.m_nNode
.GetIndex()+1 == nPosNd
) &&
203 (rEntry
.m_aPtPos
.m_nContent
>= nPosCt
)
206 if ( !rEntry
.m_isAnnotationOnEnd
207 || rEntry
.m_aPtPos
.m_nContent
> nPosCt
)
209 assert(!(rEntry
.m_isAnnotationOnEnd
&& rEntry
.m_aPtPos
.m_nContent
> nPosCt
));
210 if ( eMode
== MoveAttrsMode::POSTIT_INSERTED
211 && rEntry
.m_aPtPos
.m_nContent
== nPosCt
212 && rEntry
.m_pAttr
->Which() == RES_FLTR_ANNOTATIONMARK
)
214 rEntry
.m_isAnnotationOnEnd
= true;
215 eMode
= MoveAttrsMode::DEFAULT
; // only set 1 flag
217 rEntry
.m_aPtPos
.m_nContent
++;
218 OSL_ENSURE( rEntry
.m_aPtPos
.m_nContent
219 <= m_rDoc
.GetNodes()[nPosNd
]->GetContentNode()->Len(),
220 "Attribute ends after end of line" );
226 void SwFltControlStack::MarkAllAttrsOld()
228 size_t nCnt
= m_Entries
.size();
229 for (size_t i
=0; i
< nCnt
; ++i
)
230 m_Entries
[i
]->m_bOld
= true;
235 bool couldExtendEntry(const SwFltStackEntry
*pExtendCandidate
,
236 const SfxPoolItem
& rAttr
)
238 return (pExtendCandidate
&&
239 !pExtendCandidate
->m_bConsumedByField
&&
240 //if we bring character attributes into the fold we need to both
241 //a) consider RES_CHRATR_FONTSIZE and RES_CHRATR_FONT wrt Word's CJK/CTL variants
242 //b) consider crossing table cell boundaries (tdf#102334)
243 isPARATR_LIST(rAttr
.Which()) &&
244 *(pExtendCandidate
->m_pAttr
) == rAttr
);
248 void SwFltControlStack::NewAttr(const SwPosition
& rPos
, const SfxPoolItem
& rAttr
)
250 sal_uInt16 nWhich
= rAttr
.Which();
251 // Set end position of potentially equal attributes on stack, so
252 // as to avoid having them accumulate
253 SwFltStackEntry
*pExtendCandidate
= SetAttr(rPos
, nWhich
);
254 if (couldExtendEntry(pExtendCandidate
, rAttr
))
256 //Here we optimize by seeing if there is an attribute uncommitted
257 //to the document which
259 //a) has the same value as this attribute
260 //b) is already open, or ends at the same place as where we're starting
261 //from. If so we merge it with this one and elide adding another
263 pExtendCandidate
->SetEndPos(rPos
);
264 pExtendCandidate
->m_bOpen
=true;
268 SwFltStackEntry
*pTmp
= new SwFltStackEntry(rPos
, std::unique_ptr
<SfxPoolItem
>(rAttr
.Clone()) );
269 m_Entries
.push_back(std::unique_ptr
<SwFltStackEntry
>(pTmp
));
273 void SwFltControlStack::DeleteAndDestroy(Entries::size_type nCnt
)
275 OSL_ENSURE(nCnt
< m_Entries
.size(), "Out of range!");
276 if (nCnt
< m_Entries
.size())
278 auto aElement
= m_Entries
.begin() + nCnt
;
279 m_Entries
.erase(aElement
);
283 // SwFltControlStack::StealAttr() removes attributes of the given type
284 // from the stack. Allowed as nAttrId: 0 meaning any, or a specific
285 // type. This makes them disappear from the doc structure. Only
286 // attributes from the same paragraph as rPos are removed. Used for
287 // graphic apos -> images.
288 void SwFltControlStack::StealAttr(const SwNode
& rNode
)
290 size_t nCnt
= m_Entries
.size();
295 SwFltStackEntry
& rEntry
= *m_Entries
[nCnt
];
296 if (rEntry
.m_aPtPos
.m_nNode
.GetIndex()+1 == rNode
.GetIndex())
298 DeleteAndDestroy(nCnt
); // delete from the stack
303 // SwFltControlStack::KillUnlockedAttr() removes all attributes from
304 // the stack, which are assigned to an rPos. This makes them disappear
305 // from the doc structure. Used in WW import for ignoring attributes
306 // assigned to the 0x0c section break symbol.
307 void SwFltControlStack::KillUnlockedAttrs(const SwPosition
& rPos
)
309 SwFltPosition
aFltPos(rPos
);
311 size_t nCnt
= m_Entries
.size();
315 SwFltStackEntry
& rEntry
= *m_Entries
[nCnt
];
318 && (rEntry
.m_aMkPos
== aFltPos
)
319 && (rEntry
.m_aPtPos
== aFltPos
))
321 DeleteAndDestroy( nCnt
); // remove from stack
326 // Unlock all locked attributes and move to the end, all others will
327 // be applied to the document and removed from the stack.
328 // Returns if there were any selected attributes on the stack
329 SwFltStackEntry
* SwFltControlStack::SetAttr(const SwPosition
& rPos
,
330 sal_uInt16 nAttrId
, bool bTstEnd
, tools::Long nHand
,
331 bool consumedByField
)
333 SwFltStackEntry
*pRet
= nullptr;
335 SwFltPosition
aFltPos(rPos
);
337 OSL_ENSURE(!nAttrId
||
338 (POOLATTR_BEGIN
<= nAttrId
&& POOLATTR_END
> nAttrId
) ||
339 (RES_FLTRATTR_BEGIN
<= nAttrId
&& RES_FLTRATTR_END
> nAttrId
),
340 "Wrong id for attribute");
342 auto aI
= m_Entries
.begin();
343 while (aI
!= m_Entries
.end())
345 bool bLastEntry
= aI
== m_Entries
.end() - 1;
347 SwFltStackEntry
& rEntry
= **aI
;
350 // set end of attribute
356 else if (nAttrId
== rEntry
.m_pAttr
->Which())
358 if( nAttrId
!= RES_FLTR_BOOKMARK
&& nAttrId
!= RES_FLTR_ANNOTATIONMARK
&& nAttrId
!= RES_FLTR_RDFMARK
)
363 else if (nAttrId
== RES_FLTR_BOOKMARK
&& nHand
== static_cast<SwFltBookmark
*>(rEntry
.m_pAttr
.get())->GetHandle())
367 else if (nAttrId
== RES_FLTR_ANNOTATIONMARK
&& nHand
== static_cast<CntUInt16Item
*>(rEntry
.m_pAttr
.get())->GetValue())
371 else if (nAttrId
== RES_FLTR_RDFMARK
&& nHand
== static_cast<SwFltRDFMark
*>(rEntry
.m_pAttr
.get())->GetHandle())
378 rEntry
.m_bConsumedByField
= consumedByField
;
379 rEntry
.SetEndPos(rPos
);
380 if (bLastEntry
&& nAttrId
== rEntry
.m_pAttr
->Which())
382 //potential candidate for merging with an identical
383 //property beginning at rPos
391 // if the end position is equal to the cursor position, then
392 // refrain from applying it; there needs to be following text,
393 // except at the very end. (attribute expansion !!)
394 // Never apply end stack except at document ending
403 //defer inserting this attribute into the document until
404 //we advance to the next node, or finish processing the document
405 if (rEntry
.m_aPtPos
.m_nNode
.GetIndex() == aFltPos
.m_nNode
.GetIndex())
407 if (bLastEntry
&& nAttrId
== rEntry
.m_pAttr
->Which() &&
408 rEntry
.m_aPtPos
.m_nContent
== aFltPos
.m_nContent
)
410 //potential candidate for merging with an identical
411 //property beginning at rPos
419 SetAttrInDoc(rPos
, rEntry
);
420 aI
= m_Entries
.erase(aI
);
426 static bool MakePoint(const SwFltStackEntry
& rEntry
, SwDoc
& rDoc
,
429 // the anchor is the Pam's Point. It's modified when inserting
430 // text, etc.; therefore it is kept on the stack. Only the
431 // attribute's format needs to be set.
432 rRegion
.DeleteMark();
434 SwNodeOffset nMk
= rEntry
.m_aMkPos
.m_nNode
.GetIndex() + 1;
435 const SwNodes
& rMkNodes
= rEntry
.m_aMkPos
.m_nNode
.GetNodes();
436 if (nMk
>= rMkNodes
.Count())
439 rRegion
.GetPoint()->Assign(nMk
);
440 GetContentNode(rDoc
, *rRegion
.GetPoint(), true);
441 rRegion
.GetPoint()->SetContent(rEntry
.m_aMkPos
.m_nContent
);
445 // MakeBookRegionOrPoint() behaves like MakeRegionOrPoint, except that
446 // it adheres to certain restrictions on bookmarks in tables (cannot
447 // span more than one cell)
448 static bool MakeBookRegionOrPoint(const SwFltStackEntry
& rEntry
, SwDoc
& rDoc
,
451 if (rEntry
.MakeRegion(rDoc
, rRegion
, SwFltStackEntry::RegionMode::CheckNodes
))
453 if (rRegion
.GetPoint()->GetNode().FindTableBoxStartNode()
454 != rRegion
.GetMark()->GetNode().FindTableBoxStartNode())
456 rRegion
.Exchange(); // invalid range
457 rRegion
.DeleteMark(); // -> both to mark
461 return MakePoint(rEntry
, rDoc
, rRegion
);
464 // IterateNumrulePiece() looks for the first range valid for Numrules
465 // between rTmpStart and rEnd.
467 // rNds denotes the doc nodes
468 // rEnd denotes the range end,
469 // rTmpStart is an in/out parameter: in: start of range to be searched,
470 // out: start of valid range
471 // rTmpEnd is an out parameter
472 // Returns true for valid range
473 static bool IterateNumrulePiece( const SwPosition
& rEnd
,
474 SwNodeIndex
& rTmpStart
, SwNodeIndex
& rTmpEnd
)
476 while( ( rTmpStart
<= rEnd
.GetNode() )
477 && !( rTmpStart
.GetNode().IsTextNode() ) ) // look for valid start
481 while( ( rTmpEnd
<= rEnd
.GetNode() )
482 && ( rTmpEnd
.GetNode().IsTextNode() ) ) // look for valid end + 1
485 --rTmpEnd
; // valid end
487 return rTmpStart
<= rTmpEnd
; // valid ?
490 void SwFltControlStack::SetAttrInDoc(const SwPosition
& rTmpPos
,
491 SwFltStackEntry
& rEntry
)
493 SwPaM
aRegion( rTmpPos
);
495 switch(rEntry
.m_pAttr
->Which())
497 case RES_FLTR_ANCHOR
:
499 SwFrameFormat
* pFormat
= static_cast<SwFltAnchor
*>(rEntry
.m_pAttr
.get())->GetFrameFormat();
500 if (pFormat
!= nullptr)
502 MakePoint(rEntry
, m_rDoc
, aRegion
);
503 SwFormatAnchor
aAnchor(pFormat
->GetAnchor());
504 aAnchor
.SetAnchor(aRegion
.GetPoint());
505 pFormat
->SetFormatAttr(aAnchor
);
506 // So the frames will be created when inserting into
507 // existing doc (after setting the anchor!):
508 if (m_rDoc
.getIDocumentLayoutAccess().GetCurrentViewShell()
509 && (RndStdIds::FLY_AT_PARA
== pFormat
->GetAnchor().GetAnchorId()))
511 pFormat
->MakeFrames();
517 case RES_TXTATR_FIELD
:
518 case RES_TXTATR_ANNOTATION
:
519 case RES_TXTATR_INPUTFIELD
:
522 case RES_TXTATR_TOXMARK
:
525 case RES_FLTR_NUMRULE
: // insert Numrule
527 const OUString
& rNumNm
= static_cast<SfxStringItem
*>(rEntry
.m_pAttr
.get())->GetValue();
528 SwNumRule
* pNumRule
= m_rDoc
.FindNumRulePtr( rNumNm
);
531 if (rEntry
.MakeRegion(m_rDoc
, aRegion
, SwFltStackEntry::RegionMode::CheckNodes
))
533 SwNodeIndex
aTmpStart( aRegion
.Start()->GetNode() );
534 SwNodeIndex
aTmpEnd( aTmpStart
);
535 SwPosition
& rRegEndNd
= *aRegion
.End();
536 while( IterateNumrulePiece( rRegEndNd
,
537 aTmpStart
, aTmpEnd
) )
539 SwPaM
aTmpPam( aTmpStart
, aTmpEnd
);
540 // no start of a new list
541 m_rDoc
.SetNumRule( aTmpPam
, *pNumRule
, false );
543 aTmpStart
= aTmpEnd
; // here starts the next range
548 m_rDoc
.DelNumRule( rNumNm
);
553 case RES_FLTR_BOOKMARK
:
555 SwFltBookmark
* pB
= static_cast<SwFltBookmark
*>(rEntry
.m_pAttr
.get());
556 const OUString
& rName
= static_cast<SwFltBookmark
*>(rEntry
.m_pAttr
.get())->GetName();
558 if (IsFlagSet(BOOK_TO_VAR_REF
))
560 SwFieldType
* pFT
= m_rDoc
.getIDocumentFieldsAccess().GetFieldType(SwFieldIds::SetExp
, rName
, false);
563 SwSetExpFieldType
aS(&m_rDoc
, rName
, nsSwGetSetExpType::GSE_STRING
);
564 pFT
= m_rDoc
.getIDocumentFieldsAccess().InsertFieldType(aS
);
566 SwSetExpField
aField(static_cast<SwSetExpFieldType
*>(pFT
), pB
->GetValSys());
567 aField
.SetSubType( nsSwExtendedSubType::SUB_INVISIBLE
);
568 MakePoint(rEntry
, m_rDoc
, aRegion
);
569 m_rDoc
.getIDocumentContentOperations().InsertPoolItem(aRegion
, SwFormatField(aField
));
570 MoveAttrs( *(aRegion
.GetPoint()) );
572 if ( ( !IsFlagSet(HYPO
) || IsFlagSet(BOOK_AND_REF
) ) &&
573 !rEntry
.m_bConsumedByField
)
575 MakeBookRegionOrPoint(rEntry
, m_rDoc
, aRegion
);
576 // #i120879# - create a cross reference heading bookmark if appropriate.
577 const IDocumentMarkAccess::MarkType eBookmarkType
=
578 ( pB
->IsTOCBookmark() &&
579 IDocumentMarkAccess::IsLegalPaMForCrossRefHeadingBookmark( aRegion
) )
580 ? IDocumentMarkAccess::MarkType::CROSSREF_HEADING_BOOKMARK
581 : IDocumentMarkAccess::MarkType::BOOKMARK
;
582 m_rDoc
.getIDocumentMarkAccess()->makeMark(aRegion
, rName
, eBookmarkType
, sw::mark::InsertMode::New
);
586 case RES_FLTR_ANNOTATIONMARK
:
588 if (MakeBookRegionOrPoint(rEntry
, m_rDoc
, aRegion
))
590 SwTextNode
const*const pTextNode(
591 aRegion
.End()->GetNode().GetTextNode());
592 SwTextField
const*const pField
= pTextNode
? pTextNode
->GetFieldTextAttrAt(
593 aRegion
.End()->GetContentIndex() - 1, ::sw::GetTextAttrMode::Default
) : nullptr;
596 SwPostItField
const*const pPostIt(
597 dynamic_cast<SwPostItField
const*>(pField
->GetFormatField().GetField()));
600 assert(pPostIt
->GetName().isEmpty());
602 if (!aRegion
.HasMark())
604 // Annotation range was found in the file, but start/end is the same,
605 // pointing after the postit placeholder (see assert above).
606 // Adjust the start of the range to actually cover the comment, similar
607 // to what the UI and the UNO API does.
609 aRegion
.Start()->AdjustContent(-1);
612 m_rDoc
.getIDocumentMarkAccess()->makeAnnotationMark(aRegion
, OUString());
616 SAL_WARN("sw", "RES_FLTR_ANNOTATIONMARK: unexpected field");
621 SAL_WARN("sw", "RES_FLTR_ANNOTATIONMARK: missing field");
625 SAL_WARN("sw", "failed to make book region or point");
628 case RES_FLTR_RDFMARK
:
630 if (MakeBookRegionOrPoint(rEntry
, m_rDoc
, aRegion
))
632 SwFltRDFMark
* pMark
= static_cast<SwFltRDFMark
*>(rEntry
.m_pAttr
.get());
633 if (aRegion
.GetPointNode().IsTextNode())
635 SwTextNode
& rTextNode
= *aRegion
.GetPointNode().GetTextNode();
637 for (const std::pair
<OUString
, OUString
>& rAttribute
: pMark
->GetAttributes())
639 OUString aTypeNS
= rAttribute
.first
;
640 OUString aMetadataFilePath
= lcl_getTypePath(aTypeNS
);
641 if (aMetadataFilePath
.isEmpty())
644 SwRDFHelper::addTextNodeStatement(aTypeNS
, aMetadataFilePath
, rTextNode
, rAttribute
.first
, rAttribute
.second
);
649 SAL_WARN("sw", "failed to make book region or point");
654 MakePoint(rEntry
, m_rDoc
, aRegion
);
656 SwPosition
* pPoint
= aRegion
.GetPoint();
658 SwFltTOX
* pTOXAttr
= static_cast<SwFltTOX
*>(rEntry
.m_pAttr
.get());
660 // test if on this node there had been a pagebreak BEFORE the
661 // tox attribute was put on the stack
662 SfxItemSetFixed
<RES_PAGEDESC
, RES_BREAK
> aBkSet( m_rDoc
.GetAttrPool() );
663 SwContentNode
* pNd
= nullptr;
664 if( !pTOXAttr
->HadBreakItem() || !pTOXAttr
->HadPageDescItem() )
666 pNd
= pPoint
->GetNode().GetContentNode();
669 const SfxItemSet
* pSet
= pNd
->GetpSwAttrSet();
670 const SfxPoolItem
* pItem
;
673 if( !pTOXAttr
->HadBreakItem()
674 && SfxItemState::SET
== pSet
->GetItemState( RES_BREAK
, false, &pItem
) )
676 aBkSet
.Put( *pItem
);
677 pNd
->ResetAttr( RES_BREAK
);
679 if( !pTOXAttr
->HadPageDescItem()
680 && SfxItemState::SET
== pSet
->GetItemState( RES_PAGEDESC
, false, &pItem
) )
682 aBkSet
.Put( *pItem
);
683 pNd
->ResetAttr( RES_PAGEDESC
);
689 // set (above saved and removed) the break item at the node following the TOX
690 if (pNd
&& aBkSet
.Count())
691 pNd
->SetAttr(aBkSet
);
694 case RES_FLTR_REDLINE
:
696 if (rEntry
.MakeRegion(m_rDoc
, aRegion
,
697 SwFltStackEntry::RegionMode::CheckNodes
|SwFltStackEntry::RegionMode::CheckFieldmark
))
699 m_rDoc
.getIDocumentRedlineAccess().SetRedlineFlags( RedlineFlags::On
700 | RedlineFlags::ShowInsert
701 | RedlineFlags::ShowDelete
);
702 SwFltRedline
& rFltRedline
= *static_cast<SwFltRedline
*>(rEntry
.m_pAttr
.get());
704 SwRedlineData
aData(rFltRedline
.m_eType
,
705 rFltRedline
.m_nAutorNo
,
706 rFltRedline
.m_aStamp
,
710 m_rDoc
.getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline(aData
, aRegion
), true );
711 m_rDoc
.getIDocumentRedlineAccess().SetRedlineFlags( RedlineFlags::NONE
712 | RedlineFlags::ShowInsert
713 | RedlineFlags::ShowDelete
);
719 if (rEntry
.MakeRegion(m_rDoc
, aRegion
, SwFltStackEntry::RegionMode::NoCheck
))
721 m_rDoc
.getIDocumentContentOperations().InsertPoolItem(aRegion
, *rEntry
.m_pAttr
);
728 SfxPoolItem
* SwFltControlStack::GetFormatStackAttr(sal_uInt16 nWhich
, sal_uInt16
* pPos
)
730 size_t nSize
= m_Entries
.size();
734 // is it the looked-for attribute ? (only applies to locked, meaning
735 // currently set attributes!!)
736 SwFltStackEntry
&rEntry
= *m_Entries
[--nSize
];
737 if (rEntry
.m_bOpen
&& rEntry
.m_pAttr
->Which() == nWhich
)
741 return rEntry
.m_pAttr
.get(); // Ok, so stop
747 const SfxPoolItem
* SwFltControlStack::GetOpenStackAttr(const SwPosition
& rPos
, sal_uInt16 nWhich
)
749 SwFltPosition
aFltPos(rPos
);
751 size_t nSize
= m_Entries
.size();
755 SwFltStackEntry
&rEntry
= *m_Entries
[--nSize
];
756 if (rEntry
.m_bOpen
&& rEntry
.m_pAttr
->Which() == nWhich
&& rEntry
.m_aMkPos
== aFltPos
)
758 return rEntry
.m_pAttr
.get();
764 void SwFltControlStack::Delete(const SwPaM
&rPam
)
766 auto [pStt
, pEnd
] = rPam
.StartEnd(); // SwPosition*
768 if( !rPam
.HasMark() || *pStt
>= *pEnd
)
771 SwNodeIndex
aStartNode(pStt
->GetNode(), -1);
772 const sal_Int32 nStartIdx
= pStt
->GetContentIndex();
773 SwNodeIndex
aEndNode(pEnd
->GetNode(), -1);
774 const sal_Int32 nEndIdx
= pEnd
->GetContentIndex();
776 // We don't support deleting content that is over one node, or removing a node.
777 OSL_ENSURE(aEndNode
== aStartNode
, "nodes must be the same, or this method extended");
778 if (aEndNode
!= aStartNode
)
781 for (size_t nSize
= m_Entries
.size(); nSize
> 0;)
783 SwFltStackEntry
& rEntry
= *m_Entries
[--nSize
];
785 bool bEntryStartAfterSelStart
=
786 (rEntry
.m_aMkPos
.m_nNode
== aStartNode
&&
787 rEntry
.m_aMkPos
.m_nContent
>= nStartIdx
);
789 bool bEntryStartBeforeSelEnd
=
790 (rEntry
.m_aMkPos
.m_nNode
== aEndNode
&&
791 rEntry
.m_aMkPos
.m_nContent
<= nEndIdx
);
793 bool bEntryEndAfterSelStart
= false;
794 bool bEntryEndBeforeSelEnd
= false;
797 bEntryEndAfterSelStart
=
798 (rEntry
.m_aPtPos
.m_nNode
== aStartNode
&&
799 rEntry
.m_aPtPos
.m_nContent
>= nStartIdx
);
801 bEntryEndBeforeSelEnd
=
802 (rEntry
.m_aPtPos
.m_nNode
== aEndNode
&&
803 rEntry
.m_aPtPos
.m_nContent
<= nEndIdx
);
806 bool bTotallyContained
= false;
808 bEntryStartAfterSelStart
&& bEntryStartBeforeSelEnd
&&
809 bEntryEndAfterSelStart
&& bEntryEndBeforeSelEnd
812 bTotallyContained
= true;
815 if (bTotallyContained
)
817 // after start, before end, delete
818 DeleteAndDestroy(nSize
);
822 const sal_Int32 nContentDiff
= nEndIdx
- nStartIdx
;
825 if (bEntryStartAfterSelStart
)
827 if (bEntryStartBeforeSelEnd
)
829 // move start to new start
830 rEntry
.m_aMkPos
.SetPos(aStartNode
, nStartIdx
);
833 rEntry
.m_aMkPos
.m_nContent
-= nContentDiff
;
836 if (bEntryEndAfterSelStart
)
838 if (bEntryEndBeforeSelEnd
)
839 rEntry
.m_aPtPos
.SetPos(aStartNode
, nStartIdx
);
841 rEntry
.m_aPtPos
.m_nContent
-= nContentDiff
;
844 //That's what Open is, end equal to start, and nPtContent is invalid
846 rEntry
.m_aPtPos
= rEntry
.m_aMkPos
;
850 // methods of SwFltAnchor follow
851 SwFltAnchor::SwFltAnchor(SwFrameFormat
* pFormat
) :
852 SfxPoolItem(RES_FLTR_ANCHOR
), m_pFrameFormat(pFormat
)
854 m_pListener
.reset(new SwFltAnchorListener(this));
855 m_pListener
->StartListening(m_pFrameFormat
->GetNotifier());
858 SwFltAnchor::SwFltAnchor(const SwFltAnchor
& rCpy
) :
859 SfxPoolItem(RES_FLTR_ANCHOR
), m_pFrameFormat(rCpy
.m_pFrameFormat
)
861 m_pListener
.reset(new SwFltAnchorListener(this));
862 m_pListener
->StartListening(m_pFrameFormat
->GetNotifier());
865 SwFltAnchor::~SwFltAnchor()
869 void SwFltAnchor::SetFrameFormat(SwFrameFormat
* _pFrameFormat
)
871 m_pFrameFormat
= _pFrameFormat
;
875 bool SwFltAnchor::operator==(const SfxPoolItem
& rItem
) const
877 return SfxPoolItem::operator==(rItem
) &&
878 m_pFrameFormat
== static_cast<const SwFltAnchor
&>(rItem
).m_pFrameFormat
;
881 SwFltAnchor
* SwFltAnchor::Clone(SfxItemPool
*) const
883 return new SwFltAnchor(*this);
886 SwFltAnchorListener::SwFltAnchorListener(SwFltAnchor
* pFltAnchor
)
887 : m_pFltAnchor(pFltAnchor
)
890 void SwFltAnchorListener::Notify(const SfxHint
& rHint
)
892 if (rHint
.GetId() == SfxHintId::Dying
)
893 m_pFltAnchor
->SetFrameFormat(nullptr);
894 else if (rHint
.GetId() == SfxHintId::SwDrawFrameFormat
)
896 auto pDrawFrameFormatHint
= static_cast<const sw::DrawFrameFormatHint
*>(&rHint
);
897 if (pDrawFrameFormatHint
->m_eId
!= sw::DrawFrameFormatHintId::DYING
)
899 m_pFltAnchor
->SetFrameFormat(nullptr);
901 else if (rHint
.GetId() == SfxHintId::SwLegacyModify
)
903 auto pLegacyHint
= static_cast<const sw::LegacyModifyHint
*>(&rHint
);
904 if(pLegacyHint
->m_pNew
->Which() != RES_FMT_CHG
)
906 auto pFormatChg
= dynamic_cast<const SwFormatChg
*>(pLegacyHint
->m_pNew
);
907 auto pFrameFormat
= pFormatChg
? dynamic_cast<SwFrameFormat
*>(pFormatChg
->pChangedFormat
) : nullptr;
909 m_pFltAnchor
->SetFrameFormat(pFrameFormat
);
913 // methods of SwFltRedline follow
914 bool SwFltRedline::operator==(const SfxPoolItem
& rItem
) const
916 return SfxPoolItem::operator==(rItem
) &&
920 SwFltRedline
* SwFltRedline::Clone( SfxItemPool
* ) const
922 return new SwFltRedline(*this);
925 // methods of SwFltBookmark follow
926 SwFltBookmark::SwFltBookmark( const OUString
& rNa
, OUString aVa
,
927 tools::Long nHand
, const bool bIsTOCBookmark
)
928 : SfxPoolItem( RES_FLTR_BOOKMARK
)
931 , maVal(std::move( aVa
))
932 , mbIsTOCBookmark( bIsTOCBookmark
)
934 // eSrc: CHARSET_DONTKNOW for no transform at operator <<
935 // Upcase is always done.
936 // Transform is never done at XXXStack.NewAttr(...).
937 // otherwise: Src Charset from argument for aName
938 // Src Charset from filter for aVal ( Text )
940 if ( IsTOCBookmark() && ! rNa
.startsWith(IDocumentMarkAccess::GetCrossRefHeadingBookmarkNamePrefix()) )
942 maName
= IDocumentMarkAccess::GetCrossRefHeadingBookmarkNamePrefix();
947 bool SwFltBookmark::operator==(const SfxPoolItem
& rItem
) const
949 return SfxPoolItem::operator==(rItem
)
950 && maName
== static_cast<const SwFltBookmark
&>(rItem
).maName
951 && mnHandle
== static_cast<const SwFltBookmark
&>(rItem
).mnHandle
;
954 SwFltBookmark
* SwFltBookmark::Clone(SfxItemPool
*) const
956 return new SwFltBookmark(*this);
959 SwFltRDFMark::SwFltRDFMark()
960 : SfxPoolItem(RES_FLTR_RDFMARK
),
965 bool SwFltRDFMark::operator==(const SfxPoolItem
& rItem
) const
967 if (!SfxPoolItem::operator==(rItem
))
970 const SwFltRDFMark
& rMark
= static_cast<const SwFltRDFMark
&>(rItem
);
972 return m_nHandle
== rMark
.m_nHandle
&& m_aAttributes
== rMark
.m_aAttributes
;
975 SwFltRDFMark
* SwFltRDFMark::Clone(SfxItemPool
*) const
977 return new SwFltRDFMark(*this);
980 void SwFltRDFMark::SetHandle(tools::Long nHandle
)
985 tools::Long
SwFltRDFMark::GetHandle() const
990 void SwFltRDFMark::SetAttributes( std::vector
< std::pair
<OUString
, OUString
> >&& rAttributes
)
992 m_aAttributes
= std::move(rAttributes
);
995 const std::vector
< std::pair
<OUString
, OUString
> >& SwFltRDFMark::GetAttributes() const
997 return m_aAttributes
;
1000 // methods of SwFltTOX follow
1001 SwFltTOX::SwFltTOX(std::shared_ptr
<SwTOXBase
> xBase
)
1002 : SfxPoolItem(RES_FLTR_TOX
), m_xTOXBase(std::move(xBase
)),
1003 m_bHadBreakItem( false ), m_bHadPageDescItem( false )
1007 bool SwFltTOX::operator==(const SfxPoolItem
& rItem
) const
1009 return SfxPoolItem::operator==(rItem
) &&
1010 m_xTOXBase
.get() == static_cast<const SwFltTOX
&>(rItem
).m_xTOXBase
.get();
1013 SwFltTOX
* SwFltTOX::Clone(SfxItemPool
*) const
1015 return new SwFltTOX(*this);
1018 // UpdatePageDescs needs to be called at end of parsing to make Writer actually
1019 // accept Pagedescs contents
1020 void UpdatePageDescs(SwDoc
&rDoc
, size_t nInPageDescOffset
)
1022 // Update document page descriptors (only this way also left pages
1025 // PageDesc "Standard"
1026 rDoc
.ChgPageDesc(0, rDoc
.GetPageDesc(0));
1028 // PageDescs "Convert..."
1029 for (size_t i
= nInPageDescOffset
; i
< rDoc
.GetPageDescCnt(); ++i
)
1030 rDoc
.ChgPageDesc(i
, rDoc
.GetPageDesc(i
));
1033 FrameDeleteWatch::FrameDeleteWatch(SwFrameFormat
* pFormat
)
1034 : m_pFormat(pFormat
)
1037 StartListening(pFormat
->GetNotifier());
1040 void FrameDeleteWatch::Notify(const SfxHint
& rHint
)
1042 bool bDying
= false;
1043 if (rHint
.GetId() == SfxHintId::Dying
)
1045 else if (rHint
.GetId() == SfxHintId::SwDrawFrameFormat
)
1047 auto pDrawFrameFormatHint
= static_cast<const sw::DrawFrameFormatHint
*>(&rHint
);
1048 bDying
= pDrawFrameFormatHint
->m_eId
== sw::DrawFrameFormatHintId::DYING
;
1052 m_pFormat
= nullptr;
1057 FrameDeleteWatch::~FrameDeleteWatch()
1059 m_pFormat
= nullptr;
1063 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */