/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
// macros, determining how table boxes are merged: // - 1. remove empty lines, all boxes separated with blanks, // all lines separated with ParaBreak // - 2. remove all empty lines and remove all empty boxes at beginning and end, // all boxes separated with Blank, // all lines separated with ParaBreak // - 3. remove all empty boxes, all boxes separated with blanks, // all lines separated with ParaBreak
Point aCurrentTopLeft( LONG_MAX, LONG_MAX );
Point aCurrentTopRight( 0, LONG_MAX );
Point aCurrentBottomLeft( LONG_MAX, 0 );
Point aCurrentBottomRight( 0, 0 ); const SwCellFrame* pCurrentTopLeftFrame = nullptr; const SwCellFrame* pCurrentTopRightFrame = nullptr; const SwCellFrame* pCurrentBottomLeftFrame = nullptr; const SwCellFrame* pCurrentBottomRightFrame = nullptr;
// Now find boxes for each entry and emit for (size_t i = 0; i < aUnions.size() && bTableIsValid; ++i)
{
SwSelUnion *pUnion = &aUnions[i]; const SwTabFrame *pTable = pUnion->GetTable();
if ( pCells )
{ const Point aTopLeft( pCell->getFrameArea().TopLeft() ); const Point aTopRight( pCell->getFrameArea().TopRight() ); const Point aBottomLeft( pCell->getFrameArea().BottomLeft() ); const Point aBottomRight( pCell->getFrameArea().BottomRight() );
// --> Make code robust, check if pStart has // been deleted due to the formatting of the table: if ( aDelCheck.HasBeenDeleted() )
{
OSL_FAIL( "Current box has been deleted during GetTableSel()" ); break;
}
rBoxes.clear();
--nLoopMax;
} while( true );
OSL_ENSURE( nLoopMax, "Table layout is still invalid!" );
}
// if table is invisible, return // (layout needed for forming table selection further down, so we can't // continue with invisible tables) // #i22135# - Also the content of the table could be // invisible - e.g. in a hidden section // Robust: check, if content was found (e.g. empty table cells) if ( !pCNd || pCNd->getLayoutFrame( pCNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout() ) == nullptr ) returnfalse;
// #i22135# - Robust: check, if content was found and if it's visible if ( !pCNd || pCNd->getLayoutFrame( pCNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout() ) == nullptr )
{ returnfalse;
}
// all boxes together, do not check the // row, if a formula or value was found
bTstRow = 0 == nWhichId || USHRT_MAX == nWhichId;
bFound = true; break;
}
// all boxes together, do not check the // row if a formula or value was found
bFound = 0 != nWhichId && USHRT_MAX != nWhichId;
bTstRow = false; break;
}
OSL_ENSURE( rPam.GetPointContentNode() && rPam.GetMarkContentNode(), "Tabselection not on Cnt." );
//JP 24.09.96: Merge with repeating TableHeadLines does not work properly. // Why not use point 0,0? Then it is assured the first // headline is contained.
Point aPt( 0, 0 );
if( pUndo )
pUndo->AddNewBox( pBox->GetSttIdx() );
} // is right side of box part of the selected area? elseif( ( pCell->getFrameArea().Right() - COLFUZZY ) < rUnion.Right() &&
( pCell->getFrameArea().Right() - COLFUZZY ) > rUnion.Left() &&
( pCell->getFrameArea().Left() + COLFUZZY ) < rUnion.Left() )
{ // then we should insert a new box and adjust the widths
sal_uInt16 nInsPos = pBox->GetUpper()->GetBoxPos( pBox )+1;
lcl_InsTableBox( pTableNd, rDoc, pBox, nInsPos );
if( pUndo )
pUndo->AddNewBox( pBox->GetSttIdx() );
}
} if ( pCell->GetNext() )
{
pCell = static_cast<const SwLayoutFrame*>(pCell->GetNext()); // --> Check if table cell is not empty if ( pCell->Lower() && pCell->Lower()->IsRowFrame() )
pCell = pCell->FirstCell();
} else
pCell = ::lcl_FindNextCellFrame( pCell );
}
}
pRow = static_cast<const SwLayoutFrame*>(pRow->GetNext());
}
}
// no SSelection / no boxes found if( 1 >= rBoxes.size() ) return;
// now search all horizontally adjacent boxes and connect // their contents with blanks. All vertically adjacent will be tied // together as paragraphs
// 1. Solution: map array and all on same Y-level // are separated with blanks // all others are separated with paragraphs bool bCalcWidth = true; const SwTableBox* pFirstBox = aPosArr[ 0 ].pSelBox;
// JP 27.03.98: Optimise - if boxes on one row are empty, // then do not insert blanks or carriage returns //Block to assure SwPaM, SwPosition are deleted from stack
{
SwPaM aPam( rDoc.GetNodes() );
for( n = 0; n < aPosArr.Count(); ++n )
{ const CmpLPt& rPt = aPosArr[ n ]; if( n && aPosArr[ n - 1 ].Y() == rPt.Y() ) // same Y level?
{ if( bEmptyLine && !IsEmptyBox( *rPt.pSelBox, aPam ))
bEmptyLine = sal_False; if( bCalcWidth )
nWidth += rPt.pSelBox->GetFrameFormat()->GetFrameSize().GetWidth();
} else
{ if( bCalcWidth && n )
bCalcWidth = false; // one line is ready
if( bEmptyLine && nSttPos < n )
{ // now complete line is empty and should not // be filled with blanks and be inserted as paragraph if( pUndo ) for( sal_uInt16 i = nSttPos; i < n; ++i )
pUndo->SaveCollection( *aPosArr[ i ].pSelBox );
aPosArr.Remove( nSttPos, n - nSttPos );
n = nSttPos;
} else
nSttPos = n;
bEmptyLine = IsEmptyBox( *aPosArr[n].pSelBox, aPam );
}
} if( bEmptyLine && nSttPos < n )
{ if( pUndo ) for( sal_uInt16 i = nSttPos; i < n; ++i )
pUndo->SaveCollection( *aPosArr[ i ].pSelBox );
aPosArr.Remove( nSttPos, n - nSttPos );
} #elifdefined( DEL_EMPTY_BOXES_AT_START_AND_END )
for( n = 0; n < aPosArr.Count(); ++n )
{ const CmpLPt& rPt = aPosArr[ n ]; if( n && aPosArr[ n - 1 ].Y() == rPt.Y() ) // same Y level?
{ bool bEmptyBox = IsEmptyBox( *rPt.pSelBox, aPam ); if( bEmptyBox )
{ if( nSEndPos == n ) // beginning is empty
nESttPos = ++nSEndPos;
} else// end could be empty
nESttPos = n+1;
if( bCalcWidth )
nWidth += rPt.pSelBox->GetFrameFormat()->GetFrameSize().GetWidth();
} else
{ if( bCalcWidth && n )
bCalcWidth = false; // one line ready
// first those at the beginning if( nSttPos < nSEndPos )
{ // now the beginning of the line is empty and should // not be filled with blanks if( pUndo ) for( sal_uInt16 i = nSttPos; i < nSEndPos; ++i )
pUndo->SaveCollection( *aPosArr[ i ].pSelBox );
if( nESttPos < n )
{ // now the beginning of the line is empty and should // not be filled with blanks if( pUndo ) for( sal_uInt16 i = nESttPos; i < n; ++i )
pUndo->SaveCollection( *aPosArr[ i ].pSelBox );
sal_uInt16 nCnt = n - nESttPos;
aPosArr.Remove( nESttPos, nCnt );
n -= nCnt;
}
// first those at the beginning if( nSttPos < nSEndPos )
{ // now the beginning of the line is empty and should // not be filled with blanks if( pUndo ) for( sal_uInt16 i = nSttPos; i < nSEndPos; ++i )
pUndo->SaveCollection( *aPosArr[ i ].pSelBox );
sal_uInt16 nCnt = nSEndPos - nSttPos;
aPosArr.Remove( nSttPos, nCnt );
nESttPos -= nCnt;
n -= nCnt;
} if( nESttPos < n )
{ // now the beginning of the line is empty and should // not be filled with blanks if( pUndo ) for( sal_uInt16 i = nESttPos; i < n; ++i )
pUndo->SaveCollection( *aPosArr[ i ].pSelBox );
// the MergeBox should contain the complete text // now erase the initial TextNode
OSL_ENSURE( (*ppMergeBox)->GetSttIdx()+2 <
(*ppMergeBox)->GetSttNd()->EndOfSectionIndex(), "empty box" );
SwNodeIndex aIdx( *(*ppMergeBox)->GetSttNd()->EndOfSectionNode(), -1 );
rDoc.GetNodes().Delete( aIdx );
}
// set width of the box
(*ppMergeBox)->GetFrameFormat()->SetFormatAttr( SwFormatFrameSize( SwFrameSize::Variable, nWidth, 0 )); if( pUndo )
pUndo->AddNewBox( (*ppMergeBox)->GetSttIdx() );
}
TableMergeErr CheckMergeSel( const SwPaM& rPam )
{
SwSelBoxes aBoxes; //JP 24.09.96: Merge with repeating TableHeadLines does not work properly. // Why not use point 0,0? Then it is assured the first // headline is contained.
staticvoid lcl_FindStartEndRow( const SwLayoutFrame *&rpStart, const SwLayoutFrame *&rpEnd, constbool bChkProtected )
{ // Put Start at beginning of a row. // Put End at the end of its row.
rpStart = static_cast<const SwLayoutFrame*>(rpStart->GetUpper()->Lower()); while ( rpEnd->GetNext() )
rpEnd = static_cast<const SwLayoutFrame*>(rpEnd->GetNext());
for( std::deque<const SwLayoutFrame *>::size_type n = 0; n < aEndArr.size() && n < aSttArr.size(); ++n ) if( aSttArr[ n ] != aEndArr[ n ] )
{ // first unequal line or box - all odds are if( n & 1 ) // 1, 3, 5, ... are boxes
{
rpStart = aSttArr[ n ];
rpEnd = aEndArr[ n ];
} else// 0, 2, 4, ... are lines
{ // check if start & end line are the first & last Line of the // box. If not return these cells. // Else the whole line with all Boxes has to be deleted.
rpStart = aSttArr[ n+1 ];
rpEnd = aEndArr[ n+1 ]; if( n )
{ const SwCellFrame* pCellFrame = static_cast<const SwCellFrame*>(aSttArr[ n-1 ]); const SwTableLines& rLns = pCellFrame->
GetTabBox()->GetTabLines(); if( rLns[ 0 ] == static_cast<const SwRowFrame*>(aSttArr[ n ])->GetTabLine() &&
rLns[ rLns.size() - 1 ] == static_cast<const SwRowFrame*>(aEndArr[ n ])->GetTabLine() )
{
rpStart = rpEnd = pCellFrame; while ( rpStart->GetPrev() )
rpStart = static_cast<const SwLayoutFrame*>(rpStart->GetPrev()); while ( rpEnd->GetNext() )
rpEnd = static_cast<const SwLayoutFrame*>(rpEnd->GetNext());
}
}
} break;
}
if( !bChkProtected ) // protected cell ? return;
// Beginning and end should not be in protected cells while ( rpStart->GetFormat()->GetProtect().IsContentProtected() )
rpStart = static_cast<const SwLayoutFrame*>(rpStart->GetNext()); while ( rpEnd->GetFormat()->GetProtect().IsContentProtected() )
rpEnd = static_cast<const SwLayoutFrame*>(rpEnd->GetPrev());
}
staticvoid lcl_FindStartEndCol( const SwLayoutFrame *&rpStart, const SwLayoutFrame *&rpEnd, constbool bChkProtected )
{ // Beginning and end vertical till the border of the table; // Consider the whole table, including master and follows. // In order to start we need the mother-tableFrame if( !rpStart ) return; const SwTabFrame *pOrg = rpStart->FindTabFrame(); const SwTabFrame *pTab = pOrg;
SwFrame const*const pLastContent = pTab->FindLastContentOrTable();
rpEnd = pLastContent ? pLastContent->GetUpper() : nullptr; // --> Made code robust. If pTab does not have a lower, // we would crash here. if ( !pLastContent ) return;
if( !(SwTableSearchType::NoUnionCorrect & eSearchType ))
{ // Unfortunately the union contains rounding errors now, therefore // erroneous results could occur during split/merge. // To prevent these we will determine the first and last row // within the union and use their values for a new union const SwLayoutFrame* pRow = nullptr; if (pTable->IsFollow())
{
SwRowFrame* pRowFrame = pTable->GetFirstNonHeadlineRow(); //tdf#159027: follow returns a frame without height if // merged cells are involved if (pRowFrame->getFrameArea().IsEmpty())
pRowFrame = static_cast<SwRowFrame*>(pRowFrame->GetNext());
pRow = pRowFrame;
} else
pRow = static_cast<const SwLayoutFrame*>(pTable->Lower());
// #i31976# // A follow flow row may contain empty cells. These are not // considered by FirstCell(). Therefore we have to find // the first cell manually: const SwFrame* pTmpCell = nullptr; if ( pTable->IsFollow() && pRow && pRow->IsInFollowFlowRow() )
{ const SwFrame* pTmpRow = pRow; while ( pTmpRow && pTmpRow->IsRowFrame() )
{
pTmpCell = static_cast<const SwRowFrame*>(pTmpRow)->Lower();
pTmpRow = static_cast<const SwCellFrame*>(pTmpCell)->Lower();
}
OSL_ENSURE( !pTmpCell || pTmpCell->IsCellFrame(), "Lower of rowframe != cellframe?!" );
}
// These Classes copy the current table selections (rBoxes), // into a new structure, retaining the table structure // new: SS for targeted erasing/restoring of the layout
staticvoid lcl_InsertRow( SwTableLine const &rLine, SwLayoutFrame *pUpper, SwFrame *pSibling )
{
SwRowFrame *pRow = new SwRowFrame( rLine, pUpper ); if ( pUpper->IsTabFrame() && static_cast<SwTabFrame*>(pUpper)->IsFollow() )
{
SwTabFrame* pTabFrame = static_cast<SwTabFrame*>(pUpper);
pTabFrame->FindMaster()->InvalidatePos(); //can absorb the line
if ( pSibling && pTabFrame->IsInHeadline( *pSibling ) )
{ // Skip any repeated headlines in the follow:
pSibling = pTabFrame->GetFirstNonHeadlineRow();
}
}
pRow->Paste( pUpper, pSibling );
pRow->RegistFlys();
}
void FndBox_::SetTableLines( const SwSelBoxes &rBoxes, const SwTable &rTable )
{ // Set pointers to lines before and after the area to process. // If the first/last lines are contained in the area, then the pointers // are 0. We first search for the positions of the first/last affected // lines in array of the SwTable. In order to use 0 for 'no line' // we adjust the positions by 1.
void FndBox_::SetTableLines( const SwTable &rTable )
{ // Set pointers to lines before and after the area to process. // If the first/last lines are contained in the area, then the pointers // are 0. The positions of the first/last affected lines in the array // of the SwTable are in FndBox. In order to use 0 for 'no line' // we adjust the positions by 1.
if( GetLines().empty() ) return;
SwTableLine* pTmpLine = GetLines().front()->GetLine();
sal_uInt16 nPos = rTable.GetTabLines().GetPos( pTmpLine );
OSL_ENSURE( USHRT_MAX != nPos, "Line is not in table" ); if( nPos )
m_pLineBefore = rTable.GetTabLines()[ nPos - 1 ];
pTmpLine = GetLines().back()->GetLine();
nPos = rTable.GetTabLines().GetPos( pTmpLine );
OSL_ENSURE( USHRT_MAX != nPos, "Line is not in the table" ); if( ++nPos < rTable.GetTabLines().size() )
m_pLineBehind = rTable.GetTabLines()[nPos];
}
void FndBox_::DelFrames( SwTable &rTable )
{ // All lines between pLineBefore and pLineBehind should be cut // from the layout and erased. // If this creates empty Follows we should destroy these. // If a master is destroyed, the follow should become master. // Always a TabFrame should remain.
sal_uInt16 nStPos = 0;
sal_uInt16 nEndPos= rTable.GetTabLines().size() - 1; if( rTable.IsNewModel() && m_pLineBefore )
rTable.CheckRowSpan( m_pLineBefore, true ); if ( m_pLineBefore )
{
nStPos = rTable.GetTabLines().GetPos( const_cast<const SwTableLine*&>(m_pLineBefore) );
OSL_ENSURE( nStPos != USHRT_MAX, "The fox stole the line!" );
++nStPos;
} if( rTable.IsNewModel() && m_pLineBehind )
rTable.CheckRowSpan( m_pLineBehind, false ); if ( m_pLineBehind )
{
nEndPos = rTable.GetTabLines().GetPos( const_cast<const SwTableLine*&>(m_pLineBehind) );
OSL_ENSURE( nEndPos != USHRT_MAX, "The fox stole the line!" ); if (nEndPos != 0)
--nEndPos;
}
for ( sal_uInt16 i = nStPos; i <= nEndPos; ++i)
{
SwFrameFormat *pFormat = rTable.GetTabLines()[i]->GetFrameFormat();
SwIterator<SwRowFrame,SwFormat> aIter( *pFormat ); for ( SwRowFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next() )
{ if ( pFrame->GetTabLine() == rTable.GetTabLines()[i] )
{ bool bDel = true;
SwTabFrame *pUp = !pFrame->GetPrev() && !pFrame->GetNext() ? static_cast<SwTabFrame*>(pFrame->GetUpper()) : nullptr; if ( !pUp )
{ const sal_uInt16 nRepeat = static_cast<SwTabFrame*>(pFrame->GetUpper())->GetTable()->GetRowsToRepeat(); if ( nRepeat > 0 && static_cast<SwTabFrame*>(pFrame->GetUpper())->IsFollow() )
{ if ( !pFrame->GetNext() )
{
SwRowFrame* pFirstNonHeadline = static_cast<SwTabFrame*>(pFrame->GetUpper())->GetFirstNonHeadlineRow(); if ( pFirstNonHeadline == pFrame )
{
pUp = static_cast<SwTabFrame*>(pFrame->GetUpper());
}
}
}
} if ( pUp )
{
SwTabFrame *pFollow = pUp->GetFollow();
SwTabFrame *pPrev = pUp->IsFollow() ? pUp : nullptr; if ( pPrev )
{
SwFrame *pTmp = pPrev->FindPrev();
OSL_ENSURE( pTmp->IsTabFrame(), "Predecessor of Follow is no Master.");
pPrev = static_cast<SwTabFrame*>(pTmp);
} if ( pPrev )
{
pPrev->SetFollow( pFollow ); // #i60340# Do not transfer the // flag from pUp to pPrev. pUp may still have the // flag set although there is not more follow flow // line associated with pUp.
pPrev->SetFollowFlowLine( false );
} elseif ( pFollow )
::UnsetFollow( pFollow );
// A TableFrame should always remain! if ( pPrev || pFollow )
{ // OD 26.08.2003 #i18103# - if table is in a section, // lock the section, to avoid its delete.
{
SwSectionFrame* pSctFrame = pUp->FindSctFrame(); bool bOldSectLock = false; if ( pSctFrame )
{
bOldSectLock = pSctFrame->IsColLocked();
pSctFrame->ColLock();
}
pUp->Cut(); if ( pSctFrame && !bOldSectLock )
{
pSctFrame->ColUnlock();
}
}
SwFrame::DestroyFrame(pUp);
bDel = false; // Row goes to /dev/null.
}
} if ( bDel )
{
SwFrame* pTabFrame = pFrame->GetUpper(); if ( pTabFrame->IsTabFrame() &&
!pFrame->GetNext() && static_cast<SwTabFrame*>(pTabFrame)->GetFollow() )
{ // We do not delete the follow flow line, // this will be done automatically in the // next turn. static_cast<SwTabFrame*>(pTabFrame)->SetFollowFlowLine( false );
}
pFrame->Cut();
SwFrame::DestroyFrame(pFrame);
}
}
}
}
}
void FndBox_::MakeFrames( SwTable &rTable )
{ // All lines between pLineBefore and pLineBehind should be re-generated in layout. // And this for all instances of a table (for example in header/footer).
sal_uInt16 nStPos = 0;
sal_uInt16 nEndPos= rTable.GetTabLines().size() - 1;
SwRootFrame* pLayout =
rTable.GetFrameFormat()->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout(); bool bHideChanges = pLayout && pLayout->IsHideRedlines();
for ( ; i < nMax; ++i )
::lcl_InsertRow( *rTable.GetTabLines()[i], pUpperFrame, pSibling ); if ( pUpperFrame->IsTabFrame() ) static_cast<SwTabFrame*>(pUpperFrame)->SetCalcLowers();
} else// insert before
{
sal_uInt16 i;
// We are looking for the frame that is behind the row frame // that should be inserted. for ( i = 0; !pSibling; ++i )
{
SwTableLine* pLine = m_pLineBefore ? m_pLineBefore : rTable.GetTabLines()[i];
if ( nBfPos == nBhPos ) // Should never occur.
{
OSL_FAIL( "Table, erase but not on any area !?!" ); returnfalse;
}
if ( rTable.GetRowsToRepeat() > 0 )
{ // oops: should the repeated headline have been deleted??
SwIterator<SwTabFrame,SwFormat> aIter( *rTable.GetFrameFormat() ); for( SwTabFrame* pTable = aIter.First(); pTable; pTable = aIter.Next() )
{ if( pTable->IsFollow() )
{ // Insert new headlines:
lcl_UpdateRepeatedHeadlines( *pTable, false );
}
}
}
// Some adjacent lines at the beginning of the table have been deleted: if ( nBfPos == USHRT_MAX && nBhPos == 0 ) returnfalse;
// Some adjacent lines at the end of the table have been deleted: if ( nBhPos == USHRT_MAX && nBfPos == (rTable.GetTabLines().size() - 1) ) returnfalse;
// Some adjacent lines in the middle of the table have been deleted: if ( nBfPos != USHRT_MAX && nBhPos != USHRT_MAX && (nBfPos + 1) == nBhPos ) returnfalse;
// The structure of the deleted lines is more complex due to split lines. // A call of MakeFrames() is necessary. returntrue;
}
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.43Bemerkung:
(vorverarbeitet am 2026-05-06)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.