atrflyin.cxx Modify no more
the fragile tests depending on specific order of objects any a bit
unfortunate ...
Change-Id: Ib74ec2a69c95e6ca859d7c75796081ac889ac32d
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/107647
Tested-by: Jenkins
Reviewed-by: Bjoern Michaelsen <bjoern.michaelsen@libreoffice.org>
diff --git a/sw/qa/core/txtnode/txtnode.cxx b/sw/qa/core/txtnode/txtnode.cxx
index 1c4d48b..3874f0f 100644
--- a/sw/qa/core/txtnode/txtnode.cxx
+++ b/sw/qa/core/txtnode/txtnode.cxx
@@ -80,7 +80,7 @@ CPPUNIT_TEST_FIXTURE(SwCoreTxtnodeTest, testTextBoxNodeSplit)
SwWrtShell* pWrtShell = pShell->GetWrtShell();
pWrtShell->SttEndDoc(/*bStart=*/false);
// Without the accompanying fix in place, this would have crashed in
// SwFlyAtContentFrame::Modify().
// SwFlyAtContentFrame::SwClientNotify().
pWrtShell->SplitNode();
}
diff --git a/sw/qa/extras/mailmerge/mailmerge.cxx b/sw/qa/extras/mailmerge/mailmerge.cxx
index 17d92d3..824c4bb 100644
--- a/sw/qa/extras/mailmerge/mailmerge.cxx
+++ b/sw/qa/extras/mailmerge/mailmerge.cxx
@@ -397,7 +397,7 @@ DECLARE_FILE_MAILMERGE_TEST(testMissingDefaultLineColor, "missing-default-line-c
executeMailMerge();
// The document was created by LO version which didn't write out the default value for line color
// (see XMLGraphicsDefaultStyle::SetDefaults()).
uno::Reference<beans::XPropertySet> xPropertySet(getShape(1), uno::UNO_QUERY);
uno::Reference<beans::XPropertySet> xPropertySet(getShape(4), uno::UNO_QUERY);
// Lines do not have a line color.
CPPUNIT_ASSERT( !xPropertySet->getPropertySetInfo()->hasPropertyByName( "LineColor" ));
SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument *>(mxComponent.get());
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport.cxx
index 26151eb..6275ee8 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport.cxx
@@ -467,31 +467,31 @@ DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testMsoPosition, "bnc884615-mso-position.doc
// We write the frames out in different order than they were read, so check it's the correct
// textbox first by checking width. These tests may need reordering if that gets fixed.
OUString style1 = getXPath(doc, "/w:ftr/w:p/w:r[3]/mc:AlternateContent/mc:Fallback/w:pict/v:rect", "style");
CPPUNIT_ASSERT( style1.indexOf( ";width:531pt;" ) >= 0 );
CPPUNIT_ASSERT( style1.indexOf( ";mso-position-vertical-relative:page" ) >= 0 );
CPPUNIT_ASSERT( style1.indexOf( ";mso-position-horizontal-relative:page" ) >= 0 );
CPPUNIT_ASSERT( style1.indexOf( ";width:36pt;" ) >= 0 );
CPPUNIT_ASSERT( style1.indexOf( ";mso-position-horizontal-relative:text" ) >= 0 );
CPPUNIT_ASSERT( style1.indexOf( ";mso-position-vertical-relative:text" ) >= 0 );
OUString style2 = getXPath(doc, "/w:ftr/w:p/w:r[4]/mc:AlternateContent/mc:Fallback/w:pict/v:rect", "style");
CPPUNIT_ASSERT( style2.indexOf( ";width:549pt;" ) >= 0 );
CPPUNIT_ASSERT( style2.indexOf( ";mso-position-vertical-relative:text" ) >= 0 );
CPPUNIT_ASSERT( style2.indexOf( ";mso-position-horizontal:center" ) >= 0 );
CPPUNIT_ASSERT( style2.indexOf( ";mso-position-horizontal-relative:text" ) >= 0 );
OUString style3 = getXPath(doc, "/w:ftr/w:p/w:r[5]/mc:AlternateContent/mc:Fallback/w:pict/v:rect", "style");
CPPUNIT_ASSERT( style3.indexOf( ";width:36pt;" ) >= 0 );
CPPUNIT_ASSERT( style3.indexOf( ";mso-position-horizontal-relative:text" ) >= 0 );
CPPUNIT_ASSERT( style3.indexOf( ";mso-position-vertical-relative:text" ) >= 0 );
CPPUNIT_ASSERT( style3.indexOf( ";width:531pt;" ) >= 0 );
CPPUNIT_ASSERT( style3.indexOf( ";mso-position-vertical-relative:page" ) >= 0 );
CPPUNIT_ASSERT( style3.indexOf( ";mso-position-horizontal-relative:page" ) >= 0 );
}
xmlDocUniquePtr doc = parseExport("word/header1.xml");
OUString style1 = getXPath(doc, "/w:hdr/w:p/w:r[2]/mc:AlternateContent/mc:Fallback/w:pict/v:rect", "style");
CPPUNIT_ASSERT( style1.indexOf( ";width:335.75pt;" ) >= 0 );
CPPUNIT_ASSERT( style1.indexOf( ";width:138.15pt;" ) >= 0 );
CPPUNIT_ASSERT( style1.indexOf( ";mso-position-horizontal-relative:page" ) >= 0 );
CPPUNIT_ASSERT( style1.indexOf( ";mso-position-vertical-relative:page" ) >= 0 );
OUString style2 = getXPath(doc, "/w:hdr/w:p/w:r[3]/mc:AlternateContent/mc:Fallback/w:pict/v:rect", "style");
CPPUNIT_ASSERT( style2.indexOf( ";width:138.15pt;" ) >= 0 );
CPPUNIT_ASSERT( style2.indexOf( ";width:163.8pt;" ) >= 0 );
CPPUNIT_ASSERT( style2.indexOf( ";mso-position-horizontal-relative:page" ) >= 0 );
CPPUNIT_ASSERT( style2.indexOf( ";mso-position-vertical-relative:page" ) >= 0 );
OUString style3 = getXPath(doc, "/w:hdr/w:p/w:r[4]/mc:AlternateContent/mc:Fallback/w:pict/v:rect", "style");
CPPUNIT_ASSERT( style3.indexOf( ";width:163.8pt;" ) >= 0 );
CPPUNIT_ASSERT( style3.indexOf( ";width:335.75pt;" ) >= 0 );
CPPUNIT_ASSERT( style3.indexOf( ";mso-position-horizontal-relative:page" ) >= 0 );
CPPUNIT_ASSERT( style3.indexOf( ";mso-position-vertical-relative:page" ) >= 0 );
diff --git a/sw/source/core/inc/flyfrm.hxx b/sw/source/core/inc/flyfrm.hxx
index fec9a49..52295f3 100644
--- a/sw/source/core/inc/flyfrm.hxx
+++ b/sw/source/core/inc/flyfrm.hxx
@@ -75,6 +75,7 @@ class SW_DLLPUBLIC SwFlyFrame : public SwLayoutFrame, public SwAnchoredObject
protected:
// Predecessor/Successor for chaining with text flow
SwFlyFrame *m_pPrevLink, *m_pNextLink;
static const SwFormatAnchor* GetAnchorFromPoolItem(const SfxPoolItem& rItem);
private:
// It must be possible to block Content-bound flys so that they will be not
diff --git a/sw/source/core/inc/flyfrms.hxx b/sw/source/core/inc/flyfrms.hxx
index a401e4a..cb9ef4f 100644
--- a/sw/source/core/inc/flyfrms.hxx
+++ b/sw/source/core/inc/flyfrms.hxx
@@ -154,9 +154,8 @@ public:
};
// Flys that are bound to Content but not in Content
class SwFlyAtContentFrame : public SwFlyFreeFrame
class SwFlyAtContentFrame final: public SwFlyFreeFrame
{
protected:
virtual void MakeAll(vcl::RenderContext* pRenderContext) override;
// #i28701#
@@ -168,7 +167,7 @@ protected:
#i28701#
*/
virtual void RegisterAtCorrectPage() override;
virtual void Modify( const SfxPoolItem*, const SfxPoolItem* ) override;
virtual void SwClientNotify(const SwModify&, const SfxHint&) override;
public:
// #i28701#
diff --git a/sw/source/core/layout/fly.cxx b/sw/source/core/layout/fly.cxx
index 5dd10de..b45509d 100644
--- a/sw/source/core/layout/fly.cxx
+++ b/sw/source/core/layout/fly.cxx
@@ -2927,4 +2927,16 @@ SwTwips SwFlyFrame::CalcContentHeight(const SwBorderAttrs *pAttrs, const SwTwips
return nHeight;
}
const SwFormatAnchor* SwFlyFrame::GetAnchorFromPoolItem(const SfxPoolItem& rItem)
{
switch(rItem.Which())
{
case RES_ATTRSET_CHG:
return static_cast<const SwAttrSetChg*>(&rItem)->GetChgSet()->GetItem(RES_ANCHOR, false);
case RES_ANCHOR:
return static_cast<const SwFormatAnchor*>(&rItem);
default:
return nullptr;
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/layout/flycnt.cxx b/sw/source/core/layout/flycnt.cxx
index 4dc2db5..0b159ea 100644
--- a/sw/source/core/layout/flycnt.cxx
+++ b/sw/source/core/layout/flycnt.cxx
@@ -79,123 +79,107 @@ SwFlyAtContentFrame::SwFlyAtContentFrame( SwFlyFrameFormat *pFormat, SwFrame* pS
// #i28701#
void SwFlyAtContentFrame::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew )
void SwFlyAtContentFrame::SwClientNotify(const SwModify&, const SfxHint& rHint)
{
const SwFormatAnchor *pAnch = nullptr;
if (pNew)
auto pLegacy = dynamic_cast<const sw::LegacyModifyHint*>(&rHint);
if(!pLegacy)
return;
const SwFormatAnchor* pAnch = pLegacy->m_pNew ? GetAnchorFromPoolItem(*pLegacy->m_pNew) : nullptr;
if(!pAnch)
{
const sal_uInt16 nWhich = pNew->Which();
if( RES_ATTRSET_CHG == nWhich && SfxItemState::SET ==
static_cast<const SwAttrSetChg*>(pNew)->GetChgSet()->GetItemState( RES_ANCHOR, false,
reinterpret_cast<const SfxPoolItem**>(&pAnch) ))
; // The anchor pointer is set at GetItemState!
else if( RES_ANCHOR == nWhich )
{
//Change anchor, I move myself to a new place.
//The anchor type must not change, this is only possible using
//SwFEShell.
pAnch = static_cast<const SwFormatAnchor*>(pNew);
}
SwFlyFrame::Modify(pLegacy->m_pOld, pLegacy->m_pNew);
return;
}
OSL_ENSURE(pAnch->GetAnchorId() == GetFormat()->GetAnchor().GetAnchorId(),
"Illegal change of anchor type.");
if( pAnch )
//Unregister, get hold of a new anchor and attach it
SwRect aOld(GetObjRectWithSpaces());
SwPageFrame* pOldPage = FindPageFrame();
const SwFrame* pOldAnchor = GetAnchorFrame();
SwContentFrame* pContent = const_cast<SwContentFrame*>(static_cast<const SwContentFrame*>(GetAnchorFrame()));
AnchorFrame()->RemoveFly(this);
const bool bBodyFootnote = (pContent->IsInDocBody() || pContent->IsInFootnote());
// Search the new anchor using the NodeIdx; the relation between old
// and new NodeIdx determines the search direction
const SwNodeIndex aNewIdx(pAnch->GetContentAnchor()->nNode);
SwNodeIndex aOldIdx(pContent->IsTextFrame()
// sw_redlinehide: can pick any node here, the compare with
// FrameContainsNode should catch it
? *static_cast<SwTextFrame *>(pContent)->GetTextNodeFirst()
: *static_cast<SwNoTextFrame *>(pContent)->GetNode());
//fix: depending on which index was smaller, searching in the do-while
//loop previously was done forward or backwards respectively. This however
//could lead to an infinite loop. To at least avoid the loop, searching
//is now done in only one direction. Getting hold of a frame from the node
//is still possible if the new anchor could not be found. Chances are
//good that this will be the correct one.
// consider the case that at found anchor frame candidate already a
// fly frame of the given fly format is registered.
// consider, that <pContent> is the already
// the new anchor frame.
bool bFound(FrameContainsNode(*pContent, aNewIdx.GetIndex()));
const bool bNext = !bFound && aOldIdx < aNewIdx;
while(pContent && !bFound)
{
OSL_ENSURE( pAnch->GetAnchorId() == GetFormat()->GetAnchor().GetAnchorId(),
"Illegal change of anchor type. " );
//Unregister, get hold of a new anchor and attach it
SwRect aOld( GetObjRectWithSpaces() );
SwPageFrame *pOldPage = FindPageFrame();
const SwFrame *pOldAnchor = GetAnchorFrame();
SwContentFrame *pContent = const_cast<SwContentFrame*>(static_cast<const SwContentFrame*>(GetAnchorFrame()));
AnchorFrame()->RemoveFly( this );
const bool bBodyFootnote = (pContent->IsInDocBody() || pContent->IsInFootnote());
// Search the new anchor using the NodeIdx; the relation between old
// and new NodeIdx determines the search direction
const SwNodeIndex aNewIdx( pAnch->GetContentAnchor()->nNode );
SwNodeIndex aOldIdx( pContent->IsTextFrame()
// sw_redlinehide: can pick any node here, the compare with
// FrameContainsNode should catch it
? *static_cast<SwTextFrame *>(pContent)->GetTextNodeFirst()
: *static_cast<SwNoTextFrame *>(pContent)->GetNode() );
//fix: depending on which index was smaller, searching in the do-while
//loop previously was done forward or backwards respectively. This however
//could lead to an infinite loop. To at least avoid the loop, searching
//is now done in only one direction. Getting hold of a frame from the node
//is still possible if the new anchor could not be found. Chances are
//good that this will be the correct one.
// consider the case that at found anchor frame candidate already a
// fly frame of the given fly format is registered.
// consider, that <pContent> is the already
// the new anchor frame.
bool bFound( FrameContainsNode(*pContent, aNewIdx.GetIndex()) );
const bool bNext = !bFound && aOldIdx < aNewIdx;
while ( pContent && !bFound )
do
{
do
{
if ( bNext )
pContent = pContent->GetNextContentFrame();
else
pContent = pContent->GetPrevContentFrame();
} while ( pContent &&
( bBodyFootnote != ( pContent->IsInDocBody() ||
pContent->IsInFootnote() ) ) );
if ( pContent )
bFound = FrameContainsNode(*pContent, aNewIdx.GetIndex());
if(bNext)
pContent = pContent->GetNextContentFrame();
else
pContent = pContent->GetPrevContentFrame();
} while(pContent &&
(bBodyFootnote != (pContent->IsInDocBody() || pContent->IsInFootnote())));
if(pContent)
bFound = FrameContainsNode(*pContent, aNewIdx.GetIndex());
// check, if at found anchor frame candidate already a fly frame
// of the given fly frame format is registered.
if (bFound && pContent && pContent->GetDrawObjs())
// check, if at found anchor frame candidate already a fly frame
// of the given fly frame format is registered.
if(bFound && pContent && pContent->GetDrawObjs())
{
SwFrameFormat* pMyFlyFrameFormat(&GetFrameFormat());
SwSortedObjs &rObjs = *pContent->GetDrawObjs();
for(SwAnchoredObject* rObj : rObjs)
{
SwFrameFormat* pMyFlyFrameFormat( &GetFrameFormat() );
SwSortedObjs &rObjs = *pContent->GetDrawObjs();
for(SwAnchoredObject* rObj : rObjs)
SwFlyFrame* pFlyFrame = dynamic_cast<SwFlyFrame*>(rObj);
if (pFlyFrame &&
&(pFlyFrame->GetFrameFormat()) == pMyFlyFrameFormat)
{
SwFlyFrame* pFlyFrame = dynamic_cast<SwFlyFrame*>(rObj);
if ( pFlyFrame &&
&(pFlyFrame->GetFrameFormat()) == pMyFlyFrameFormat )
{
bFound = false;
break;
}
bFound = false;
break;
}
}
}
if ( !pContent )
{
SwContentNode *pNode = aNewIdx.GetNode().GetContentNode();
std::pair<Point, bool> const tmp(pOldAnchor->getFrameArea().Pos(), false);
pContent = pNode->getLayoutFrame(getRootFrame(), nullptr, &tmp);
OSL_ENSURE( pContent, "New anchor not found" );
}
//Flys are never attached to a follow, but always on the master which
//we are going to search now.
SwContentFrame* pFlow = pContent;
while ( pFlow->IsFollow() )
pFlow = pFlow->FindMaster();
pContent = pFlow;
//and *puff* it's attached...
pContent->AppendFly( this );
if ( pOldPage && pOldPage != FindPageFrame() )
NotifyBackground( pOldPage, aOld, PrepareHint::FlyFrameLeave );
//Fix(3495)
InvalidatePos_();
InvalidatePage();
SetNotifyBack();
// #i28701# - reset member <maLastCharRect> and
// <mnLastTopOfLine> for to-character anchored objects.
ClearCharRectAndTopOfLine();
}
else
SwFlyFrame::Modify( pOld, pNew );
if(!pContent)
{
SwContentNode *pNode = aNewIdx.GetNode().GetContentNode();
std::pair<Point, bool> const tmp(pOldAnchor->getFrameArea().Pos(), false);
pContent = pNode->getLayoutFrame(getRootFrame(), nullptr, &tmp);
OSL_ENSURE(pContent, "New anchor not found");
}
//Flys are never attached to a follow, but always on the master which
//we are going to search now.
SwContentFrame* pFlow = pContent;
while(pFlow->IsFollow())
pFlow = pFlow->FindMaster();
pContent = pFlow;
//and *puff* it's attached...
pContent->AppendFly( this );
if(pOldPage && pOldPage != FindPageFrame())
NotifyBackground(pOldPage, aOld, PrepareHint::FlyFrameLeave);
//Fix(3495)
InvalidatePos_();
InvalidatePage();
SetNotifyBack();
// #i28701# - reset member <maLastCharRect> and
// <mnLastTopOfLine> for to-character anchored objects.
ClearCharRectAndTopOfLine();
}
//We need some helper classes to monitor the oscillation and a few functions
diff --git a/sw/source/core/layout/flyincnt.cxx b/sw/source/core/layout/flyincnt.cxx
index 69417d7..c5c647e 100644
--- a/sw/source/core/layout/flyincnt.cxx
+++ b/sw/source/core/layout/flyincnt.cxx
@@ -90,7 +90,7 @@ void SwFlyInContentFrame::SetRefPoint( const Point& rPoint,
}
}
void SwFlyInContentFrame::SwClientNotify(const SwModify&, const SfxHint& rHint)
void SwFlyInContentFrame::SwClientNotify(const SwModify& rMod, const SfxHint& rHint)
{
auto pLegacy = dynamic_cast<const sw::LegacyModifyHint*>(&rHint);
if(!pLegacy)
@@ -130,7 +130,7 @@ void SwFlyInContentFrame::SwClientNotify(const SwModify&, const SfxHint& rHint)
}
if(aSuperArgs.second)
{
SwFlyFrame::Modify(aSuperArgs.first, aSuperArgs.second);
SwFlyFrame::SwClientNotify(rMod, sw::LegacyModifyHint(aSuperArgs.first, aSuperArgs.second));
if(GetAnchorFrame())
AnchorFrame()->Prepare(PrepareHint::FlyFrameAttributesChanged, GetFormat());
}
diff --git a/sw/source/core/layout/flylay.cxx b/sw/source/core/layout/flylay.cxx
index 2a084e6..4159be4 100644
--- a/sw/source/core/layout/flylay.cxx
+++ b/sw/source/core/layout/flylay.cxx
@@ -728,19 +728,9 @@ SwFlyLayFrame::SwFlyLayFrame( SwFlyFrameFormat *pFormat, SwFrame* pSib, SwFrame
void SwFlyLayFrame::SwClientNotify(const SwModify&, const SfxHint& rHint)
{
auto pLegacy = dynamic_cast<const sw::LegacyModifyHint*>(&rHint);
if(!pLegacy)
if(!pLegacy || !pLegacy->m_pNew)
return;
const SwFormatAnchor* pAnch = nullptr;
switch(pLegacy->GetWhich())
{
case RES_ATTRSET_CHG:
{
pAnch = static_cast<const SwAttrSetChg*>(pLegacy->m_pNew)->GetChgSet()->GetItem(RES_ANCHOR, false);
break;
}
case RES_ANCHOR:
pAnch = static_cast<const SwFormatAnchor*>(pLegacy->m_pNew);
}
const auto pAnch = GetAnchorFromPoolItem(*pLegacy->m_pNew);
if(!pAnch)
{
diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx
index 8d64d23..57b4d43 100644
--- a/sw/source/core/layout/wsfrm.cxx
+++ b/sw/source/core/layout/wsfrm.cxx
@@ -4371,7 +4371,7 @@ static void UnHideRedlines(SwRootFrame & rLayout,
pObject->InvalidateObjPos();
}
}
// SwFlyAtContentFrame::Modify() always appends to
// SwFlyAtContentFrame::SwClientNotify() always appends to
// the master frame, so do the same here.
// (RemoveFootnotesForNode must be called at least once)
if (!pFrame->IsFollow())
diff --git a/sw/source/core/txtnode/atrflyin.cxx b/sw/source/core/txtnode/atrflyin.cxx
index d04da84..49c9d1d 100644
--- a/sw/source/core/txtnode/atrflyin.cxx
+++ b/sw/source/core/txtnode/atrflyin.cxx
@@ -209,7 +209,7 @@ void SwTextFlyCnt::SetAnchor( const SwTextNode *pNode )
SwFormatAnchor aTextBoxAnchor(pTextBox->GetAnchor());
aTextBoxAnchor.SetAnchor(aAnchor.GetContentAnchor());
// SwFlyAtContentFrame::Modify() assumes the anchor has a matching layout frame, which
// SwFlyAtContentFrame::SwClientNotify() assumes the anchor has a matching layout frame, which
// may not be the case when we're in the process of a node split, so block
// notifications.
bool bIsInSplitNode = pNode->GetpSwpHints() && pNode->GetpSwpHints()->IsInSplitNode();