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 .
20 #include <sal/config.h>
21 #include <sal/log.hxx>
23 #include <com/sun/star/util/CloseVetoException.hpp>
26 #include "writerhelper.hxx"
27 #include <msfilter.hxx>
28 #include <com/sun/star/container/XChild.hpp>
31 #include <svl/itemiter.hxx>
32 #include <svx/svdobj.hxx>
33 #include <svx/svdoole2.hxx>
34 #include <tools/UnitConversion.hxx>
35 #include <editeng/formatbreakitem.hxx>
36 #include <osl/diagnose.h>
38 #include <ndnotxt.hxx>
39 #include <fmtcntnt.hxx>
40 #include <swtable.hxx>
43 #include <fmtanchr.hxx>
44 #include <fmtfsize.hxx>
45 #include <SwStyleNameMapper.hxx>
47 #include <charfmt.hxx>
48 #include <fchrfmt.hxx>
49 #include <redline.hxx>
51 #include <svtools/embedhlp.hxx>
52 #include <numrule.hxx>
54 #include <vcl/svapp.hxx>
55 #include <IDocumentDrawModelAccess.hxx>
56 #include <IDocumentLayoutAccess.hxx>
57 #include <IDocumentRedlineAccess.hxx>
58 #include <IDocumentStylePoolAccess.hxx>
59 #include <IDocumentMarkAccess.hxx>
62 #include <poolfmt.hxx>
64 using namespace com::sun::star
;
68 // #i98791# - adjust sorting
69 // Utility to sort SwTextFormatColl's by their assigned outline style list level
73 bool operator()(const SwTextFormatColl
*pA
, const SwTextFormatColl
*pB
) const
76 bool bResult( false );
77 const bool bIsAAssignedToOutlineStyle( pA
->IsAssignedToListLevelOfOutlineStyle() );
78 const bool bIsBAssignedToOutlineStyle( pB
->IsAssignedToListLevelOfOutlineStyle() );
79 if ( bIsAAssignedToOutlineStyle
!= bIsBAssignedToOutlineStyle
)
81 bResult
= bIsBAssignedToOutlineStyle
;
83 else if ( !bIsAAssignedToOutlineStyle
)
85 // pA and pB are equal regarding the sorting criteria.
86 // Thus return value does not matter.
91 bResult
= pA
->GetAssignedOutlineStyleLevel() < pB
->GetAssignedOutlineStyleLevel();
98 bool IsValidSlotWhich(sal_uInt16 nSlotId
, sal_uInt16 nWhichId
)
100 return (nSlotId
!= 0 && nWhichId
!= 0 && nSlotId
!= nWhichId
);
104 Utility to convert a SwPosFlyFrames into a simple vector of ww8::Frames
106 The crucial thing is that a ww8::Frame always has an anchor which
107 points to some content in the document. This is a requirement of exporting
110 ww8::Frames
SwPosFlyFramesToFrames(const SwPosFlyFrames
&rFlys
)
114 for(const auto& rFly
: rFlys
)
116 const SwFrameFormat
&rEntry
= rFly
.GetFormat();
117 const SwFormat
* pParent
= rEntry
.DerivedFrom();
118 const SwFormatAnchor
& rAnchor
= rEntry
.GetAnchor();
119 // keep only Inline Heading frames from the frames anchored as characters
120 bool bAsChar
= rAnchor
.GetAnchorId() ==
121 static_cast<RndStdIds
>(css::text::TextContentAnchorType_AS_CHARACTER
);
123 !(pParent
&& pParent
->GetPoolFormatId() == RES_POOLFRM_INLINE_HEADING
) )
127 if (const SwNode
* pAnchor
= rAnchor
.GetAnchorNode())
129 // the anchor position will be invalidated by SetRedlineFlags
130 // so set a dummy position and fix it in UpdateFramePositions
131 SwPosition
const dummy(const_cast<SwNodes
&>(pAnchor
->GetNodes()));
132 aRet
.emplace_back(rEntry
, dummy
);
136 SwPosition
aPos(rFly
.GetNode());
137 aRet
.emplace_back(rEntry
, aPos
);
143 //Utility to test if a frame is anchored at a given node
147 const SwNode
& mrNode
;
149 explicit anchoredto(const SwNode
& rNode
) : mrNode(rNode
) {}
150 bool operator()(const ww8::Frame
&rFrame
) const
152 return (mrNode
== rFrame
.GetPosition().GetNode());
159 //For i120928,size conversion before exporting graphic of bullet
160 Frame::Frame(const Graphic
&rGrf
, SwPosition aPos
)
161 : mpFlyFrame(nullptr)
162 , maPos(std::move(aPos
))
163 , meWriterType(eBulletGrf
)
164 , mpStartFrameContent(nullptr)
169 const MapMode
aMap100mm( MapUnit::Map100thMM
);
170 Size
aSize( rGrf
.GetPrefSize() );
171 if ( MapUnit::MapPixel
== rGrf
.GetPrefMapMode().GetMapUnit() )
173 aSize
= Application::GetDefaultDevice()->PixelToLogic(aSize
, aMap100mm
);
177 aSize
= OutputDevice::LogicToLogic( aSize
,rGrf
.GetPrefMapMode(), aMap100mm
);
180 maLayoutSize
= maSize
;
183 Frame::Frame(const SwFrameFormat
&rFormat
, SwPosition aPos
)
184 : mpFlyFrame(&rFormat
)
185 , maPos(std::move(aPos
))
186 , meWriterType(eTextBox
)
187 , mpStartFrameContent(nullptr)
188 // #i43447# - move to initialization list
189 , mbIsInline( (rFormat
.GetAnchor().GetAnchorId() == RndStdIds::FLY_AS_CHAR
) )
190 // #i120928# - handle graphic of bullet within existing implementation
193 switch (rFormat
.Which())
196 if (const SwNodeIndex
* pIdx
= rFormat
.GetContent().GetContentIdx())
198 SwNodeIndex
aIdx(*pIdx
, 1);
199 const SwNode
&rNd
= aIdx
.GetNode();
200 // #i43447# - determine layout size
202 SwRect
aLayRect( rFormat
.FindLayoutRect() );
203 tools::Rectangle
aRect( aLayRect
.SVRect() );
204 // The Object is not rendered (e.g. something in unused
205 // header/footer) - thus, get the values from the format.
206 if ( aLayRect
.IsEmpty() )
208 aRect
.SetSize( rFormat
.GetFrameSize().GetSize() );
210 maLayoutSize
= aRect
.GetSize();
212 switch (rNd
.GetNodeType())
214 case SwNodeType::Grf
:
215 meWriterType
= eGraphic
;
216 maSize
= rNd
.GetNoTextNode()->GetTwipSize();
218 case SwNodeType::Ole
:
220 maSize
= rNd
.GetNoTextNode()->GetTwipSize();
223 meWriterType
= eTextBox
;
224 // #i43447# - Size equals layout size for text boxes
225 maSize
= maLayoutSize
;
228 mpStartFrameContent
= &rNd
;
232 OSL_ENSURE(false, "Impossible");
233 meWriterType
= eTextBox
;
237 if (const SdrObject
* pObj
= rFormat
.FindRealSdrObject())
239 if (pObj
->GetObjInventor() == SdrInventor::FmForm
)
240 meWriterType
= eFormControl
;
242 meWriterType
= eDrawing
;
243 maSize
= pObj
->GetSnapRect().GetSize();
244 maLayoutSize
= maSize
;
248 OSL_ENSURE(false, "Impossible");
249 meWriterType
= eDrawing
;
256 void Frame::ForceTreatAsInline()
267 sal_uInt16
TransformWhichBetweenPools(const SfxItemPool
&rDestPool
,
268 const SfxItemPool
&rSrcPool
, sal_uInt16 nWhich
)
270 sal_uInt16 nSlotId
= rSrcPool
.GetSlotId(nWhich
);
271 if (IsValidSlotWhich(nSlotId
, nWhich
))
272 nWhich
= rDestPool
.GetWhichIDFromSlotID(nSlotId
);
278 sal_uInt16
GetSetWhichFromSwDocWhich(const SfxItemSet
&rSet
,
279 const SwDoc
&rDoc
, sal_uInt16 nWhich
)
281 if (RES_WHICHHINT_END
< rSet
.GetRanges()[0].first
)
283 nWhich
= TransformWhichBetweenPools(*rSet
.GetPool(),
284 rDoc
.GetAttrPool(), nWhich
);
289 DrawingOLEAdaptor::DrawingOLEAdaptor(SdrOle2Obj
&rObj
,
290 SfxObjectShell
&rPers
)
291 : mxIPRef(rObj
.GetObjRef()), mrPers(rPers
),
292 mpGraphic( rObj
.GetGraphic() )
294 rObj
.AbandonObject();
297 bool DrawingOLEAdaptor::TransferToDoc( OUString
&rName
)
299 OSL_ENSURE(mxIPRef
.is(), "Transferring invalid object to doc");
303 uno::Reference
< container::XChild
> xChild( mxIPRef
, uno::UNO_QUERY
);
305 xChild
->setParent( mrPers
.GetModel() );
307 bool bSuccess
= mrPers
.GetEmbeddedObjectContainer().InsertEmbeddedObject( mxIPRef
, rName
);
311 ::svt::EmbeddedObjectRef::SetGraphicToContainer( *mpGraphic
,
312 mrPers
.GetEmbeddedObjectContainer(),
322 DrawingOLEAdaptor::~DrawingOLEAdaptor()
327 OSL_ENSURE( !mrPers
.GetEmbeddedObjectContainer().HasEmbeddedObject( mxIPRef
), "Object in adaptor is inserted?!" );
330 mxIPRef
->close(true);
332 catch ( const css::util::CloseVetoException
& )
342 SwTwips
MakeSafePositioningValue(SwTwips nIn
)
346 else if (nIn
< SHRT_MIN
)
351 void SetLayer::SendObjectToHell(SdrObject
&rObject
) const
353 SetObjectLayer(rObject
, eHell
);
356 void SetLayer::SendObjectToHeaven(SdrObject
&rObject
) const
358 SetObjectLayer(rObject
, eHeaven
);
361 void SetLayer::SetObjectLayer(SdrObject
&rObject
, Layer eLayer
) const
363 if (SdrInventor::FmForm
== rObject
.GetObjInventor())
364 rObject
.SetLayer(mnFormLayer
);
370 rObject
.SetLayer(mnHeavenLayer
);
373 rObject
.SetLayer(mnHellLayer
);
379 //SetLayer boilerplate begin
381 // #i38889# - by default put objects into the invisible layers.
382 SetLayer::SetLayer(const SwDoc
&rDoc
)
383 : mnHeavenLayer(rDoc
.getIDocumentDrawModelAccess().GetInvisibleHeavenId()),
384 mnHellLayer(rDoc
.getIDocumentDrawModelAccess().GetInvisibleHellId()),
385 mnFormLayer(rDoc
.getIDocumentDrawModelAccess().GetInvisibleControlsId())
388 //SetLayer boilerplate end
390 void GetPoolItems(const SfxItemSet
&rSet
, ww8::PoolItems
&rItems
, bool bExportParentItemSet
)
392 if( bExportParentItemSet
)
394 for (SfxItemIter
aIter(rSet
); !aIter
.IsAtEnd(); aIter
.NextItem())
396 const SfxPoolItem
* pItem(nullptr);
397 if(SfxItemState::SET
== aIter
.GetItemState(true, &pItem
))
398 rItems
[aIter
.GetCurWhich()] = pItem
;
401 else if( rSet
.Count())
403 for (SfxItemIter
aIter(rSet
); !aIter
.IsAtEnd(); aIter
.NextItem())
404 rItems
[aIter
.GetCurWhich()] = aIter
.GetCurItem();
406 // DeduplicateItems(rItems);
409 const SfxPoolItem
*SearchPoolItems(const ww8::PoolItems
&rItems
,
412 auto aIter
= rItems
.find(eType
);
413 if (aIter
!= rItems
.end())
414 return aIter
->second
;
418 void ClearOverridesFromSet(const SwFormatCharFormat
&rFormat
, SfxItemSet
&rSet
)
420 if (const SwCharFormat
* pCharFormat
= rFormat
.GetCharFormat())
422 if (pCharFormat
->GetAttrSet().Count())
424 SfxItemIter
aIter(pCharFormat
->GetAttrSet());
425 const SfxPoolItem
*pItem
= aIter
.GetCurItem();
427 rSet
.ClearItem(pItem
->Which());
428 while ((pItem
= aIter
.NextItem()));
433 ww8::ParaStyles
GetParaStyles(const SwDoc
&rDoc
)
435 ww8::ParaStyles aStyles
;
436 typedef ww8::ParaStyles::size_type mysizet
;
438 const SwTextFormatColls
*pColls
= rDoc
.GetTextFormatColls();
439 mysizet nCount
= pColls
? pColls
->size() : 0;
440 aStyles
.reserve(nCount
);
441 for (mysizet nI
= 0; nI
< nCount
; ++nI
)
442 aStyles
.push_back((*pColls
)[ static_cast< sal_uInt16
>(nI
) ]);
446 SwTextFormatColl
* GetParaStyle(SwDoc
&rDoc
, const OUString
& rName
)
448 // Search first in the Doc-Styles
449 SwTextFormatColl
* pColl
= rDoc
.FindTextFormatCollByName(rName
);
452 // Collection not found, try in Pool ?
453 sal_uInt16 n
= SwStyleNameMapper::GetPoolIdFromUIName(rName
,
454 SwGetPoolIdFromName::TxtColl
);
455 if (n
!= SAL_MAX_UINT16
) // found or standard
456 pColl
= rDoc
.getIDocumentStylePoolAccess().GetTextCollFromPool(n
, false);
461 SwCharFormat
* GetCharStyle(SwDoc
&rDoc
, const OUString
& rName
)
463 SwCharFormat
*pFormat
= rDoc
.FindCharFormatByName(rName
);
466 // Collection not found, try in Pool ?
467 sal_uInt16 n
= SwStyleNameMapper::GetPoolIdFromUIName(rName
,
468 SwGetPoolIdFromName::ChrFmt
);
469 if (n
!= SAL_MAX_UINT16
) // found or standard
470 pFormat
= rDoc
.getIDocumentStylePoolAccess().GetCharFormatFromPool(n
);
475 // #i98791# - adjust sorting algorithm
476 void SortByAssignedOutlineStyleListLevel(ww8::ParaStyles
&rStyles
)
478 std::sort(rStyles
.begin(), rStyles
.end(), outlinecmp());
482 Utility to extract FlyFormats from a document, potentially from a
485 ww8::Frames
GetFrames(const SwDoc
&rDoc
, SwPaM
const *pPaM
/*, bool bAll*/)
487 SwPosFlyFrames
aFlys(rDoc
.GetAllFlyFormats(pPaM
, /*bDrawAlso=*/true, /*bAsCharAlso=*/true));
488 ww8::Frames
aRet(SwPosFlyFramesToFrames(aFlys
));
492 void UpdateFramePositions(ww8::Frames
& rFrames
)
494 for (ww8::Frame
& rFrame
: rFrames
)
496 SwFormatAnchor
const& rAnchor
= rFrame
.GetFrameFormat().GetAnchor();
497 if (SwPosition
const*const pAnchor
= rAnchor
.GetContentAnchor())
499 rFrame
.SetPosition(*pAnchor
);
502 { // these don't need to be corrected, they're not in redlines
503 assert(RndStdIds::FLY_AT_PAGE
== rAnchor
.GetAnchorId());
508 ww8::Frames
GetFramesInNode(const ww8::Frames
&rFrames
, const SwNode
&rNode
)
511 std::copy_if(rFrames
.begin(), rFrames
.end(),
512 std::back_inserter(aRet
), anchoredto(rNode
));
516 const SwNumFormat
* GetNumFormatFromSwNumRuleLevel(const SwNumRule
&rRule
,
519 if (nLevel
< 0 || nLevel
>= MAXLEVEL
)
521 OSL_FAIL("Invalid level");
524 return &(rRule
.Get( static_cast< sal_uInt16
>(nLevel
) ));
527 const SwNumFormat
* GetNumFormatFromTextNode(const SwTextNode
&rTextNode
)
529 const SwNumRule
*pRule
= nullptr;
531 rTextNode
.IsNumbered() && rTextNode
.IsCountedInList() &&
532 nullptr != (pRule
= rTextNode
.GetNumRule())
535 return GetNumFormatFromSwNumRuleLevel(*pRule
,
536 rTextNode
.GetActualListLevel());
540 rTextNode
.IsNumbered() && rTextNode
.IsCountedInList() &&
541 nullptr != (pRule
= rTextNode
.GetDoc().GetOutlineNumRule())
544 return GetNumFormatFromSwNumRuleLevel(*pRule
,
545 rTextNode
.GetActualListLevel());
551 const SwNumRule
* GetNumRuleFromTextNode(const SwTextNode
&rTextNode
)
553 return GetNormalNumRuleFromTextNode(rTextNode
);
556 const SwNumRule
* GetNormalNumRuleFromTextNode(const SwTextNode
&rTextNode
)
558 const SwNumRule
*pRule
= nullptr;
561 rTextNode
.IsNumbered() && rTextNode
.IsCountedInList() &&
562 nullptr != (pRule
= rTextNode
.GetNumRule())
570 SwNoTextNode
*GetNoTextNodeFromSwFrameFormat(const SwFrameFormat
&rFormat
)
572 const SwNodeIndex
*pIndex
= rFormat
.GetContent().GetContentIdx();
573 OSL_ENSURE(pIndex
, "No NodeIndex in SwFrameFormat ?, suspicious");
576 SwNodeIndex
aIdx(*pIndex
, 1);
577 return aIdx
.GetNode().GetNoTextNode();
580 bool HasPageBreak(const SwNode
&rNd
)
582 const SvxFormatBreakItem
*pBreak
= nullptr;
583 if (rNd
.IsTableNode() && rNd
.GetTableNode())
585 const SwTable
& rTable
= rNd
.GetTableNode()->GetTable();
586 const SwFrameFormat
* pApply
= rTable
.GetFrameFormat();
587 OSL_ENSURE(pApply
, "impossible");
589 pBreak
= &pApply
->GetFormatAttr(RES_BREAK
);
591 else if (const SwContentNode
*pNd
= rNd
.GetContentNode())
592 pBreak
= &pNd
->GetAttr(RES_BREAK
);
594 return pBreak
&& pBreak
->GetBreak() == SvxBreak::PageBefore
;
597 tools::Polygon
PolygonFromPolyPolygon(const tools::PolyPolygon
&rPolyPoly
)
599 if(1 == rPolyPoly
.Count())
605 // This method will now just concatenate the polygons contained
606 // in the given PolyPolygon. Anything else which might be thought of
607 // for reducing to a single polygon will just need more power and
608 // cannot create more correct results.
609 sal_uInt32
nPointCount(0);
611 for( auto const& rPoly
: rPolyPoly
)
613 nPointCount
+= static_cast<sal_uInt32
>(rPoly
.GetSize());
616 if(nPointCount
> 0x0000ffff)
618 OSL_FAIL("PolygonFromPolyPolygon: too many points for a single polygon (!)");
619 nPointCount
= 0x0000ffff;
622 tools::Polygon
aRetval(o3tl::narrowing
<sal_uInt16
>(nPointCount
));
623 sal_uInt32
nAppendIndex(0);
625 for( auto const& rCandidate
: rPolyPoly
)
627 for(sal_uInt16
b(0); nAppendIndex
<= nPointCount
&& b
< rCandidate
.GetSize(); b
++)
629 aRetval
[o3tl::narrowing
<sal_uInt16
>(nAppendIndex
++)] = rCandidate
[b
];
637 tools::Polygon
CorrectWordWrapPolygonForExport(const tools::PolyPolygon
& rPolyPoly
, const SwNoTextNode
* pNd
, bool bCorrectCrop
)
639 tools::Polygon
aPoly(PolygonFromPolyPolygon(rPolyPoly
));
640 const Size aOrigSize
= pNd
->GetGraphic().GetPrefSize();
642 const SwAttrSet
* pAttrSet
= pNd
->GetpSwAttrSet();
643 if (bCorrectCrop
&& pAttrSet
)
645 if (pAttrSet
->HasItem(RES_GRFATR_CROPGRF
))
647 // Word's wrap polygon deals with a canvas which has the size of the already
648 // cropped graphic, do the opposite of correctCrop() in writerfilter/.
649 const SwCropGrf
& rCrop
= pAttrSet
->GetCropGrf();
650 sal_Int32 nCropLeft
= convertTwipToMm100(rCrop
.GetLeft());
651 sal_Int32 nCropRight
= convertTwipToMm100(rCrop
.GetRight());
652 sal_Int32 nCropTop
= convertTwipToMm100(rCrop
.GetTop());
653 sal_Int32 nCropBottom
= convertTwipToMm100(rCrop
.GetBottom());
654 aPoly
.Move(-nCropLeft
, -nCropTop
);
656 Fraction
aScaleX(aOrigSize
.getWidth(), aOrigSize
.getWidth() - nCropLeft
- nCropRight
);
657 Fraction
aScaleY(aOrigSize
.getHeight(), aOrigSize
.getHeight() - nCropTop
- nCropBottom
);
658 aPoly
.Scale(double(aScaleX
), double(aScaleY
));
662 Fraction
aMapPolyX(ww::nWrap100Percent
, aOrigSize
.Width());
663 Fraction
aMapPolyY(ww::nWrap100Percent
, aOrigSize
.Height());
664 aPoly
.Scale(double(aMapPolyX
), double(aMapPolyY
));
667 a) stretch right bound by 15twips
668 b) shrink bottom bound to where it would have been in word
669 c) Move it to the left by 15twips
671 See the import for details
673 const Size aSize
= pNd
->GetTwipSize();
674 Fraction
aMoveHack(ww::nWrap100Percent
, aSize
.Width());
675 aMoveHack
*= Fraction(15, 1);
676 tools::Long
nMove(aMoveHack
);
678 Fraction
aHackX(ww::nWrap100Percent
+ nMove
,
679 ww::nWrap100Percent
);
680 Fraction
aHackY(ww::nWrap100Percent
- nMove
,
681 ww::nWrap100Percent
);
682 aPoly
.Scale(double(aHackX
), double(aHackY
));
684 aPoly
.Move(-nMove
, 0);
688 void RedlineStack::open(const SwPosition
& rPos
, const SfxPoolItem
& rAttr
)
690 OSL_ENSURE(rAttr
.Which() == RES_FLTR_REDLINE
, "not a redline");
691 maStack
.emplace_back(new SwFltStackEntry(rPos
, std::unique_ptr
<SfxPoolItem
>(rAttr
.Clone())));
696 class SameOpenRedlineType
701 explicit SameOpenRedlineType(RedlineType eType
) : meType(eType
) {}
702 bool operator()(const std::unique_ptr
<SwFltStackEntry
> & pEntry
) const
704 const SwFltRedline
*pTest
= static_cast<const SwFltRedline
*>
705 (pEntry
->m_pAttr
.get());
706 return (pEntry
->m_bOpen
&& (pTest
->m_eType
== meType
));
712 bool RedlineStack::close(const SwPosition
& rPos
, RedlineType eType
)
714 //Search from end for same type
715 auto aResult
= std::find_if(maStack
.rbegin(), maStack
.rend(),
716 SameOpenRedlineType(eType
));
717 if (aResult
!= maStack
.rend())
719 SwTextNode
*const pNode(rPos
.GetNode().GetTextNode());
720 sal_Int32
const nIndex(rPos
.GetContentIndex());
721 // HACK to prevent overlap of field-mark and redline,
722 // which would destroy field-mark invariants when the redline
723 // is hidden: move the redline end one to the left
724 if (pNode
&& nIndex
> 0
725 && pNode
->GetText()[nIndex
- 1] == CH_TXT_ATR_FIELDEND
)
727 SwPosition
const end(*rPos
.GetNode().GetTextNode(),
729 sw::mark::Fieldmark
*const pFieldMark(
730 rPos
.GetDoc().getIDocumentMarkAccess()->getFieldmarkAt(end
));
731 SAL_WARN_IF(!pFieldMark
, "sw.ww8", "expected a field mark");
732 if (pFieldMark
&& pFieldMark
->GetMarkPos().GetNodeIndex() == (*aResult
)->m_aMkPos
.m_nNode
.GetIndex()+1
733 && pFieldMark
->GetMarkPos().GetContentIndex() < (*aResult
)->m_aMkPos
.m_nContent
)
735 (*aResult
)->SetEndPos(end
);
739 (*aResult
)->SetEndPos(rPos
);
745 void RedlineStack::closeall(const SwPosition
& rPos
)
747 std::for_each(maStack
.begin(), maStack
.end(), SetEndIfOpen(rPos
));
750 void MoveAttrFieldmarkInserted(SwFltPosition
& rMkPos
, SwFltPosition
& rPtPos
, const SwPosition
& rPos
)
752 sal_Int32
const nInserted
= 2; // CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FIELDSEP
753 SwNodeOffset nPosNd
= rPos
.GetNodeIndex();
754 sal_Int32 nPosCt
= rPos
.GetContentIndex() - nInserted
;
756 bool const isPoint(rMkPos
== rPtPos
);
757 if ((rMkPos
.m_nNode
.GetIndex()+1 == nPosNd
) &&
758 (nPosCt
<= rMkPos
.m_nContent
))
760 rMkPos
.m_nContent
+= nInserted
;
761 SAL_WARN_IF(rMkPos
.m_nContent
> rPos
.GetNodes()[nPosNd
]->GetContentNode()->Len(),
762 "sw.ww8", "redline ends after end of line");
763 if (isPoint
) // sigh ... important special case...
765 rPtPos
.m_nContent
+= nInserted
;
769 // for the end position, leave it alone if it's *on* the dummy
770 // char position, that should remain *before*
771 if ((rPtPos
.m_nNode
.GetIndex()+1 == nPosNd
) &&
772 (nPosCt
< rPtPos
.m_nContent
))
774 rPtPos
.m_nContent
+= nInserted
;
775 SAL_WARN_IF(rPtPos
.m_nContent
> rPos
.GetNodes()[nPosNd
]->GetContentNode()->Len(),
776 "sw.ww8", "range ends after end of line");
780 void RedlineStack::MoveAttrsFieldmarkInserted(const SwPosition
& rPos
)
782 for (size_t i
= 0, nCnt
= maStack
.size(); i
< nCnt
; ++i
)
784 SwFltStackEntry
& rEntry
= *maStack
[i
];
785 MoveAttrFieldmarkInserted(rEntry
.m_aMkPos
, rEntry
.m_aPtPos
, rPos
);
789 void SetInDocAndDelete::operator()(std::unique_ptr
<SwFltStackEntry
>& pEntry
)
791 SwPaM
aRegion(pEntry
->m_aMkPos
.m_nNode
);
792 if (pEntry
->MakeRegion(aRegion
,
793 SwFltStackEntry::RegionMode::CheckNodes
|SwFltStackEntry::RegionMode::CheckFieldmark
) &&
794 (*aRegion
.GetPoint() != *aRegion
.GetMark())
797 mrDoc
.getIDocumentRedlineAccess().SetRedlineFlags(RedlineFlags::On
| RedlineFlags::ShowInsert
|
798 RedlineFlags::ShowDelete
);
799 const SwFltRedline
*pFltRedline
= static_cast<const SwFltRedline
*>
800 (pEntry
->m_pAttr
.get());
802 SwRedlineData
aData(pFltRedline
->m_eType
, pFltRedline
->m_nAutorNo
,
803 pFltRedline
->m_aStamp
, 0, OUString(), nullptr);
805 SwRangeRedline
*const pNewRedline(new SwRangeRedline(aData
, aRegion
));
806 // the point node may be deleted in AppendRedline, so park
807 // the PaM somewhere safe
808 aRegion
.DeleteMark();
809 aRegion
.GetPoint()->Assign(*mrDoc
.GetNodes()[SwNodeOffset(0)]);
810 mrDoc
.getIDocumentRedlineAccess().AppendRedline(pNewRedline
, true);
811 mrDoc
.getIDocumentRedlineAccess().SetRedlineFlags(RedlineFlags::NONE
| RedlineFlags::ShowInsert
|
812 RedlineFlags::ShowDelete
);
817 bool CompareRedlines::operator()(const std::unique_ptr
<SwFltStackEntry
> & pOneE
,
818 const std::unique_ptr
<SwFltStackEntry
> & pTwoE
) const
820 const SwFltRedline
*pOne
= static_cast<const SwFltRedline
*>
821 (pOneE
->m_pAttr
.get());
822 const SwFltRedline
*pTwo
= static_cast<const SwFltRedline
*>
823 (pTwoE
->m_pAttr
.get());
825 //Return the earlier time, if two have the same time, prioritize
826 //inserts over deletes
827 if (pOne
->m_aStamp
== pTwo
->m_aStamp
)
828 return (pOne
->m_eType
== RedlineType::Insert
&& pTwo
->m_eType
!= RedlineType::Insert
);
830 return (pOne
->m_aStamp
< pTwo
->m_aStamp
);
833 void RedlineStack::ImplDestroy()
835 std::stable_sort(maStack
.begin(), maStack
.end(), CompareRedlines());
836 std::for_each(maStack
.begin(), maStack
.end(), SetInDocAndDelete(mrDoc
));
839 RedlineStack::~RedlineStack()
841 suppress_fun_call_w_exception(ImplDestroy());
844 sal_uInt16
WrtRedlineAuthor::AddName( const OUString
& rNm
)
847 auto aIter
= std::find(maAuthors
.begin(), maAuthors
.end(), rNm
);
848 if (aIter
!= maAuthors
.end())
849 nRet
= static_cast< sal_uInt16
>(aIter
- maAuthors
.begin());
852 nRet
= static_cast< sal_uInt16
>(maAuthors
.size());
853 maAuthors
.push_back(rNm
);
861 InsertedTableListener::InsertedTableListener(SwTableNode
& rNode
)
862 : m_pTableNode(&rNode
)
864 StartListening(rNode
.GetNotifier());
867 SwTableNode
* InsertedTableListener::GetTableNode()
868 { return m_pTableNode
; }
870 void InsertedTableListener::Notify(const SfxHint
& rHint
)
872 if(rHint
.GetId() == SfxHintId::Dying
)
873 m_pTableNode
= nullptr;
876 InsertedTablesManager::InsertedTablesManager(const SwDoc
&rDoc
)
877 : mbHasRoot(rDoc
.getIDocumentLayoutAccess().GetCurrentLayout())
880 void InsertedTablesManager::DelAndMakeTableFrames()
884 for (auto& aTable
: maTables
)
886 // If already a layout exists, then the BoxFrames must recreated at this table
887 SwTableNode
*pTable
= aTable
.first
->GetTableNode();
888 OSL_ENSURE(pTable
, "Why no expected table");
891 SwFrameFormat
* pFrameFormat
= pTable
->GetTable().GetFrameFormat();
893 if (pFrameFormat
!= nullptr)
895 SwPosition
*pIndex
= aTable
.second
;
897 pTable
->MakeOwnFrames(pIndex
);
903 void InsertedTablesManager::InsertTable(SwTableNode
& rTableNode
, SwPaM
& rPaM
)
907 //Associate this tablenode with this after position, replace an old
908 //node association if necessary
910 std::unique_ptr
<InsertedTableListener
>(new InsertedTableListener(rTableNode
)),
917 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */