diff options
Diffstat (limited to 'sw/source/core/table/swnewtable.cxx')
-rw-r--r-- | sw/source/core/table/swnewtable.cxx | 142 |
1 files changed, 100 insertions, 42 deletions
diff --git a/sw/source/core/table/swnewtable.cxx b/sw/source/core/table/swnewtable.cxx index 85592b9a7458..a8b7e0e0d233 100644 --- a/sw/source/core/table/swnewtable.cxx +++ b/sw/source/core/table/swnewtable.cxx @@ -18,6 +18,7 @@ */ #include <swtable.hxx> +#include <swcrsr.hxx> #include <tblsel.hxx> #include <tblrwcl.hxx> #include <ndtxt.hxx> @@ -34,6 +35,7 @@ #include <IDocumentContentOperations.hxx> #include <IDocumentFieldsAccess.hxx> #include <IDocumentLayoutAccess.hxx> +#include <IDocumentRedlineAccess.hxx> #include <cstdlib> #include <vector> #include <set> @@ -326,15 +328,15 @@ static void lcl_ChangeRowSpan( const SwTable& rTable, const tools::Long nDiff, and prepares the selected cells for merging */ -std::unique_ptr<SwBoxSelection> SwTable::CollectBoxSelection( const SwPaM& rPam ) const +std::optional<SwBoxSelection> SwTable::CollectBoxSelection( const SwPaM& rPam ) const { OSL_ENSURE( m_bNewModel, "Don't call me for old tables" ); if( m_aLines.empty() ) - return nullptr; - const SwNode* pStartNd = rPam.Start()->nNode.GetNode().FindTableBoxStartNode(); - const SwNode* pEndNd = rPam.End()->nNode.GetNode().FindTableBoxStartNode(); + return std::nullopt; + const SwNode* pStartNd = rPam.Start()->GetNode().FindTableBoxStartNode(); + const SwNode* pEndNd = rPam.End()->GetNode().FindTableBoxStartNode(); if( !pStartNd || !pEndNd || pStartNd == pEndNd ) - return nullptr; + return std::nullopt; const size_t nLines = m_aLines.size(); size_t nTop = 0; @@ -369,12 +371,12 @@ std::unique_ptr<SwBoxSelection> SwTable::CollectBoxSelection( const SwPaM& rPam } } if( nFound < 2 ) - return nullptr; + return std::nullopt; bool bOkay = true; tools::Long nMid = ( nMin + nMax ) / 2; - auto pRet(std::make_unique<SwBoxSelection>()); + std::optional<SwBoxSelection> pRet(std::in_place); std::vector< std::pair< SwTableBox*, tools::Long > > aNewWidthVector; size_t nCheckBottom = nBottom; tools::Long nLeftSpan = 0; @@ -651,7 +653,7 @@ insertion behind (true) or before (false) the selected boxes */ bool SwTable::NewInsertCol( SwDoc& rDoc, const SwSelBoxes& rBoxes, - sal_uInt16 nCnt, bool bBehind ) + sal_uInt16 nCnt, bool bBehind, bool bInsertDummy ) { if( m_aLines.empty() || !nCnt ) return false; @@ -745,6 +747,24 @@ bool SwTable::NewInsertCol( SwDoc& rDoc, const SwSelBoxes& rBoxes, for( sal_uInt16 j = 0; j < nCnt; ++j ) { SwTableBox *pCurrBox = pLine->GetTabBoxes()[nInsPos+j]; + + // set tracked insertion by inserting a dummy redline + // drag & drop: no need to insert dummy character + if ( rDoc.getIDocumentRedlineAccess().IsRedlineOn() ) + { + SwPosition aPos(*pCurrBox->GetSttNd()); + SwCursor aCursor( aPos, nullptr ); + if ( bInsertDummy ) + { + SwNodeIndex aInsDummyPos(*pCurrBox->GetSttNd(), 1 ); + SwPaM aPaM(aInsDummyPos); + rDoc.getIDocumentContentOperations().InsertString( aPaM, + OUStringChar(CH_TXT_TRACKED_DUMMY_CHAR) ); + } + SvxPrintItem aHasTextChangesOnly(RES_PRINT, false); + rDoc.SetBoxAttr( aCursor, aHasTextChangesOnly ); + } + if( bNewSpan ) { pCurrBox->setRowSpan( nLastRowSpan ); @@ -816,7 +836,7 @@ bool SwTable::PrepareMerge( const SwPaM& rPam, SwSelBoxes& rBoxes, } CHECK_TABLE( *this ) // We have to assert a "rectangular" box selection before we start to merge - std::unique_ptr< SwBoxSelection > pSel( CollectBoxSelection( rPam ) ); + std::optional< SwBoxSelection > pSel( CollectBoxSelection( rPam ) ); if (!pSel || pSel->isEmpty()) return false; // Now we should have a rectangle of boxes, @@ -884,11 +904,12 @@ bool SwTable::PrepareMerge( const SwPaM& rPam, SwSelBoxes& rBoxes, // we do not transfer this paragraph. if( !IsEmptyBox( *pBox, aChkPam ) ) { - SwNodeIndex& rInsPosNd = aInsPos.nNode; + SwNode& rInsPosNd = aInsPos.GetNode(); SwPaM aPam( aInsPos ); - aPam.GetPoint()->nNode.Assign( *pBox->GetSttNd()->EndOfSectionNode(), -1 ); - SwContentNode* pCNd = aPam.GetContentNode(); - aPam.GetPoint()->nContent.Assign( pCNd, pCNd ? pCNd->Len() : 0 ); + aPam.GetPoint()->Assign( *pBox->GetSttNd()->EndOfSectionNode(), SwNodeOffset(-1) ); + SwContentNode* pCNd = aPam.GetPointContentNode(); + if( pCNd ) + aPam.GetPoint()->SetContent( pCNd->Len() ); SwNodeIndex aSttNdIdx( *pBox->GetSttNd(), 1 ); bool const bUndo = pDoc->GetIDocumentUndoRedo().DoesUndo(); if( pUndo ) @@ -900,7 +921,7 @@ bool SwTable::PrepareMerge( const SwPaM& rPam, SwSelBoxes& rBoxes, { pDoc->GetIDocumentUndoRedo().DoUndo(bUndo); } - SwNodeRange aRg( aSttNdIdx, aPam.GetPoint()->nNode ); + SwNodeRange aRg( aSttNdIdx.GetNode(), aPam.GetPoint()->GetNode() ); if( pUndo ) pUndo->MoveBoxContent( *pDoc, aRg, rInsPosNd ); else @@ -948,14 +969,14 @@ bool SwTable::PrepareMerge( const SwPaM& rPam, SwSelBoxes& rBoxes, if( nCurrLine ) { SwPaM aPam( *pBox->GetSttNd(), 0 ); - aPam.GetPoint()->nNode++; - SwTextNode* pNd = aPam.GetNode().GetTextNode(); + aPam.GetPoint()->Adjust(SwNodeOffset(+1)); + SwTextNode* pNd = aPam.GetPointNode().GetTextNode(); while( pNd ) { pNd->SetCountedInList( false ); - aPam.GetPoint()->nNode++; - pNd = aPam.GetNode().GetTextNode(); + aPam.GetPoint()->Adjust(SwNodeOffset(+1)); + pNd = aPam.GetPointNode().GetTextNode(); } } } @@ -1062,7 +1083,7 @@ SwTableBox& SwTableBox::FindEndOfRowSpan( const SwTable& rTable, sal_uInt16 nMax return *this; if( nMaxStep > --nAbsSpan ) - nMaxStep = static_cast<sal_uInt16>(nAbsSpan); + nMaxStep = o3tl::narrowing<sal_uInt16>(nAbsSpan); const SwTableLine* pMyUpper = GetUpper(); sal_uInt16 nLine = rTable.GetTabLines().GetPos( pMyUpper ); nMaxStep = nLine + nMaxStep; @@ -1184,7 +1205,7 @@ void SwTable::InsertSpannedRow( SwDoc& rDoc, sal_uInt16 nRowIdx, sal_uInt16 nCnt aFSz.SetHeight( nNewHeight ); pFrameFormat->SetFormatAttr( aFSz ); } - InsertRow_( &rDoc, aBoxes, nCnt, true ); + InsertRow_( &rDoc, aBoxes, nCnt, true, true ); const size_t nBoxCount = rLine.GetTabBoxes().size(); for( sal_uInt16 n = 0; n < nCnt; ++n ) { @@ -1388,7 +1409,7 @@ static sal_uInt16 lcl_LineIndex( const SwTable& rTable, const SwSelBoxes& rBoxes nSpan = 0; else if( nSpan ) { - sal_uInt16 nEndOfRowSpan = static_cast<sal_uInt16>(nPos + nRowSpan - 1); + sal_uInt16 nEndOfRowSpan = o3tl::narrowing<sal_uInt16>(nPos + nRowSpan - 1); if( nEndOfRowSpan > nSpan || nSpan == USHRT_MAX ) nSpan = nEndOfRowSpan; } @@ -1489,7 +1510,7 @@ bool SwTable::NewSplitRow( SwDoc& rDoc, const SwSelBoxes& rBoxes, sal_uInt16 nCn */ bool SwTable::InsertRow( SwDoc* pDoc, const SwSelBoxes& rBoxes, - sal_uInt16 nCnt, bool bBehind ) + sal_uInt16 nCnt, bool bBehind, bool bInsertDummy ) { bool bRet = false; if( IsNewModel() ) @@ -1506,7 +1527,7 @@ bool SwTable::InsertRow( SwDoc* pDoc, const SwSelBoxes& rBoxes, SwTableLine *pLine = GetTabLines()[ nRowIdx ]; SwSelBoxes aLineBoxes; lcl_FillSelBoxes( aLineBoxes, *pLine ); - InsertRow_( pDoc, aLineBoxes, nCnt, bBehind ); + InsertRow_( pDoc, aLineBoxes, nCnt, bBehind, bInsertDummy ); const size_t nBoxCount = pLine->GetTabBoxes().size(); sal_uInt16 nOfs = bBehind ? 0 : 1; for( sal_uInt16 n = 0; n < nCnt; ++n ) @@ -1531,8 +1552,7 @@ bool SwTable::InsertRow( SwDoc* pDoc, const SwSelBoxes& rBoxes, SwContentNode* pCNd = aIdx.GetNode().GetContentNode(); if( pCNd && pCNd->IsTextNode() && pCNd->GetTextNode()->GetNumRule() ) { - SwPosition aPos( *pCNd->GetTextNode() ); - SwPaM aPam( aPos, aPos ); + SwPaM aPam( *pCNd->GetTextNode(), *pCNd->GetTextNode() ); pDoc->DelNumRules( aPam ); } } @@ -1557,7 +1577,7 @@ bool SwTable::InsertRow( SwDoc* pDoc, const SwSelBoxes& rBoxes, CHECK_TABLE( *this ) } else - bRet = InsertRow_( pDoc, rBoxes, nCnt, bBehind ); + bRet = InsertRow_( pDoc, rBoxes, nCnt, bBehind, bInsertDummy ); return bRet; } @@ -1675,8 +1695,8 @@ void SwTable::CreateSelection( const SwPaM& rPam, SwSelBoxes& rBoxes, OSL_ENSURE( m_bNewModel, "Don't call me for old tables" ); if( m_aLines.empty() ) return; - const SwNode* pStartNd = rPam.GetPoint()->nNode.GetNode().FindTableBoxStartNode(); - const SwNode* pEndNd = rPam.GetMark()->nNode.GetNode().FindTableBoxStartNode(); + const SwNode* pStartNd = rPam.GetPoint()->GetNode().FindTableBoxStartNode(); + const SwNode* pEndNd = rPam.GetMark()->GetNode().FindTableBoxStartNode(); if( !pStartNd || !pEndNd ) return; CreateSelection( pStartNd, pEndNd, rBoxes, eSearch, bChkProtected ); @@ -1719,7 +1739,11 @@ void SwTable::CreateSelection( const SwNode* pStartNd, const SwNode* pEndNd, rBoxes.insert( pBox ); if( nFound ) { - nBottom = nRow; + //if box is hiding cells bottom needs to be moved + if (pBox->getRowSpan() > 1) + nBottom = std::max(nBottom, size_t(nRow + pBox->getRowSpan() - 1)); + else + nBottom = std::max(nRow, nBottom); lcl_CheckMinMax( nLowerMin, nLowerMax, *pLine, nCol, true ); ++nFound; break; @@ -1727,6 +1751,9 @@ void SwTable::CreateSelection( const SwNode* pStartNd, const SwNode* pEndNd, else { nTop = nRow; + //if box is hiding cells bottom needs to be moved + if (pBox->getRowSpan() > 1) + nBottom = nRow + pBox->getRowSpan() - 1; lcl_CheckMinMax( nUpperMin, nUpperMax, *pLine, nCol, true ); ++nFound; // If start and end node are identical, we're nearly done... @@ -2101,7 +2128,7 @@ void SwTable::CleanUpBottomRowSpan( sal_uInt16 nDelLines ) if( nRowSp > 1 ) { lcl_ChangeRowSpan( *this, -static_cast<tools::Long>(nDelLines), - static_cast<sal_uInt16>(nLastLine), false ); + o3tl::narrowing<sal_uInt16>(nLastLine), false ); break; } } @@ -2133,12 +2160,16 @@ void SwTable::ConvertSubtableBox(sal_uInt16 const nRow, sal_uInt16 const nBox) assert(!pSubTableBox->GetTabLines().empty()); // are relative (%) heights possible? apparently not SwFormatFrameSize const outerSize(pSourceLine->GetFrameFormat()->GetFrameSize()); + if (outerSize.GetHeightSizeType() != SwFrameSize::Variable) + { // tdf#145871 clear fixed size in first row + pSourceLine->ClaimFrameFormat(); + pSourceLine->GetFrameFormat()->ResetFormatAttr(RES_FRM_SIZE); + } tools::Long minHeights(0); { - SwFormatFrameSize const* pSize(nullptr); SwFrameFormat const& rSubLineFormat(*pSubTableBox->GetTabLines()[0]->GetFrameFormat()); - if (rSubLineFormat.GetItemState(RES_FRM_SIZE, true, - reinterpret_cast<SfxPoolItem const**>(&pSize)) == SfxItemState::SET) + SwFormatFrameSize const* pSize = rSubLineFormat.GetItemIfSet(RES_FRM_SIZE); + if (pSize) { // for first row, apply height from inner row to outer row. // in case the existing outer row height was larger than the entire // subtable, the last inserted row needs to be tweaked (below) @@ -2157,9 +2188,8 @@ void SwTable::ConvertSubtableBox(sal_uInt16 const nRow, sal_uInt16 const nBox) pSourceLine->GetTabBoxes().size() - 1 + pSubLine->GetTabBoxes().size(), nullptr); SwFrameFormat const& rSubLineFormat(*pSubLine->GetFrameFormat()); - SwFormatFrameSize const* pSize(nullptr); - if (rSubLineFormat.GetItemState(RES_FRM_SIZE, true, - reinterpret_cast<SfxPoolItem const**>(&pSize)) == SfxItemState::SET) + SwFormatFrameSize const* pSize = rSubLineFormat.GetItemIfSet(RES_FRM_SIZE); + if (pSize) { // for rows 2..N, copy inner row height to outer row pNewLine->ClaimFrameFormat(); pNewLine->GetFrameFormat()->SetFormatAttr(*pSize); @@ -2179,6 +2209,7 @@ void SwTable::ConvertSubtableBox(sal_uInt16 const nRow, sal_uInt16 const nBox) { lastSize.SetHeightSizeType(SwFrameSize::Minimum); } + pNewLine->ClaimFrameFormat(); pNewLine->GetFrameFormat()->SetFormatAttr(lastSize); } SfxPoolItem const* pRowBrush(nullptr); @@ -2200,9 +2231,9 @@ void SwTable::ConvertSubtableBox(sal_uInt16 const nRow, sal_uInt16 const nBox) pSourceBox, j+k, 1); // insert dummy text node... pDoc->GetNodes().MakeTextNode( - SwNodeIndex(*pSourceBox->GetSttNd(), +1), + SwNodeIndex(*pSourceBox->GetSttNd(), +1).GetNode(), pDoc->GetDfltTextFormatColl()); - SwNodeRange content(*pSourceBox->GetSttNd(), +2, + SwNodeRange content(*pSourceBox->GetSttNd(), SwNodeOffset(+2), *pSourceBox->GetSttNd()->EndOfSectionNode()); SwTableBox *const pNewBox(pNewLine->GetTabBoxes()[j+k]); SwNodeIndex insPos(*pNewBox->GetSttNd(), 1); @@ -2211,14 +2242,13 @@ void SwTable::ConvertSubtableBox(sal_uInt16 const nRow, sal_uInt16 const nBox) #if 0 pDoc->GetNodes().MoveNodes(content, pDoc->GetNodes(), insPos, false); #else - pDoc->getIDocumentContentOperations().MoveNodeRange(content, insPos, SwMoveFlags::NO_DELFRMS|SwMoveFlags::REDLINES); + pDoc->getIDocumentContentOperations().MoveNodeRange(content, insPos.GetNode(), SwMoveFlags::NO_DELFRMS|SwMoveFlags::REDLINES); #endif // delete the empty node that was bundled in the new box pDoc->GetNodes().Delete(insPos); if (pRowBrush) { - SfxPoolItem const* pCellBrush(nullptr); - if (pNewBox->GetFrameFormat()->GetItemState(RES_BACKGROUND, true, &pCellBrush) != SfxItemState::SET) + if (pNewBox->GetFrameFormat()->GetItemState(RES_BACKGROUND, true) != SfxItemState::SET) { // set inner row background on inner cell pNewBox->ClaimFrameFormat(); pNewBox->GetFrameFormat()->SetFormatAttr(*pRowBrush); @@ -2298,6 +2328,7 @@ bool SwTable::CanConvertSubtables() const return false; } haveSubtable = true; + bool haveNonFixedInnerLine(false); for (SwTableLine const*const pInnerLine : pBox->GetTabLines()) { // bitmap row background will look different @@ -2314,6 +2345,17 @@ bool SwTable::CanConvertSubtables() const return false; } } + if (SwFormatFrameSize const* pSize = rRowFormat.GetItemIfSet(RES_FRM_SIZE)) + { + if (pSize->GetHeightSizeType() != SwFrameSize::Fixed) + { + haveNonFixedInnerLine = true; + } + } + else + { + haveNonFixedInnerLine = true; // default + } for (SwTableBox const*const pInnerBox : pInnerLine->GetTabBoxes()) { if (!pInnerBox->GetTabLines().empty()) @@ -2322,6 +2364,17 @@ bool SwTable::CanConvertSubtables() const } } } + if (haveNonFixedInnerLine) + { + if (SwFormatFrameSize const* pSize = pLine->GetFrameFormat()->GetItemIfSet(RES_FRM_SIZE)) + { + if (pSize->GetHeightSizeType() != SwFrameSize::Variable) + { + // not possible to distribute fixed outer row height on rows without layout + return false; + } + } + } } } } @@ -2337,7 +2390,9 @@ bool SwTable::CanConvertSubtables() const { return false; // no formulas in fields yet } - if (pDoc->GetAttrPool().GetItemCount2(RES_BOXATR_FORMULA) != 0) + ItemSurrogates aSurrogates; + pDoc->GetAttrPool().GetItemSurrogates(aSurrogates, RES_BOXATR_FORMULA); + if (!aSurrogates.empty()) { return false; // no table box formulas yet } @@ -2359,6 +2414,8 @@ bool SwTable::CanConvertSubtables() const void SwTable::ConvertSubtables() { + FndBox_ all(nullptr, nullptr); + all.DelFrames(*this); // tdf#151375 avoid UAF by frames on deleted cells for (size_t i = 0; i < GetTabLines().size(); ++i) { SwTableLine *const pLine(GetTabLines()[i]); @@ -2374,6 +2431,7 @@ void SwTable::ConvertSubtables() } GCLines(); m_bNewModel = true; + all.MakeFrames(*this); #if 0 // note: outline nodes (and ordinary lists) are sorted by MoveNodes() itself // (this could change order inside table of contents, but that's a |