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>
63 using namespace com::sun::star
;
67 // #i98791# - adjust sorting
68 // Utility to sort SwTextFormatColl's by their assigned outline style list level
72 bool operator()(const SwTextFormatColl
*pA
, const SwTextFormatColl
*pB
) const
75 bool bResult( false );
76 const bool bIsAAssignedToOutlineStyle( pA
->IsAssignedToListLevelOfOutlineStyle() );
77 const bool bIsBAssignedToOutlineStyle( pB
->IsAssignedToListLevelOfOutlineStyle() );
78 if ( bIsAAssignedToOutlineStyle
!= bIsBAssignedToOutlineStyle
)
80 bResult
= bIsBAssignedToOutlineStyle
;
82 else if ( !bIsAAssignedToOutlineStyle
)
84 // pA and pB are equal regarding the sorting criteria.
85 // Thus return value does not matter.
90 bResult
= pA
->GetAssignedOutlineStyleLevel() < pB
->GetAssignedOutlineStyleLevel();
97 bool IsValidSlotWhich(sal_uInt16 nSlotId
, sal_uInt16 nWhichId
)
99 return (nSlotId
!= 0 && nWhichId
!= 0 && nSlotId
!= nWhichId
);
103 Utility to convert a SwPosFlyFrames into a simple vector of ww8::Frames
105 The crucial thing is that a ww8::Frame always has an anchor which
106 points to some content in the document. This is a requirement of exporting
109 ww8::Frames
SwPosFlyFramesToFrames(const SwPosFlyFrames
&rFlys
)
113 for(const auto& rFly
: rFlys
)
115 const SwFrameFormat
&rEntry
= rFly
.GetFormat();
117 if (const SwNode
* pAnchor
= rEntry
.GetAnchor().GetAnchorNode())
119 // the anchor position will be invalidated by SetRedlineFlags
120 // so set a dummy position and fix it in UpdateFramePositions
121 SwPosition
const dummy(const_cast<SwNodes
&>(pAnchor
->GetNodes()));
122 aRet
.emplace_back(rEntry
, dummy
);
126 SwPosition
aPos(rFly
.GetNode());
127 aRet
.emplace_back(rEntry
, aPos
);
133 //Utility to test if a frame is anchored at a given node
137 const SwNode
& mrNode
;
139 explicit anchoredto(const SwNode
& rNode
) : mrNode(rNode
) {}
140 bool operator()(const ww8::Frame
&rFrame
) const
142 return (mrNode
== rFrame
.GetPosition().GetNode());
149 //For i120928,size conversion before exporting graphic of bullet
150 Frame::Frame(const Graphic
&rGrf
, SwPosition aPos
)
151 : mpFlyFrame(nullptr)
152 , maPos(std::move(aPos
))
153 , meWriterType(eBulletGrf
)
154 , mpStartFrameContent(nullptr)
159 const MapMode
aMap100mm( MapUnit::Map100thMM
);
160 Size
aSize( rGrf
.GetPrefSize() );
161 if ( MapUnit::MapPixel
== rGrf
.GetPrefMapMode().GetMapUnit() )
163 aSize
= Application::GetDefaultDevice()->PixelToLogic(aSize
, aMap100mm
);
167 aSize
= OutputDevice::LogicToLogic( aSize
,rGrf
.GetPrefMapMode(), aMap100mm
);
170 maLayoutSize
= maSize
;
173 Frame::Frame(const SwFrameFormat
&rFormat
, SwPosition aPos
)
174 : mpFlyFrame(&rFormat
)
175 , maPos(std::move(aPos
))
176 , meWriterType(eTextBox
)
177 , mpStartFrameContent(nullptr)
178 // #i43447# - move to initialization list
179 , mbIsInline( (rFormat
.GetAnchor().GetAnchorId() == RndStdIds::FLY_AS_CHAR
) )
180 // #i120928# - handle graphic of bullet within existing implementation
183 switch (rFormat
.Which())
186 if (const SwNodeIndex
* pIdx
= rFormat
.GetContent().GetContentIdx())
188 SwNodeIndex
aIdx(*pIdx
, 1);
189 const SwNode
&rNd
= aIdx
.GetNode();
190 // #i43447# - determine layout size
192 SwRect
aLayRect( rFormat
.FindLayoutRect() );
193 tools::Rectangle
aRect( aLayRect
.SVRect() );
194 // The Object is not rendered (e.g. something in unused
195 // header/footer) - thus, get the values from the format.
196 if ( aLayRect
.IsEmpty() )
198 aRect
.SetSize( rFormat
.GetFrameSize().GetSize() );
200 maLayoutSize
= aRect
.GetSize();
202 switch (rNd
.GetNodeType())
204 case SwNodeType::Grf
:
205 meWriterType
= eGraphic
;
206 maSize
= rNd
.GetNoTextNode()->GetTwipSize();
208 case SwNodeType::Ole
:
210 maSize
= rNd
.GetNoTextNode()->GetTwipSize();
213 meWriterType
= eTextBox
;
214 // #i43447# - Size equals layout size for text boxes
215 maSize
= maLayoutSize
;
218 mpStartFrameContent
= &rNd
;
222 OSL_ENSURE(false, "Impossible");
223 meWriterType
= eTextBox
;
227 if (const SdrObject
* pObj
= rFormat
.FindRealSdrObject())
229 if (pObj
->GetObjInventor() == SdrInventor::FmForm
)
230 meWriterType
= eFormControl
;
232 meWriterType
= eDrawing
;
233 maSize
= pObj
->GetSnapRect().GetSize();
234 maLayoutSize
= maSize
;
238 OSL_ENSURE(false, "Impossible");
239 meWriterType
= eDrawing
;
246 void Frame::ForceTreatAsInline()
257 sal_uInt16
TransformWhichBetweenPools(const SfxItemPool
&rDestPool
,
258 const SfxItemPool
&rSrcPool
, sal_uInt16 nWhich
)
260 sal_uInt16 nSlotId
= rSrcPool
.GetSlotId(nWhich
);
261 if (IsValidSlotWhich(nSlotId
, nWhich
))
262 nWhich
= rDestPool
.GetWhich(nSlotId
);
268 sal_uInt16
GetSetWhichFromSwDocWhich(const SfxItemSet
&rSet
,
269 const SwDoc
&rDoc
, sal_uInt16 nWhich
)
271 if (RES_WHICHHINT_END
< rSet
.GetRanges()[0].first
)
273 nWhich
= TransformWhichBetweenPools(*rSet
.GetPool(),
274 rDoc
.GetAttrPool(), nWhich
);
279 DrawingOLEAdaptor::DrawingOLEAdaptor(SdrOle2Obj
&rObj
,
280 SfxObjectShell
&rPers
)
281 : mxIPRef(rObj
.GetObjRef()), mrPers(rPers
),
282 mpGraphic( rObj
.GetGraphic() )
284 rObj
.AbandonObject();
287 bool DrawingOLEAdaptor::TransferToDoc( OUString
&rName
)
289 OSL_ENSURE(mxIPRef
.is(), "Transferring invalid object to doc");
293 uno::Reference
< container::XChild
> xChild( mxIPRef
, uno::UNO_QUERY
);
295 xChild
->setParent( mrPers
.GetModel() );
297 bool bSuccess
= mrPers
.GetEmbeddedObjectContainer().InsertEmbeddedObject( mxIPRef
, rName
);
301 ::svt::EmbeddedObjectRef::SetGraphicToContainer( *mpGraphic
,
302 mrPers
.GetEmbeddedObjectContainer(),
312 DrawingOLEAdaptor::~DrawingOLEAdaptor()
317 OSL_ENSURE( !mrPers
.GetEmbeddedObjectContainer().HasEmbeddedObject( mxIPRef
), "Object in adaptor is inserted?!" );
320 mxIPRef
->close(true);
322 catch ( const css::util::CloseVetoException
& )
332 SwTwips
MakeSafePositioningValue(SwTwips nIn
)
336 else if (nIn
< SHRT_MIN
)
341 void SetLayer::SendObjectToHell(SdrObject
&rObject
) const
343 SetObjectLayer(rObject
, eHell
);
346 void SetLayer::SendObjectToHeaven(SdrObject
&rObject
) const
348 SetObjectLayer(rObject
, eHeaven
);
351 void SetLayer::SetObjectLayer(SdrObject
&rObject
, Layer eLayer
) const
353 if (SdrInventor::FmForm
== rObject
.GetObjInventor())
354 rObject
.SetLayer(mnFormLayer
);
360 rObject
.SetLayer(mnHeavenLayer
);
363 rObject
.SetLayer(mnHellLayer
);
369 //SetLayer boilerplate begin
371 // #i38889# - by default put objects into the invisible layers.
372 SetLayer::SetLayer(const SwDoc
&rDoc
)
373 : mnHeavenLayer(rDoc
.getIDocumentDrawModelAccess().GetInvisibleHeavenId()),
374 mnHellLayer(rDoc
.getIDocumentDrawModelAccess().GetInvisibleHellId()),
375 mnFormLayer(rDoc
.getIDocumentDrawModelAccess().GetInvisibleControlsId())
378 //SetLayer boilerplate end
380 void GetPoolItems(const SfxItemSet
&rSet
, ww8::PoolItems
&rItems
, bool bExportParentItemSet
)
382 if( bExportParentItemSet
)
384 sal_uInt16 nTotal
= rSet
.TotalCount();
385 for( sal_uInt16 nItem
=0; nItem
< nTotal
; ++nItem
)
387 const SfxPoolItem
* pItem
= nullptr;
388 if( SfxItemState::SET
== rSet
.GetItemState( rSet
.GetWhichByPos( nItem
), true, &pItem
) )
390 rItems
[pItem
->Which()] = pItem
;
394 else if( rSet
.Count())
396 SfxItemIter
aIter(rSet
);
397 if (const SfxPoolItem
*pItem
= aIter
.GetCurItem())
400 rItems
[pItem
->Which()] = pItem
;
401 while ((pItem
= aIter
.NextItem()));
404 // DeduplicateItems(rItems);
407 void DeduplicateItems(ww8::PoolItems
& rItems
)
409 if (rItems
.find(RES_CHRATR_WEIGHT
) != rItems
.end()
410 && rItems
.find(RES_CHRATR_CJK_WEIGHT
) != rItems
.end())
412 // avoid duplicate w:b element (DOC and DOCX map Western and
413 // CJK the same - inconsistently RTF maps CJK and CTL the same?)
414 rItems
.erase(rItems
.find(RES_CHRATR_CJK_WEIGHT
));
418 const SfxPoolItem
*SearchPoolItems(const ww8::PoolItems
&rItems
,
421 auto aIter
= rItems
.find(eType
);
422 if (aIter
!= rItems
.end())
423 return aIter
->second
;
427 void ClearOverridesFromSet(const SwFormatCharFormat
&rFormat
, SfxItemSet
&rSet
)
429 if (const SwCharFormat
* pCharFormat
= rFormat
.GetCharFormat())
431 if (pCharFormat
->GetAttrSet().Count())
433 SfxItemIter
aIter(pCharFormat
->GetAttrSet());
434 const SfxPoolItem
*pItem
= aIter
.GetCurItem();
436 rSet
.ClearItem(pItem
->Which());
437 while ((pItem
= aIter
.NextItem()));
442 ww8::ParaStyles
GetParaStyles(const SwDoc
&rDoc
)
444 ww8::ParaStyles aStyles
;
445 typedef ww8::ParaStyles::size_type mysizet
;
447 const SwTextFormatColls
*pColls
= rDoc
.GetTextFormatColls();
448 mysizet nCount
= pColls
? pColls
->size() : 0;
449 aStyles
.reserve(nCount
);
450 for (mysizet nI
= 0; nI
< nCount
; ++nI
)
451 aStyles
.push_back((*pColls
)[ static_cast< sal_uInt16
>(nI
) ]);
455 SwTextFormatColl
* GetParaStyle(SwDoc
&rDoc
, const OUString
& rName
)
457 // Search first in the Doc-Styles
458 SwTextFormatColl
* pColl
= rDoc
.FindTextFormatCollByName(rName
);
461 // Collection not found, try in Pool ?
462 sal_uInt16 n
= SwStyleNameMapper::GetPoolIdFromUIName(rName
,
463 SwGetPoolIdFromName::TxtColl
);
464 if (n
!= SAL_MAX_UINT16
) // found or standard
465 pColl
= rDoc
.getIDocumentStylePoolAccess().GetTextCollFromPool(n
, false);
470 SwCharFormat
* GetCharStyle(SwDoc
&rDoc
, const OUString
& rName
)
472 SwCharFormat
*pFormat
= rDoc
.FindCharFormatByName(rName
);
475 // Collection not found, try in Pool ?
476 sal_uInt16 n
= SwStyleNameMapper::GetPoolIdFromUIName(rName
,
477 SwGetPoolIdFromName::ChrFmt
);
478 if (n
!= SAL_MAX_UINT16
) // found or standard
479 pFormat
= rDoc
.getIDocumentStylePoolAccess().GetCharFormatFromPool(n
);
484 // #i98791# - adjust sorting algorithm
485 void SortByAssignedOutlineStyleListLevel(ww8::ParaStyles
&rStyles
)
487 std::sort(rStyles
.begin(), rStyles
.end(), outlinecmp());
491 Utility to extract FlyFormats from a document, potentially from a
494 ww8::Frames
GetFrames(const SwDoc
&rDoc
, SwPaM
const *pPaM
/*, bool bAll*/)
496 SwPosFlyFrames
aFlys(rDoc
.GetAllFlyFormats(pPaM
, true));
497 ww8::Frames
aRet(SwPosFlyFramesToFrames(aFlys
));
501 void UpdateFramePositions(ww8::Frames
& rFrames
)
503 for (ww8::Frame
& rFrame
: rFrames
)
505 SwFormatAnchor
const& rAnchor
= rFrame
.GetFrameFormat().GetAnchor();
506 if (SwPosition
const*const pAnchor
= rAnchor
.GetContentAnchor())
508 rFrame
.SetPosition(*pAnchor
);
511 { // these don't need to be corrected, they're not in redlines
512 assert(RndStdIds::FLY_AT_PAGE
== rAnchor
.GetAnchorId());
517 ww8::Frames
GetFramesInNode(const ww8::Frames
&rFrames
, const SwNode
&rNode
)
520 std::copy_if(rFrames
.begin(), rFrames
.end(),
521 std::back_inserter(aRet
), anchoredto(rNode
));
525 const SwNumFormat
* GetNumFormatFromSwNumRuleLevel(const SwNumRule
&rRule
,
528 if (nLevel
< 0 || nLevel
>= MAXLEVEL
)
530 OSL_FAIL("Invalid level");
533 return &(rRule
.Get( static_cast< sal_uInt16
>(nLevel
) ));
536 const SwNumFormat
* GetNumFormatFromTextNode(const SwTextNode
&rTextNode
)
538 const SwNumRule
*pRule
= nullptr;
540 rTextNode
.IsNumbered() && rTextNode
.IsCountedInList() &&
541 nullptr != (pRule
= rTextNode
.GetNumRule())
544 return GetNumFormatFromSwNumRuleLevel(*pRule
,
545 rTextNode
.GetActualListLevel());
549 rTextNode
.IsNumbered() && rTextNode
.IsCountedInList() &&
550 nullptr != (pRule
= rTextNode
.GetDoc().GetOutlineNumRule())
553 return GetNumFormatFromSwNumRuleLevel(*pRule
,
554 rTextNode
.GetActualListLevel());
560 const SwNumRule
* GetNumRuleFromTextNode(const SwTextNode
&rTextNode
)
562 return GetNormalNumRuleFromTextNode(rTextNode
);
565 const SwNumRule
* GetNormalNumRuleFromTextNode(const SwTextNode
&rTextNode
)
567 const SwNumRule
*pRule
= nullptr;
570 rTextNode
.IsNumbered() && rTextNode
.IsCountedInList() &&
571 nullptr != (pRule
= rTextNode
.GetNumRule())
579 SwNoTextNode
*GetNoTextNodeFromSwFrameFormat(const SwFrameFormat
&rFormat
)
581 const SwNodeIndex
*pIndex
= rFormat
.GetContent().GetContentIdx();
582 OSL_ENSURE(pIndex
, "No NodeIndex in SwFrameFormat ?, suspicious");
585 SwNodeIndex
aIdx(*pIndex
, 1);
586 return aIdx
.GetNode().GetNoTextNode();
589 bool HasPageBreak(const SwNode
&rNd
)
591 const SvxFormatBreakItem
*pBreak
= nullptr;
592 if (rNd
.IsTableNode() && rNd
.GetTableNode())
594 const SwTable
& rTable
= rNd
.GetTableNode()->GetTable();
595 const SwFrameFormat
* pApply
= rTable
.GetFrameFormat();
596 OSL_ENSURE(pApply
, "impossible");
598 pBreak
= &pApply
->GetFormatAttr(RES_BREAK
);
600 else if (const SwContentNode
*pNd
= rNd
.GetContentNode())
601 pBreak
= &pNd
->GetAttr(RES_BREAK
);
603 return pBreak
&& pBreak
->GetBreak() == SvxBreak::PageBefore
;
606 tools::Polygon
PolygonFromPolyPolygon(const tools::PolyPolygon
&rPolyPoly
)
608 if(1 == rPolyPoly
.Count())
614 // This method will now just concatenate the polygons contained
615 // in the given PolyPolygon. Anything else which might be thought of
616 // for reducing to a single polygon will just need more power and
617 // cannot create more correct results.
618 sal_uInt32
nPointCount(0);
621 for(a
= 0; a
< rPolyPoly
.Count(); a
++)
623 nPointCount
+= static_cast<sal_uInt32
>(rPolyPoly
[a
].GetSize());
626 if(nPointCount
> 0x0000ffff)
628 OSL_FAIL("PolygonFromPolyPolygon: too many points for a single polygon (!)");
629 nPointCount
= 0x0000ffff;
632 tools::Polygon
aRetval(o3tl::narrowing
<sal_uInt16
>(nPointCount
));
633 sal_uInt32
nAppendIndex(0);
635 for(a
= 0; a
< rPolyPoly
.Count(); a
++)
637 const tools::Polygon
& rCandidate
= rPolyPoly
[a
];
639 for(sal_uInt16
b(0); nAppendIndex
<= nPointCount
&& b
< rCandidate
.GetSize(); b
++)
641 aRetval
[o3tl::narrowing
<sal_uInt16
>(nAppendIndex
++)] = rCandidate
[b
];
649 tools::Polygon
CorrectWordWrapPolygonForExport(const tools::PolyPolygon
& rPolyPoly
, const SwNoTextNode
* pNd
, bool bCorrectCrop
)
651 tools::Polygon
aPoly(PolygonFromPolyPolygon(rPolyPoly
));
652 const Size
&rOrigSize
= pNd
->GetGraphic().GetPrefSize();
654 const SwAttrSet
* pAttrSet
= pNd
->GetpSwAttrSet();
655 if (bCorrectCrop
&& pAttrSet
)
657 if (pAttrSet
->HasItem(RES_GRFATR_CROPGRF
))
659 // Word's wrap polygon deals with a canvas which has the size of the already
660 // cropped graphic, do the opposite of correctCrop() in writerfilter/.
661 const SwCropGrf
& rCrop
= pAttrSet
->GetCropGrf();
662 sal_Int32 nCropLeft
= convertTwipToMm100(rCrop
.GetLeft());
663 sal_Int32 nCropRight
= convertTwipToMm100(rCrop
.GetRight());
664 sal_Int32 nCropTop
= convertTwipToMm100(rCrop
.GetTop());
665 sal_Int32 nCropBottom
= convertTwipToMm100(rCrop
.GetBottom());
666 aPoly
.Move(-nCropLeft
, -nCropTop
);
668 Fraction
aScaleX(rOrigSize
.getWidth(), rOrigSize
.getWidth() - nCropLeft
- nCropRight
);
669 Fraction
aScaleY(rOrigSize
.getHeight(), rOrigSize
.getHeight() - nCropTop
- nCropBottom
);
670 aPoly
.Scale(double(aScaleX
), double(aScaleY
));
674 Fraction
aMapPolyX(ww::nWrap100Percent
, rOrigSize
.Width());
675 Fraction
aMapPolyY(ww::nWrap100Percent
, rOrigSize
.Height());
676 aPoly
.Scale(double(aMapPolyX
), double(aMapPolyY
));
679 a) stretch right bound by 15twips
680 b) shrink bottom bound to where it would have been in word
681 c) Move it to the left by 15twips
683 See the import for details
685 const Size
&rSize
= pNd
->GetTwipSize();
686 Fraction
aMoveHack(ww::nWrap100Percent
, rSize
.Width());
687 aMoveHack
*= Fraction(15, 1);
688 tools::Long
nMove(aMoveHack
);
690 Fraction
aHackX(ww::nWrap100Percent
+ nMove
,
691 ww::nWrap100Percent
);
692 Fraction
aHackY(ww::nWrap100Percent
- nMove
,
693 ww::nWrap100Percent
);
694 aPoly
.Scale(double(aHackX
), double(aHackY
));
696 aPoly
.Move(-nMove
, 0);
700 void RedlineStack::open(const SwPosition
& rPos
, const SfxPoolItem
& rAttr
)
702 OSL_ENSURE(rAttr
.Which() == RES_FLTR_REDLINE
, "not a redline");
703 maStack
.emplace_back(new SwFltStackEntry(rPos
, std::unique_ptr
<SfxPoolItem
>(rAttr
.Clone())));
708 class SameOpenRedlineType
713 explicit SameOpenRedlineType(RedlineType eType
) : meType(eType
) {}
714 bool operator()(const std::unique_ptr
<SwFltStackEntry
> & pEntry
) const
716 const SwFltRedline
*pTest
= static_cast<const SwFltRedline
*>
717 (pEntry
->m_pAttr
.get());
718 return (pEntry
->m_bOpen
&& (pTest
->m_eType
== meType
));
724 bool RedlineStack::close(const SwPosition
& rPos
, RedlineType eType
)
726 //Search from end for same type
727 auto aResult
= std::find_if(maStack
.rbegin(), maStack
.rend(),
728 SameOpenRedlineType(eType
));
729 if (aResult
!= maStack
.rend())
731 SwTextNode
*const pNode(rPos
.GetNode().GetTextNode());
732 sal_Int32
const nIndex(rPos
.GetContentIndex());
733 // HACK to prevent overlap of field-mark and redline,
734 // which would destroy field-mark invariants when the redline
735 // is hidden: move the redline end one to the left
736 if (pNode
&& nIndex
> 0
737 && pNode
->GetText()[nIndex
- 1] == CH_TXT_ATR_FIELDEND
)
739 SwPosition
const end(*rPos
.GetNode().GetTextNode(),
741 sw::mark::IFieldmark
*const pFieldMark(
742 rPos
.GetDoc().getIDocumentMarkAccess()->getFieldmarkAt(end
));
743 SAL_WARN_IF(!pFieldMark
, "sw.ww8", "expected a field mark");
744 if (pFieldMark
&& pFieldMark
->GetMarkPos().GetNodeIndex() == (*aResult
)->m_aMkPos
.m_nNode
.GetIndex()+1
745 && pFieldMark
->GetMarkPos().GetContentIndex() < (*aResult
)->m_aMkPos
.m_nContent
)
747 (*aResult
)->SetEndPos(end
);
751 (*aResult
)->SetEndPos(rPos
);
757 void RedlineStack::closeall(const SwPosition
& rPos
)
759 std::for_each(maStack
.begin(), maStack
.end(), SetEndIfOpen(rPos
));
762 void MoveAttrFieldmarkInserted(SwFltPosition
& rMkPos
, SwFltPosition
& rPtPos
, const SwPosition
& rPos
)
764 sal_Int32
const nInserted
= 2; // CH_TXT_ATR_FIELDSTART, CH_TXT_ATR_FIELDSEP
765 SwNodeOffset nPosNd
= rPos
.GetNodeIndex();
766 sal_Int32 nPosCt
= rPos
.GetContentIndex() - nInserted
;
768 bool const isPoint(rMkPos
== rPtPos
);
769 if ((rMkPos
.m_nNode
.GetIndex()+1 == nPosNd
) &&
770 (nPosCt
<= rMkPos
.m_nContent
))
772 rMkPos
.m_nContent
+= nInserted
;
773 SAL_WARN_IF(rMkPos
.m_nContent
> rPos
.GetNodes()[nPosNd
]->GetContentNode()->Len(),
774 "sw.ww8", "redline ends after end of line");
775 if (isPoint
) // sigh ... important special case...
777 rPtPos
.m_nContent
+= nInserted
;
781 // for the end position, leave it alone if it's *on* the dummy
782 // char position, that should remain *before*
783 if ((rPtPos
.m_nNode
.GetIndex()+1 == nPosNd
) &&
784 (nPosCt
< rPtPos
.m_nContent
))
786 rPtPos
.m_nContent
+= nInserted
;
787 SAL_WARN_IF(rPtPos
.m_nContent
> rPos
.GetNodes()[nPosNd
]->GetContentNode()->Len(),
788 "sw.ww8", "range ends after end of line");
792 void RedlineStack::MoveAttrsFieldmarkInserted(const SwPosition
& rPos
)
794 for (size_t i
= 0, nCnt
= maStack
.size(); i
< nCnt
; ++i
)
796 SwFltStackEntry
& rEntry
= *maStack
[i
];
797 MoveAttrFieldmarkInserted(rEntry
.m_aMkPos
, rEntry
.m_aPtPos
, rPos
);
801 void SetInDocAndDelete::operator()(std::unique_ptr
<SwFltStackEntry
>& pEntry
)
803 SwPaM
aRegion(pEntry
->m_aMkPos
.m_nNode
);
804 if (pEntry
->MakeRegion(mrDoc
, aRegion
,
805 SwFltStackEntry::RegionMode::CheckNodes
|SwFltStackEntry::RegionMode::CheckFieldmark
) &&
806 (*aRegion
.GetPoint() != *aRegion
.GetMark())
809 mrDoc
.getIDocumentRedlineAccess().SetRedlineFlags(RedlineFlags::On
| RedlineFlags::ShowInsert
|
810 RedlineFlags::ShowDelete
);
811 const SwFltRedline
*pFltRedline
= static_cast<const SwFltRedline
*>
812 (pEntry
->m_pAttr
.get());
814 SwRedlineData
aData(pFltRedline
->m_eType
, pFltRedline
->m_nAutorNo
,
815 pFltRedline
->m_aStamp
, OUString(), nullptr);
817 SwRangeRedline
*const pNewRedline(new SwRangeRedline(aData
, aRegion
));
818 // the point node may be deleted in AppendRedline, so park
819 // the PaM somewhere safe
820 aRegion
.DeleteMark();
821 aRegion
.GetPoint()->Assign(*mrDoc
.GetNodes()[SwNodeOffset(0)]);
822 mrDoc
.getIDocumentRedlineAccess().AppendRedline(pNewRedline
, true);
823 mrDoc
.getIDocumentRedlineAccess().SetRedlineFlags(RedlineFlags::NONE
| RedlineFlags::ShowInsert
|
824 RedlineFlags::ShowDelete
);
829 bool CompareRedlines::operator()(const std::unique_ptr
<SwFltStackEntry
> & pOneE
,
830 const std::unique_ptr
<SwFltStackEntry
> & pTwoE
) const
832 const SwFltRedline
*pOne
= static_cast<const SwFltRedline
*>
833 (pOneE
->m_pAttr
.get());
834 const SwFltRedline
*pTwo
= static_cast<const SwFltRedline
*>
835 (pTwoE
->m_pAttr
.get());
837 //Return the earlier time, if two have the same time, prioritize
838 //inserts over deletes
839 if (pOne
->m_aStamp
== pTwo
->m_aStamp
)
840 return (pOne
->m_eType
== RedlineType::Insert
&& pTwo
->m_eType
!= RedlineType::Insert
);
842 return (pOne
->m_aStamp
< pTwo
->m_aStamp
);
845 RedlineStack::~RedlineStack()
847 std::stable_sort(maStack
.begin(), maStack
.end(), CompareRedlines());
848 std::for_each(maStack
.begin(), maStack
.end(), SetInDocAndDelete(mrDoc
));
851 sal_uInt16
WrtRedlineAuthor::AddName( const OUString
& rNm
)
854 auto aIter
= std::find(maAuthors
.begin(), maAuthors
.end(), rNm
);
855 if (aIter
!= maAuthors
.end())
856 nRet
= static_cast< sal_uInt16
>(aIter
- maAuthors
.begin());
859 nRet
= static_cast< sal_uInt16
>(maAuthors
.size());
860 maAuthors
.push_back(rNm
);
868 InsertedTableListener::InsertedTableListener(SwTableNode
& rNode
)
869 : m_pTableNode(&rNode
)
871 StartListening(rNode
.GetNotifier());
874 SwTableNode
* InsertedTableListener::GetTableNode()
875 { return m_pTableNode
; }
877 void InsertedTableListener::Notify(const SfxHint
& rHint
)
879 if(rHint
.GetId() == SfxHintId::Dying
)
880 m_pTableNode
= nullptr;
883 InsertedTablesManager::InsertedTablesManager(const SwDoc
&rDoc
)
884 : mbHasRoot(rDoc
.getIDocumentLayoutAccess().GetCurrentLayout())
887 void InsertedTablesManager::DelAndMakeTableFrames()
891 for (auto& aTable
: maTables
)
893 // If already a layout exists, then the BoxFrames must recreated at this table
894 SwTableNode
*pTable
= aTable
.first
->GetTableNode();
895 OSL_ENSURE(pTable
, "Why no expected table");
898 SwFrameFormat
* pFrameFormat
= pTable
->GetTable().GetFrameFormat();
900 if (pFrameFormat
!= nullptr)
902 SwPosition
*pIndex
= aTable
.second
;
904 pTable
->MakeOwnFrames(pIndex
);
910 void InsertedTablesManager::InsertTable(SwTableNode
& rTableNode
, SwPaM
& rPaM
)
914 //Associate this tablenode with this after position, replace an old
915 //node association if necessary
917 std::unique_ptr
<InsertedTableListener
>(new InsertedTableListener(rTableNode
)),
924 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */