diff options
Diffstat (limited to 'sw/source')
30 files changed, 377 insertions, 98 deletions
diff --git a/sw/source/core/bastyp/swrect.cxx b/sw/source/core/bastyp/swrect.cxx index 8702d8f15733..ddd2849b6358 100644 --- a/sw/source/core/bastyp/swrect.cxx +++ b/sw/source/core/bastyp/swrect.cxx @@ -19,6 +19,8 @@ #include <swrect.hxx> +#include <libxml/xmlwriter.h> + #ifdef DBG_UTIL #include <tools/stream.hxx> #endif @@ -221,6 +223,16 @@ void SwRect::SetUpperRightCorner( const Point& rNew ) void SwRect::SetLowerLeftCorner( const Point& rNew ) { m_Point = Point(rNew.X(), rNew.Y() - m_Size.getHeight()); } +void SwRect::dumpAsXmlAttributes(xmlTextWriterPtr writer) const +{ + xmlTextWriterWriteFormatAttribute(writer, BAD_CAST("left"), "%li", Left()); + xmlTextWriterWriteFormatAttribute(writer, BAD_CAST("top"), "%li", Top()); + xmlTextWriterWriteFormatAttribute(writer, BAD_CAST("width"), "%li", Width()); + xmlTextWriterWriteFormatAttribute(writer, BAD_CAST("height"), "%li", Height()); + xmlTextWriterWriteFormatAttribute(writer, BAD_CAST("bottom"), "%li", Bottom()); + xmlTextWriterWriteFormatAttribute(writer, BAD_CAST("right"), "%li", Right()); +} + #ifdef DBG_UTIL SvStream& WriteSwRect(SvStream &rStream, const SwRect &rRect) { diff --git a/sw/source/core/crsr/callnk.cxx b/sw/source/core/crsr/callnk.cxx index 81240340376f..a87b42080f77 100644 --- a/sw/source/core/crsr/callnk.cxx +++ b/sw/source/core/crsr/callnk.cxx @@ -36,6 +36,7 @@ #include <flyfrm.hxx> #include <breakit.hxx> #include <vcl/window.hxx> +#include <UndoTable.hxx> SwCallLink::SwCallLink( SwCursorShell & rSh ) : rShell( rSh ) @@ -65,26 +66,51 @@ SwCallLink::SwCallLink( SwCursorShell & rSh ) } } -static void lcl_notifyRow(const SwContentNode* pNode, SwCursorShell const & rShell) +namespace sw { + +/** + An empty paragraph inside a table with a nested table preceding it + should be hidden, unless the cursor is positioned in the paragraph. + + If the cursor is now (or was previously) inside such a paragraph, + send a size change notification on the row frame to force reformatting. + */ +void NotifyTableCollapsedParagraph(const SwContentNode *const pNode, SwCursorShell *const pShell) { if ( !pNode ) return; - SwFrame *const pMyFrame = pNode->getLayoutFrame( rShell.GetLayout() ); + SwFrame *const pMyFrame = pNode->getLayoutFrame(pShell ? pShell->GetLayout() : nullptr); if ( !pMyFrame ) return; - // We need to emulated a change of the row height in order - // to have the complete row redrawn + // important: only invalidate layout if something is actually hidden or + // shown! Otherwise performance is going to suffer with "difficult" tables. + if (!pMyFrame->IsCollapse()) + return; + SwRowFrame *const pRow = pMyFrame->FindRowFrame(); if ( !pRow ) return; const SwTableLine* pLine = pRow->GetTabLine( ); + + if (pShell && (pShell->IsTableMode() || (pShell->StartsWithTable() && pShell->ExtendedSelectedAll()))) + { + // If we have a table selection, then avoid the notification: it's not necessary (the text + // cursor needs no updating) and the notification may kill the selection overlay, leading to + // flicker. + // Same for whole-document selection when it starts with a table. + return; + } + + // notify a change in frame size to force reformatting of the row SwFormatFrameSize aSize = pLine->GetFrameFormat()->GetFrameSize(); pRow->ModifyNotification(nullptr, &aSize); } +} // namespace sw + SwCallLink::~SwCallLink() COVERITY_NOEXCEPT_FALSE { if( nNdTyp == SwNodeType::NONE || !rShell.m_bCallChgLnk ) // see ctor @@ -97,15 +123,17 @@ SwCallLink::~SwCallLink() COVERITY_NOEXCEPT_FALSE if( !pCNd ) return; - lcl_notifyRow(pCNd, rShell); - - const SwDoc *pDoc=rShell.GetDoc(); - const SwContentNode *pNode = nullptr; - if ( pDoc && nNode < pDoc->GetNodes( ).Count( ) ) + if (pCNd->GetIndex() != nNode) // only if moved to different node { - pNode = pDoc->GetNodes()[nNode]->GetContentNode(); + ::sw::NotifyTableCollapsedParagraph(pCNd, &rShell); + + const SwDoc *pDoc=rShell.GetDoc(); + if (nNode < pDoc->GetNodes().Count()) + { + const SwContentNode *const pNode = pDoc->GetNodes()[nNode]->GetContentNode(); + ::sw::NotifyTableCollapsedParagraph(pNode, &rShell); + } } - lcl_notifyRow(pNode, rShell); sal_Int32 nCmp, nCurrentContent = pCurrentCursor->GetPoint()->nContent.GetIndex(); SwNodeType nNdWhich = pCNd->GetNodeType(); diff --git a/sw/source/core/doc/docfmt.cxx b/sw/source/core/doc/docfmt.cxx index e7e42b679554..d634a4f3c049 100644 --- a/sw/source/core/doc/docfmt.cxx +++ b/sw/source/core/doc/docfmt.cxx @@ -1942,6 +1942,7 @@ void SwDoc::dumpAsXml(xmlTextWriterPtr pWriter) const mpFrameFormatTable->dumpAsXml(pWriter, "frmFormatTable"); mpSpzFrameFormatTable->dumpAsXml(pWriter, "spzFrameFormatTable"); mpSectionFormatTable->dumpAsXml(pWriter); + mpTableFrameFormatTable->dumpAsXml(pWriter, "tableFrameFormatTable"); mpNumRuleTable->dumpAsXml(pWriter); getIDocumentRedlineAccess().GetRedlineTable().dumpAsXml(pWriter); getIDocumentRedlineAccess().GetExtraRedlineTable().dumpAsXml(pWriter); diff --git a/sw/source/core/inc/UndoTable.hxx b/sw/source/core/inc/UndoTable.hxx index 269644245dd0..39e46afbea28 100644 --- a/sw/source/core/inc/UndoTable.hxx +++ b/sw/source/core/inc/UndoTable.hxx @@ -43,6 +43,14 @@ class SwStartNode; class SwTableNode; class SwTableAutoFormat; class SwTableSortBoxes; +class SwContentNode; +class SwCursorShell; + +namespace sw { + +void NotifyTableCollapsedParagraph(const SwContentNode* pNode, SwCursorShell *const pShell); + +} class SwUndoInsTable : public SwUndo { diff --git a/sw/source/core/inc/frame.hxx b/sw/source/core/inc/frame.hxx index ec78d7b40188..4dadc50df4db 100644 --- a/sw/source/core/inc/frame.hxx +++ b/sw/source/core/inc/frame.hxx @@ -129,6 +129,8 @@ namespace drawinglayer { namespace attribute { class SW_DLLPUBLIC SwFrameAreaDefinition { private: + friend void FriendHackInvalidateRowFrame(SwFrameAreaDefinition &); + // The absolute position and size of the SwFrame in the document. // This values are set by the layouter implementations SwRect maFrameArea; @@ -419,7 +421,7 @@ protected: bool mbColLocked : 1; // lock Grow/Shrink for column-wise section // or fly frames, will be set in Format bool m_isInDestroy : 1; - bool mbForbidDelete : 1; + int mnForbidDelete; void ColLock() { mbColLocked = true; } void ColUnlock() { mbColLocked = false; } @@ -852,7 +854,7 @@ public: bool IsProtected() const; bool IsColLocked() const { return mbColLocked; } - virtual bool IsDeleteForbidden() const { return mbForbidDelete; } + virtual bool IsDeleteForbidden() const { return mnForbidDelete > 0; } /// this is the only way to delete a SwFrame instance static void DestroyFrame(SwFrame *const pFrame); @@ -895,8 +897,8 @@ public: void RegisterToFormat( SwFormat& rFormat ); void ValidateThisAndAllLowers( const sal_uInt16 nStage ); - void ForbidDelete() { mbForbidDelete = true; } - void AllowDelete() { mbForbidDelete = false; } + void ForbidDelete() { ++mnForbidDelete; } + void AllowDelete() { assert(mnForbidDelete > 0); --mnForbidDelete; } drawinglayer::attribute::SdrAllFillAttributesHelperPtr getSdrAllFillAttributesHelper() const; bool supportsFullDrawingLayerFillAttributeSet() const; @@ -1224,8 +1226,7 @@ public: //it in e.g. SwSectionFrame::MergeNext etc because we will need it //again after the SwFrameDeleteGuard dtor explicit SwFrameDeleteGuard(SwFrame* pFrame) - : m_pForbidFrame((pFrame && !pFrame->IsDeleteForbidden()) ? - pFrame : nullptr) + : m_pForbidFrame(pFrame) { if (m_pForbidFrame) m_pForbidFrame->ForbidDelete(); diff --git a/sw/source/core/layout/flowfrm.cxx b/sw/source/core/layout/flowfrm.cxx index 34a3258e68b4..3707c9b6db46 100644 --- a/sw/source/core/layout/flowfrm.cxx +++ b/sw/source/core/layout/flowfrm.cxx @@ -1076,6 +1076,18 @@ bool SwFlowFrame::IsPrevObjMove() const OSL_ENSURE( SwFlowFrame::CastFlowFrame( pPre ), "new flowfrm?" ); if( SwFlowFrame::CastFlowFrame( pPre )->IsAnFollow( this ) ) return false; + if (SwFlowFrame::CastFlowFrame(pPre)->IsJoinLocked()) + { + SwBorderAttrAccess baa(SwFrame::GetCache(), pPre); + SwBorderAttrs const& rAttrs(*baa.Get()); + if (SwFlowFrame::CastFlowFrame(pPre)->IsKeep(rAttrs.GetAttrSet().GetKeep(), pPre->GetBreakItem())) + { // pPre is currently being formatted - maybe it moved back but + // its objects still have the old page's body as + // mpVertPosOrientFrame and SwContentFrame::MakeAll() is calling + // pNxt->Calc() in this case so allow this frame to move back + return false; // too, else pPre is forced to move forward again. + } + } SwLayoutFrame* pPreUp = pPre->GetUpper(); // If the upper is a SectionFrame, or a column of a SectionFrame, we're // allowed to protrude out of it. However, we need to respect the diff --git a/sw/source/core/layout/ftnfrm.cxx b/sw/source/core/layout/ftnfrm.cxx index 7fd3bcbbd2f7..9400c71ea24c 100644 --- a/sw/source/core/layout/ftnfrm.cxx +++ b/sw/source/core/layout/ftnfrm.cxx @@ -2786,6 +2786,9 @@ bool SwContentFrame::MoveFootnoteCntFwd( bool bMakePage, SwFootnoteBossFrame *pO OSL_ENSURE( pTmp->IsTabFrame(), "GetNextSctLeaf: Wrong Type" ); pTmpNxt = static_cast<SwTabFrame*>(pTmp); } + // we will dereference pNewUp in the following MoveSubTree call + // so it certainly should not be deleted before that + SwFrameDeleteGuard aDeleteGuard(pNewUp); pTmpNxt->MoveSubTree( pTmpFootnote, pNewUp->GetNext() ); } } diff --git a/sw/source/core/layout/layact.cxx b/sw/source/core/layout/layact.cxx index e26c4fd3bafe..b1e029207eb0 100644 --- a/sw/source/core/layout/layact.cxx +++ b/sw/source/core/layout/layact.cxx @@ -298,7 +298,8 @@ bool SwLayAction::RemoveEmptyBrowserPages() do { if ( (pPage->GetSortedObjs() && pPage->GetSortedObjs()->size()) || - pPage->ContainsContent() ) + pPage->ContainsContent() || + pPage->FindFootnoteCont() ) pPage = static_cast<SwPageFrame*>(pPage->GetNext()); else { diff --git a/sw/source/core/layout/objectformattertxtfrm.cxx b/sw/source/core/layout/objectformattertxtfrm.cxx index 88f0bc28904f..815fb4324102 100644 --- a/sw/source/core/layout/objectformattertxtfrm.cxx +++ b/sw/source/core/layout/objectformattertxtfrm.cxx @@ -641,6 +641,7 @@ static void lcl_FormatContentOfLayoutFrame( SwLayoutFrame* pLayFrame, if ( pLowerFrame->IsLayoutFrame() ) { SwFrameDeleteGuard aCrudeHack(pLowerFrame); // ??? any issue setting this for non-footnote frames? + // prevent moving footnotes by formatting if they are already being moved lcl_FormatContentOfLayoutFrame( static_cast<SwLayoutFrame*>(pLowerFrame), pLastLowerFrame ); } @@ -686,21 +687,46 @@ void SwObjectFormatterTextFrame::FormatAnchorFrameAndItsPrevs( SwTextFrame& _rAn // for follow text frames. if ( !_rAnchorTextFrame.IsFollow() ) { + // In case the anchor frame is in a column or section, format its + // previous frames first - but don't jump out of the current layout + // environment, e.g. from footnotes into the footnote boss. + SwFrame * pSectFrame(nullptr); + SwFrame * pColFrameOfAnchor(nullptr); + for (SwFrame* pUpper = _rAnchorTextFrame.GetUpper(); + pUpper != nullptr; pUpper = pUpper->GetUpper()) + { + if (pUpper->IsCellFrame()) + { + break; // apparently nothing to be done? + } + if (pUpper->IsFootnoteFrame()) + { + SAL_INFO_IF(pColFrameOfAnchor == nullptr && pUpper->FindColFrame(), + "sw.layout", "tdf#122894 skipping column for footnote in column"); + break; // stop: prevent crash in case footnotes are being moved + } + if (pUpper->IsSctFrame()) + { + pColFrameOfAnchor = nullptr; + pSectFrame = pUpper; + break; + } + if (pColFrameOfAnchor != nullptr) + { // parent of column not a section frame => column not in section + break; + } + if (pUpper->IsColumnFrame()) + { + pColFrameOfAnchor = pUpper; + } + } + // if anchor frame is directly inside a section, format this section and // its previous frames. // Note: It's a very simple format without formatting objects. - if ( _rAnchorTextFrame.IsInSct() ) + if (pSectFrame) { - SwFrame* pSectFrame = _rAnchorTextFrame.GetUpper(); - while ( pSectFrame ) - { - if ( pSectFrame->IsSctFrame() || pSectFrame->IsCellFrame() ) - { - break; - } - pSectFrame = pSectFrame->GetUpper(); - } - if ( pSectFrame && pSectFrame->IsSctFrame() ) + assert(pSectFrame->IsSctFrame()); { // #i44049# _rAnchorTextFrame.LockJoin(); @@ -710,6 +736,8 @@ void SwObjectFormatterTextFrame::FormatAnchorFrameAndItsPrevs( SwTextFrame& _rAn // Thus, check for valid <pFrame>. while ( pFrame && pFrame != pSectFrame ) { + SwFrameDeleteGuard aDeleteFrameGuard(pFrame); + if ( pFrame->IsLayoutFrame() ) lcl_FormatContentOfLayoutFrame( static_cast<SwLayoutFrame*>(pFrame) ); else @@ -727,9 +755,9 @@ void SwObjectFormatterTextFrame::FormatAnchorFrameAndItsPrevs( SwTextFrame& _rAn // #i40140# - if anchor frame is inside a column, // format the content of the previous columns. // Note: It's a very simple format without formatting objects. - SwFrame* pColFrameOfAnchor = _rAnchorTextFrame.FindColFrame(); - if ( pColFrameOfAnchor ) + if (pColFrameOfAnchor) { + assert(pColFrameOfAnchor->IsColumnFrame()); // #i44049# _rAnchorTextFrame.LockJoin(); SwFrame* pColFrame = pColFrameOfAnchor->GetUpper()->GetLower(); diff --git a/sw/source/core/layout/sectfrm.cxx b/sw/source/core/layout/sectfrm.cxx index e085f98a262c..31a4469c510b 100644 --- a/sw/source/core/layout/sectfrm.cxx +++ b/sw/source/core/layout/sectfrm.cxx @@ -2853,7 +2853,8 @@ void SwRootFrame::DeleteEmptySct_() mpDestroy->erase( mpDestroy->begin() ); OSL_ENSURE( !pSect->IsColLocked() && !pSect->IsJoinLocked(), "DeleteEmptySct: Locked SectionFrame" ); - if( !pSect->getFrameArea().HasArea() && !pSect->ContainsContent() ) + SAL_WARN_IF(pSect->IsDeleteForbidden(), "sw.layout", "not allowed delete SwFrame"); + if( !pSect->getFrameArea().HasArea() && !pSect->ContainsContent() && !pSect->IsDeleteForbidden() ) { SwLayoutFrame* pUp = pSect->GetUpper(); pSect->RemoveFromLayout(); diff --git a/sw/source/core/layout/tabfrm.cxx b/sw/source/core/layout/tabfrm.cxx index a3449bfaad1e..07857266045e 100644 --- a/sw/source/core/layout/tabfrm.cxx +++ b/sw/source/core/layout/tabfrm.cxx @@ -23,6 +23,7 @@ #include <viewimp.hxx> #include <fesh.hxx> #include <swtable.hxx> +#include <deletelistener.hxx> #include <dflyobj.hxx> #include <anchoreddrawobject.hxx> #include <fmtanchr.hxx> @@ -58,6 +59,7 @@ #include <DocumentSettingManager.hxx> #include <docary.hxx> #include <o3tl/make_unique.hxx> +#include <boost/optional.hpp> using namespace ::com::sun::star; @@ -1305,13 +1307,30 @@ bool SwTabFrame::Split( const SwTwips nCutPos, bool bTryToSplit, bool bTableRowK return bRet; } +namespace +{ + bool CanDeleteFollow(SwTabFrame *pFoll) + { + if (pFoll->IsJoinLocked()) + return false; + + if (pFoll->IsDeleteForbidden()) + { + SAL_WARN("sw.layout", "Delete Forbidden"); + return false; + } + + return true; + } +} + bool SwTabFrame::Join() { OSL_ENSURE( !HasFollowFlowLine(), "Joining follow flow line" ); SwTabFrame *pFoll = GetFollow(); - if (pFoll && !pFoll->IsJoinLocked()) + if (pFoll && CanDeleteFollow(pFoll)) { SwRectFnSet aRectFnSet(this); pFoll->Cut(); //Cut out first to avoid unnecessary notifications. @@ -1540,6 +1559,8 @@ static bool lcl_InnerCalcLayout( SwFrame *pFrame, if ( pFrame->IsLayoutFrame() && ( !_bOnlyRowsAndCells || pFrame->IsRowFrame() || pFrame->IsCellFrame() ) ) { + SwFrameDeleteGuard aDeleteGuard(pFrame); + // #130744# An invalid locked table frame will // not be calculated => It will not become valid => // Loop in lcl_RecalcRow(). Therefore we do not consider them for bRet. @@ -1770,6 +1791,14 @@ namespace { return bRet; } } + +// extern because static can't be friend +void FriendHackInvalidateRowFrame(SwFrameAreaDefinition & rRowFrame) +{ + // hilariously static_cast<SwTabFrame*>(GetLower()) would not require friend declaration, but it's UB... + rRowFrame.setFrameAreaPositionValid(false); +} + void SwTabFrame::MakeAll(vcl::RenderContext* pRenderContext) { if ( IsJoinLocked() || StackHack::IsLocked() || StackHack::Count() > 50 ) @@ -1799,7 +1828,7 @@ void SwTabFrame::MakeAll(vcl::RenderContext* pRenderContext) // is not locked. Otherwise, join will not be performed and this loop // will be endless. while ( GetNext() && GetNext() == GetFollow() && - !GetFollow()->IsJoinLocked() + CanDeleteFollow(GetFollow()) ) { if ( HasFollowFlowLine() ) @@ -1948,8 +1977,6 @@ void SwTabFrame::MakeAll(vcl::RenderContext* pRenderContext) pAccess.reset(); m_bCalcLowers |= pLayout->Resize( pLayout->GetBrowseWidthByTabFrame( *this ) ); - pAccess = o3tl::make_unique<SwBorderAttrAccess>(SwFrame::GetCache(), this); - pAttrs = pAccess->Get(); } setFramePrintAreaValid(false); @@ -1961,6 +1988,10 @@ void SwTabFrame::MakeAll(vcl::RenderContext* pRenderContext) { m_bCalcLowers = true; } + if (GetLower()) + { // it's possible that the rows already have valid pos - but it is surely wrong if the table's pos changed! + FriendHackInvalidateRowFrame(*GetLower()); + } } //We need to know the height of the first row, because the master needs @@ -1978,6 +2009,12 @@ void SwTabFrame::MakeAll(vcl::RenderContext* pRenderContext) const long nOldPrtWidth = aRectFnSet.GetWidth(getFramePrintArea()); const long nOldFrameWidth = aRectFnSet.GetWidth(getFrameArea()); const Point aOldPrtPos = aRectFnSet.GetPos(getFramePrintArea()); + + if (!pAccess) + { + pAccess = o3tl::make_unique<SwBorderAttrAccess>(SwFrame::GetCache(), this); + pAttrs = pAccess->Get(); + } Format( getRootFrame()->GetCurrShell()->GetOut(), pAttrs ); SwHTMLTableLayout *pLayout = GetTable()->GetHTMLTableLayout(); @@ -1988,8 +2025,6 @@ void SwTabFrame::MakeAll(vcl::RenderContext* pRenderContext) pAccess.reset(); m_bCalcLowers |= pLayout->Resize( pLayout->GetBrowseWidthByTabFrame( *this ) ); - pAccess = o3tl::make_unique<SwBorderAttrAccess>(SwFrame::GetCache(), this); - pAttrs = pAccess->Get(); } if ( aOldPrtPos != aRectFnSet.GetPos(getFramePrintArea()) ) aNotify.SetLowersComplete( false ); @@ -2017,12 +2052,18 @@ void SwTabFrame::MakeAll(vcl::RenderContext* pRenderContext) } SwFootnoteBossFrame *pOldBoss = bFootnotesInDoc ? FindFootnoteBossFrame( true ) : nullptr; bool bReformat; + boost::optional<SfxDeleteListener> oDeleteListener; + if (pOldBoss) + oDeleteListener.emplace(*pOldBoss); + SwFrameDeleteGuard g(this); if ( MoveBwd( bReformat ) ) { + SAL_WARN_IF(oDeleteListener && oDeleteListener->WasDeleted(), "sw.layout", "SwFootnoteBossFrame unexpectedly deleted"); + aRectFnSet.Refresh(this); bMovedBwd = true; aNotify.SetLowersComplete( false ); - if ( bFootnotesInDoc ) + if (bFootnotesInDoc && !oDeleteListener->WasDeleted()) MoveLowerFootnotes( nullptr, pOldBoss, nullptr, true ); if ( bReformat || bKeep ) { @@ -2037,15 +2078,22 @@ void SwTabFrame::MakeAll(vcl::RenderContext* pRenderContext) pAccess.reset(); m_bCalcLowers |= pHTMLLayout->Resize( pHTMLLayout->GetBrowseWidthByTabFrame( *this ) ); + } + + setFramePrintAreaValid(false); + if (!pAccess) + { pAccess = o3tl::make_unique<SwBorderAttrAccess>(SwFrame::GetCache(), this); pAttrs = pAccess->Get(); } - - setFramePrintAreaValid(false); Format( getRootFrame()->GetCurrShell()->GetOut(), pAttrs ); } + + pAccess.reset(); + lcl_RecalcTable( *this, nullptr, aNotify ); + m_bLowersFormatted = true; if ( bKeep && KEEPTAB ) { @@ -2209,11 +2257,18 @@ void SwTabFrame::MakeAll(vcl::RenderContext* pRenderContext) // 6. There is no section change behind the table (see IsKeep) // 7. The last table row wants to keep with its next. const SwRowFrame* pLastRow = static_cast<const SwRowFrame*>(GetLastLower()); - if (pLastRow - && IsKeep(pAttrs->GetAttrSet().GetKeep(), GetBreakItem(), true) - && pLastRow->ShouldRowKeepWithNext()) + if (pLastRow) { - bFormat = true; + if (!pAccess) + { + pAccess = o3tl::make_unique<SwBorderAttrAccess>(SwFrame::GetCache(), this); + pAttrs = pAccess->Get(); + } + if (IsKeep(pAttrs->GetAttrSet().GetKeep(), GetBreakItem(), true) + && pLastRow->ShouldRowKeepWithNext()) + { + bFormat = true; + } } } @@ -2227,9 +2282,6 @@ void SwTabFrame::MakeAll(vcl::RenderContext* pRenderContext) // is found, get its first content. const SwFrame* pTmpNxt = sw_FormatNextContentForKeep( this ); - pAccess = o3tl::make_unique<SwBorderAttrAccess>(SwFrame::GetCache(), this); - pAttrs = pAccess->Get(); - // The last row wants to keep with the frame behind the table. // Check if the next frame is on a different page and valid. // In this case we do a magic trick: @@ -2472,9 +2524,6 @@ void SwTabFrame::MakeAll(vcl::RenderContext* pRenderContext) GetFollow()->MakeAll(pRenderContext); - pAccess = o3tl::make_unique<SwBorderAttrAccess>(SwFrame::GetCache(), this); - pAttrs = pAccess->Get(); - GetFollow()->SetLowersFormatted(false); // #i43913# - lock follow table // to avoid its formatting during the format of diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx index cdce7870a536..aff410f10414 100644 --- a/sw/source/core/layout/wsfrm.cxx +++ b/sw/source/core/layout/wsfrm.cxx @@ -318,7 +318,7 @@ SwFrame::SwFrame( SwModify *pMod, SwFrame* pSib ) mbInfSct ( false ), mbColLocked(false), m_isInDestroy(false), - mbForbidDelete(false) + mnForbidDelete(0) { OSL_ENSURE( pMod, "No frame format given." ); } diff --git a/sw/source/core/table/swtable.cxx b/sw/source/core/table/swtable.cxx index fdc1633e7c73..c6a527abdb36 100644 --- a/sw/source/core/table/swtable.cxx +++ b/sw/source/core/table/swtable.cxx @@ -2326,6 +2326,7 @@ void SwTableBoxFormat::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew // format contents with the new value assigned and write to paragraph Color* pCol = nullptr; OUString sNewText; + bool bChangeFormat = true; if( DBL_MAX == fVal ) { sNewText = SwViewShell::GetShellRes()->aCalc_Error; @@ -2350,6 +2351,14 @@ void SwTableBoxFormat::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew #else sNewText = aOrigText; #endif + // Remove the newly assigned numbering format as well if text actually exists. + // Exception: assume user-defined formats are always intentional. + if (bChgText && pNumFormatr->IsTextFormat(nOldFormat) + && !pNumFormatr->IsUserDefinedAndNotOverloaded(nNewFormat)) + { + pBox->GetFrameFormat()->ResetFormatAttr(RES_BOXATR_FORMAT); + bChangeFormat = false; + } } if( !bChgText ) @@ -2359,9 +2368,11 @@ void SwTableBoxFormat::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew } // across all boxes - ChgTextToNum( *pBox, sNewText, pCol, + if (bChangeFormat) + { + ChgTextToNum( *pBox, sNewText, pCol, GetDoc()->IsInsTableAlignNum() ); - + } } else if( bNewIsTextFormat && nOldFormat != nNewFormat ) { diff --git a/sw/source/core/text/itratr.cxx b/sw/source/core/text/itratr.cxx index b6e53480d6e4..0579950353d4 100644 --- a/sw/source/core/text/itratr.cxx +++ b/sw/source/core/text/itratr.cxx @@ -399,7 +399,7 @@ static void InsertCharAttrs(SfxPoolItem const** pAttrs, SfxItemSet const& rItems } else if (nWhich == RES_TXTATR_UNKNOWN_CONTAINER) { - pAttrs[RES_CHRATR_END] = pItem; + pAttrs[RES_CHRATR_END - RES_CHRATR_BEGIN] = pItem; } } } diff --git a/sw/source/core/text/itrform2.cxx b/sw/source/core/text/itrform2.cxx index 8f3f8284d850..f1b179518f4f 100755 --- a/sw/source/core/text/itrform2.cxx +++ b/sw/source/core/text/itrform2.cxx @@ -148,6 +148,16 @@ sal_uInt16 SwTextFormatter::GetFrameRstHeight() const return sal_uInt16( nHeight ); } +bool SwTextFormatter::ClearIfIsFirstOfBorderMerge(const SwLinePortion* pPortion) +{ + if (pPortion == m_pFirstOfBorderMerge) + { + m_pFirstOfBorderMerge = nullptr; + return true; + } + return false; +} + SwLinePortion *SwTextFormatter::Underflow( SwTextFormatInfo &rInf ) { // Save values and initialize rInf @@ -276,11 +286,8 @@ SwLinePortion *SwTextFormatter::Underflow( SwTextFormatInfo &rInf ) SwLinePortion* pNext = pPor->GetPortion(); while (pNext) { - if (pNext == m_pFirstOfBorderMerge) - { - m_pFirstOfBorderMerge = nullptr; + if (ClearIfIsFirstOfBorderMerge(pNext)) break; - } pNext = pNext->GetPortion(); } pPor->Truncate(); diff --git a/sw/source/core/text/itrform2.hxx b/sw/source/core/text/itrform2.hxx index ff430b8616d1..08b0582b1569 100644 --- a/sw/source/core/text/itrform2.hxx +++ b/sw/source/core/text/itrform2.hxx @@ -239,6 +239,8 @@ public: * @param rInf contain information **/ void MergeCharacterBorder( SwLinePortion& rPortion, SwLinePortion const *pPrev, SwTextFormatInfo& rInf ); + + bool ClearIfIsFirstOfBorderMerge(SwLinePortion const *pPortion); }; #endif diff --git a/sw/source/core/text/porfld.cxx b/sw/source/core/text/porfld.cxx index 14e5320f234d..af50ee61d778 100644 --- a/sw/source/core/text/porfld.cxx +++ b/sw/source/core/text/porfld.cxx @@ -174,7 +174,16 @@ SwFieldSlot::SwFieldSlot( const SwTextFormatInfo* pNew, const SwFieldPortion *pP } else { - aText = (*pOldText).replaceAt(sal_Int32(nIdx), 1, aText); + TextFrameIndex nEnd(pOldText->getLength()); + if (nIdx < nEnd) + { + //sal_Int32 const nFieldLen(pPor->GetFieldLen()); + aText = (*pOldText).replaceAt(sal_Int32(nIdx), 1/*nFieldLen*/, aText); + } + else if (nIdx == nEnd) + aText = *pOldText + aText; + else + SAL_WARN("sw.core", "SwFieldSlot bad SwFieldPortion index."); } pInf->SetText( aText ); } diff --git a/sw/source/core/text/porlay.cxx b/sw/source/core/text/porlay.cxx index 1968e48a30ab..be7a30c3468d 100644 --- a/sw/source/core/text/porlay.cxx +++ b/sw/source/core/text/porlay.cxx @@ -369,7 +369,9 @@ void SwLineLayout::CalcLine( SwTextFormatter &rLine, SwTextFormatInfo &rInf ) if( !GetAscent() ) SetAscent( pPos->GetAscent() ); } - delete pLast->Cut( pPos ); + SwLinePortion* pPortion = pLast->Cut( pPos ); + rLine.ClearIfIsFirstOfBorderMerge(pPortion); + delete pPortion; pPos = pLast->GetPortion(); continue; } diff --git a/sw/source/core/text/porrst.cxx b/sw/source/core/text/porrst.cxx index 654ddec99fea..213cb3b5e7e0 100644 --- a/sw/source/core/text/porrst.cxx +++ b/sw/source/core/text/porrst.cxx @@ -540,7 +540,7 @@ bool SwBookmarkPortion::DoPaint(SwTextPaintInfo const& rInf, Size size(rTmpFont.GetSize(rTmpFont.GetActual())); // use also the external leading (line gap) of the portion, but don't use // 100% of it because i can't figure out how to baseline align that - auto const nFactor = (Height() * 95) / size.Height(); + auto const nFactor = size.Height() > 0 ? (Height() * 95) / size.Height() : Height(); rTmpFont.SetProportion(nFactor); rTmpFont.SetWeight(WEIGHT_THIN, rTmpFont.GetActual()); rTmpFont.SetColor(NON_PRINTING_CHARACTER_COLOR); diff --git a/sw/source/core/text/txtfrm.cxx b/sw/source/core/text/txtfrm.cxx index 377dd17c5103..707bc37938b2 100644 --- a/sw/source/core/text/txtfrm.cxx +++ b/sw/source/core/text/txtfrm.cxx @@ -2463,7 +2463,13 @@ bool SwTextFrame::Prepare( const PrepareHint ePrep, const void* pVoid, if( aTextFly.IsOn() ) { // Does any free-flying frame overlap? - bFormat = aTextFly.Relax() || IsUndersized(); + const bool bRelaxed = aTextFly.Relax(); + bFormat = bRelaxed || IsUndersized(); + if (bRelaxed) + { + // It's possible that pPara was deleted above; retrieve it again + pPara = aAccess.GetPara(); + } } } } diff --git a/sw/source/core/text/xmldump.cxx b/sw/source/core/text/xmldump.cxx index 7c4ac4b4b034..d72cdd57d668 100644 --- a/sw/source/core/text/xmldump.cxx +++ b/sw/source/core/text/xmldump.cxx @@ -327,6 +327,12 @@ void SwFrame::dumpAsXml( xmlTextWriterPtr writer ) const xmlTextWriterWriteAttribute(writer, BAD_CAST("ValidLayout"), BAD_CAST(OString::boolean(!pPageFrame->IsInvalidLayout()).getStr())); xmlTextWriterWriteAttribute(writer, BAD_CAST("ValidContent"), BAD_CAST(OString::boolean(!pPageFrame->IsInvalidContent()).getStr())); xmlTextWriterEndElement(writer); + xmlTextWriterStartElement(writer, BAD_CAST("page_info")); + xmlTextWriterWriteFormatAttribute(writer, BAD_CAST("phyNum"), "%d", pPageFrame->GetPhyPageNum()); + xmlTextWriterWriteFormatAttribute(writer, BAD_CAST("virtNum"), "%d", pPageFrame->GetVirtPageNum()); + OUString aFormatName = pPageFrame->GetPageDesc()->GetName(); + xmlTextWriterWriteFormatAttribute( writer, BAD_CAST("pageDesc"), "%s", BAD_CAST(OUStringToOString(aFormatName, RTL_TEXTENCODING_UTF8).getStr())); + xmlTextWriterEndElement(writer); } if (IsTextFrame()) @@ -399,22 +405,16 @@ void SwFrame::dumpInfosAsXml( xmlTextWriterPtr writer ) const { // output the Frame xmlTextWriterStartElement( writer, BAD_CAST( "bounds" ) ); - xmlTextWriterWriteFormatAttribute( writer, BAD_CAST( "left" ), "%ld", getFrameArea().Left() ); - xmlTextWriterWriteFormatAttribute( writer, BAD_CAST( "top" ), "%ld", getFrameArea().Top() ); - xmlTextWriterWriteFormatAttribute( writer, BAD_CAST( "width" ), "%ld", getFrameArea().Width() ); - xmlTextWriterWriteFormatAttribute( writer, BAD_CAST( "height" ), "%ld", getFrameArea().Height() ); + getFrameArea().dumpAsXmlAttributes(writer); xmlTextWriterWriteAttribute(writer, BAD_CAST("mbFixSize"), BAD_CAST(OString::boolean(HasFixSize()).getStr())); xmlTextWriterWriteAttribute(writer, BAD_CAST("mbValidPos"), BAD_CAST(OString::boolean(isFrameAreaPositionValid()).getStr())); xmlTextWriterWriteAttribute(writer, BAD_CAST("mbValidSize"), BAD_CAST(OString::boolean(isFrameAreaSizeValid()).getStr())); xmlTextWriterWriteAttribute(writer, BAD_CAST("mbValidPrtArea"), BAD_CAST(OString::boolean(isFramePrintAreaValid()).getStr())); xmlTextWriterEndElement( writer ); - // output the Prt + // output the print area xmlTextWriterStartElement( writer, BAD_CAST( "prtBounds" ) ); - xmlTextWriterWriteFormatAttribute( writer, BAD_CAST( "left" ), "%ld", getFramePrintArea().Left() ); - xmlTextWriterWriteFormatAttribute( writer, BAD_CAST( "top" ), "%ld", getFramePrintArea().Top() ); - xmlTextWriterWriteFormatAttribute( writer, BAD_CAST( "width" ), "%ld", getFramePrintArea().Width() ); - xmlTextWriterWriteFormatAttribute( writer, BAD_CAST( "height" ), "%ld", getFramePrintArea().Height() ); + getFramePrintArea().dumpAsXmlAttributes(writer); xmlTextWriterEndElement( writer ); } @@ -478,10 +478,7 @@ void SwAnchoredObject::dumpAsXml( xmlTextWriterPtr writer ) const xmlTextWriterWriteFormatAttribute( writer, BAD_CAST( "ptr" ), "%p", this ); xmlTextWriterStartElement( writer, BAD_CAST( "bounds" ) ); - xmlTextWriterWriteFormatAttribute( writer, BAD_CAST( "left" ), "%ld", GetObjBoundRect().Left() ); - xmlTextWriterWriteFormatAttribute( writer, BAD_CAST( "top" ), "%ld", GetObjBoundRect().Top() ); - xmlTextWriterWriteFormatAttribute( writer, BAD_CAST( "width" ), "%ld", GetObjBoundRect().Width() ); - xmlTextWriterWriteFormatAttribute( writer, BAD_CAST( "height" ), "%ld", GetObjBoundRect().Height() ); + GetObjBoundRect().dumpAsXmlAttributes(writer); xmlTextWriterEndElement( writer ); if (const SdrObject* pObject = GetDrawObj()) diff --git a/sw/source/core/undo/untbl.cxx b/sw/source/core/undo/untbl.cxx index 524ac22d08e8..28681ad9d8df 100644 --- a/sw/source/core/undo/untbl.cxx +++ b/sw/source/core/undo/untbl.cxx @@ -277,6 +277,8 @@ void SwUndoInsTable::UndoImpl(::sw::UndoRedoContext & rContext) if( SfxItemState::SET == pTableFormat->GetItemState( RES_BREAK, false, &pItem ) ) pNextNd->SetAttr( *pItem ); + + ::sw::NotifyTableCollapsedParagraph(pNextNd, nullptr); } sTableNm = pTableNd->GetTable().GetFrameFormat()->GetName(); diff --git a/sw/source/core/unocore/unodraw.cxx b/sw/source/core/unocore/unodraw.cxx index 876cad2231df..4f8c59dd3fb6 100644 --- a/sw/source/core/unocore/unodraw.cxx +++ b/sw/source/core/unocore/unodraw.cxx @@ -1177,6 +1177,8 @@ void SwXShape::setPropertyValue(const OUString& rPropertyName, const uno::Any& a SwFormatFlyCnt aFormat( pFormat ); pNd->InsertItem(aFormat, pInternalPam->GetPoint() ->nContent.GetIndex(), 0 ); + //Refetch in case SwTextNode::InsertItem causes it to be deleted + pFormat = GetFrameFormat(); } else { diff --git a/sw/source/core/unocore/unoframe.cxx b/sw/source/core/unocore/unoframe.cxx index b0de9f773463..6328408cb0af 100644 --- a/sw/source/core/unocore/unoframe.cxx +++ b/sw/source/core/unocore/unoframe.cxx @@ -2713,8 +2713,13 @@ void SwXFrame::attachToRange(const uno::Reference< text::XTextRange > & xTextRan aFrameSet.Put( SwFormatAnchor( RndStdIds::FLY_AT_PAGE, 1 )); } - aPam.DeleteMark(); // mark position node will be deleted! - aIntPam.DeleteMark(); // mark position node will be deleted! + // park these no longer needed PaMs somewhere safe so MakeFlyAndMove + // can delete what it likes without any assert these are pointing to + // that content + aPam.DeleteMark(); + aIntPam.DeleteMark(); + *aPam.GetPoint() = *aIntPam.GetPoint() = SwPosition(pDoc->GetNodes()); + pFormat = pDoc->MakeFlyAndMove( *m_pCopySource, aFrameSet, nullptr, pParentFrameFormat ); diff --git a/sw/source/filter/html/htmlplug.cxx b/sw/source/filter/html/htmlplug.cxx index 19ef7252094a..955eeab36ee9 100644 --- a/sw/source/filter/html/htmlplug.cxx +++ b/sw/source/filter/html/htmlplug.cxx @@ -1006,7 +1006,12 @@ void SwHTMLParser::InsertFloatingFrame() bool bHasBorder = aFrameDesc.HasFrameBorder(); Size aMargin = aFrameDesc.GetMargin(); - xSet->setPropertyValue("FrameURL", uno::makeAny( aFrameDesc.GetURL().GetMainURL( INetURLObject::DecodeMechanism::NONE ) ) ); + OUString sHRef = aFrameDesc.GetURL().GetMainURL( INetURLObject::DecodeMechanism::NONE ); + + if (INetURLObject(sHRef).GetProtocol() == INetProtocol::Macro) + NotifyMacroEventRead(); + + xSet->setPropertyValue("FrameURL", uno::makeAny( sHRef ) ); xSet->setPropertyValue("FrameName", uno::makeAny( aName ) ); if ( eScroll == ScrollingMode::Auto ) diff --git a/sw/source/filter/ww8/wrtw8sty.cxx b/sw/source/filter/ww8/wrtw8sty.cxx index 7289bdd8f9d2..b054439b9457 100644 --- a/sw/source/filter/ww8/wrtw8sty.cxx +++ b/sw/source/filter/ww8/wrtw8sty.cxx @@ -150,13 +150,13 @@ MSWordStyles::MSWordStyles( MSWordExportBase& rExport, bool bListStyles ) m_rExport.m_pDoc->GetFootnoteInfo().GetAnchorCharFormat( *m_rExport.m_pDoc ); m_rExport.m_pDoc->GetFootnoteInfo().GetCharFormat( *m_rExport.m_pDoc ); } - sal_uInt16 nAlloc = WW8_RESERVED_SLOTS + m_rExport.m_pDoc->GetCharFormats()->size() - 1 + + sal_uInt32 nAlloc = WW8_RESERVED_SLOTS + m_rExport.m_pDoc->GetCharFormats()->size() - 1 + m_rExport.m_pDoc->GetTextFormatColls()->size() - 1 + (bListStyles ? m_rExport.m_pDoc->GetNumRuleTable().size() - 1 : 0); + nAlloc = std::min<sal_uInt32>(nAlloc, MSWORD_MAX_STYLES_LIMIT); // somewhat generous ( free for up to 15 ) - m_pFormatA.reset( new SwFormat*[ nAlloc ] ); - memset( m_pFormatA.get(), 0, nAlloc * sizeof( SwFormat* ) ); + m_aFormatA.resize(nAlloc, nullptr); memset( m_aHeadingParagraphStyles, -1 , MAXLEVEL * sizeof( sal_uInt16)); BuildStylesTable(); @@ -172,7 +172,7 @@ sal_uInt16 MSWordStyles::GetSlot( const SwFormat* pFormat ) const { sal_uInt16 n; for ( n = 0; n < m_nUsedSlots; n++ ) - if ( m_pFormatA[n] == pFormat ) + if ( m_aFormatA[n] == pFormat ) return n; return 0xfff; // 0xfff: WW: zero } @@ -281,19 +281,19 @@ void MSWordStyles::BuildStylesTable() const SwCharFormats& rArr = *m_rExport.m_pDoc->GetCharFormats(); // first CharFormat // the default character style ( 0 ) will not be outputted ! - for( size_t n = 1; n < rArr.size(); n++ ) + for( size_t n = 1; n < rArr.size() && m_nUsedSlots < MSWORD_MAX_STYLES_LIMIT; n++ ) { SwCharFormat* pFormat = rArr[n]; - m_pFormatA[ BuildGetSlot( *pFormat ) ] = pFormat; + m_aFormatA[ BuildGetSlot( *pFormat ) ] = pFormat; } const SwTextFormatColls& rArr2 = *m_rExport.m_pDoc->GetTextFormatColls(); // then TextFormatColls // the default character style ( 0 ) will not be outputted ! - for( size_t n = 1; n < rArr2.size(); n++ ) + for( size_t n = 1; n < rArr2.size() && m_nUsedSlots < MSWORD_MAX_STYLES_LIMIT; n++ ) { SwTextFormatColl* pFormat = rArr2[n]; sal_uInt16 nId = BuildGetSlot( *pFormat ) ; - m_pFormatA[ nId ] = pFormat; + m_aFormatA[ nId ] = pFormat; if ( pFormat->IsAssignedToListLevelOfOutlineStyle() ) { int nLvl = pFormat->GetAssignedOutlineStyleLevel() ; @@ -306,7 +306,7 @@ void MSWordStyles::BuildStylesTable() return; const SwNumRuleTable& rNumRuleTable = m_rExport.m_pDoc->GetNumRuleTable(); - for (size_t i = 0; i < rNumRuleTable.size(); ++i) + for (size_t i = 0; i < rNumRuleTable.size() && m_nUsedSlots < MSWORD_MAX_STYLES_LIMIT; ++i) { const SwNumRule* pNumRule = rNumRuleTable[i]; if (pNumRule->IsAutoRule() || pNumRule->GetName().startsWith("WWNum")) @@ -326,8 +326,8 @@ void MSWordStyles::BuildStyleIds() for (sal_uInt16 n = 1; n < m_nUsedSlots; ++n) { OUString aName; - if(m_pFormatA[n]) - aName = m_pFormatA[n]->GetName(); + if (m_aFormatA[n]) + aName = m_aFormatA[n]->GetName(); else if (m_aNumRules.find(n) != m_aNumRules.end()) aName = m_aNumRules[n]->GetName(); OStringBuffer aStyleIdBuf(aName.getLength()); @@ -606,8 +606,8 @@ void MSWordStyles::OutputStyle( SwFormat* pFormat, sal_uInt16 nPos ) for ( int nSuffix = 0; ; ++nSuffix ) { bool clash=false; for ( sal_uInt16 n = 1; n < m_nUsedSlots; ++n ) - if ( m_pFormatA[n] && - m_pFormatA[n]->GetName().equalsIgnoreAsciiCase(aName) ) + if ( m_aFormatA[n] && + m_aFormatA[n]->GetName().equalsIgnoreAsciiCase(aName) ) { clash = true; break; @@ -682,7 +682,7 @@ void MSWordStyles::OutputStylesTable() if (m_aNumRules.find(n) != m_aNumRules.end()) OutputStyle(m_aNumRules[n], n); else - OutputStyle( m_pFormatA[n], n ); + OutputStyle(m_aFormatA[n], n); } m_rExport.AttrOutput().EndStyles( m_nUsedSlots ); diff --git a/sw/source/filter/ww8/wrtww8.hxx b/sw/source/filter/ww8/wrtww8.hxx index ec31a1b41622..801d07d3a167 100644 --- a/sw/source/filter/ww8/wrtww8.hxx +++ b/sw/source/filter/ww8/wrtww8.hxx @@ -1539,7 +1539,7 @@ class MSWordStyles { MSWordExportBase& m_rExport; sal_uInt16 m_aHeadingParagraphStyles[MAXLEVEL]; - std::unique_ptr<SwFormat*[]> m_pFormatA; ///< Slot <-> Character and paragraph style array (0 for list styles). + std::vector<SwFormat*> m_aFormatA; ///< Slot <-> Character and paragraph style array (0 for list styles). sal_uInt16 m_nUsedSlots; bool m_bListStyles; ///< If list styles are requested to be exported as well. std::map<sal_uInt16, const SwNumRule*> m_aNumRules; ///< Slot <-> List style map. @@ -1587,7 +1587,7 @@ public: /// Get styleId of the nId-th style (nId is its position in pFormatA). OString const & GetStyleId(sal_uInt16 nId) const; - const SwFormat* GetSwFormat(sal_uInt16 nId) const { return m_pFormatA[nId]; } + const SwFormat* GetSwFormat(sal_uInt16 nId) const { return m_aFormatA[nId]; } /// Get numbering rule of the nId-th style const SwNumRule* GetSwNumRule(sal_uInt16 nId) const; sal_uInt16 GetHeadingParagraphStyleId(sal_uInt16 nLevel) const { return m_aHeadingParagraphStyles[ nLevel ]; } diff --git a/sw/source/filter/xml/XMLRedlineImportHelper.cxx b/sw/source/filter/xml/XMLRedlineImportHelper.cxx index 250a31688151..15e6651661b3 100644 --- a/sw/source/filter/xml/XMLRedlineImportHelper.cxx +++ b/sw/source/filter/xml/XMLRedlineImportHelper.cxx @@ -31,6 +31,10 @@ #include <IDocumentStylePoolAccess.hxx> #include <tools/datetime.hxx> #include <poolfmt.hxx> +#include <fmtanchr.hxx> +#include <ftnidx.hxx> +#include <txtftn.hxx> +#include <ndtxt.hxx> #include <unoredline.hxx> #include <o3tl/any.hxx> #include <xmloff/xmltoken.hxx> @@ -562,6 +566,73 @@ inline bool XMLRedlineImportHelper::IsReady(RedlineInfo* pRedline) !pRedline->bNeedsAdjustment ); } +/// recursively check if rPos or its anchor (if in fly or footnote) is in redline section +static auto RecursiveContains(SwStartNode const& rRedlineSection, SwNode const& rPos) -> bool +{ + if (rRedlineSection.GetIndex() <= rPos.GetIndex() + && rPos.GetIndex() <= rRedlineSection.EndOfSectionIndex()) + { + return true; + } + // loop to iterate "up" in the node tree and find an anchored XText + for (SwStartNode const* pStartNode = rPos.StartOfSectionNode(); + pStartNode != nullptr && pStartNode->GetIndex() != 0; + pStartNode = pStartNode->StartOfSectionNode()) + { + switch (pStartNode->GetStartNodeType()) + { + case SwNormalStartNode: + case SwTableBoxStartNode: + continue; + break; + case SwFlyStartNode: + { + SwFrameFormat const*const pFormat(pStartNode->GetFlyFormat()); + assert(pFormat); + SwFormatAnchor const& rAnchor(pFormat->GetAnchor()); + if (rAnchor.GetAnchorId() == RndStdIds::FLY_AT_PAGE) + { + return false; + } + else if (rAnchor.GetAnchorId() == RndStdIds::FLY_AT_FLY) + { // anchor is on a start node, avoid skipping it: + pStartNode = rAnchor.GetContentAnchor()->nNode.GetNode().GetStartNode(); + assert(pStartNode); + // pass the next node to recursive call - it will call + // call StartOfSectionNode on it and go back to pStartNode + SwNodeIndex const next(*pStartNode, +1); + return RecursiveContains(rRedlineSection, next.GetNode()); + } + else + { + return RecursiveContains(rRedlineSection, rAnchor.GetContentAnchor()->nNode.GetNode()); + } + } + break; + case SwFootnoteStartNode: + { // sigh ... need to search + for (SwTextFootnote const*const pFootnote : rRedlineSection.GetDoc()->GetFootnoteIdxs()) + { + if (pStartNode == pFootnote->GetStartNode()->GetNode().GetStartNode()) + { + return RecursiveContains(rRedlineSection, pFootnote->GetTextNode()); + } + } + assert(false); + } + break; + case SwHeaderStartNode: + case SwFooterStartNode: + return false; // headers aren't anchored + break; + default: + assert(false); + break; + } + } + return false; +} + void XMLRedlineImportHelper::InsertIntoDocument(RedlineInfo* pRedlineInfo) { OSL_ENSURE(nullptr != pRedlineInfo, "need redline info"); @@ -631,6 +702,17 @@ void XMLRedlineImportHelper::InsertIntoDocument(RedlineInfo* pRedlineInfo) } } } + else if (pRedlineInfo->pContentIndex != nullptr + // should be enough to check 1 position of aPaM bc CheckNodesRange() above + && RecursiveContains(*pRedlineInfo->pContentIndex->GetNode().GetStartNode(), aPaM.GetPoint()->nNode.GetNode())) + { + SAL_WARN("sw.xml", "Recursive change tracking, removing"); + // reuse aPaM to remove it from nodes that will be deleted + *aPaM.GetPoint() = SwPosition(pRedlineInfo->pContentIndex->GetNode()); + aPaM.SetMark(); + *aPaM.GetMark() = SwPosition(*pRedlineInfo->pContentIndex->GetNode().EndOfSectionNode()); + pDoc->getIDocumentContentOperations().DeleteRange(aPaM); + } else { // regular file loading: insert redline diff --git a/sw/source/filter/xml/xmltbli.cxx b/sw/source/filter/xml/xmltbli.cxx index 98ddb181baf1..13b0063e02da 100644 --- a/sw/source/filter/xml/xmltbli.cxx +++ b/sw/source/filter/xml/xmltbli.cxx @@ -2053,7 +2053,7 @@ SwTableBox *SwXMLTableContext::MakeTableBox( { const SwTableBoxNumFormat* pNumFormat = static_cast<const SwTableBoxNumFormat*>( pItem ); - if( ( pNumFormat != nullptr ) && ( pNumFormat->GetValue() == 0 ) ) + if (pNumFormat && (pNumFormat->GetValue() % SV_COUNTRY_LANGUAGE_OFFSET) == 0) { // only one text node? SwNodeIndex aNodeIndex( *(pCell->GetStartNode()), 1 ); diff --git a/sw/source/filter/xml/xmltexti.cxx b/sw/source/filter/xml/xmltexti.cxx index 0cbf9fd85677..8366f0ae3804 100644 --- a/sw/source/filter/xml/xmltexti.cxx +++ b/sw/source/filter/xml/xmltexti.cxx @@ -854,9 +854,14 @@ uno::Reference< XPropertySet > SwXMLTextImportHelper::createAndInsertFloatingFra uno::Reference < beans::XPropertySet > xSet( xObj->getComponent(), uno::UNO_QUERY ); if ( xSet.is() ) { + OUString sHRef = URIHelper::SmartRel2Abs( + INetURLObject( GetXMLImport().GetBaseURL() ), rHRef ); + + if (INetURLObject(sHRef).GetProtocol() == INetProtocol::Macro) + GetXMLImport().NotifyMacroEventRead(); + xSet->setPropertyValue("FrameURL", - makeAny( URIHelper::SmartRel2Abs( - INetURLObject( GetXMLImport().GetBaseURL() ), rHRef ) ) ); + makeAny( sHRef ) ); xSet->setPropertyValue("FrameName", makeAny( rName ) ); |