android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / filter / basflt / fltshell.cxx
blobfbfec5eaeccf2c5f6d945605fc0140fb2159ee20
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 <memory>
21 #include <sal/config.h>
22 #include <sal/log.hxx>
23 #include <osl/diagnose.h>
25 #include <cstddef>
27 #include <hintids.hxx>
28 #include <hints.hxx>
30 #include <svl/cintitem.hxx>
31 #include <svl/stritem.hxx>
32 #include <fmtanchr.hxx>
33 #include <fmtfld.hxx>
34 #include <redline.hxx>
35 #include <pam.hxx>
36 #include <doc.hxx>
37 #include <IDocumentFieldsAccess.hxx>
38 #include <IDocumentRedlineAccess.hxx>
39 #include <IDocumentLayoutAccess.hxx>
40 #include <IDocumentMarkAccess.hxx>
41 #include <ndtxt.hxx>
42 #include <fldbas.hxx>
43 #include <docufld.hxx>
44 #include <txtfld.hxx>
45 #include <tox.hxx>
46 #include <expfld.hxx>
47 #include <bookmark.hxx>
48 #include <fltshell.hxx>
49 #include <rdfhelper.hxx>
50 #include <utility>
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");
64 return pCNd;
67 static OUString lcl_getTypePath(OUString& rType)
69 OUString aRet;
70 if (rType.startsWith("urn:bails"))
72 rType = "urn:bails";
73 aRet = "tscp/bails.rdf";
75 return aRet;
78 // Stack entry for all text attributes
79 SwFltStackEntry::SwFltStackEntry(const SwPosition& rStartPos, std::unique_ptr<SfxPoolItem> pHt)
80 : m_aMkPos(rStartPos)
81 , m_aPtPos(rStartPos)
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,
107 sal_uInt16 nWhich)
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())
115 return false;
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 ))
123 return false;
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()) );
132 rRegion.SetMark();
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())
138 return false;
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" );
148 bool bRet = true;
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);
158 return bRet;
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];
191 if (
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" );
201 if (
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;
233 namespace
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
262 //to the stack
263 pExtendCandidate->SetEndPos(rPos);
264 pExtendCandidate->m_bOpen=true;
266 else
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();
292 while (nCnt)
294 nCnt --;
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();
312 while( nCnt )
314 nCnt --;
315 SwFltStackEntry& rEntry = *m_Entries[nCnt];
316 if( !rEntry.m_bOld
317 && !rEntry.m_bOpen
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;
348 if (rEntry.m_bOpen)
350 // set end of attribute
351 bool bF = false;
352 if (!nAttrId )
354 bF = true;
356 else if (nAttrId == rEntry.m_pAttr->Which())
358 if( nAttrId != RES_FLTR_BOOKMARK && nAttrId != RES_FLTR_ANNOTATIONMARK && nAttrId != RES_FLTR_RDFMARK )
360 // query handle
361 bF = true;
363 else if (nAttrId == RES_FLTR_BOOKMARK && nHand == static_cast<SwFltBookmark*>(rEntry.m_pAttr.get())->GetHandle())
365 bF = true;
367 else if (nAttrId == RES_FLTR_ANNOTATIONMARK && nHand == static_cast<CntUInt16Item*>(rEntry.m_pAttr.get())->GetValue())
369 bF = true;
371 else if (nAttrId == RES_FLTR_RDFMARK && nHand == static_cast<SwFltRDFMark*>(rEntry.m_pAttr.get())->GetHandle())
373 bF = true;
376 if (bF)
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
384 pRet = &rEntry;
387 ++aI;
388 continue;
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
395 if (bTstEnd)
397 if (m_bIsEndStack)
399 ++aI;
400 continue;
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
412 pRet = &rEntry;
415 ++aI;
416 continue;
419 SetAttrInDoc(rPos, rEntry);
420 aI = m_Entries.erase(aI);
423 return pRet;
426 static bool MakePoint(const SwFltStackEntry& rEntry, SwDoc& rDoc,
427 SwPaM& rRegion)
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())
437 return false;
439 rRegion.GetPoint()->Assign(nMk);
440 GetContentNode(rDoc, *rRegion.GetPoint(), true);
441 rRegion.GetPoint()->SetContent(rEntry.m_aMkPos.m_nContent);
442 return true;
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,
449 SwPaM& rRegion )
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
459 return true;
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
478 ++rTmpStart;
480 rTmpEnd = rTmpStart;
481 while( ( rTmpEnd <= rEnd.GetNode() )
482 && ( rTmpEnd.GetNode().IsTextNode() ) ) // look for valid end + 1
483 ++rTmpEnd;
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();
515 break;
517 case RES_TXTATR_FIELD:
518 case RES_TXTATR_ANNOTATION:
519 case RES_TXTATR_INPUTFIELD:
520 break;
522 case RES_TXTATR_TOXMARK:
523 break;
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 );
529 if( pNumRule )
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
544 ++aTmpStart;
547 else
548 m_rDoc.DelNumRule( rNumNm );
551 break;
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);
561 if (!pFT)
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);
585 break;
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;
594 if (pField)
596 SwPostItField const*const pPostIt(
597 dynamic_cast<SwPostItField const*>(pField->GetFormatField().GetField()));
598 if (pPostIt)
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.
608 aRegion.SetMark();
609 aRegion.Start()->AdjustContent(-1);
612 m_rDoc.getIDocumentMarkAccess()->makeAnnotationMark(aRegion, OUString());
614 else
616 SAL_WARN("sw", "RES_FLTR_ANNOTATIONMARK: unexpected field");
619 else
621 SAL_WARN("sw", "RES_FLTR_ANNOTATIONMARK: missing field");
624 else
625 SAL_WARN("sw", "failed to make book region or point");
627 break;
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())
642 continue;
644 SwRDFHelper::addTextNodeStatement(aTypeNS, aMetadataFilePath, rTextNode, rAttribute.first, rAttribute.second);
648 else
649 SAL_WARN("sw", "failed to make book region or point");
651 break;
652 case RES_FLTR_TOX:
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();
667 if( pNd )
669 const SfxItemSet* pSet = pNd->GetpSwAttrSet();
670 const SfxPoolItem* pItem;
671 if( pSet )
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);
693 break;
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,
707 OUString(),
708 nullptr
710 m_rDoc.getIDocumentRedlineAccess().AppendRedline( new SwRangeRedline(aData, aRegion), true );
711 m_rDoc.getIDocumentRedlineAccess().SetRedlineFlags( RedlineFlags::NONE
712 | RedlineFlags::ShowInsert
713 | RedlineFlags::ShowDelete );
716 break;
717 default:
719 if (rEntry.MakeRegion(m_rDoc, aRegion, SwFltStackEntry::RegionMode::NoCheck))
721 m_rDoc.getIDocumentContentOperations().InsertPoolItem(aRegion, *rEntry.m_pAttr);
724 break;
728 SfxPoolItem* SwFltControlStack::GetFormatStackAttr(sal_uInt16 nWhich, sal_uInt16 * pPos)
730 size_t nSize = m_Entries.size();
732 while (nSize)
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)
739 if (pPos)
740 *pPos = nSize;
741 return rEntry.m_pAttr.get(); // Ok, so stop
744 return nullptr;
747 const SfxPoolItem* SwFltControlStack::GetOpenStackAttr(const SwPosition& rPos, sal_uInt16 nWhich)
749 SwFltPosition aFltPos(rPos);
751 size_t nSize = m_Entries.size();
753 while (nSize)
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();
761 return nullptr;
764 void SwFltControlStack::Delete(const SwPaM &rPam)
766 auto [pStt, pEnd] = rPam.StartEnd(); // SwPosition*
768 if( !rPam.HasMark() || *pStt >= *pEnd )
769 return;
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)
779 return;
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;
795 if (!rEntry.m_bOpen)
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;
807 if (
808 bEntryStartAfterSelStart && bEntryStartBeforeSelEnd &&
809 bEntryEndAfterSelStart && bEntryEndBeforeSelEnd
812 bTotallyContained = true;
815 if (bTotallyContained)
817 // after start, before end, delete
818 DeleteAndDestroy(nSize);
819 continue;
822 const sal_Int32 nContentDiff = nEndIdx - nStartIdx;
824 // to be adjusted
825 if (bEntryStartAfterSelStart)
827 if (bEntryStartBeforeSelEnd)
829 // move start to new start
830 rEntry.m_aMkPos.SetPos(aStartNode, nStartIdx);
832 else
833 rEntry.m_aMkPos.m_nContent -= nContentDiff;
836 if (bEntryEndAfterSelStart)
838 if (bEntryEndBeforeSelEnd)
839 rEntry.m_aPtPos.SetPos(aStartNode, nStartIdx);
840 else
841 rEntry.m_aPtPos.m_nContent -= nContentDiff;
844 //That's what Open is, end equal to start, and nPtContent is invalid
845 if (rEntry.m_bOpen)
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)
898 return;
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)
905 return;
906 auto pFormatChg = dynamic_cast<const SwFormatChg*>(pLegacyHint->m_pNew);
907 auto pFrameFormat = pFormatChg ? dynamic_cast<SwFrameFormat*>(pFormatChg->pChangedFormat) : nullptr;
908 if(pFrameFormat)
909 m_pFltAnchor->SetFrameFormat(pFrameFormat);
913 // methods of SwFltRedline follow
914 bool SwFltRedline::operator==(const SfxPoolItem& rItem) const
916 return SfxPoolItem::operator==(rItem) &&
917 this == &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 )
929 , mnHandle( nHand )
930 , maName( rNa )
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();
943 maName += rNa;
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),
961 m_nHandle(0)
965 bool SwFltRDFMark::operator==(const SfxPoolItem& rItem) const
967 if (!SfxPoolItem::operator==(rItem))
968 return false;
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)
982 m_nHandle = nHandle;
985 tools::Long SwFltRDFMark::GetHandle() const
987 return m_nHandle;
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
1023 // get adjusted)
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)
1036 if(m_pFormat)
1037 StartListening(pFormat->GetNotifier());
1040 void FrameDeleteWatch::Notify(const SfxHint& rHint)
1042 bool bDying = false;
1043 if (rHint.GetId() == SfxHintId::Dying)
1044 bDying = true;
1045 else if (rHint.GetId() == SfxHintId::SwDrawFrameFormat)
1047 auto pDrawFrameFormatHint = static_cast<const sw::DrawFrameFormatHint*>(&rHint);
1048 bDying = pDrawFrameFormatHint->m_eId == sw::DrawFrameFormatHintId::DYING;
1050 if (bDying)
1052 m_pFormat = nullptr;
1053 EndListeningAll();
1057 FrameDeleteWatch::~FrameDeleteWatch()
1059 m_pFormat = nullptr;
1060 EndListeningAll();
1063 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */