diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 09:44:04 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 09:44:04 +0000 |
commit | eb358d77291eba677141bab113dc27d7aabb0f3e (patch) | |
tree | 2e96f3b5d0c79beaeb536bbf05c3b8564846e65f /sw/source | |
parent | Adding debian version 4:24.2.1-4. (diff) | |
download | libreoffice-eb358d77291eba677141bab113dc27d7aabb0f3e.tar.xz libreoffice-eb358d77291eba677141bab113dc27d7aabb0f3e.zip |
Merging upstream version 4:24.2.2.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sw/source')
50 files changed, 822 insertions, 599 deletions
diff --git a/sw/source/core/crsr/crsrsh.cxx b/sw/source/core/crsr/crsrsh.cxx index 173414ed4d..b7f6962982 100644 --- a/sw/source/core/crsr/crsrsh.cxx +++ b/sw/source/core/crsr/crsrsh.cxx @@ -775,6 +775,8 @@ static typename SwCursorShell::StartsWith StartsWith(SwStartNode const& rStart) switch (rNode.GetNodeType()) { case SwNodeType::Section: + if (rNode.GetSectionNode()->GetSection().IsHidden()) + return SwCursorShell::StartsWith::HiddenSection; continue; case SwNodeType::Table: return SwCursorShell::StartsWith::Table; @@ -799,11 +801,16 @@ static typename SwCursorShell::StartsWith EndsWith(SwStartNode const& rStart) switch (rNode.GetNodeType()) { case SwNodeType::End: - if (rNode.StartOfSectionNode()->IsTableNode()) + if (auto pStartNode = rNode.StartOfSectionNode(); pStartNode->IsTableNode()) { return SwCursorShell::StartsWith::Table; } -//TODO buggy SwUndoRedline in testTdf137503? assert(rNode.StartOfSectionNode()->IsSectionNode()); + else if (pStartNode->IsSectionNode()) + { + if (pStartNode->GetSectionNode()->GetSection().IsHidden()) + return SwCursorShell::StartsWith::HiddenSection; + } + //TODO buggy SwUndoRedline in testTdf137503? assert(rNode.StartOfSectionNode()->IsSectionNode()); break; case SwNodeType::Text: if (rNode.GetTextNode()->IsHidden()) @@ -944,14 +951,14 @@ bool SwCursorShell::MovePage( SwWhichPage fnWhichPage, SwPosPage fnPosPage ) return bRet; } -bool SwCursorShell::isInHiddenTextFrame(SwShellCursor* pShellCursor) +bool SwCursorShell::isInHiddenFrame(SwShellCursor* pShellCursor) { SwContentNode *pCNode = pShellCursor->GetPointContentNode(); std::pair<Point, bool> tmp(pShellCursor->GetPtPos(), false); SwContentFrame *const pFrame = pCNode ? pCNode->getLayoutFrame(GetLayout(), pShellCursor->GetPoint(), &tmp) : nullptr; - return !pFrame || (pFrame->IsTextFrame() && static_cast<SwTextFrame*>(pFrame)->IsHiddenNow()); + return !pFrame || pFrame->IsHiddenNow(); } // sw_redlinehide: this should work for all cases: GoCurrPara, GoNextPara, GoPrevPara @@ -992,7 +999,7 @@ bool SwCursorShell::MovePara(SwWhichPara fnWhichPara, SwMoveFnCollection const & //which is what SwCursorShell::UpdateCursorPos will reset //the position to if we pass it a position in an //invisible hidden paragraph field - while (isInHiddenTextFrame(pTmpCursor) + while (isInHiddenFrame(pTmpCursor) || !IsAtStartOrEndOfFrame(this, pTmpCursor, fnPosPara)) { if (!pTmpCursor->MovePara(fnWhichPara, fnPosPara)) @@ -1796,7 +1803,7 @@ void SwCursorShell::UpdateCursorPos() SwShellCursor* pShellCursor = getShellCursor( true ); Size aOldSz( GetDocSize() ); - if (isInHiddenTextFrame(pShellCursor) && !ExtendedSelectedAll()) + if (isInHiddenFrame(pShellCursor) && !ExtendedSelectedAll()) { SwCursorMoveState aTmpState(CursorMoveState::SetOnlyText); aTmpState.m_bSetInReadOnly = IsReadOnlyAvailable(); @@ -1805,14 +1812,14 @@ void SwCursorShell::UpdateCursorPos() pShellCursor->DeleteMark(); // kde45196-1.html: try to get to a non-hidden paragraph, there must // be one in the document body - while (isInHiddenTextFrame(pShellCursor)) + while (isInHiddenFrame(pShellCursor)) { if (!pShellCursor->MovePara(GoNextPara, fnParaStart)) { break; } } - while (isInHiddenTextFrame(pShellCursor)) + while (isInHiddenFrame(pShellCursor)) { if (!pShellCursor->MovePara(GoPrevPara, fnParaStart)) { @@ -3470,7 +3477,7 @@ bool SwCursorShell::FindValidContentNode( bool bOnlyText ) GetDoc()->GetDocShell()->IsReadOnlyUI() ) return true; - if( m_pCurrentCursor->HasMark() ) + if( m_pCurrentCursor->HasMark() && !mbSelectAll ) ClearMark(); // first check for frames diff --git a/sw/source/core/crsr/pam.cxx b/sw/source/core/crsr/pam.cxx index 25bf8d0ef6..4f2ceb0a84 100644 --- a/sw/source/core/crsr/pam.cxx +++ b/sw/source/core/crsr/pam.cxx @@ -1060,7 +1060,7 @@ SwContentNode* GetNode( SwPaM & rPam, bool& rbFirst, SwMoveFnCollection const & ( nullptr == pFrame || ( !bInReadOnly && pFrame->IsProtected() ) || - (pFrame->IsTextFrame() && static_cast<SwTextFrame const*>(pFrame)->IsHiddenNow()) + pFrame->IsHiddenNow() ) || ( !bInReadOnly && pNd->FindSectionNode() && pNd->FindSectionNode()->GetSection().IsProtect() @@ -1101,8 +1101,7 @@ SwContentNode* GetNode( SwPaM & rPam, bool& rbFirst, SwMoveFnCollection const & SwContentFrame const*const pFrame(pNd->getLayoutFrame(pLayout)); if (nullptr == pFrame || ( !bInReadOnly && pFrame->IsProtected() ) || - ( pFrame->IsTextFrame() && - static_cast<SwTextFrame const*>(pFrame)->IsHiddenNow())) + pFrame->IsHiddenNow()) { pNd = nullptr; continue; diff --git a/sw/source/core/crsr/swcrsr.cxx b/sw/source/core/crsr/swcrsr.cxx index 8d0246bed1..5a2f9afead 100644 --- a/sw/source/core/crsr/swcrsr.cxx +++ b/sw/source/core/crsr/swcrsr.cxx @@ -913,7 +913,7 @@ static bool lcl_MakeSelFwrd( const SwNode& rSttNd, const SwNode& rEndNd, rPam.SetMark(); rPam.GetPoint()->Assign(rEndNd); - pCNd = SwNodes::GoPrevious( rPam.GetPoint() ); + pCNd = SwNodes::GoPrevious(rPam.GetPoint(), true); if( !pCNd ) return false; rPam.GetPoint()->AssignEndIndex(*pCNd); @@ -933,7 +933,7 @@ static bool lcl_MakeSelBkwrd( const SwNode& rSttNd, const SwNode& rEndNd, if( !bFirst ) { rPam.GetPoint()->Assign(rSttNd); - pCNd = SwNodes::GoPrevious( rPam.GetPoint() ); + pCNd = SwNodes::GoPrevious(rPam.GetPoint(), true); if( !pCNd ) return false; rPam.GetPoint()->AssignEndIndex(*pCNd); diff --git a/sw/source/core/doc/DocumentContentOperationsManager.cxx b/sw/source/core/doc/DocumentContentOperationsManager.cxx index 09e0a1233e..57b8e58310 100644 --- a/sw/source/core/doc/DocumentContentOperationsManager.cxx +++ b/sw/source/core/doc/DocumentContentOperationsManager.cxx @@ -3788,11 +3788,16 @@ void DocumentContentOperationsManager::CopyWithFlyInFly( SwDoc& rDest = rInsPos.GetDoc(); SwNodeIndex aSavePos( rInsPos ); + SwPaM aCopiedPaM(rRg.aStart, rRg.aEnd); + if (pCopiedPaM) + aCopiedPaM = pCopiedPaM->first; + if (rRg.aStart != rRg.aEnd) { bool bEndIsEqualEndPos = rInsPos == rRg.aEnd.GetNode(); --aSavePos; SaveRedlEndPosForRestore aRedlRest( rInsPos, 0 ); + auto savedEndContentIndex = aCopiedPaM.End()->GetContentIndex(); // insert behind the already copied start node m_rDoc.GetNodes().CopyNodes( rRg, rInsPos, false, true ); @@ -3801,6 +3806,10 @@ void DocumentContentOperationsManager::CopyWithFlyInFly( if (bEndIsEqualEndPos) { const_cast<SwNodeIndex&>(rRg.aEnd).Assign(aSavePos.GetNode(), +1); + // pCopiedPaM->first now spans a range from the start of the original selection + // to the end of newly added text, and the insertion point is in the middle of + // that range. Adjust the local copy to cover the original copied PaM. + aCopiedPaM.End()->Assign(rRg.aEnd, savedEndContentIndex); } } @@ -3810,7 +3819,6 @@ void DocumentContentOperationsManager::CopyWithFlyInFly( // sw_fieldmarkhide: also needs to be done before making frames if (m_rDoc.getIDocumentMarkAccess()->getAllMarksCount()) { - SwPaM aRgTmp( rRg.aStart, rRg.aEnd ); SwPosition targetPos(aSavePos, SwNodeOffset(rRg.aStart != rRg.aEnd ? +1 : 0)); if (pCopiedPaM && rRg.aStart != pCopiedPaM->first.Start()->GetNode()) { @@ -3823,7 +3831,7 @@ void DocumentContentOperationsManager::CopyWithFlyInFly( targetPos = pCopiedPaM->second; } - sw::CopyBookmarks(pCopiedPaM ? pCopiedPaM->first : aRgTmp, targetPos, flags); + sw::CopyBookmarks(aCopiedPaM, targetPos, flags); } if (rRg.aStart != rRg.aEnd) @@ -3914,7 +3922,7 @@ void DocumentContentOperationsManager::CopyWithFlyInFly( { ::sw::UndoGuard const undoGuard(rDest.GetIDocumentUndoRedo()); - CopyFlyInFlyImpl(rRg, pCopiedPaM ? &pCopiedPaM->first : nullptr, + CopyFlyInFlyImpl(rRg, pCopiedPaM ? &aCopiedPaM : nullptr, // see comment below regarding use of pCopiedPaM->second (pCopiedPaM && rRg.aStart != pCopiedPaM->first.Start()->GetNode()) ? pCopiedPaM->second.GetNode() diff --git a/sw/source/core/doc/docedt.cxx b/sw/source/core/doc/docedt.cxx index c78d8e18b6..2a5aad64de 100644 --- a/sw/source/core/doc/docedt.cxx +++ b/sw/source/core/doc/docedt.cxx @@ -553,7 +553,7 @@ uno::Any SwDoc::Spell( SwPaM& rPaM, { nCurrNd = pNd->EndOfSectionIndex(); } - else if( !static_cast<SwTextFrame*>(pContentFrame)->IsHiddenNow() ) + else if( !pContentFrame->IsHiddenNow() ) { if( pPageCnt && *pPageCnt && pPageSt ) { @@ -766,7 +766,7 @@ static bool lcl_HyphenateNode( SwNode* pNd, void* pArgs ) // sw_redlinehide: this will be called once per node for merged nodes; // the fully deleted ones won't have frames so are skipped. SwContentFrame* pContentFrame = pNode->getLayoutFrame( pNode->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout() ); - if( pContentFrame && !static_cast<SwTextFrame*>(pContentFrame)->IsHiddenNow() ) + if( pContentFrame && !pContentFrame->IsHiddenNow() ) { sal_uInt16 *pPageSt = pHyphArgs->GetPageSt(); sal_uInt16 *pPageCnt = pHyphArgs->GetPageCnt(); diff --git a/sw/source/core/doc/docfmt.cxx b/sw/source/core/doc/docfmt.cxx index d6c943dbcd..1c696bebb6 100644 --- a/sw/source/core/doc/docfmt.cxx +++ b/sw/source/core/doc/docfmt.cxx @@ -1553,21 +1553,21 @@ void SwDoc::CopyPageDesc( const SwPageDesc& rSrcDesc, SwPageDesc& rDstDesc, { if (pStashedFormatSrc->GetDoc() != this) { - SwFrameFormat* pNewFormat = new SwFrameFormat(GetAttrPool(), "CopyDesc", GetDfltFrameFormat()); + SwFrameFormat newFormat(GetAttrPool(), "CopyDesc", GetDfltFrameFormat()); SfxItemSet aAttrSet(pStashedFormatSrc->GetAttrSet()); aAttrSet.ClearItem(RES_HEADER); aAttrSet.ClearItem(RES_FOOTER); - pNewFormat->DelDiffs( aAttrSet ); - pNewFormat->SetFormatAttr( aAttrSet ); + newFormat.DelDiffs(aAttrSet); + newFormat.SetFormatAttr(aAttrSet); if (bHeader) - CopyHeader(*pStashedFormatSrc, *pNewFormat); + CopyHeader(*pStashedFormatSrc, newFormat); else - CopyFooter(*pStashedFormatSrc, *pNewFormat); + CopyFooter(*pStashedFormatSrc, newFormat); - rDstDesc.StashFrameFormat(*pNewFormat, bHeader, bLeft, bFirst); + rDstDesc.StashFrameFormat(newFormat, bHeader, bLeft, bFirst); } else { diff --git a/sw/source/core/doc/doctxm.cxx b/sw/source/core/doc/doctxm.cxx index f03687d810..d29223050b 100644 --- a/sw/source/core/doc/doctxm.cxx +++ b/sw/source/core/doc/doctxm.cxx @@ -1057,7 +1057,7 @@ void SwTOXBaseSection::Update(const SfxItemSet* pAttr, SwSectionFormat* pSectFormat = rDoc.MakeSectionFormat(); rDoc.GetNodes().InsertTextSection( *pHeadNd, *pSectFormat, headerData, nullptr, &aIdx.GetNode(), true, false); - + pSectFormat->GetSection()->SetProtect(SwTOXBase::IsProtected()); if (pUndo) { pUndo->TitleSectionInserted(*pSectFormat); diff --git a/sw/source/core/docnode/ndsect.cxx b/sw/source/core/docnode/ndsect.cxx index cf96e1d509..1da9ecb43e 100644 --- a/sw/source/core/docnode/ndsect.cxx +++ b/sw/source/core/docnode/ndsect.cxx @@ -1022,9 +1022,9 @@ SwSectionNode::~SwSectionNode() } } -SwFrame *SwSectionNode::MakeFrame( SwFrame *pSib ) +SwFrame* SwSectionNode::MakeFrame(SwFrame* pSib, bool bHidden) { - m_pSection->m_Data.SetHiddenFlag(false); + m_pSection->m_Data.SetHiddenFlag(bHidden); return new SwSectionFrame( *m_pSection, pSib ); } diff --git a/sw/source/core/docnode/ndtbl.cxx b/sw/source/core/docnode/ndtbl.cxx index a7a2bee478..f3b3a07d63 100644 --- a/sw/source/core/docnode/ndtbl.cxx +++ b/sw/source/core/docnode/ndtbl.cxx @@ -888,6 +888,34 @@ const SwTable* SwDoc::TextToTable( const SwInsertTableOptions& rInsTableOpts, return &rNdTable; } +static void lcl_RemoveBreaksTable(SwTableNode & rNode, SwTableFormat *const pTableFormat) +{ + // delete old layout frames, new ones need to be created... + rNode.DelFrames(nullptr); + + // remove PageBreaks/PageDesc/ColBreak + SwFrameFormat & rFormat(*rNode.GetTable().GetFrameFormat()); + + if (const SvxFormatBreakItem* pItem = rFormat.GetItemIfSet(RES_BREAK, false)) + { + if (pTableFormat) + { + pTableFormat->SetFormatAttr(*pItem); + } + rFormat.ResetFormatAttr(RES_BREAK); + } + + SwFormatPageDesc const*const pPageDescItem(rFormat.GetItemIfSet(RES_PAGEDESC, false)); + if (pPageDescItem && pPageDescItem->GetPageDesc()) + { + if (pTableFormat) + { + pTableFormat->SetFormatAttr(*pPageDescItem); + } + rFormat.ResetFormatAttr(RES_PAGEDESC); + } +} + static void lcl_RemoveBreaks(SwContentNode & rNode, SwTableFormat *const pTableFormat) { // delete old layout frames, new ones need to be created... @@ -1385,10 +1413,19 @@ SwTableNode* SwNodes::TextToTable( const SwNodes::TableRanges_t & rTableNodes, // delete frames of all contained content nodes for( nLines = 0; aNodeIndex <= rTableNodes.rbegin()->rbegin()->aEnd; ++aNodeIndex,++nLines ) { - SwNode& rNode = aNodeIndex.GetNode(); - if( rNode.IsContentNode() ) + SwNode* pNode(&aNodeIndex.GetNode()); + while (pNode->IsSectionNode()) // could be ToX field in table + { + pNode = pNode->GetNodes()[pNode->GetIndex()+1]; + } + if (pNode->IsTableNode()) + { + lcl_RemoveBreaksTable(static_cast<SwTableNode&>(*pNode), + (0 == nLines) ? pTableFormat : nullptr); + } + else if (pNode->IsContentNode()) { - lcl_RemoveBreaks(static_cast<SwContentNode&>(rNode), + lcl_RemoveBreaks(static_cast<SwContentNode&>(*pNode), (0 == nLines) ? pTableFormat : nullptr); } } diff --git a/sw/source/core/docnode/nodes.cxx b/sw/source/core/docnode/nodes.cxx index c6ecb9ccf9..3506dff230 100644 --- a/sw/source/core/docnode/nodes.cxx +++ b/sw/source/core/docnode/nodes.cxx @@ -1336,34 +1336,68 @@ SwContentNode* SwNodes::GoNext(SwPosition *pIdx) const return static_cast<SwContentNode*>(pNd); } -SwContentNode* SwNodes::GoPrevious(SwNodeIndex *pIdx) +SwNodeOffset SwNodes::StartOfGlobalSection(const SwNode& node) const +{ + const SwNodeOffset pos = node.GetIndex(); + if (GetEndOfExtras().GetIndex() < pos) + // Regular ContentSection + return GetEndOfExtras().GetIndex() + SwNodeOffset(1); + if (GetEndOfAutotext().GetIndex() < pos) + // Redlines + return GetEndOfAutotext().GetIndex() + SwNodeOffset(1); + if (GetEndOfInserts().GetIndex() < pos) + { + // Flys/Headers/Footers + if (auto* p = node.FindFlyStartNode()) + return p->GetIndex(); + if (auto* p = node.FindHeaderStartNode()) + return p->GetIndex(); + if (auto* p = node.FindFooterStartNode()) + return p->GetIndex(); + return GetEndOfInserts().GetIndex() + SwNodeOffset(1); + } + if (GetEndOfPostIts().GetIndex() < pos) + { + // Footnotes + if (auto* p = node.FindFootnoteStartNode()) + return p->GetIndex(); + return GetEndOfPostIts().GetIndex() + SwNodeOffset(1); + } + return SwNodeOffset(0); +} + +SwContentNode* SwNodes::GoPrevious(SwNodeIndex* pIdx, bool canCrossBoundary) { if( !pIdx->GetIndex() ) return nullptr; SwNodeIndex aTmp( *pIdx, -1 ); + SwNodeOffset aGlobalStart( + canCrossBoundary ? SwNodeOffset(0) : aTmp.GetNodes().StartOfGlobalSection(pIdx->GetNode())); SwNode* pNd = nullptr; - while( aTmp.GetIndex() && !( pNd = &aTmp.GetNode())->IsContentNode() ) + while (aTmp > aGlobalStart && !(pNd = &aTmp.GetNode())->IsContentNode()) --aTmp; - if( !aTmp.GetIndex() ) + if (aTmp <= aGlobalStart) pNd = nullptr; else (*pIdx) = aTmp; return static_cast<SwContentNode*>(pNd); } -SwContentNode* SwNodes::GoPrevious(SwPosition *pIdx) +SwContentNode* SwNodes::GoPrevious(SwPosition* pIdx, bool canCrossBoundary) { if( !pIdx->GetNodeIndex() ) return nullptr; SwNodeIndex aTmp( pIdx->GetNode(), -1 ); + SwNodeOffset aGlobalStart( + canCrossBoundary ? SwNodeOffset(0) : aTmp.GetNodes().StartOfGlobalSection(pIdx->GetNode())); SwNode* pNd = nullptr; - while( aTmp.GetIndex() && !( pNd = &aTmp.GetNode())->IsContentNode() ) + while( aTmp > aGlobalStart && !( pNd = &aTmp.GetNode())->IsContentNode() ) --aTmp; - if( !aTmp.GetIndex() ) + if (aTmp <= aGlobalStart) pNd = nullptr; else pIdx->Assign(aTmp); @@ -1963,7 +1997,7 @@ SwContentNode* SwNodes::GoNextSection( SwNodeIndex * pIdx, if (SwNodeType::Section == pNd->GetNodeType()) { const SwSection& rSect = static_cast<const SwSectionNode*>(pNd)->GetSection(); - if( (bSkipHidden && rSect.IsHiddenFlag()) || + if( (bSkipHidden && rSect.CalcHiddenFlag()) || (bSkipProtect && rSect.IsProtectFlag()) ) // than skip the section aTmp = *pNd->EndOfSectionNode(); @@ -1974,7 +2008,7 @@ SwContentNode* SwNodes::GoNextSection( SwNodeIndex * pIdx, { const SwSection& rSect = static_cast<SwSectionNode*>(pNd-> m_pStartOfSection)->GetSection(); - if( (bSkipHidden && rSect.IsHiddenFlag()) || + if( (bSkipHidden && rSect.CalcHiddenFlag()) || (bSkipProtect && rSect.IsProtectFlag()) ) // than skip the section aTmp = *pNd->EndOfSectionNode(); @@ -1985,7 +2019,7 @@ SwContentNode* SwNodes::GoNextSection( SwNodeIndex * pIdx, const SwSectionNode* pSectNd; if( ( bSkipHidden || bSkipProtect ) && nullptr != (pSectNd = pNd->FindSectionNode() ) && - ( ( bSkipHidden && pSectNd->GetSection().IsHiddenFlag() ) || + ( ( bSkipHidden && pSectNd->GetSection().CalcHiddenFlag() ) || ( bSkipProtect && pSectNd->GetSection().IsProtectFlag() )) ) { aTmp = *pSectNd->EndOfSectionNode(); @@ -2072,8 +2106,9 @@ SwContentNode* SwNodes::GoPrevSection( SwNodeIndex * pIdx, { bool bFirst = true; SwNodeIndex aTmp( *pIdx ); + SwNodeOffset aGlobalStart(aTmp.GetNodes().StartOfGlobalSection(pIdx->GetNode())); const SwNode* pNd; - while( aTmp > SwNodeOffset(0) ) + while (aTmp > aGlobalStart) { pNd = & aTmp.GetNode(); if (SwNodeType::End == pNd->GetNodeType()) @@ -2129,8 +2164,9 @@ SwContentNode* SwNodes::GoPrevSection( SwPosition * pIdx, { bool bFirst = true; SwNodeIndex aTmp( pIdx->GetNode() ); + SwNodeOffset aGlobalStart(aTmp.GetNodes().StartOfGlobalSection(pIdx->GetNode())); const SwNode* pNd; - while( aTmp > SwNodeOffset(0) ) + while (aTmp > aGlobalStart) { pNd = & aTmp.GetNode(); if (SwNodeType::End == pNd->GetNodeType()) diff --git a/sw/source/core/docnode/section.cxx b/sw/source/core/docnode/section.cxx index 12d9e281c2..53418541eb 100644 --- a/sw/source/core/docnode/section.cxx +++ b/sw/source/core/docnode/section.cxx @@ -299,14 +299,11 @@ void SwSection::ImplSetHiddenFlag(bool const bTmpHidden, bool const bCondition) // Tell all Children that they are hidden const sw::SectionHidden aHint; pFormat->CallSwClientNotify(aHint); - - // Delete all Frames - pFormat->DelFrames(); } } else if (m_Data.IsHiddenFlag()) // show Nodes again { - // Show all Frames (Child Sections are accounted for by MakeFrames) + // Show all Frames // Only if the Parent Section is not restricting us! SwSection* pParentSect = pFormat->GetParentSection(); if( !pParentSect || !pParentSect->IsHiddenFlag() ) @@ -314,8 +311,6 @@ void SwSection::ImplSetHiddenFlag(bool const bTmpHidden, bool const bCondition) // Tell all Children that the Parent is not hidden anymore const sw::SectionHidden aHint(false); pFormat->CallSwClientNotify(aHint); - - pFormat->MakeFrames(); } } } diff --git a/sw/source/core/edit/editsh.cxx b/sw/source/core/edit/editsh.cxx index 333eecd352..0400dc8871 100644 --- a/sw/source/core/edit/editsh.cxx +++ b/sw/source/core/edit/editsh.cxx @@ -796,7 +796,7 @@ void SwEditShell::SetNumberingRestart() if( nullptr != pContentFrame ) { // skip hidden frames - ignore protection! - if( !static_cast<SwTextFrame*>(pContentFrame)->IsHiddenNow() ) + if( !pContentFrame->IsHiddenNow() ) { // if the node is numbered and the starting value of the numbering equals the // start value of the numbering rule then set this value as hard starting value diff --git a/sw/source/core/edit/edsect.cxx b/sw/source/core/edit/edsect.cxx index a7e652aea9..070a37a90d 100644 --- a/sw/source/core/edit/edsect.cxx +++ b/sw/source/core/edit/edsect.cxx @@ -308,89 +308,121 @@ static const SwNode* lcl_SpecialInsertNode(const SwPosition* pCurrentPos) // pInnermostNode contains the section/table before/after which we should // insert our empty paragraph, or it will be NULL if none is found. const SwNode* pInnermostNode = nullptr; + const SwSection* pSection = nullptr; { const SwNode* pTableNode = rCurrentNode.FindTableNode(); const SwNode* pSectionNode = rCurrentNode.FindSectionNode(); // find the table/section which is close if( pTableNode == nullptr ) + { + if( pSectionNode == nullptr ) + return nullptr; + pInnermostNode = pSectionNode; + pSection = &static_cast<const SwSectionNode*>(pSectionNode)->GetSection(); + } else if ( pSectionNode == nullptr ) pInnermostNode = pTableNode; else { // compare and choose the larger one - pInnermostNode = - ( pSectionNode->GetIndex() > pTableNode->GetIndex() ) - ? pSectionNode : pTableNode; + if (pSectionNode->GetIndex() > pTableNode->GetIndex()) + { + pInnermostNode = pSectionNode; + pSection = &static_cast<const SwSectionNode*>(pSectionNode)->GetSection(); + } + else + pInnermostNode = pTableNode; } } - - // The previous version had a check to skip empty read-only sections. Those - // shouldn't occur, so we only need to check whether our pInnermostNode is - // inside a protected area. - - // Now, pInnermostNode is NULL or the innermost section or table node. - if( (pInnermostNode != nullptr) && !pInnermostNode->IsProtect() ) + if(pInnermostNode != nullptr) { - OSL_ENSURE( pInnermostNode->IsTableNode() || - pInnermostNode->IsSectionNode(), "wrong node found" ); - OSL_ENSURE( ( pInnermostNode->GetIndex() <= rCurrentNode.GetIndex() )&& - ( pInnermostNode->EndOfSectionNode()->GetIndex() >= - rCurrentNode.GetIndex() ), "wrong node found" ); - - // we now need to find the possible start/end positions - - // we found a start if - // - we're at or just before a start node - // - there are only start nodes between the current and pInnermostNode - SwNodeIndex aBegin( pCurrentPos->GetNode() ); - if( rCurrentNode.IsContentNode() && - (pCurrentPos->GetContentIndex() == 0)) - --aBegin; - while( (aBegin != pInnermostNode->GetIndex()) && - aBegin.GetNode().IsStartNode() ) - --aBegin; - bool bStart = ( aBegin == pInnermostNode->GetIndex() ); - - // we found an end if - // - we're at or just before an end node - // - there are only end nodes between the current node and - // pInnermostNode's end node or - // - there are only end nodes between the last table cell merged with - // the current cell and pInnermostNode's end node - SwNodeIndex aEnd( pCurrentPos->GetNode() ); - if( rCurrentNode.IsContentNode() && - ( pCurrentPos->GetContentIndex() == - rCurrentNode.GetContentNode()->Len() ) ) + bool bIsProtected = pInnermostNode->IsProtect(); + + //special case - ToxSection + // - in this case the inner section could be tox header + // section but the new node should be before the content section + // protection of the tox should not prevent the insertion + // only protection outside needs to be checked + if( pSection && + (SectionType::ToxHeader == pSection->GetType() || + SectionType::ToxContent == pSection->GetType())) { - ++aEnd; + if (SectionType::ToxHeader == pSection->GetType()) + { + if (const SwSection* pSectionParent = pSection->GetParent()) + pInnermostNode = pSectionParent->GetFormat()->GetSectionNode(); + } + bIsProtected = static_cast<const SwSectionNode*>(pInnermostNode)->IsInProtectSect(); + } - // tdf#156492 handle cells merged vertically in the bottom right corner - if ( pInnermostNode->IsTableNode() ) + // The previous version had a check to skip empty read-only sections. Those + // shouldn't occur, so we only need to check whether our pInnermostNode is + // inside a protected area. + + // Now, pInnermostNode is NULL or the innermost section or table node. + if(!bIsProtected) + { + OSL_ENSURE( pInnermostNode->IsTableNode() || + pInnermostNode->IsSectionNode(), "wrong node found" ); + OSL_ENSURE( ( pInnermostNode->GetIndex() <= rCurrentNode.GetIndex() )&& + ( pInnermostNode->EndOfSectionNode()->GetIndex() >= + rCurrentNode.GetIndex() ), "wrong node found" ); + + // we now need to find the possible start/end positions + + // we found a start if + // - we're at or just before a start node + // - there are only start nodes between the current and pInnermostNode + SwNodeIndex aBegin( pCurrentPos->GetNode() ); + if( rCurrentNode.IsContentNode() && + (pCurrentPos->GetContentIndex() == 0)) + --aBegin; + while( (aBegin != pInnermostNode->GetIndex()) && + aBegin.GetNode().IsStartNode() ) + --aBegin; + bool bStart = ( aBegin == pInnermostNode->GetIndex() ); + + // we found an end if + // - we're at or just before an end node + // - there are only end nodes between the current node and + // pInnermostNode's end node or + // - there are only end nodes between the last table cell merged with + // the current cell and pInnermostNode's end node + SwNodeIndex aEnd( pCurrentPos->GetNode() ); + if( rCurrentNode.IsContentNode() && + ( pCurrentPos->GetContentIndex() == + rCurrentNode.GetContentNode()->Len() ) ) { - const SwNode* pTableBoxStartNode = pCurrentPos->GetNode().FindTableBoxStartNode(); - const SwTableBox* pTableBox = pTableBoxStartNode->GetTableBox(); - if ( pTableBox && pTableBox->getRowSpan() > 1 ) + ++aEnd; + + // tdf#156492 handle cells merged vertically in the bottom right corner + if ( pInnermostNode->IsTableNode() ) { - const SwTableNode* pTableNd = pInnermostNode->FindTableNode(); - pTableBox = & pTableBox->FindEndOfRowSpan( pTableNd->GetTable(), - pTableBox->getRowSpan() ); - pTableBoxStartNode = pTableBox->GetSttNd(); - aEnd = pTableBoxStartNode->GetIndex() + 2; + const SwNode* pTableBoxStartNode = pCurrentPos->GetNode().FindTableBoxStartNode(); + const SwTableBox* pTableBox = pTableBoxStartNode->GetTableBox(); + if ( pTableBox && pTableBox->getRowSpan() > 1 ) + { + const SwTableNode* pTableNd = pInnermostNode->FindTableNode(); + pTableBox = & pTableBox->FindEndOfRowSpan( pTableNd->GetTable(), + pTableBox->getRowSpan() ); + pTableBoxStartNode = pTableBox->GetSttNd(); + aEnd = pTableBoxStartNode->GetIndex() + 2; + } } } + while( (aEnd != pInnermostNode->EndOfSectionNode()->GetIndex()) && + aEnd.GetNode().IsEndNode() ) + ++aEnd; + bool bEnd = ( aEnd == pInnermostNode->EndOfSectionNode()->GetIndex() ); + + // evaluate result: if both start + end, end is preferred + if( bEnd ) + pReturn = pInnermostNode->EndOfSectionNode(); + else if ( bStart ) + pReturn = pInnermostNode; } - while( (aEnd != pInnermostNode->EndOfSectionNode()->GetIndex()) && - aEnd.GetNode().IsEndNode() ) - ++aEnd; - bool bEnd = ( aEnd == pInnermostNode->EndOfSectionNode()->GetIndex() ); - - // evaluate result: if both start + end, end is preferred - if( bEnd ) - pReturn = pInnermostNode->EndOfSectionNode(); - else if ( bStart ) - pReturn = pInnermostNode; } OSL_ENSURE( ( pReturn == nullptr ) || pReturn->IsStartNode() || diff --git a/sw/source/core/inc/frame.hxx b/sw/source/core/inc/frame.hxx index d57654f6a9..604488a18c 100644 --- a/sw/source/core/inc/frame.hxx +++ b/sw/source/core/inc/frame.hxx @@ -891,6 +891,8 @@ public: // Fly in ... and footnotes bool IsProtected() const; + virtual bool IsHiddenNow() const; + bool IsColLocked() const { return mbColLocked; } virtual bool IsDeleteForbidden() const { return mnForbidDelete > 0; } diff --git a/sw/source/core/inc/sectfrm.hxx b/sw/source/core/inc/sectfrm.hxx index c07d78b12b..69158b3358 100644 --- a/sw/source/core/inc/sectfrm.hxx +++ b/sw/source/core/inc/sectfrm.hxx @@ -88,6 +88,8 @@ public: virtual void Cut() override; virtual void Paste( SwFrame* pParent, SwFrame* pSibling = nullptr ) override; + virtual bool IsHiddenNow() const override; + inline const SwSectionFrame *GetFollow() const; inline SwSectionFrame *GetFollow(); SwSectionFrame* FindMaster() const; diff --git a/sw/source/core/inc/txtfrm.hxx b/sw/source/core/inc/txtfrm.hxx index e60dbd20fb..df11ca589b 100644 --- a/sw/source/core/inc/txtfrm.hxx +++ b/sw/source/core/inc/txtfrm.hxx @@ -559,7 +559,7 @@ public: #endif /// Hidden - bool IsHiddenNow() const; // bHidden && pOut == pPrt + virtual bool IsHiddenNow() const override; // bHidden && pOut == pPrt void HideHidden(); // Remove appendage if Hidden void HideFootnotes(TextFrameIndex nStart, TextFrameIndex nEnd); diff --git a/sw/source/core/layout/calcmove.cxx b/sw/source/core/layout/calcmove.cxx index c2bbdd8904..e13fdf0121 100644 --- a/sw/source/core/layout/calcmove.cxx +++ b/sw/source/core/layout/calcmove.cxx @@ -177,7 +177,7 @@ bool SwContentFrame::ShouldBwdMoved( SwLayoutFrame *pNewUpper, bool & ) if ( nMoveAnyway < 3 ) { - if ( nSpace ) + if (nSpace || IsHiddenNow()) { // Do not notify footnotes which are stuck to the paragraph: // This would require extremely confusing code, taking into @@ -209,7 +209,7 @@ bool SwContentFrame::ShouldBwdMoved( SwLayoutFrame *pNewUpper, bool & ) } // Check for space left in new upper - return nSpace != 0; + return nSpace != 0 || IsHiddenNow(); } } return false; @@ -532,7 +532,7 @@ static SwFrame* lcl_NotHiddenPrev( SwFrame* pFrame ) do { pRet = lcl_Prev( pRet ); - } while ( pRet && pRet->IsTextFrame() && static_cast<SwTextFrame*>(pRet)->IsHiddenNow() ); + } while ( pRet && pRet->IsHiddenNow() ); return pRet; } @@ -1083,9 +1083,8 @@ void SwContentFrame::MakePrtArea( const SwBorderAttrs &rAttrs ) setFramePrintAreaValid(true); SwRectFnSet aRectFnSet(this); - const bool bTextFrame = IsTextFrame(); SwTwips nUpper = 0; - if ( bTextFrame && static_cast<SwTextFrame*>(this)->IsHiddenNow() ) + if (IsTextFrame() && IsHiddenNow()) { if ( static_cast<SwTextFrame*>(this)->HasFollow() ) static_cast<SwTextFrame*>(this)->JoinFrame(); @@ -1715,7 +1714,7 @@ void SwContentFrame::MakeAll(vcl::RenderContext* /*pRenderContext*/) const bool bMoveFwdInvalid = nullptr != GetIndNext(); const bool bNxtNew = ( 0 == aRectFnSet.GetHeight(pNxt->getFramePrintArea()) ) && - (!pNxt->IsTextFrame() ||!static_cast<SwTextFrame*>(pNxt)->IsHiddenNow()); + !pNxt->IsHiddenNow(); pNxt->Calc(getRootFrame()->GetCurrShell()->GetOut()); @@ -2217,7 +2216,7 @@ bool SwContentFrame::WouldFit_( SwTwips nSpace, pTmpPrev = nullptr; else { - if( pFrame->IsTextFrame() && static_cast<SwTextFrame*>(pFrame)->IsHiddenNow() ) + if (pFrame->IsHiddenNow()) pTmpPrev = lcl_NotHiddenPrev( pFrame ); else pTmpPrev = pFrame; diff --git a/sw/source/core/layout/findfrm.cxx b/sw/source/core/layout/findfrm.cxx index 5331baacd9..0dd64c6aec 100644 --- a/sw/source/core/layout/findfrm.cxx +++ b/sw/source/core/layout/findfrm.cxx @@ -994,7 +994,7 @@ SwFrame *SwFrame::FindNext_() (!bFootnote || pSct->IsInFootnote() ) ) return pSct; } - return pRet; + return pRet == this ? nullptr : pRet; } // #i27138# - add parameter <_bInSameFootnote> @@ -1380,11 +1380,7 @@ void SwFrame::InvalidateNextPrtArea() SwFrame* pNextFrame = FindNext(); // skip empty section frames and hidden text frames { - while ( pNextFrame && - ( ( pNextFrame->IsSctFrame() && - !static_cast<SwSectionFrame*>(pNextFrame)->GetSection() ) || - ( pNextFrame->IsTextFrame() && - static_cast<SwTextFrame*>(pNextFrame)->IsHiddenNow() ) ) ) + while (pNextFrame && pNextFrame->IsHiddenNow()) { pNextFrame = pNextFrame->FindNext(); } diff --git a/sw/source/core/layout/flowfrm.cxx b/sw/source/core/layout/flowfrm.cxx index da509e2a6b..88158161c5 100644 --- a/sw/source/core/layout/flowfrm.cxx +++ b/sw/source/core/layout/flowfrm.cxx @@ -1271,8 +1271,7 @@ bool SwFlowFrame::IsPageBreak( bool bAct ) const // Determine predecessor const SwFrame *pPrev = m_rThis.FindPrev(); - while ( pPrev && ( !pPrev->IsInDocBody() || - ( pPrev->IsTextFrame() && static_cast<const SwTextFrame*>(pPrev)->IsHiddenNow() ) ) ) + while (pPrev && (!pPrev->IsInDocBody() || pPrev->IsHiddenNow())) pPrev = pPrev->FindPrev(); if ( pPrev ) @@ -1333,7 +1332,7 @@ bool SwFlowFrame::IsColBreak( bool bAct ) const // Determine predecessor const SwFrame *pPrev = m_rThis.FindPrev(); while( pPrev && ( ( !pPrev->IsInDocBody() && !m_rThis.IsInFly() && !m_rThis.FindFooterOrHeader() ) || - ( pPrev->IsTextFrame() && static_cast<const SwTextFrame*>(pPrev)->IsHiddenNow() ) ) ) + pPrev->IsHiddenNow() ) ) pPrev = pPrev->FindPrev(); if ( pPrev ) @@ -1364,6 +1363,14 @@ bool SwFlowFrame::IsColBreak( bool bAct ) const return false; } +// Skip hidden paragraphs and empty sections on the same level +static const SwFrame* skipHiddenSiblingFrames_(const SwFrame* pFrame) +{ + while (pFrame && pFrame->IsHiddenNow()) + pFrame = pFrame->GetPrev(); + return pFrame; +} + bool SwFlowFrame::HasParaSpaceAtPages( bool bSct ) const { if( m_rThis.IsInSct() ) @@ -1379,7 +1386,7 @@ bool SwFlowFrame::HasParaSpaceAtPages( bool bSct ) const return !pTmp->GetPrev() || IsPageBreak(true); if( pTmp->IsColumnFrame() && pTmp->GetPrev() ) return IsColBreak( true ); - if( pTmp->IsSctFrame() && ( !bSct || pTmp->GetPrev() ) ) + if (pTmp->IsSctFrame() && (!bSct || skipHiddenSiblingFrames_(pTmp->GetPrev()))) return false; pTmp = pTmp->GetUpper(); } @@ -1401,6 +1408,31 @@ bool SwFlowFrame::HasParaSpaceAtPages( bool bSct ) const return pTmp && !pTmp->GetPrev(); } +// Skip hidden paragraphs and empty sections +static const SwFrame* skipHiddenFrames_(const SwFrame* pFrame) +{ + do + { + pFrame = skipHiddenSiblingFrames_(pFrame); + if (!pFrame || !pFrame->IsSctFrame()) + return pFrame; + // Special case: found previous frame is a section + // Search for the last content in the section + auto pSectFrame = static_cast<const SwSectionFrame*>(pFrame); + pFrame = pSectFrame->FindLastContent(); + // If the last content is in a table _inside_ the section, + // take the table herself. + // Correction: Check directly, if table is inside table, instead of indirectly + // by checking, if section isn't inside a table + if (pFrame && pFrame->IsInTab()) + { + const SwTabFrame* pTableFrame = pFrame->FindTabFrame(); + if (pSectFrame->IsAnLower(pTableFrame)) + return pTableFrame; + } + } while (true); +} + /** helper method to determine previous frame for calculation of the upper space @@ -1408,73 +1440,21 @@ bool SwFlowFrame::HasParaSpaceAtPages( bool bSct ) const */ const SwFrame* SwFlowFrame::GetPrevFrameForUpperSpaceCalc_( const SwFrame* _pProposedPrevFrame ) const { - const SwFrame* pPrevFrame = _pProposedPrevFrame - ? _pProposedPrevFrame - : m_rThis.GetPrev(); - - // Skip hidden paragraphs and empty sections - while ( pPrevFrame && - ( ( pPrevFrame->IsTextFrame() && - static_cast<const SwTextFrame*>(pPrevFrame)->IsHiddenNow() ) || - ( pPrevFrame->IsSctFrame() && - !static_cast<const SwSectionFrame*>(pPrevFrame)->GetSection() ) ) ) - { - pPrevFrame = pPrevFrame->GetPrev(); - } + const SwFrame* pPrevFrame + = skipHiddenFrames_(_pProposedPrevFrame ? _pProposedPrevFrame : m_rThis.GetPrev()); + if (pPrevFrame || !m_rThis.IsInFootnote() + || !(m_rThis.IsSctFrame() || !m_rThis.IsInSct() || !m_rThis.FindSctFrame()->IsInFootnote())) + return pPrevFrame; // Special case: no direct previous frame is found but frame is in footnote // Search for a previous frame in previous footnote, // if frame isn't in a section, which is also in the footnote - if ( !pPrevFrame && m_rThis.IsInFootnote() && - ( m_rThis.IsSctFrame() || - !m_rThis.IsInSct() || !m_rThis.FindSctFrame()->IsInFootnote() ) ) - { - const SwFootnoteFrame* pPrevFootnoteFrame = - static_cast<const SwFootnoteFrame*>(m_rThis.FindFootnoteFrame()->GetPrev()); - if ( pPrevFootnoteFrame ) - { - pPrevFrame = pPrevFootnoteFrame->GetLastLower(); - - // Skip hidden paragraphs and empty sections - while ( pPrevFrame && - ( ( pPrevFrame->IsTextFrame() && - static_cast<const SwTextFrame*>(pPrevFrame)->IsHiddenNow() ) || - ( pPrevFrame->IsSctFrame() && - !static_cast<const SwSectionFrame*>(pPrevFrame)->GetSection() ) ) ) - { - pPrevFrame = pPrevFrame->GetPrev(); - } - } - } - // Special case: found previous frame is a section - // Search for the last content in the section - if( pPrevFrame && pPrevFrame->IsSctFrame() ) - { - const SwSectionFrame* pPrevSectFrame = - static_cast<const SwSectionFrame*>(pPrevFrame); - pPrevFrame = pPrevSectFrame->FindLastContent(); - // If the last content is in a table _inside_ the section, - // take the table herself. - // Correction: Check directly, if table is inside table, instead of indirectly - // by checking, if section isn't inside a table - if ( pPrevFrame && pPrevFrame->IsInTab() ) - { - const SwTabFrame* pTableFrame = pPrevFrame->FindTabFrame(); - if ( pPrevSectFrame->IsAnLower( pTableFrame ) ) - { - pPrevFrame = pTableFrame; - } - } - // Correction: skip hidden text frames - while ( pPrevFrame && - pPrevFrame->IsTextFrame() && - static_cast<const SwTextFrame*>(pPrevFrame)->IsHiddenNow() ) - { - pPrevFrame = pPrevFrame->GetPrev(); - } - } + const SwFootnoteFrame* pPrevFootnoteFrame = + static_cast<const SwFootnoteFrame*>(m_rThis.FindFootnoteFrame()->GetPrev()); + if ( pPrevFootnoteFrame ) + return skipHiddenFrames_(pPrevFootnoteFrame->GetLastLower()); - return pPrevFrame; + return nullptr; } // This should be renamed to something like lcl_UseULSpacing @@ -1912,6 +1892,8 @@ SwTwips SwFlowFrame::CalcAddLowerSpaceAsLastInTableCell( /// Moves the Frame forward if it seems necessary regarding the current conditions and attributes. bool SwFlowFrame::CheckMoveFwd( bool& rbMakePage, bool bKeep, bool bIgnoreMyOwnKeepValue ) { + if (m_rThis.IsHiddenNow()) + return false; const SwFrame* pNxt = m_rThis.GetIndNext(); if ( bKeep && //!bMovedBwd && @@ -2299,7 +2281,8 @@ bool SwFlowFrame::MoveBwd( bool &rbReformat ) ) pNewUpper = m_rThis.GetLeaf( MAKEPAGE_FTN, false ); } - else if ( IsPageBreak( true ) ) // Do we have to respect a PageBreak? + // Do we have to respect a PageBreak? + else if (IsPageBreak(true) && (!m_rThis.IsInSct() || !m_rThis.FindSctFrame()->IsHiddenNow())) { // If the previous page doesn't have a Frame in the body, // flowing back makes sense despite the PageBreak (otherwise, @@ -2366,7 +2349,7 @@ bool SwFlowFrame::MoveBwd( bool &rbReformat ) } } } - else if ( IsColBreak( true ) ) + else if (IsColBreak(true)) { // If the previous column doesn't contain a ContentFrame, flowing back // makes sense despite the ColumnBreak, as otherwise we'd get diff --git a/sw/source/core/layout/frmtool.cxx b/sw/source/core/layout/frmtool.cxx index eeab5c60c1..baf632d6eb 100644 --- a/sw/source/core/layout/frmtool.cxx +++ b/sw/source/core/layout/frmtool.cxx @@ -844,11 +844,7 @@ void SwContentNotify::ImplDestroy() SwFrame* pPrevFrame = pCnt->FindPrev(); // skip empty section frames and hidden text frames { - while ( pPrevFrame && - ( ( pPrevFrame->IsSctFrame() && - !static_cast<SwSectionFrame*>(pPrevFrame)->GetSection() ) || - ( pPrevFrame->IsTextFrame() && - static_cast<SwTextFrame*>(pPrevFrame)->IsHiddenNow() ) ) ) + while (pPrevFrame && pPrevFrame->IsHiddenNow()) { pPrevFrame = pPrevFrame->FindPrev(); } @@ -1608,7 +1604,7 @@ void InsertCnt_( SwLayoutFrame *pLay, SwDoc *pDoc, pFrame = pNode->IsTextNode() ? sw::MakeTextFrame(*pNode->GetTextNode(), pLay, eMode) : pNode->MakeFrame(pLay); - if( pPageMaker ) + if (pPageMaker && !pLay->IsHiddenNow()) pPageMaker->CheckInsert( nIndex ); pFrame->InsertBehind( pLay, pPrv ); @@ -1766,15 +1762,11 @@ void InsertCnt_( SwLayoutFrame *pLay, SwDoc *pDoc, continue; // skip it } SwSectionNode *pNode = static_cast<SwSectionNode*>(pNd); - if( pNode->GetSection().CalcHiddenFlag() ) - // is hidden, skip the area - nIndex = pNode->EndOfSectionIndex(); - else { if (pActualSection) pActualSection->SetLastPos(pPrv); - pFrame = pNode->MakeFrame( pLay ); + pFrame = pNode->MakeFrame(pLay, pNode->GetSection().CalcHiddenFlag()); pActualSection.reset( new SwActualSection( pActualSection.release(), static_cast<SwSectionFrame*>(pFrame), pNode ) ); if ( pActualSection->GetUpper() ) @@ -1945,7 +1937,8 @@ void InsertCnt_( SwLayoutFrame *pLay, SwDoc *pDoc, } else { - pFrame = pActualSection->GetSectionNode()->MakeFrame( pLay ); + pFrame = pActualSection->GetSectionNode()->MakeFrame( + pLay, pActualSection->GetSectionNode()->GetSection().IsHiddenFlag()); pFrame->InsertBehind( pLay, pPrv ); static_cast<SwSectionFrame*>(pFrame)->Init(); @@ -2523,8 +2516,7 @@ void SwBorderAttrs::CalcJoinedWithPrev( const SwFrame& _rFrame, // one as previous frame. const SwFrame* pPrevFrame = _pPrevFrame ? _pPrevFrame : _rFrame.GetPrev(); // OD 2004-02-13 #i25029# - skip hidden text frames. - while ( pPrevFrame && pPrevFrame->IsTextFrame() && - static_cast<const SwTextFrame*>(pPrevFrame)->IsHiddenNow() ) + while (pPrevFrame && pPrevFrame->IsHiddenNow()) { pPrevFrame = pPrevFrame->GetPrev(); } @@ -2555,8 +2547,7 @@ void SwBorderAttrs::CalcJoinedWithNext( const SwFrame& _rFrame ) // corresponding attribute set is set at current text frame. // OD 2004-02-13 #i25029# - get next frame, but skip hidden text frames. const SwFrame* pNextFrame = _rFrame.GetNext(); - while ( pNextFrame && pNextFrame->IsTextFrame() && - static_cast<const SwTextFrame*>(pNextFrame)->IsHiddenNow() ) + while (pNextFrame && pNextFrame->IsHiddenNow()) { pNextFrame = pNextFrame->GetNext(); } diff --git a/sw/source/core/layout/ftnfrm.cxx b/sw/source/core/layout/ftnfrm.cxx index 70453c5727..f4e6072498 100644 --- a/sw/source/core/layout/ftnfrm.cxx +++ b/sw/source/core/layout/ftnfrm.cxx @@ -2965,13 +2965,9 @@ SwContentFrame* SwFootnoteFrame::FindLastContent() while ( pTmpLastLower && pTmpLastLower->GetNext() ) { pTmpLastLower = pTmpLastLower->GetNext(); - if ( ( pTmpLastLower->IsTextFrame() && - !static_cast<SwTextFrame*>(pTmpLastLower)->IsHiddenNow() ) || - ( pTmpLastLower->IsSctFrame() && - static_cast<SwSectionFrame*>(pTmpLastLower)->GetSection() && - static_cast<SwSectionFrame*>(pTmpLastLower)->ContainsContent() ) || - ( pTmpLastLower->IsTabFrame() && - static_cast<SwTabFrame*>(pTmpLastLower)->ContainsContent() ) ) + if (!pTmpLastLower->IsHiddenNow() + && (!pTmpLastLower->IsLayoutFrame() + || static_cast<SwLayoutFrame*>(pTmpLastLower)->ContainsContent())) { pLastLowerOfFootnote = pTmpLastLower; } diff --git a/sw/source/core/layout/pagechg.cxx b/sw/source/core/layout/pagechg.cxx index bf4bcc45ea..f8c029ea12 100644 --- a/sw/source/core/layout/pagechg.cxx +++ b/sw/source/core/layout/pagechg.cxx @@ -789,7 +789,10 @@ SwPageDesc *SwPageFrame::FindPageDesc() return pRet; } - SwFrame *pFlow = FindFirstBodyContent(); + SwContentFrame* pFirstContent = FindFirstBodyContent(); + while (pFirstContent && pFirstContent->IsHiddenNow()) + pFirstContent = pFirstContent->GetNextContentFrame(); + SwFrame* pFlow = pFirstContent; if ( pFlow && pFlow->IsInTab() ) pFlow = pFlow->FindTabFrame(); diff --git a/sw/source/core/layout/pagedesc.cxx b/sw/source/core/layout/pagedesc.cxx index 2b78823327..f9679bb2a8 100644 --- a/sw/source/core/layout/pagedesc.cxx +++ b/sw/source/core/layout/pagedesc.cxx @@ -83,13 +83,13 @@ SwPageDesc::SwPageDesc( const SwPageDesc &rCpy ) , m_FootnoteInfo( rCpy.GetFootnoteInfo() ) , m_pdList( nullptr ) { - m_aStashedHeader.m_pStashedFirst = rCpy.m_aStashedHeader.m_pStashedFirst; - m_aStashedHeader.m_pStashedLeft = rCpy.m_aStashedHeader.m_pStashedLeft; - m_aStashedHeader.m_pStashedFirstLeft = rCpy.m_aStashedHeader.m_pStashedFirstLeft; + m_aStashedHeader.m_oStashedFirst = rCpy.m_aStashedHeader.m_oStashedFirst; + m_aStashedHeader.m_oStashedLeft = rCpy.m_aStashedHeader.m_oStashedLeft; + m_aStashedHeader.m_oStashedFirstLeft = rCpy.m_aStashedHeader.m_oStashedFirstLeft; - m_aStashedFooter.m_pStashedFirst = rCpy.m_aStashedFooter.m_pStashedFirst; - m_aStashedFooter.m_pStashedLeft = rCpy.m_aStashedFooter.m_pStashedLeft; - m_aStashedFooter.m_pStashedFirstLeft = rCpy.m_aStashedFooter.m_pStashedFirstLeft; + m_aStashedFooter.m_oStashedFirst = rCpy.m_aStashedFooter.m_oStashedFirst; + m_aStashedFooter.m_oStashedLeft = rCpy.m_aStashedFooter.m_oStashedLeft; + m_aStashedFooter.m_oStashedFirstLeft = rCpy.m_aStashedFooter.m_oStashedFirstLeft; if (rCpy.m_pTextFormatColl && rCpy.m_aDepends.IsListeningTo(rCpy.m_pTextFormatColl)) { @@ -110,13 +110,13 @@ SwPageDesc & SwPageDesc::operator = (const SwPageDesc & rSrc) m_FirstMaster = rSrc.m_FirstMaster; m_FirstLeft = rSrc.m_FirstLeft; - m_aStashedHeader.m_pStashedFirst = rSrc.m_aStashedHeader.m_pStashedFirst; - m_aStashedHeader.m_pStashedLeft = rSrc.m_aStashedHeader.m_pStashedLeft; - m_aStashedHeader.m_pStashedFirstLeft = rSrc.m_aStashedHeader.m_pStashedFirstLeft; + m_aStashedHeader.m_oStashedFirst = rSrc.m_aStashedHeader.m_oStashedFirst; + m_aStashedHeader.m_oStashedLeft = rSrc.m_aStashedHeader.m_oStashedLeft; + m_aStashedHeader.m_oStashedFirstLeft = rSrc.m_aStashedHeader.m_oStashedFirstLeft; - m_aStashedFooter.m_pStashedFirst = rSrc.m_aStashedFooter.m_pStashedFirst; - m_aStashedFooter.m_pStashedLeft = rSrc.m_aStashedFooter.m_pStashedLeft; - m_aStashedFooter.m_pStashedFirstLeft = rSrc.m_aStashedFooter.m_pStashedFirstLeft; + m_aStashedFooter.m_oStashedFirst = rSrc.m_aStashedFooter.m_oStashedFirst; + m_aStashedFooter.m_oStashedLeft = rSrc.m_aStashedFooter.m_oStashedLeft; + m_aStashedFooter.m_oStashedFirstLeft = rSrc.m_aStashedFooter.m_oStashedFirstLeft; m_aDepends.EndListeningAll(); if (rSrc.m_pTextFormatColl && rSrc.m_aDepends.IsListeningTo(rSrc.m_pTextFormatColl)) @@ -416,30 +416,30 @@ void SwPageDesc::ChgFirstShare( bool bNew ) void SwPageDesc::StashFrameFormat(const SwFrameFormat& rFormat, bool bHeader, bool bLeft, bool bFirst) { assert(rFormat.GetRegisteredIn()); - std::shared_ptr<SwFrameFormat>* pFormat = nullptr; + std::optional<SwFrameFormat>* pFormat = nullptr; if (bHeader) { if (bLeft && !bFirst) - pFormat = &m_aStashedHeader.m_pStashedLeft; + pFormat = &m_aStashedHeader.m_oStashedLeft; else if (!bLeft && bFirst) - pFormat = &m_aStashedHeader.m_pStashedFirst; + pFormat = &m_aStashedHeader.m_oStashedFirst; else if (bLeft && bFirst) - pFormat = &m_aStashedHeader.m_pStashedFirstLeft; + pFormat = &m_aStashedHeader.m_oStashedFirstLeft; } else { if (bLeft && !bFirst) - pFormat = &m_aStashedFooter.m_pStashedLeft; + pFormat = &m_aStashedFooter.m_oStashedLeft; else if (!bLeft && bFirst) - pFormat = &m_aStashedFooter.m_pStashedFirst; + pFormat = &m_aStashedFooter.m_oStashedFirst; else if (bLeft && bFirst) - pFormat = &m_aStashedFooter.m_pStashedFirstLeft; + pFormat = &m_aStashedFooter.m_oStashedFirstLeft; } if (pFormat) { - *pFormat = std::make_shared<SwFrameFormat>(rFormat); + pFormat->emplace(rFormat); } else { @@ -451,24 +451,24 @@ void SwPageDesc::StashFrameFormat(const SwFrameFormat& rFormat, bool bHeader, bo const SwFrameFormat* SwPageDesc::GetStashedFrameFormat(bool bHeader, bool bLeft, bool bFirst) const { - std::shared_ptr<SwFrameFormat>* pFormat = nullptr; + std::optional<SwFrameFormat>* pFormat = nullptr; if (bLeft && !bFirst) { - pFormat = bHeader ? &m_aStashedHeader.m_pStashedLeft : &m_aStashedFooter.m_pStashedLeft; + pFormat = bHeader ? &m_aStashedHeader.m_oStashedLeft : &m_aStashedFooter.m_oStashedLeft; } else if (!bLeft && bFirst) { - pFormat = bHeader ? &m_aStashedHeader.m_pStashedFirst : &m_aStashedFooter.m_pStashedFirst; + pFormat = bHeader ? &m_aStashedHeader.m_oStashedFirst : &m_aStashedFooter.m_oStashedFirst; } else if (bLeft && bFirst) { - pFormat = bHeader ? &m_aStashedHeader.m_pStashedFirstLeft : &m_aStashedFooter.m_pStashedFirstLeft; + pFormat = bHeader ? &m_aStashedHeader.m_oStashedFirstLeft : &m_aStashedFooter.m_oStashedFirstLeft; } if (pFormat) { - return pFormat->get(); + return pFormat->has_value() ? &**pFormat : nullptr; } else { @@ -483,15 +483,15 @@ bool SwPageDesc::HasStashedFormat(bool bHeader, bool bLeft, bool bFirst) const { if (bLeft && !bFirst) { - return m_aStashedHeader.m_pStashedLeft != nullptr; + return m_aStashedHeader.m_oStashedLeft.has_value(); } else if (!bLeft && bFirst) { - return m_aStashedHeader.m_pStashedFirst != nullptr; + return m_aStashedHeader.m_oStashedFirst.has_value(); } else if (bLeft && bFirst) { - return m_aStashedHeader.m_pStashedFirstLeft != nullptr; + return m_aStashedHeader.m_oStashedFirstLeft.has_value(); } else { @@ -503,15 +503,15 @@ bool SwPageDesc::HasStashedFormat(bool bHeader, bool bLeft, bool bFirst) const { if (bLeft && !bFirst) { - return m_aStashedFooter.m_pStashedLeft != nullptr; + return m_aStashedFooter.m_oStashedLeft.has_value(); } else if (!bLeft && bFirst) { - return m_aStashedFooter.m_pStashedFirst != nullptr; + return m_aStashedFooter.m_oStashedFirst.has_value(); } else if (bLeft && bFirst) { - return m_aStashedFooter.m_pStashedFirstLeft != nullptr; + return m_aStashedFooter.m_oStashedFirstLeft.has_value(); } else { @@ -527,15 +527,15 @@ void SwPageDesc::RemoveStashedFormat(bool bHeader, bool bLeft, bool bFirst) { if (bLeft && !bFirst) { - m_aStashedHeader.m_pStashedLeft.reset(); + m_aStashedHeader.m_oStashedLeft.reset(); } else if (!bLeft && bFirst) { - m_aStashedHeader.m_pStashedFirst.reset(); + m_aStashedHeader.m_oStashedFirst.reset(); } else if (bLeft && bFirst) { - m_aStashedHeader.m_pStashedFirstLeft.reset(); + m_aStashedHeader.m_oStashedFirstLeft.reset(); } else { @@ -546,15 +546,15 @@ void SwPageDesc::RemoveStashedFormat(bool bHeader, bool bLeft, bool bFirst) { if (bLeft && !bFirst) { - m_aStashedFooter.m_pStashedLeft.reset(); + m_aStashedFooter.m_oStashedLeft.reset(); } else if (!bLeft && bFirst) { - m_aStashedFooter.m_pStashedFirst.reset(); + m_aStashedFooter.m_oStashedFirst.reset(); } else if (bLeft && bFirst) { - m_aStashedFooter.m_pStashedFirstLeft.reset(); + m_aStashedFooter.m_oStashedFirstLeft.reset(); } else { diff --git a/sw/source/core/layout/sectfrm.cxx b/sw/source/core/layout/sectfrm.cxx index a1fd849ec4..3967a1f564 100644 --- a/sw/source/core/layout/sectfrm.cxx +++ b/sw/source/core/layout/sectfrm.cxx @@ -189,6 +189,13 @@ SwSectionFrame::~SwSectionFrame() { } +//virtual +bool SwSectionFrame::IsHiddenNow() const +{ + const auto* pSection = GetSection(); + return !pSection || pSection->CalcHiddenFlag(); +} + void SwSectionFrame::DelEmpty( bool bRemove ) { if( IsColLocked() ) @@ -1371,6 +1378,20 @@ void SwSectionFrame::Format( vcl::RenderContext* pRenderContext, const SwBorderA SwRectFnSet aRectFnSet(this); + if (GetSection()->CalcHiddenFlag()) + { + { + SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this); + aRectFnSet.SetHeight(aFrm, 0); + } + { + SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this); + aRectFnSet.SetHeight(aPrt, 0); + } + setFrameAreaSizeValid(true); + setFramePrintAreaValid(true); + } + if ( !isFramePrintAreaValid() ) { PROTOCOL( this, PROT::PrintArea, DbgAction::NONE, nullptr ) @@ -2182,6 +2203,11 @@ bool SwSectionFrame::Growable() const SwTwips SwSectionFrame::Grow_( SwTwips nDist, bool bTst ) { + if (GetSection()->CalcHiddenFlag()) + { + return 0; + } + if ( !IsColLocked() && !HasFixSize() ) { SwRectFnSet aRectFnSet(this); @@ -2646,6 +2672,17 @@ void SwSectionFrame::SwClientNotify(const SwModify& rMod, const SfxHint& rHint) return; SwSectionFrame::MoveContentAndDelete(this, pHint->IsSaveContent()); } + else if (rHint.GetId() == SfxHintId::SwSectionHidden) + { + InvalidateAll(); + InvalidateObjs(false); + + for (SwFrame* pLowerFrame = Lower(); pLowerFrame; pLowerFrame = pLowerFrame->GetNext()) + { + pLowerFrame->InvalidateAll(); + pLowerFrame->InvalidateObjs(false); + } + } else SwFrame::SwClientNotify(rMod, rHint); } diff --git a/sw/source/core/layout/tabfrm.cxx b/sw/source/core/layout/tabfrm.cxx index f757824561..c4a742c037 100644 --- a/sw/source/core/layout/tabfrm.cxx +++ b/sw/source/core/layout/tabfrm.cxx @@ -667,7 +667,7 @@ static bool lcl_RecalcSplitLine( SwRowFrame& rLastLine, SwRowFrame& rFollowLine, { SwContentFrame const*const pAnchor = pFootnote->GetRef(); SwTabFrame const* pTab = pAnchor->FindTabFrame(); - if (pTab == &rTab) + if (pTab) { while (pTab->GetUpper()->IsInTab()) { @@ -1454,6 +1454,8 @@ namespace auto IsAllHiddenSection(SwSectionFrame const& rSection) -> bool { + if (rSection.IsHiddenNow()) + return true; for (SwFrame const* pFrame = rSection.Lower(); pFrame; pFrame = pFrame->GetNext()) { if (pFrame->IsColumnFrame()) @@ -1474,7 +1476,7 @@ namespace } else if (pFrame->IsTextFrame()) { - if (!static_cast<SwTextFrame const*>(pFrame)->IsHiddenNow()) + if (!pFrame->IsHiddenNow()) { return false; } @@ -1509,7 +1511,7 @@ namespace } else if (pFrame->IsTextFrame()) { - if (!static_cast<SwTextFrame const*>(pFrame)->IsHiddenNow()) + if (!pFrame->IsHiddenNow()) { return false; } @@ -3371,7 +3373,15 @@ bool SwTabFrame::CalcFlyOffsets( SwTwips& rUpper, } bool bFlyHoriOrientLeft = text::HoriOrientation::LEFT == rHori.GetHoriOrient(); - if (bSplitFly && !bFlyHoriOrientLeft) + + bool bToplevelSplitFly = false; + if (bSplitFly) + { + // Floating table wrapped by table: avoid this in the nested case. + bToplevelSplitFly = !pFly->GetAnchorFrame()->IsInTab(); + } + + if (bToplevelSplitFly && !bFlyHoriOrientLeft) { // Only shift to the right if we don't have enough space on the left. SwTwips nTabWidth = getFramePrintArea().Width(); diff --git a/sw/source/core/layout/trvlfrm.cxx b/sw/source/core/layout/trvlfrm.cxx index a8445e90dd..89a5f03302 100644 --- a/sw/source/core/layout/trvlfrm.cxx +++ b/sw/source/core/layout/trvlfrm.cxx @@ -52,6 +52,7 @@ #include <ndtxt.hxx> #include <undobj.hxx> #include <flyfrms.hxx> +#include <sectfrm.hxx> #include <swselectionlist.hxx> #include <comphelper/lok.hxx> @@ -828,8 +829,7 @@ static bool lcl_UpDown( SwPaM *pPam, const SwContentFrame *pStart, //If I'm in the DocumentBody, I want to stay there. if ( pStart->IsInDocBody() ) { - while ( pCnt && (!pCnt->IsInDocBody() || - (pCnt->IsTextFrame() && static_cast<const SwTextFrame*>(pCnt)->IsHiddenNow()))) + while (pCnt && (!pCnt->IsInDocBody() || pCnt->IsHiddenNow())) { pCnt = (*fnNxtPrv)( pCnt ); pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, true, bInReadOnly, bTableSel ); @@ -840,8 +840,7 @@ static bool lcl_UpDown( SwPaM *pPam, const SwContentFrame *pStart, //case of necessity. else if ( pStart->IsInFootnote() ) { - while ( pCnt && (!pCnt->IsInFootnote() || - (pCnt->IsTextFrame() && static_cast<const SwTextFrame*>(pCnt)->IsHiddenNow()))) + while (pCnt && (!pCnt->IsInFootnote() || pCnt->IsHiddenNow())) { pCnt = (*fnNxtPrv)( pCnt ); pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, true, bInReadOnly, bTableSel ); @@ -851,7 +850,7 @@ static bool lcl_UpDown( SwPaM *pPam, const SwContentFrame *pStart, //In Flys we can go ahead blindly as long as we find a Content. else if ( pStart->IsInFly() ) { - if ( pCnt && pCnt->IsTextFrame() && static_cast<const SwTextFrame*>(pCnt)->IsHiddenNow() ) + if (pCnt && pCnt->IsHiddenNow()) { pCnt = (*fnNxtPrv)( pCnt ); pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, true, bInReadOnly, bTableSel ); @@ -875,7 +874,7 @@ static bool lcl_UpDown( SwPaM *pPam, const SwContentFrame *pStart, } if ( !bSame ) pCnt = nullptr; - else if (pCnt->IsTextFrame() && static_cast<const SwTextFrame*>(pCnt)->IsHiddenNow()) // i73332 + else if (pCnt->IsHiddenNow()) // i73332 { pCnt = (*fnNxtPrv)( pCnt ); pCnt = ::lcl_MissProtectedFrames( pCnt, fnNxtPrv, true, bInReadOnly, bTableSel ); @@ -958,8 +957,7 @@ static bool lcl_UpDown( SwPaM *pPam, const SwContentFrame *pStart, } } - } while ( !bEnd || - (pCnt && pCnt->IsTextFrame() && static_cast<const SwTextFrame*>(pCnt)->IsHiddenNow())); + } while (!bEnd || (pCnt && pCnt->IsHiddenNow())); if (pCnt == nullptr) { @@ -1246,7 +1244,7 @@ const SwContentFrame *SwLayoutFrame::GetContentPos( Point& rPoint, if ( pComp != pContent ) continue; - if ( !pContent->IsTextFrame() || !static_cast<const SwTextFrame*>(pContent)->IsHiddenNow() ) + if (!pContent->IsHiddenNow()) { SwRect aContentFrame( pContent->UnionFrame() ); if ( aContentFrame.Contains( rPoint ) ) @@ -1727,6 +1725,15 @@ bool SwFrame::IsProtected() const return false; } +// virtual +bool SwFrame::IsHiddenNow() const +{ + if (const auto* pSectFrame = FindSctFrame()) + return pSectFrame->IsHiddenNow(); + + return false; +} + /** @return the physical page number */ sal_uInt16 SwFrame::GetPhyPageNum() const { diff --git a/sw/source/core/text/txtfrm.cxx b/sw/source/core/text/txtfrm.cxx index 302302a9a2..52a51ff1a5 100644 --- a/sw/source/core/text/txtfrm.cxx +++ b/sw/source/core/text/txtfrm.cxx @@ -1485,6 +1485,9 @@ bool SwTextFrame::IsHiddenNow() const return true; } + if (SwContentFrame::IsHiddenNow()) + return true; + bool bHiddenCharsHidePara(false); bool bHiddenParaField(false); if (m_pMergedPara) @@ -1554,22 +1557,14 @@ bool SwTextFrame::IsHiddenNow() const // be visible - check this for the 1st body paragraph if (IsInDocBody() && FindPrevCnt() == nullptr) { - bool isAllHidden(true); for (SwContentFrame const* pNext = FindNextCnt(true); pNext != nullptr; pNext = pNext->FindNextCnt(true)) { - if (!pNext->IsTextFrame() - || !static_cast<SwTextFrame const*>(pNext)->IsHiddenNow()) - { - isAllHidden = false; - break; - } - } - if (isAllHidden) - { - SAL_INFO("sw.core", "unhiding one body paragraph"); - return false; + if (!pNext->IsHiddenNow()) + return true; } + SAL_INFO("sw.core", "unhiding one body paragraph"); + return false; } return true; } diff --git a/sw/source/core/tox/tox.cxx b/sw/source/core/tox/tox.cxx index 04f43e5d41..b29bafde11 100644 --- a/sw/source/core/tox/tox.cxx +++ b/sw/source/core/tox/tox.cxx @@ -148,7 +148,13 @@ void SwTOXMark::RegisterToTOXType(SwTOXType& rType) bool SwTOXMark::operator==( const SfxPoolItem& rAttr ) const { assert(SfxPoolItem::operator==(rAttr)); - return m_pType == static_cast<const SwTOXMark&>(rAttr).m_pType; + // tdf#158783 this item was never 'pooled', so operator== was not really + // ever used. We discussed to implement it (there is quite some + // content), but we came to the point that it's only safe to say + // instances are equal when same instance -> fallback to ptr compare. + // NOTE: Do *not* use areSfxPoolItemPtrsEqual here, with DBG_UTIL + // active the contol/test code there would again call operator== + return this == &rAttr; } SwTOXMark* SwTOXMark::Clone( SfxItemPool* ) const diff --git a/sw/source/core/unocore/unocrsrhelper.cxx b/sw/source/core/unocore/unocrsrhelper.cxx index 70a724814c..30f6d6e619 100644 --- a/sw/source/core/unocore/unocrsrhelper.cxx +++ b/sw/source/core/unocore/unocrsrhelper.cxx @@ -225,7 +225,7 @@ void GetSelectableFromAny(uno::Reference<uno::XInterface> const& xIfc, return; } - uno::Reference<text::XTextRange> const xTextRange(xTunnel, UNO_QUERY); + uno::Reference<text::XTextRange> const xTextRange(xIfc, UNO_QUERY); if (xTextRange.is()) { SwUnoInternalPaM aPam(rTargetDoc); diff --git a/sw/source/core/unocore/unomap1.cxx b/sw/source/core/unocore/unomap1.cxx index 12db464a87..f9e16b1f42 100644 --- a/sw/source/core/unocore/unomap1.cxx +++ b/sw/source/core/unocore/unomap1.cxx @@ -307,6 +307,7 @@ std::span<const SfxItemPropertyMapEntry> SwUnoPropertyMapProvider::GetAutoCharS { UNO_NAME_CHAR_BORDER_TOP_COMPLEX_COLOR, RES_CHRATR_BOX, cppu::UnoType<css::util::XComplexColor>::get(), PropertyAttribute::MAYBEVOID, MID_BORDER_TOP_COLOR }, { UNO_NAME_CHAR_BORDER_BOTTOM_COMPLEX_COLOR, RES_CHRATR_BOX, cppu::UnoType<css::util::XComplexColor>::get(), PropertyAttribute::MAYBEVOID, MID_BORDER_BOTTOM_COLOR }, { UNO_NAME_CHAR_SHADOW_FORMAT, RES_CHRATR_SHADOW, cppu::UnoType<css::table::ShadowFormat>::get(), PROPERTY_NONE, CONVERT_TWIPS}, + { UNO_NAME_CHAR_STYLE_NAME, RES_TXTATR_CHARFMT, cppu::UnoType<OUString>::get(), PropertyAttribute::MAYBEVOID, 0 }, }; return aAutoCharStyleMap; diff --git a/sw/source/core/unocore/unoobj.cxx b/sw/source/core/unocore/unoobj.cxx index b2f83fee30..49562c1d02 100644 --- a/sw/source/core/unocore/unoobj.cxx +++ b/sw/source/core/unocore/unoobj.cxx @@ -539,11 +539,6 @@ SwUnoCursorHelper::SetCursorPropertyValue( rMap.getByName(prop.Name); if (!pEntry) { - if (prop.Name == "CharStyleName") - { - lcl_setCharStyle(rPam.GetDoc(), prop.Value, items); - continue; - } throw beans::UnknownPropertyException( "Unknown property: " + prop.Name); } @@ -552,7 +547,14 @@ SwUnoCursorHelper::SetCursorPropertyValue( throw beans::PropertyVetoException( "Property is read-only: " + prop.Name); } - rPropSet.setPropertyValue(*pEntry, prop.Value, items); + if (prop.Name == "CharStyleName") + { + lcl_setCharStyle(rPam.GetDoc(), prop.Value, items); + } + else + { + rPropSet.setPropertyValue(*pEntry, prop.Value, items); + } } IStyleAccess& rStyleAccess = rPam.GetDoc().GetIStyleAccess(); diff --git a/sw/source/core/unocore/unoportenum.cxx b/sw/source/core/unocore/unoportenum.cxx index 186b5c5b23..494cec7468 100644 --- a/sw/source/core/unocore/unoportenum.cxx +++ b/sw/source/core/unocore/unoportenum.cxx @@ -84,7 +84,17 @@ static void lcl_CreatePortions( namespace { enum class BkmType { - Start, End, StartEnd + // The order is important: BookmarkCompareStruct::operator () depends on it. + // When different bookmarks' starts/ends appear at one position, by default (when there's no + // frames at the position - see lcl_ExportBookmark), first previous bookmarks close, then + // collapsed ones appear, then new bookmarks open. + End, StartEnd, Start + }; + + enum class ExportBookmarkPass + { + before_frames, + after_frames, }; struct SwXBookmarkPortion_Impl @@ -124,7 +134,8 @@ namespace // start of the 2nd bookmark BEFORE the end of the first bookmark // See bug #i58438# for more details. The below code is correct and // fixes both #i58438 and #i16896# - return r1->aPosition < r2->aPosition; + return std::make_pair(r1->aPosition, r1->nBkmType) + < std::make_pair(r2->aPosition, r2->nBkmType); } }; typedef std::multiset < SwXBookmarkPortion_ImplSharedPtr, BookmarkCompareStruct > SwXBookmarkPortion_ImplList; @@ -132,13 +143,15 @@ namespace /// Inserts pBkmk to rBkmArr in case it starts or ends at rOwnNode void lcl_FillBookmark(sw::mark::IMark* const pBkmk, const SwNode& rOwnNode, SwDoc& rDoc, SwXBookmarkPortion_ImplList& rBkmArr) { - bool const hasOther = pBkmk->IsExpanded(); + bool const isExpanded = pBkmk->IsExpanded(); const SwPosition& rStartPos = pBkmk->GetMarkStart(); const SwPosition& rEndPos = pBkmk->GetMarkEnd(); + // A bookmark where the text was deleted becomes collapsed + bool const hasOther = isExpanded && rStartPos != rEndPos; bool const bStartPosInNode = rStartPos.GetNode() == rOwnNode; bool const bEndPosInNode = rEndPos.GetNode() == rOwnNode; sw::mark::CrossRefBookmark* const pCrossRefMark - = !hasOther && (bStartPosInNode || bEndPosInNode) + = !isExpanded && bStartPosInNode ? dynamic_cast<sw::mark::CrossRefBookmark*>(pBkmk) : nullptr; @@ -560,15 +573,23 @@ lcl_CreateContentControlPortion(const css::uno::Reference<SwXText>& xParent, * Exports all bookmarks from rBkmArr into rPortions that have the same start * or end position as nIndex. * - * @param rBkmArr the array of bookmarks. If bOnlyFrameStarts is true, then - * this is only read, otherwise consumed entries are removed. + * @param rBkmArr the array of bookmarks. * * @param rFramePositions the list of positions where there is an at-char / * anchored frame. + * Collapsed (BkmType::StartEnd) bookmarks, as well as bookmarks that start/end + * at the frame anchor position, are considered as wrapping the frames, if any + * (i.e., starts are output before the frames; ends are output after frames). + * When there's no frame here, bookmarks are expected to not overlap (#i58438): + * first, non-collapsed bookmarks' ends are output; then collapsed bookmarks; + * then non-collapsed bookmarks' starts. * - * @param bOnlyFrameStarts If true: export only the start of the bookmarks - * which cover an at-char anchored frame. If false: export the end of the same - * bookmarks and everything else. + * @param stage Case before_frames: if there is a frame at this index, output + * starts of both collapsed and non-collapsed bookmarks (remove non-collapsed + * starts from rBkmArr, convert collapsed ones to ends); if there's no frame, + * doesn't output anything. + * Case after_frames: outputs (and removes from rBkmArr) everything (left) at + * this index, in the order of occurrence in rBkmArr (see #i58438). */ static void lcl_ExportBookmark( TextRangeList_t & rPortions, @@ -577,54 +598,56 @@ static void lcl_ExportBookmark( SwXBookmarkPortion_ImplList& rBkmArr, const sal_Int32 nIndex, const o3tl::sorted_vector<sal_Int32>& rFramePositions, - bool bOnlyFrameStarts) + ExportBookmarkPass stage) { for ( SwXBookmarkPortion_ImplList::iterator aIter = rBkmArr.begin(), aEnd = rBkmArr.end(); aIter != aEnd; ) { const SwXBookmarkPortion_ImplSharedPtr& pPtr = *aIter; if ( nIndex > pPtr->getIndex() ) { - if (bOnlyFrameStarts) - ++aIter; - else - aIter = rBkmArr.erase(aIter); + assert(!"Some bookmarks were not consumed earlier"); continue; } if ( nIndex < pPtr->getIndex() ) break; - if ((BkmType::Start == pPtr->nBkmType && bOnlyFrameStarts) || - (BkmType::StartEnd == pPtr->nBkmType)) + if (stage == ExportBookmarkPass::before_frames) { - bool bFrameStart = rFramePositions.find(nIndex) != rFramePositions.end(); - bool bEnd = pPtr->nBkmType == BkmType::StartEnd && bFrameStart && !bOnlyFrameStarts; - if (pPtr->nBkmType == BkmType::Start || bFrameStart || !bOnlyFrameStarts) + if (rFramePositions.find(nIndex) == rFramePositions.end()) // No frames at this index + break; // Do nothing; everything will be output at after_frames pass + + if (pPtr->nBkmType == BkmType::End) { - // At this we create a text portion, due to one of these - // reasons: - // - this is the real start of a non-collapsed bookmark - // - this is the real position of a collapsed bookmark - // - this is the start or end (depending on bOnlyFrameStarts) - // of a collapsed bookmark at the same position as an at-char - // anchored frame - rtl::Reference<SwXTextPortion> pPortion = - new SwXTextPortion(pUnoCursor, xParent, bEnd ? PORTION_BOOKMARK_END : PORTION_BOOKMARK_START); - rPortions.emplace_back(pPortion); - pPortion->SetBookmark(pPtr->xBookmark); - pPortion->SetCollapsed( BkmType::StartEnd == pPtr->nBkmType && !bFrameStart ); + ++aIter; + continue; // Only consider BkmType::Start and BkmType::StartEnd in this pass } } - else if (BkmType::End == pPtr->nBkmType && !bOnlyFrameStarts) - { - rtl::Reference<SwXTextPortion> pPortion = - new SwXTextPortion(pUnoCursor, xParent, PORTION_BOOKMARK_END); - rPortions.emplace_back(pPortion); - pPortion->SetBookmark(pPtr->xBookmark); - } + + // At this we create a text portion, due to one of these + // reasons: + // - this is the real start of a non-collapsed bookmark + // - this is the real end of a non-collapsed bookmark + // - this is the real position of a collapsed bookmark + // - this is the start or end of a collapsed bookmark at the same position as an at-char + // anchored frame + const SwTextPortionType portionType + = pPtr->nBkmType == BkmType::End ? PORTION_BOOKMARK_END : PORTION_BOOKMARK_START; + const bool collapsed + = pPtr->nBkmType == BkmType::StartEnd && stage == ExportBookmarkPass::after_frames; + + rtl::Reference<SwXTextPortion> pPortion = new SwXTextPortion(pUnoCursor, xParent, portionType); + rPortions.emplace_back(pPortion); + pPortion->SetBookmark(pPtr->xBookmark); + pPortion->SetCollapsed(collapsed); // next bookmark - if (bOnlyFrameStarts) + if (pPtr->nBkmType == BkmType::StartEnd && stage == ExportBookmarkPass::before_frames) + { + // This is a collapsed bookmark around a frame, and its start portion was just emitted; + // turn it into an end bookmark to process after_frames + pPtr->nBkmType = BkmType::End; ++aIter; + } else aIter = rBkmArr.erase(aIter); } @@ -1168,13 +1191,12 @@ static void lcl_ExportBkmAndRedline( SwSoftPageBreakList& rBreakArr, const sal_Int32 nIndex, const o3tl::sorted_vector<sal_Int32>& rFramePositions, - bool bOnlyFrameBookmarkStarts) + ExportBookmarkPass stage) { if (!rBkmArr.empty()) - lcl_ExportBookmark(rPortions, xParent, pUnoCursor, rBkmArr, nIndex, rFramePositions, - bOnlyFrameBookmarkStarts); + lcl_ExportBookmark(rPortions, xParent, pUnoCursor, rBkmArr, nIndex, rFramePositions, stage); - if (bOnlyFrameBookmarkStarts) + if (stage == ExportBookmarkPass::before_frames) // Only exporting the start of some collapsed bookmarks: no export of // other arrays. return; @@ -1401,7 +1423,7 @@ static void lcl_CreatePortions( // Then export start of collapsed bookmarks which "cover" at-char // anchored frames. lcl_ExportBkmAndRedline( *PortionStack.top().first, i_xParentText, - pUnoCursor, Bookmarks, Redlines, SoftPageBreaks, nCurrentIndex, aFramePositions, /*bOnlyFrameBookmarkStarts=*/true ); + pUnoCursor, Bookmarks, Redlines, SoftPageBreaks, nCurrentIndex, aFramePositions, ExportBookmarkPass::before_frames ); lcl_ExportAnnotationStarts( *PortionStack.top().first, @@ -1419,7 +1441,7 @@ static void lcl_CreatePortions( // Export ends of the previously started collapsed bookmarks + all // other bookmarks, redlines, etc. lcl_ExportBkmAndRedline( *PortionStack.top().first, i_xParentText, - pUnoCursor, Bookmarks, Redlines, SoftPageBreaks, nCurrentIndex, aFramePositions, /*bOnlyFrameBookmarkStarts=*/false ); + pUnoCursor, Bookmarks, Redlines, SoftPageBreaks, nCurrentIndex, aFramePositions, ExportBookmarkPass::after_frames ); lcl_ExportAnnotationStarts( *PortionStack.top().first, diff --git a/sw/source/core/unocore/unotext.cxx b/sw/source/core/unocore/unotext.cxx index f959d6a610..93603d6d40 100644 --- a/sw/source/core/unocore/unotext.cxx +++ b/sw/source/core/unocore/unotext.cxx @@ -1634,6 +1634,9 @@ SwXText::convertToTextFrame( // see testFlyInFly for why this checks only the edges of the selection, // and testFloatingTablesAnchor for why it excludes pre/post table // added nodes + // TODO: isGraphicNode here looks dubious; see also tdf#47036 fix; + // this needs more investigation when exactly Word considers something + // anchored in text frame vs. anchored in body. if (!isGraphicNode(pFrameFormat) && (IsAtParaMatch(*oAnchorCheckPam, rAnchor) || (RndStdIds::FLY_AT_CHAR == rAnchor.GetAnchorId() diff --git a/sw/source/filter/html/css1atr.cxx b/sw/source/filter/html/css1atr.cxx index 30ba8d3c0a..2587edfaf2 100644 --- a/sw/source/filter/html/css1atr.cxx +++ b/sw/source/filter/html/css1atr.cxx @@ -3301,14 +3301,16 @@ SwHTMLWriter& OutCSS1_SvxBox( SwHTMLWriter& rWrt, const SfxPoolItem& rHt ) if( rHt.Which() == RES_CHRATR_BOX ) { + constexpr std::string_view inline_block("inline-block"); if( rWrt.m_bTagOn ) { // Inline-block to make the line height changing correspond to the character border - rWrt.OutCSS1_PropertyAscii(sCSS1_P_display, "inline-block"); + rWrt.OutCSS1_PropertyAscii(sCSS1_P_display, inline_block); } else { - HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), Concat2View(rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_span), false ); + if (!IgnorePropertyForReqIF(rWrt.mbReqIF, sCSS1_P_display, inline_block)) + HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), Concat2View(rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_span), false ); return rWrt; } } diff --git a/sw/source/filter/html/htmlatr.cxx b/sw/source/filter/html/htmlatr.cxx index 9f67d1ee03..c880082018 100644 --- a/sw/source/filter/html/htmlatr.cxx +++ b/sw/source/filter/html/htmlatr.cxx @@ -1058,7 +1058,7 @@ public: HTMLStartEndPos( const SfxPoolItem& rItem, sal_Int32 nStt, sal_Int32 nE ); - const SfxPoolItem* GetItem() const { return m_pItem.get(); } + const SfxPoolItem& GetItem() const { return *m_pItem; } void SetStart(sal_Int32 nStt) { m_nStart = nStt; } sal_Int32 GetStart() const { return m_nStart; } @@ -1075,7 +1075,7 @@ HTMLStartEndPos::HTMLStartEndPos(const SfxPoolItem& rItem, sal_Int32 nStt, sal_I , m_pItem(rItem.Clone()) {} -typedef std::vector<HTMLStartEndPos *> HTMLStartEndPositions; +typedef std::map<sal_Int32, std::vector<HTMLStartEndPos*>> HTMLStartEndPositions; namespace { @@ -1091,8 +1091,8 @@ enum HTMLOnOffState { HTML_NOT_SUPPORTED, // unsupported Attribute class HTMLEndPosLst { - HTMLStartEndPositions m_aStartLst; // list, sorted for start positions - HTMLStartEndPositions m_aEndLst; // list, sorted for end positions + HTMLStartEndPositions m_aStartLst; // list, each position's elements sorted by appearance order + HTMLStartEndPositions m_aEndLst; // list, no sort of elements in position std::deque<sal_Int32> m_aScriptChgLst; // positions where script changes // 0 is not contained in this list, // but the text length @@ -1110,8 +1110,7 @@ class HTMLEndPosLst // Insert/remove a SttEndPos in/from the Start and End lists. // The end position is known. - void InsertItem_( HTMLStartEndPos *pPos, HTMLStartEndPositions::size_type nEndPos ); - void RemoveItem_( HTMLStartEndPositions::size_type nEndPos ); + void InsertItem_(HTMLStartEndPos* pPos); // determine the 'type' of the attribute HTMLOnOffState GetHTMLItemState( const SfxPoolItem& rItem ); @@ -1125,8 +1124,7 @@ class HTMLEndPosLst sal_Int32 nEndPos ); // adapt the end of a split item - void FixSplittedItem( HTMLStartEndPos *pPos, sal_Int32 nNewEnd, - HTMLStartEndPositions::size_type nStartPos ); + void FixSplittedItem(HTMLStartEndPos* pPos, sal_Int32 nNewEnd); // insert an attribute in the lists and, if necessary, split it void InsertItem( const SfxPoolItem& rItem, sal_Int32 nStart, @@ -1144,6 +1142,8 @@ class HTMLEndPosLst const SwHTMLFormatInfo *GetFormatInfo( const SwFormat& rFormat, SwHTMLFormatInfos& rFormatInfos ); + void OutEndAttrs(SwHTMLWriter& rWrt, std::vector<HTMLStartEndPos*>& posItems); + public: HTMLEndPosLst( SwDoc *pDoc, SwDoc* pTemplate, std::optional<Color> xDfltColor, @@ -1169,36 +1169,46 @@ public: bool IsHTMLMode(sal_uLong nMode) const { return (m_nHTMLMode & nMode) != 0; } }; -} - -void HTMLEndPosLst::InsertItem_( HTMLStartEndPos *pPos, HTMLStartEndPositions::size_type nEndPos ) +struct SortEnds { - // Insert the attribute in the Start list behind all attributes that - // were started before, or at the same position. - sal_Int32 nStart = pPos->GetStart(); - HTMLStartEndPositions::size_type i {0}; + HTMLStartEndPositions& m_startList; + SortEnds(HTMLStartEndPositions& startList) : m_startList(startList) {} + bool operator()(const HTMLStartEndPos* p1, const HTMLStartEndPos* p2) + { + // if p1 start after p2, then it ends before + if (p1->GetStart() > p2->GetStart()) + return true; + if (p1->GetStart() < p2->GetStart()) + return false; + for (const auto p : m_startList[p1->GetStart()]) + { + if (p == p1) + return false; + if (p == p2) + return true; + } + assert(!"Neither p1 nor p2 found in their start list"); + return false; + } +}; - while (i < m_aStartLst.size() && m_aStartLst[i]->GetStart() <= nStart) - ++i; - m_aStartLst.insert(m_aStartLst.begin() + i, pPos); +#ifndef NDEBUG +bool IsEmpty(const HTMLStartEndPositions& l) +{ + return std::find_if(l.begin(), l.end(), [](auto& i) { return !i.second.empty(); }) == l.end(); +} +#endif - // the position in the End list was supplied - m_aEndLst.insert(m_aEndLst.begin() + nEndPos, pPos); } -void HTMLEndPosLst::RemoveItem_( HTMLStartEndPositions::size_type nEndPos ) +void HTMLEndPosLst::InsertItem_(HTMLStartEndPos* pPos) { - HTMLStartEndPos* pPos = m_aEndLst[nEndPos]; + // Character border attribute must be the first which is written out because of border merge. + auto& posItems1 = m_aStartLst[pPos->GetStart()]; + auto it = pPos->GetItem().Which() == RES_CHRATR_BOX ? posItems1.begin() : posItems1.end(); + posItems1.insert(it, pPos); - // now, we are looking for it in the Start list - HTMLStartEndPositions::iterator it = std::find(m_aStartLst.begin(), m_aStartLst.end(), pPos); - OSL_ENSURE(it != m_aStartLst.end(), "Item not found in Start List!"); - if (it != m_aStartLst.end()) - m_aStartLst.erase(it); - - m_aEndLst.erase(m_aEndLst.begin() + nEndPos); - - delete pPos; + m_aEndLst[pPos->GetEnd()].push_back(pPos); } HTMLOnOffState HTMLEndPosLst::GetHTMLItemState( const SfxPoolItem& rItem ) @@ -1352,23 +1362,25 @@ HTMLOnOffState HTMLEndPosLst::GetHTMLItemState( const SfxPoolItem& rItem ) bool HTMLEndPosLst::ExistsOnTagItem( sal_uInt16 nWhich, sal_Int32 nPos ) { - for (auto pTest : m_aStartLst) + for (const auto& [startPos, items] : m_aStartLst) { - if( pTest->GetStart() > nPos ) + if (startPos > nPos) { // this attribute, and all attributes that follow, start later break; } - else if( pTest->GetEnd() > nPos ) + + for (const auto* pTest : items) { - // the attribute starts before, or at, the current position and - // ends after it - const SfxPoolItem *pItem = pTest->GetItem(); - if( pItem->Which() == nWhich && - HTML_ON_VALUE == GetHTMLItemState(*pItem) ) + if (pTest->GetEnd() > nPos) { - // an OnTag attribute was found - return true; + // the attribute starts before, or at, the current position and ends after it + const SfxPoolItem& rItem = pTest->GetItem(); + if (rItem.Which() == nWhich && HTML_ON_VALUE == GetHTMLItemState(rItem)) + { + // an OnTag attribute was found + return true; + } } } } @@ -1386,24 +1398,17 @@ bool HTMLEndPosLst::ExistsOffTagItem( sal_uInt16 nWhich, sal_Int32 nStartPos, return false; } - for (auto pTest : m_aStartLst) + for (const auto* pTest : m_aStartLst[nStartPos]) { - if( pTest->GetStart() > nStartPos ) - { - // this attribute, and all attributes that follow, start later - break; - } - else if( pTest->GetStart()==nStartPos && - pTest->GetEnd()==nEndPos ) + if (pTest->GetEnd() == nEndPos) { - // the attribute starts before or at the current position and - // ends after it - const SfxPoolItem *pItem = pTest->GetItem(); - sal_uInt16 nTstWhich = pItem->Which(); + // the attribute starts before or at the current position and ends after it + const SfxPoolItem& rItem = pTest->GetItem(); + sal_uInt16 nTstWhich = rItem.Which(); if( (nTstWhich == RES_CHRATR_CROSSEDOUT || nTstWhich == RES_CHRATR_UNDERLINE || nTstWhich == RES_CHRATR_BLINK) && - HTML_OFF_VALUE == GetHTMLItemState(*pItem) ) + HTML_OFF_VALUE == GetHTMLItemState(rItem) ) { // an OffTag attribute was found that is exported the same // way as the current item @@ -1415,55 +1420,51 @@ bool HTMLEndPosLst::ExistsOffTagItem( sal_uInt16 nWhich, sal_Int32 nStartPos, return false; } -void HTMLEndPosLst::FixSplittedItem( HTMLStartEndPos *pPos, sal_Int32 nNewEnd, - HTMLStartEndPositions::size_type nStartPos ) +void HTMLEndPosLst::FixSplittedItem(HTMLStartEndPos* pPos, sal_Int32 nNewEnd) { + // remove the item from the End list + std::erase(m_aEndLst[pPos->GetEnd()], pPos); // fix the end position accordingly pPos->SetEnd( nNewEnd ); - - // remove the item from the End list - HTMLStartEndPositions::iterator it = std::find(m_aEndLst.begin(), m_aEndLst.end(), pPos); - OSL_ENSURE(it != m_aEndLst.end(), "Item not found in End List!"); - if (it != m_aEndLst.end()) - m_aEndLst.erase(it); - - // from now on, it is closed as the last one at the corresponding position - HTMLStartEndPositions::size_type nEndPos {0}; - while (nEndPos < m_aEndLst.size() && m_aEndLst[nEndPos]->GetEnd() <= nNewEnd) - ++nEndPos; - m_aEndLst.insert(m_aEndLst.begin() + nEndPos, pPos); + // from now on, it is closed at the corresponding position + m_aEndLst[nNewEnd].push_back(pPos); // now, adjust the attributes that got started afterwards - for (HTMLStartEndPositions::size_type i = nStartPos + 1; i < m_aStartLst.size(); ++i) + const sal_Int32 nPos = pPos->GetStart(); + for (const auto& [startPos, items] : m_aStartLst) { - HTMLStartEndPos* pTest = m_aStartLst[i]; - sal_Int32 nTestEnd = pTest->GetEnd(); - if( pTest->GetStart() >= nNewEnd ) - { - // the Test attribute and all the following ones start, after the - // split attribute ends + if (startPos < nPos) + continue; + + if (startPos >= nNewEnd) break; + + auto it = items.begin(); + if (startPos == nPos) + { + it = std::find(items.begin(), items.end(), pPos); + if (it != items.end()) + ++it; } - else if( nTestEnd > nNewEnd ) + for (; it != items.end(); ++it) { + HTMLStartEndPos* pTest = *it; + const sal_Int32 nTestEnd = pTest->GetEnd(); + if (nTestEnd <= nNewEnd) + continue; + // the Test attribute starts before the split attribute // ends, and ends afterwards, i.e., it must be split, as well + // remove the attribute from the End list + std::erase(m_aEndLst[pTest->GetEnd()], pTest); // set the new end pTest->SetEnd( nNewEnd ); - - // remove the attribute from the End list - it = std::find(m_aEndLst.begin(), m_aEndLst.end(), pTest); - OSL_ENSURE(it != m_aEndLst.end(), "Item not found in End List!"); - if (it != m_aEndLst.end()) - m_aEndLst.erase(it); - - // it now ends as the first attribute in the respective position. - // We already know this position in the End list. - m_aEndLst.insert(m_aEndLst.begin() + nEndPos, pTest); + // it now ends in the respective position. + m_aEndLst[nNewEnd].push_back(pTest); // insert the 'rest' of the attribute - InsertItem( *pTest->GetItem(), nNewEnd, nTestEnd ); + InsertItem( pTest->GetItem(), nNewEnd, nTestEnd ); } } } @@ -1471,36 +1472,38 @@ void HTMLEndPosLst::FixSplittedItem( HTMLStartEndPos *pPos, sal_Int32 nNewEnd, void HTMLEndPosLst::InsertItem( const SfxPoolItem& rItem, sal_Int32 nStart, sal_Int32 nEnd ) { - HTMLStartEndPositions::size_type i; - for (i = 0; i < m_aEndLst.size(); i++) + assert(nStart < nEnd); + + for (auto& [endPos, items] : m_aEndLst) { - HTMLStartEndPos* pTest = m_aEndLst[i]; - sal_Int32 nTestEnd = pTest->GetEnd(); - if( nTestEnd <= nStart ) + if (endPos <= nStart) { // the Test attribute ends, before the new one starts continue; } - else if( nTestEnd < nEnd ) + if (endPos >= nEnd) + { + // the Test attribute (and all that follow) ends, before the new + // one ends + break; + } + + std::sort(items.begin(), items.end(), SortEnds(m_aStartLst)); + + for (HTMLStartEndPos* pTest : items) { if( pTest->GetStart() < nStart ) { // the Test attribute ends, before the new one ends. Thus, the // new attribute must be split. - InsertItem_( new HTMLStartEndPos( rItem, nStart, nTestEnd ), i ); - nStart = nTestEnd; + InsertItem_(new HTMLStartEndPos(rItem, nStart, endPos)); + nStart = endPos; } } - else - { - // the Test attribute (and all that follow) ends, before the new - // one ends - break; - } } // one attribute must still be inserted - InsertItem_( new HTMLStartEndPos( rItem, nStart, nEnd ), i ); + InsertItem_(new HTMLStartEndPos(rItem, nStart, nEnd)); } void HTMLEndPosLst::SplitItem( const SfxPoolItem& rItem, sal_Int32 nStart, @@ -1511,59 +1514,47 @@ void HTMLEndPosLst::SplitItem( const SfxPoolItem& rItem, sal_Int32 nStart, // first, we must search for the old items by using the start list and // determine the new item range - for (HTMLStartEndPositions::size_type i = 0; i < m_aStartLst.size(); ++i) + for (auto& [nTestStart, items] : m_aStartLst) { - HTMLStartEndPos* pTest = m_aStartLst[i]; - sal_Int32 nTestStart = pTest->GetStart(); - sal_Int32 nTestEnd = pTest->GetEnd(); - if( nTestStart >= nEnd ) { // this attribute, and all that follow, start later break; } - else if( nTestEnd > nStart ) + + for (auto it = items.begin(); it != items.end();) { + HTMLStartEndPos* pTest = *it; + sal_Int32 nTestEnd = pTest->GetEnd(); + if (nTestEnd <= nStart) + continue; + // the Test attribute ends in the range that must be deleted - const SfxPoolItem *pItem = pTest->GetItem(); + const SfxPoolItem& rTestItem = pTest->GetItem(); // only the corresponding OnTag attributes have to be considered - if( pItem->Which() == nWhich && - HTML_ON_VALUE == GetHTMLItemState( *pItem ) ) + if (rTestItem.Which() == nWhich && HTML_ON_VALUE == GetHTMLItemState(rTestItem)) { - bool bDelete = true; + // if necessary, insert the second part of the split + // attribute + if (nTestEnd > nEnd) + InsertItem(pTest->GetItem(), nEnd, nTestEnd); - if( nTestStart < nStart ) - { - // the start of the new attribute corresponds to the new - // end of the attribute - FixSplittedItem( pTest, nStart, i ); - bDelete = false; - } - else + if (nTestStart >= nStart) { // the Test item only starts after the new end of the // attribute. Therefore, it can be completely erased. - m_aStartLst.erase(m_aStartLst.begin() + i); - i--; - - HTMLStartEndPositions::iterator it - = std::find(m_aEndLst.begin(), m_aEndLst.end(), pTest); - OSL_ENSURE(it != m_aEndLst.end(), "Item not found in End List!"); - if (it != m_aEndLst.end()) - m_aEndLst.erase(it); - } - - // if necessary, insert the second part of the split - // attribute - if( nTestEnd > nEnd ) - { - InsertItem( *pTest->GetItem(), nEnd, nTestEnd ); + it = items.erase(it); + std::erase(m_aEndLst[pTest->GetEnd()], pTest); + delete pTest; + continue; } - if( bDelete ) - delete pTest; + // the start of the new attribute corresponds to the new + // end of the attribute + FixSplittedItem(pTest, nStart); } + ++it; } } } @@ -1611,8 +1602,8 @@ HTMLEndPosLst::HTMLEndPosLst(SwDoc* pD, SwDoc* pTempl, std::optional<Color> xDfl HTMLEndPosLst::~HTMLEndPosLst() { - OSL_ENSURE(m_aStartLst.empty(), "Start List not empty in destructor"); - OSL_ENSURE(m_aEndLst.empty(), "End List not empty in destructor"); + assert(IsEmpty(m_aStartLst) && "Start List not empty in destructor"); + assert(IsEmpty(m_aEndLst) && "End List not empty in destructor"); } void HTMLEndPosLst::InsertNoScript( const SfxPoolItem& rItem, @@ -1900,53 +1891,25 @@ void HTMLEndPosLst::OutStartAttrs( SwHTMLWriter& rWrt, sal_Int32 nPos ) { rWrt.m_bTagOn = true; - // Character border attribute must be the first which is written out - // because of border merge. - HTMLStartEndPositions::size_type nCharBoxIndex = 0; - while (nCharBoxIndex < m_aStartLst.size() - && m_aStartLst[nCharBoxIndex]->GetItem()->Which() != RES_CHRATR_BOX) - { - ++nCharBoxIndex; - } - + auto it = m_aStartLst.find(nPos); + if (it == m_aStartLst.end()) + return; // the attributes of the start list are sorted in ascending order - for (HTMLStartEndPositions::size_type i = 0; i < m_aStartLst.size(); ++i) + for (HTMLStartEndPos* pPos : it->second) { - HTMLStartEndPos *pPos = nullptr; - if (nCharBoxIndex < m_aStartLst.size()) - { - if( i == 0 ) - pPos = m_aStartLst[nCharBoxIndex]; - else if( i == nCharBoxIndex ) - pPos = m_aStartLst[0]; - else - pPos = m_aStartLst[i]; - } - else - pPos = m_aStartLst[i]; - - sal_Int32 nStart = pPos->GetStart(); - if( nStart > nPos ) - { - // this attribute, and all that follow, will be opened later on - break; - } - else if( nStart == nPos ) + // output the attribute + sal_uInt16 nCSS1Script = rWrt.m_nCSS1Script; + sal_uInt16 nWhich = pPos->GetItem().Which(); + if( RES_TXTATR_CHARFMT == nWhich || + RES_TXTATR_INETFMT == nWhich || + RES_PARATR_DROP == nWhich ) { - // output the attribute - sal_uInt16 nCSS1Script = rWrt.m_nCSS1Script; - sal_uInt16 nWhich = pPos->GetItem()->Which(); - if( RES_TXTATR_CHARFMT == nWhich || - RES_TXTATR_INETFMT == nWhich || - RES_PARATR_DROP == nWhich ) - { - rWrt.m_nCSS1Script = GetScriptAtPos( nPos, nCSS1Script ); - } - HTMLOutFuncs::FlushToAscii( rWrt.Strm() ); // was one time only - do we still need it? - Out( aHTMLAttrFnTab, *pPos->GetItem(), rWrt ); - rWrt.maStartedAttributes[pPos->GetItem()->Which()]++; - rWrt.m_nCSS1Script = nCSS1Script; + rWrt.m_nCSS1Script = GetScriptAtPos( nPos, nCSS1Script ); } + HTMLOutFuncs::FlushToAscii( rWrt.Strm() ); // was one time only - do we still need it? + Out( aHTMLAttrFnTab, pPos->GetItem(), rWrt ); + rWrt.maStartedAttributes[pPos->GetItem().Which()]++; + rWrt.m_nCSS1Script = nCSS1Script; } } @@ -1954,59 +1917,55 @@ void HTMLEndPosLst::OutEndAttrs( SwHTMLWriter& rWrt, sal_Int32 nPos ) { rWrt.m_bTagOn = false; - // the attributes in the End list are sorted in ascending order - HTMLStartEndPositions::size_type i {0}; - while (i < m_aEndLst.size()) + if (nPos == SAL_MAX_INT32) + { + for (auto& element : m_aEndLst) + OutEndAttrs(rWrt, element.second); + } + else { - HTMLStartEndPos* pPos = m_aEndLst[i]; - sal_Int32 nEnd = pPos->GetEnd(); + auto it = m_aEndLst.find(nPos); + if (it != m_aEndLst.end()) + OutEndAttrs(rWrt, it->second); + } +} - if( SAL_MAX_INT32 == nPos || nEnd == nPos ) +void HTMLEndPosLst::OutEndAttrs(SwHTMLWriter& rWrt, std::vector<HTMLStartEndPos*>& posItems) +{ + std::sort(posItems.begin(), posItems.end(), SortEnds(m_aStartLst)); + for (auto it = posItems.begin(); it != posItems.end(); it = posItems.erase(it)) + { + HTMLStartEndPos* pPos = *it; + HTMLOutFuncs::FlushToAscii( rWrt.Strm() ); // was one time only - do we still need it? + // Skip closing span if next character span has the same border (border merge) + bool bSkipOut = false; + if( pPos->GetItem().Which() == RES_CHRATR_BOX ) { - HTMLOutFuncs::FlushToAscii( rWrt.Strm() ); // was one time only - do we still need it? - // Skip closing span if next character span has the same border (border merge) - bool bSkipOut = false; - if( pPos->GetItem()->Which() == RES_CHRATR_BOX ) + auto& startPosItems = m_aStartLst[pPos->GetEnd()]; + for (auto it2 = startPosItems.begin(); it2 != startPosItems.end(); ++it2) { - HTMLStartEndPositions::iterator it - = std::find(m_aStartLst.begin(), m_aStartLst.end(), pPos); - OSL_ENSURE(it != m_aStartLst.end(), "Item not found in Start List!"); - if (it != m_aStartLst.end()) - ++it; - while (it != m_aStartLst.end()) + HTMLStartEndPos* pEndPos = *it2; + if( pEndPos->GetItem().Which() == RES_CHRATR_BOX && + static_cast<const SvxBoxItem&>(pEndPos->GetItem()) == + static_cast<const SvxBoxItem&>(pPos->GetItem()) ) { - HTMLStartEndPos *pEndPos = *it; - if( pEndPos->GetItem()->Which() == RES_CHRATR_BOX && - *static_cast<const SvxBoxItem*>(pEndPos->GetItem()) == - *static_cast<const SvxBoxItem*>(pPos->GetItem()) ) - { - pEndPos->SetStart(pPos->GetStart()); - bSkipOut = true; - break; - } - ++it; + startPosItems.erase(it2); + pEndPos->SetStart(pPos->GetStart()); + auto& oldStartPosItems = m_aStartLst[pEndPos->GetStart()]; + oldStartPosItems.insert(oldStartPosItems.begin(), pEndPos); + bSkipOut = true; + break; } } - if( !bSkipOut ) - { - Out( aHTMLAttrFnTab, *pPos->GetItem(), rWrt ); - rWrt.maStartedAttributes[pPos->GetItem()->Which()]--; - } - RemoveItem_( i ); - } - else if( nEnd > nPos ) - { - // this attribute, and all that follow, are closed later on - break; } - else + if( !bSkipOut ) { - // The attribute is closed before the current position. This - // is not allowed, but we can handle it anyway. - OSL_ENSURE( nEnd >= nPos, - "The attribute should've been closed a long time ago" ); - i++; + Out( aHTMLAttrFnTab, pPos->GetItem(), rWrt ); + rWrt.maStartedAttributes[pPos->GetItem().Which()]--; } + + std::erase(m_aStartLst[pPos->GetStart()], pPos); + delete pPos; } } diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index d84549d430..28da6d2883 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -161,6 +161,8 @@ #include <frozen/bits/defines.h> #include <frozen/bits/elsa_std.h> #include <frozen/unordered_map.h> +#include <IDocumentDeviceAccess.hxx> +#include <sfx2/printer.hxx> using ::editeng::SvxBorderLine; @@ -1965,7 +1967,22 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, sal_In } // if there is some redlining in the document, output it - StartRedline( m_pRedlineData, bLastRun ); + bool bSkipRedline = false; + if (nLen == 1) + { + // Don't redline content-controls--Word doesn't do them. + SwTextAttr* pAttr + = pNode->GetTextAttrAt(nPos, RES_TXTATR_CONTENTCONTROL, sw::GetTextAttrMode::Default); + if (pAttr && pAttr->GetStart() == nPos) + { + bSkipRedline = true; + } + } + + if (!bSkipRedline) + { + StartRedline(m_pRedlineData, bLastRun); + } // XML_r node should be surrounded with bookmark-begin and bookmark-end nodes if it has bookmarks. // The same is applied for permission ranges. @@ -2042,6 +2059,13 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, sal_In // append the actual run end m_pSerializer->endElementNS( XML_w, XML_r ); + // if there is some redlining in the document, output it + // (except in the case of fields with multiple runs) + if (!bSkipRedline) + { + EndRedline(m_pRedlineData, bLastRun); + } + if (nLen != -1) { sal_Int32 nEnd = nPos + nLen; @@ -2052,10 +2076,6 @@ void DocxAttributeOutput::EndRun(const SwTextNode* pNode, sal_Int32 nPos, sal_In } } - // if there is some redlining in the document, output it - // (except in the case of fields with multiple runs) - EndRedline( m_pRedlineData, bLastRun ); - // enclose in a sdt block, if necessary: if one is already started, then don't do it for now // (so on export sdt blocks are never nested ATM) if ( !m_bAnchorLinkedToNode && !m_aRunSdt.m_bStartedSdt) @@ -9118,9 +9138,15 @@ void DocxAttributeOutput::FormatFrameSize( const SwFormatFrameSize& rSize ) } } -void DocxAttributeOutput::FormatPaperBin( const SvxPaperBinItem& ) +void DocxAttributeOutput::FormatPaperBin(const SvxPaperBinItem& rPaperBin) { - SAL_INFO("sw.ww8", "TODO DocxAttributeOutput::FormatPaperBin()" ); + sal_Int8 nPaperBin = rPaperBin.GetValue(); + rtl::Reference<FastAttributeList> attrList = FastSerializerHelper::createAttrList( ); + SfxPrinter* pPrinter = m_rExport.m_rDoc.getIDocumentDeviceAccess().getPrinter(true); + sal_Int16 nPaperSource = pPrinter->GetSourceIndexByPaperBin(nPaperBin); + attrList->add( FSNS( XML_w, XML_first ), OString::number(nPaperSource) ); + attrList->add( FSNS( XML_w, XML_other ), OString::number(nPaperSource) ); + m_pSerializer->singleElementNS( XML_w, XML_paperSrc, attrList ); } void DocxAttributeOutput::FormatFirstLineIndent(SvxFirstLineIndentItem const& rFirstLine) diff --git a/sw/source/filter/ww8/rtfattributeoutput.cxx b/sw/source/filter/ww8/rtfattributeoutput.cxx index 2d68556e8a..7dcda8f73f 100644 --- a/sw/source/filter/ww8/rtfattributeoutput.cxx +++ b/sw/source/filter/ww8/rtfattributeoutput.cxx @@ -94,6 +94,8 @@ #include <formatflysplit.hxx> #include <fmtwrapinfluenceonobjpos.hxx> #include "rtfexport.hxx" +#include <IDocumentDeviceAccess.hxx> +#include <sfx2/printer.hxx> using namespace ::com::sun::star; using namespace sw::util; @@ -3324,9 +3326,14 @@ void RtfAttributeOutput::FormatFrameSize(const SwFormatFrameSize& rSize) } } -void RtfAttributeOutput::FormatPaperBin(const SvxPaperBinItem& /*rItem*/) +void RtfAttributeOutput::FormatPaperBin(const SvxPaperBinItem& rItem) { - SAL_INFO("sw.rtf", "TODO: " << __func__); + SfxPrinter* pPrinter = m_rExport.m_rDoc.getIDocumentDeviceAccess().getPrinter(true); + sal_Int16 nPaperSource = pPrinter->GetSourceIndexByPaperBin(rItem.GetValue()); + m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_BINFSXN); + m_aSectionBreaks.append(static_cast<sal_Int32>(nPaperSource)); + m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_BINSXN); + m_aSectionBreaks.append(static_cast<sal_Int32>(nPaperSource)); } void RtfAttributeOutput::FormatFirstLineIndent(SvxFirstLineIndentItem const& rFirstLine) @@ -3747,6 +3754,12 @@ void RtfAttributeOutput::FormatFillGradient(const XFillGradientItem& rFillGradie const Color aEndColor(rColorStops.back().getStopColor()); m_aFlyProperties.push_back(std::make_pair<OString, OString>( "fillBackColor"_ostr, OString::number(wwUtility::RGBToBGR(aEndColor)))); + + if (rGradient.GetGradientStyle() == awt::GradientStyle_AXIAL) + { + m_aFlyProperties.push_back( + std::make_pair<OString, OString>("fillFocus"_ostr, OString::number(50))); + } } else { diff --git a/sw/source/filter/ww8/wrtw8nds.cxx b/sw/source/filter/ww8/wrtw8nds.cxx index 39e2f88523..68437c9529 100644 --- a/sw/source/filter/ww8/wrtw8nds.cxx +++ b/sw/source/filter/ww8/wrtw8nds.cxx @@ -2478,6 +2478,14 @@ void MSWordExportBase::OutputTextNode( SwTextNode& rNode ) bool bStartedPostponedRunProperties = false; OUString aSavedSnippet ; + // Don't redline content-controls--Word doesn't do them. + SwTextAttr* pAttr = rNode.GetTextAttrAt(nCurrentPos, RES_TXTATR_CONTENTCONTROL, + sw::GetTextAttrMode::Default); + if (pAttr && pAttr->GetStart() == nCurrentPos) + { + pRedlineData = nullptr; + } + sal_Int32 nNextAttr = GetNextPos( &aAttrIter, rNode, nCurrentPos ); // Skip un-exportable attributes. diff --git a/sw/source/filter/ww8/wrtw8num.cxx b/sw/source/filter/ww8/wrtw8num.cxx index 8d59434db6..681961a377 100644 --- a/sw/source/filter/ww8/wrtw8num.cxx +++ b/sw/source/filter/ww8/wrtw8num.cxx @@ -279,7 +279,7 @@ void WW8AttributeOutput::NumberingLevel( sal_uInt8 /*nLevel*/, sal_Int16 nListTabPos, const OUString &rNumberingString, const SvxBrushItem* pBrush, //For i120928,to transfer graphic of bullet - bool /*isLegal*/ + bool isLegal ) { // Start value @@ -303,6 +303,13 @@ void WW8AttributeOutput::NumberingLevel( sal_uInt8 /*nLevel*/, nAlign = 0; break; } + + if (isLegal) + { + // 3rd bit. + nAlign |= 0x04; + } + m_rWW8Export.m_pTableStrm->WriteUChar( nAlign ); // Write the rgbxchNums[9], positions of placeholders for paragraph diff --git a/sw/source/filter/ww8/ww8par3.cxx b/sw/source/filter/ww8/ww8par3.cxx index d0a294b144..41b203f924 100644 --- a/sw/source/filter/ww8/ww8par3.cxx +++ b/sw/source/filter/ww8/ww8par3.cxx @@ -368,6 +368,8 @@ struct WW8LVL // only THE entries, WE need! short nDxaLeft1; // first line indent sal_uInt8 nNFC; // number format code + /// Legal numbering: whether this level overrides the nfc of all inherited level numbers. + bool fLegal; // Offset of fieldcodes in Num-X-String sal_uInt8 aOfsNumsXCH[WW8ListManager::nMaxLevel]; sal_uInt8 nLenGrpprlChpx; // length, in bytes, of the LVL's grpprlChpx @@ -662,7 +664,15 @@ bool WW8ListManager::ReadLVL(SwNumFormat& rNumFormat, std::unique_ptr<SfxItemSet m_rSt.ReadUChar( aLVL.nNFC ); m_rSt.ReadUChar( aBits1 ); if( ERRCODE_NONE != m_rSt.GetError() ) return false; + // 1st..2nd bits. aLVL.nAlign = (aBits1 & 0x03); + + if (aBits1 & 0x04) + { + // 3rd bit. + aLVL.fLegal = true; + } + if( aBits1 & 0x10 ) aLVL.bV6Prev = true; if( aBits1 & 0x20 ) aLVL.bV6PrSp = true; if( aBits1 & 0x40 ) aLVL.bV6 = true; @@ -898,6 +908,7 @@ bool WW8ListManager::ReadLVL(SwNumFormat& rNumFormat, std::unique_ptr<SfxItemSet if( bSetStartNo && 0 <= aLVL.nStartAt) rNumFormat.SetStart(o3tl::narrowing<sal_uInt16>(aLVL.nStartAt)); rNumFormat.SetNumberingType( nType ); + rNumFormat.SetIsLegal(aLVL.fLegal); rNumFormat.SetNumAdjust( eAdj ); if( style::NumberingType::CHAR_SPECIAL == nType ) diff --git a/sw/source/ui/index/swuiidxmrk.cxx b/sw/source/ui/index/swuiidxmrk.cxx index 39443f7e7b..8a6f74b86e 100644 --- a/sw/source/ui/index/swuiidxmrk.cxx +++ b/sw/source/ui/index/swuiidxmrk.cxx @@ -287,19 +287,20 @@ void SwIndexMarkPane::InitControls() bool bShow = false; pMoveMark = &m_pSh->GotoTOXMark( *pMark, TOX_PRV ); - if (!SfxPoolItem::areSame( pMoveMark, pMark )) + // tdf#158783 ptr compare OK for SwTOXMark (more below) + if (!areSfxPoolItemPtrsEqual( pMoveMark, pMark )) { m_pSh->GotoTOXMark( *pMoveMark, TOX_NXT ); bShow = true; } - m_xPrevBT->set_sensitive(!SfxPoolItem::areSame(pMoveMark, pMark)); + m_xPrevBT->set_sensitive(!areSfxPoolItemPtrsEqual(pMoveMark, pMark)); pMoveMark = &m_pSh->GotoTOXMark( *pMark, TOX_NXT ); - if (!SfxPoolItem::areSame( pMoveMark, pMark )) + if (!areSfxPoolItemPtrsEqual( pMoveMark, pMark )) { m_pSh->GotoTOXMark( *pMoveMark, TOX_PRV ); bShow = true; } - m_xNextBT->set_sensitive(!SfxPoolItem::areSame(pMoveMark, pMark)); + m_xNextBT->set_sensitive(!areSfxPoolItemPtrsEqual(pMoveMark, pMark)); if( bShow ) { m_xPrevBT->show(); @@ -308,19 +309,19 @@ void SwIndexMarkPane::InitControls() } pMoveMark = &m_pSh->GotoTOXMark( *pMark, TOX_SAME_PRV ); - if (!SfxPoolItem::areSame( pMoveMark, pMark )) + if (!areSfxPoolItemPtrsEqual( pMoveMark, pMark )) { m_pSh->GotoTOXMark( *pMoveMark, TOX_SAME_NXT ); bShow = true; } - m_xPrevSameBT->set_sensitive(!SfxPoolItem::areSame(pMoveMark, pMark)); + m_xPrevSameBT->set_sensitive(!areSfxPoolItemPtrsEqual(pMoveMark, pMark)); pMoveMark = &m_pSh->GotoTOXMark( *pMark, TOX_SAME_NXT ); - if (!SfxPoolItem::areSame( pMoveMark, pMark )) + if (!areSfxPoolItemPtrsEqual( pMoveMark, pMark )) { m_pSh->GotoTOXMark( *pMoveMark, TOX_SAME_PRV ); bShow = true; } - m_xNextSameBT->set_sensitive(!SfxPoolItem::areSame(pMoveMark, pMark)); + m_xNextSameBT->set_sensitive(!areSfxPoolItemPtrsEqual(pMoveMark, pMark)); if( bShow ) { m_xNextSameBT->show(); @@ -894,25 +895,26 @@ void SwIndexMarkPane::UpdateDialog() if( m_xPrevBT->get_visible() ) { const SwTOXMark* pMoveMark = &m_pSh->GotoTOXMark( *pMark, TOX_PRV ); - if (!SfxPoolItem::areSame( pMoveMark, pMark )) + // tdf#158783 ptr compare OK for SwTOXMark (more below) + if (!areSfxPoolItemPtrsEqual( pMoveMark, pMark )) m_pSh->GotoTOXMark( *pMoveMark, TOX_NXT ); - m_xPrevBT->set_sensitive( !SfxPoolItem::areSame(pMoveMark, pMark) ); + m_xPrevBT->set_sensitive( !areSfxPoolItemPtrsEqual(pMoveMark, pMark) ); pMoveMark = &m_pSh->GotoTOXMark( *pMark, TOX_NXT ); - if (!SfxPoolItem::areSame( pMoveMark, pMark )) + if (!areSfxPoolItemPtrsEqual( pMoveMark, pMark )) m_pSh->GotoTOXMark( *pMoveMark, TOX_PRV ); - m_xNextBT->set_sensitive( !SfxPoolItem::areSame(pMoveMark, pMark) ); + m_xNextBT->set_sensitive( !areSfxPoolItemPtrsEqual(pMoveMark, pMark) ); } if (m_xPrevSameBT->get_visible()) { const SwTOXMark* pMoveMark = &m_pSh->GotoTOXMark( *pMark, TOX_SAME_PRV ); - if (!SfxPoolItem::areSame( pMoveMark, pMark )) + if (!areSfxPoolItemPtrsEqual( pMoveMark, pMark )) m_pSh->GotoTOXMark( *pMoveMark, TOX_SAME_NXT ); - m_xPrevSameBT->set_sensitive( !SfxPoolItem::areSame(pMoveMark, pMark) ); + m_xPrevSameBT->set_sensitive( !areSfxPoolItemPtrsEqual(pMoveMark, pMark) ); pMoveMark = &m_pSh->GotoTOXMark( *pMark, TOX_SAME_NXT ); - if (!SfxPoolItem::areSame( pMoveMark, pMark )) + if (!areSfxPoolItemPtrsEqual( pMoveMark, pMark )) m_pSh->GotoTOXMark( *pMoveMark, TOX_SAME_PRV ); - m_xNextSameBT->set_sensitive( !SfxPoolItem::areSame(pMoveMark, pMark) ); + m_xNextSameBT->set_sensitive( !areSfxPoolItemPtrsEqual(pMoveMark, pMark) ); } const bool bEnable = !m_pSh->HasReadonlySel(); @@ -1013,7 +1015,8 @@ void SwIndexMarkPane::ReInitDlg(SwWrtShell& rWrtShell, SwTOXMark const * pCurTOX if(pCurTOXMark) { for(sal_uInt16 i = 0; i < m_pTOXMgr->GetTOXMarkCount(); i++) - if (SfxPoolItem::areSame(m_pTOXMgr->GetTOXMark(i), pCurTOXMark)) + // tdf#158783 ptr compare OK for SwTOXMark (more below) + if (areSfxPoolItemPtrsEqual(m_pTOXMgr->GetTOXMark(i), pCurTOXMark)) { m_pTOXMgr->SetCurTOXMark(i); break; diff --git a/sw/source/uibase/dochdl/swdtflvr.cxx b/sw/source/uibase/dochdl/swdtflvr.cxx index cb96c08527..ea419d2326 100644 --- a/sw/source/uibase/dochdl/swdtflvr.cxx +++ b/sw/source/uibase/dochdl/swdtflvr.cxx @@ -382,7 +382,8 @@ const Graphic* SwTransferable::FindOLEReplacementGraphic() const void SwTransferable::RemoveDDELinkFormat(vcl::Window& rWin) { RemoveFormat( SotClipboardFormatId::LINK ); - CopyToClipboard(&rWin); + if (rWin.GetClipboard()->getContents().get() == this) + CopyToClipboard(&rWin); } void SwTransferable::DisconnectDDE() diff --git a/sw/source/uibase/docvw/AnnotationWin2.cxx b/sw/source/uibase/docvw/AnnotationWin2.cxx index a1780f9132..6b8895f1d9 100644 --- a/sw/source/uibase/docvw/AnnotationWin2.cxx +++ b/sw/source/uibase/docvw/AnnotationWin2.cxx @@ -504,7 +504,7 @@ void SwAnnotationWin::SetMenuButtonColors() const tools::Long nBorderDistanceBottom = ((aSymbolRect.GetHeight() * 150) + 500) / 1000; aSymbolRect.AdjustBottom( -nBorderDistanceBottom ); DecorationView aDecoView(xVirDev.get()); - aDecoView.DrawSymbol(aSymbolRect, SymbolType::SPIN_DOWN, GetTextColor(), + aDecoView.DrawSymbol(aSymbolRect, SymbolType::SPIN_DOWN, COL_BLACK, DrawSymbolFlags::NONE); mxMenuButton->set_image(xVirDev); mxMenuButton->set_size_request(aSize.Width() + 4, aSize.Height() + 4); diff --git a/sw/source/uibase/docvw/SidebarWinAcc.cxx b/sw/source/uibase/docvw/SidebarWinAcc.cxx index f489bc140b..3b2b4c758e 100644 --- a/sw/source/uibase/docvw/SidebarWinAcc.cxx +++ b/sw/source/uibase/docvw/SidebarWinAcc.cxx @@ -23,9 +23,9 @@ #include <viewsh.hxx> #include <accmap.hxx> #include <toolkit/awt/vclxaccessiblecomponent.hxx> +#include <vcl/svapp.hxx> #include <com/sun/star/accessibility/AccessibleRole.hpp> -#include <mutex> namespace sw::sidebarwindows { @@ -47,7 +47,7 @@ class SidebarWinAccessibleContext : public VCLXAccessibleComponent void ChangeAnchor( const SwFrame* pAnchorFrame ) { - std::scoped_lock aGuard(maMutex); + SolarMutexGuard aGuard; mpAnchorFrame = pAnchorFrame; } @@ -55,7 +55,7 @@ class SidebarWinAccessibleContext : public VCLXAccessibleComponent virtual css::uno::Reference< css::accessibility::XAccessible > SAL_CALL getAccessibleParent() override { - std::scoped_lock aGuard(maMutex); + SolarMutexGuard aGuard; css::uno::Reference< css::accessibility::XAccessible > xAccParent; @@ -70,7 +70,7 @@ class SidebarWinAccessibleContext : public VCLXAccessibleComponent virtual sal_Int64 SAL_CALL getAccessibleIndexInParent() override { - std::scoped_lock aGuard(maMutex); + SolarMutexGuard aGuard; sal_Int64 nIndex( -1 ); @@ -87,8 +87,6 @@ class SidebarWinAccessibleContext : public VCLXAccessibleComponent private: SwViewShell& mrViewShell; const SwFrame* mpAnchorFrame; - - std::mutex maMutex; }; } diff --git a/sw/source/uibase/index/toxmgr.cxx b/sw/source/uibase/index/toxmgr.cxx index 8b8ff6dbd8..c7cd813eb4 100644 --- a/sw/source/uibase/index/toxmgr.cxx +++ b/sw/source/uibase/index/toxmgr.cxx @@ -47,7 +47,8 @@ void SwTOXMgr::DeleteTOXMark() if( m_pCurTOXMark ) { pNext = const_cast<SwTOXMark*>(&m_pSh->GotoTOXMark( *m_pCurTOXMark, TOX_NXT )); - if (SfxPoolItem::areSame( pNext, m_pCurTOXMark )) + // tdf#158783 ptr compare OK for SwTOXMark (more below) + if (areSfxPoolItemPtrsEqual( pNext, m_pCurTOXMark )) pNext = nullptr; m_pSh->DeleteTOXMark( m_pCurTOXMark ); diff --git a/sw/source/uibase/shells/textsh.cxx b/sw/source/uibase/shells/textsh.cxx index 0924935b3d..97de985401 100644 --- a/sw/source/uibase/shells/textsh.cxx +++ b/sw/source/uibase/shells/textsh.cxx @@ -877,7 +877,20 @@ void SwTextShell::ExecTransliteration( SfxRequest const & rReq ) void SwTextShell::ExecRotateTransliteration( SfxRequest const & rReq ) { if( rReq.GetSlot() == SID_TRANSLITERATE_ROTATE_CASE ) - GetShell().TransliterateText( m_aRotateCase.getNextMode() ); + { + SwWrtShell& rSh = GetShell(); + if (rSh.HasSelection()) + { + rSh.TransliterateText(m_aRotateCase.getNextMode()); + } + else + { + rSh.Push(); // save cur cursor + if ((rSh.IsEndWrd() || rSh.IsStartWord() || rSh.IsInWord()) && rSh.SelWrd()) + rSh.TransliterateText(m_aRotateCase.getNextMode()); + rSh.Pop(SwCursorShell::PopMode::DeleteCurrent); + } + } } SwTextShell::SwTextShell(SwView &_rView) : diff --git a/sw/source/uibase/sidebar/PageSizeControl.cxx b/sw/source/uibase/sidebar/PageSizeControl.cxx index 4ea5995c09..a2dbe406f3 100644 --- a/sw/source/uibase/sidebar/PageSizeControl.cxx +++ b/sw/source/uibase/sidebar/PageSizeControl.cxx @@ -168,7 +168,6 @@ PageSizeControl::PageSizeControl(PageSizePopup* pControl, weld::Widget* pParent) } mxSizeValueSet->SetNoSelection(); mxSizeValueSet->SetSelectHdl( LINK(this, PageSizeControl, ImplSizeHdl ) ); - mxSizeValueSet->SetOptimalDrawingAreaHeight(); mxSizeValueSet->Show(); mxSizeValueSet->Resize(); diff --git a/sw/source/uibase/uiview/view2.cxx b/sw/source/uibase/uiview/view2.cxx index cc6faf78a3..f7a10a49f7 100644 --- a/sw/source/uibase/uiview/view2.cxx +++ b/sw/source/uibase/uiview/view2.cxx @@ -286,14 +286,21 @@ OUString SwView::GetPageStr(sal_uInt16 nPhyNum, sal_uInt16 nVirtNum, const OUStr ? SwResId(STR_PAGE_COUNT_PRINTED) : (extra.isEmpty() ? SwResId(STR_PAGE_COUNT) : SwResId(STR_PAGE_COUNT_CUSTOM))); aStr = aStr.replaceFirst("%1", OUString::number(nPhyNum)); - aStr = aStr.replaceFirst("%2", OUString::number(nPageCount)); if (nPageCount != nPrintedPageCount) { + aStr = aStr.replaceFirst("%2", OUString::number(nPageCount)); aStr = aStr.replaceFirst("%3", OUString::number(nPrintedPhyNum)); aStr = aStr.replaceFirst("%4", OUString::number(nPrintedPageCount)); } - else - aStr = aStr.replaceFirst("%3", extra); + else { + if (extra.isEmpty()) + aStr = aStr.replaceFirst("%2", OUString::number(nPageCount)); + else + { + aStr = aStr.replaceFirst("%2", extra); + aStr = aStr.replaceFirst("%3", OUString::number(nPageCount)); + } + } return aStr; } diff --git a/sw/source/uibase/utlui/uitool.cxx b/sw/source/uibase/utlui/uitool.cxx index fd50bf6678..dfaffe3480 100644 --- a/sw/source/uibase/utlui/uitool.cxx +++ b/sw/source/uibase/utlui/uitool.cxx @@ -392,6 +392,7 @@ void ItemSetToPageDesc( const SfxItemSet& rSet, SwPageDesc& rPageDesc ) if(rMaster.GetFooter().IsActive()) { rMaster.SetFormatAttr(SwFormatFooter(false)); + // why reset this? but not doing it causes testTdf112694 to fail rPageDesc.ChgFooterShare(false); } } diff --git a/sw/source/uibase/wrtsh/wrtsh1.cxx b/sw/source/uibase/wrtsh/wrtsh1.cxx index 4b2402fc93..0054eca4cb 100644 --- a/sw/source/uibase/wrtsh/wrtsh1.cxx +++ b/sw/source/uibase/wrtsh/wrtsh1.cxx @@ -115,6 +115,7 @@ #include <frmtool.hxx> #include <viewopt.hxx> +#include <IDocumentRedlineAccess.hxx> #include <IDocumentUndoRedo.hxx> #include <UndoInsert.hxx> #include <UndoCore.hxx> @@ -1177,8 +1178,12 @@ void SwWrtShell::InsertContentControl(SwContentControlType eType) Left(SwCursorSkipMode::Chars, /*bSelect=*/true, aPlaceholder.getLength(), /*bBasicCall=*/false); } + + const RedlineFlags oldRedlineFlags = getIDocumentRedlineAccess().GetRedlineFlags(); + getIDocumentRedlineAccess().SetRedlineFlags(RedlineFlags::Ignore); SwFormatContentControl aContentControl(pContentControl, RES_TXTATR_CONTENTCONTROL); SetAttrItem(aContentControl); + getIDocumentRedlineAccess().SetRedlineFlags(oldRedlineFlags); } // Insert footnote |