/* -*- 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 .
*/
if( pTableNd->GetTable().GetTabLines()[ 0 ] == pTableLn )
{ // Before the Table's first Box while( !( pNxtBox = pLine->GetTabBoxes()[0])->GetTabLines().empty() )
pLine = pNxtBox->GetTabLines()[0];
nIdxPos = pNxtBox->GetSttIdx();
bSetIdxPos = false;
}
} if( bSetIdxPos ) // Tables without content or at the end; move before the End
nIdxPos = pTableNd->EndOfSectionIndex();
} elseif( pNxtBox ) // There is a successor
nIdxPos = pNxtBox->GetSttIdx(); else// There is a predecessor
nIdxPos = pPrvBox->GetSttNd()->EndOfSectionIndex() + 1;
SwNodeIndex aEndIdx( *this, nIdxPos ); for( sal_uInt16 n = 0; n < nCnt; ++n )
{
SwStartNode* pSttNd = new SwStartNode( aEndIdx.GetNode(), SwNodeType::Start,
SwTableBoxStartNode );
pSttNd->m_pStartOfSection = pTableNd; new SwEndNode( aEndIdx.GetNode(), *pSttNd );
pPrvBox = new SwTableBox( pBoxFormat, *pSttNd, pLine );
// Start with inserting the Nodes and get the AutoFormat for the Table
SwTextFormatColl *pBodyColl = getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_TABLE ),
*pHeadColl = pBodyColl;
/* Save content node to extract FRAMEDIR from. */ const SwContentNode * pContentNd = rPos.GetNode().GetContentNode();
/* If we are called from a shell pass the attrset from pContentNd (aka the node the table is inserted at) thus causing SwNodes::InsertTable to propagate an adjust item if
necessary. */
SwTableNode *pTableNd = SwNodes::InsertTable(
rPos.GetNode(),
nCols,
pBodyColl,
nRows,
nRowsToRepeat,
pHeadColl,
bCalledFromShell ? &pContentNd->GetSwAttrSet() : nullptr );
/* If the node to insert the table at is a context node and has a
non-default FRAMEDIR propagate it to the table. */ if (pContentNd)
{ const SwAttrSet & aNdSet = pContentNd->GetSwAttrSet(); if (const SvxFrameDirectionItem* pItem = aNdSet.GetItemIfSet( RES_FRAMEDIR ))
{
pTableFormat->SetFormatAttr( *pItem );
}
}
// Set Orientation at the Table's Format
pTableFormat->SetFormatAttr( SwFormatHoriOrient( 0, eAdjust ) ); // All lines use the left-to-right Fill-Order!
pLineFormat->SetFormatAttr( SwFormatFillOrder( ATT_LEFT_TO_RIGHT ));
// For AutoFormat on input: the columns are set when inserting the Table // The Array contains the columns positions and not their widths! if( pColArr )
{
nWidth = (*pColArr)[ i + 1 ] - (*pColArr)[ i ]; if( pBoxF->GetFrameSize().GetWidth() != nWidth )
{ if( pBoxF->HasWriterListeners() ) // Create new Format
{
SwTableBoxFormat *pNewFormat = MakeTableBoxFormat();
*pNewFormat = *pBoxF;
pBoxF = pNewFormat;
}
pBoxF->SetFormatAttr( SwFormatFrameSize( SwFrameSize::Variable, nWidth ));
}
}
/** * Text to Table
*/ const SwTable* SwDoc::TextToTable( const SwInsertTableOptions& rInsTableOpts, const SwPaM& rRange, sal_Unicode cCh,
sal_Int16 eAdjust, const SwTableAutoFormat* pTAFormat )
{ // See if the selection contains a Table auto [pStart, pEnd] = rRange.StartEnd(); // SwPosition*
{
SwNodeOffset nCnt = pStart->GetNodeIndex(); for( ; nCnt <= pEnd->GetNodeIndex(); ++nCnt ) if( !GetNodes()[ nCnt ]->IsTextNode() ) return nullptr;
}
if (GetIDocumentUndoRedo().DoesUndo())
{
GetIDocumentUndoRedo().StartUndo(SwUndoId::TEXTTOTABLE, nullptr);
}
// tdf#153115 first, remove all redlines; splitting them at cell boundaries // would be tricky to implement, and it's unclear what the value of // existing redlines is once it's been converted to a table
getIDocumentRedlineAccess().AcceptRedline(rRange, true);
// Save first node in the selection if it is a context node
SwContentNode * pSttContentNd = pStart->GetNode().GetContentNode();
// Do not add splitting the TextNode to the Undo history
GetIDocumentUndoRedo().DoUndo( false );
}
::PaMCorrAbs( aOriginal, *pEnd );
// Make sure that the range is on Node Edges
SwNodeRange aRg( pStart->GetNode(), pEnd->GetNode() ); if( pStart->GetContentIndex() )
getIDocumentContentOperations().SplitNode( *pStart, false );
bool bEndContent = 0 != pEnd->GetContentIndex();
// Do not split at the End of a Line (except at the End of the Doc) if( bEndContent )
{ if( pEnd->GetNode().GetContentNode()->Len() != pEnd->GetContentIndex()
|| pEnd->GetNodeIndex() >= GetNodes().GetEndOfContent().GetIndex()-1 )
{
getIDocumentContentOperations().SplitNode( *pEnd, false ); const_cast<SwPosition*>(pEnd)->Adjust(SwNodeOffset(-1)); // A Node and at the End? if( pStart->GetNodeIndex() >= pEnd->GetNodeIndex() )
--aRg.aStart;
} else
++aRg.aEnd;
}
// All Lines have a left-to-right Fill Order
pLineFormat->SetFormatAttr( SwFormatFillOrder( ATT_LEFT_TO_RIGHT )); // The Table's SSize is USHRT_MAX
pTableFormat->SetFormatAttr( SwFormatFrameSize( SwFrameSize::Variable, USHRT_MAX )); if( !(rInsTableOpts.mnInsMode & SwInsertTableFlags::SplitLayout) )
pTableFormat->SetFormatAttr( SwFormatLayoutSplit( false ));
/* If the first node in the selection is a context node and if it has an item FRAMEDIR set (no default) propagate the item to the
replacing table. */ if (pSttContentNd)
{ const SwAttrSet & aNdSet = pSttContentNd->GetSwAttrSet(); if (const SvxFrameDirectionItem *pItem = aNdSet.GetItemIfSet( RES_FRAMEDIR ) )
{
pTableFormat->SetFormatAttr( *pItem );
}
}
//Resolves: tdf#87977, tdf#78599, disable broadcasting modifications //until after RegisterToFormat is completed bool bEnableSetModified = getIDocumentState().IsEnableSetModified();
getIDocumentState().SetEnableSetModified(false);
bool bUseBoxFormat = false; if( !pBoxFormat->HasWriterListeners() )
{ // The Box's Formats already have the right size, we must only set // the right Border/AutoFormat.
bUseBoxFormat = true;
pTableFormat->SetFormatAttr( pBoxFormat->GetFrameSize() ); delete pBoxFormat;
eAdjust = text::HoriOrientation::NONE;
}
// Set Orientation in the Table's Format
pTableFormat->SetFormatAttr( SwFormatHoriOrient( 0, eAdjust ) );
rNdTable.RegisterToFormat(*pTableFormat);
staticvoid lcl_RemoveBreaksTable(SwTableNode & rNode, SwTableFormat *const pTableFormat)
{ // delete old layout frames, new ones need to be created...
rNode.DelFrames(nullptr);
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);
}
}
staticvoid lcl_RemoveBreaks(SwContentNode & rNode, SwTableFormat *const pTableFormat)
{ // delete old layout frames, new ones need to be created...
rNode.DelFrames(nullptr);
/** * balance lines in table, insert empty boxes so all lines have the size
*/ staticvoid
lcl_BalanceTable(SwTable & rTable, size_t const nMaxBoxes,
SwTableNode & rTableNd, SwTableBoxFormat & rBoxFormat, SwTextFormatColl & rTextColl,
SwUndoTextToTable *const pUndo, std::vector<sal_uInt16> *const pPositions)
{ for (size_t n = 0; n < rTable.GetTabLines().size(); ++n)
{
SwTableLine *const pCurrLine = rTable.GetTabLines()[ n ];
size_t const nBoxes = pCurrLine->GetTabBoxes().size(); if (nMaxBoxes != nBoxes)
{
rTableNd.GetNodes().InsBoxen(&rTableNd, pCurrLine, &rBoxFormat, &rTextColl,
nullptr, nBoxes, nMaxBoxes - nBoxes);
if (pUndo)
{ for (size_t i = nBoxes; i < nMaxBoxes; ++i)
{
pUndo->AddFillBox( *pCurrLine->GetTabBoxes()[i] );
}
}
// if the first line is missing boxes, the width array is useless! if (!n && pPositions)
{
pPositions->clear();
}
}
}
}
staticvoid
lcl_SetTableBoxWidths(SwTable & rTable, size_t const nMaxBoxes,
SwTableBoxFormat & rBoxFormat, SwDoc & rDoc,
std::vector<sal_uInt16> *const pPositions)
{ if (pPositions && !pPositions->empty())
{
SwTableLines& rLns = rTable.GetTabLines();
sal_uInt16 nLastPos = 0; for (size_t n = 0; n < pPositions->size(); ++n)
{
SwTableBoxFormat *pNewFormat = rDoc.MakeTableBoxFormat();
pNewFormat->SetFormatAttr(
SwFormatFrameSize(SwFrameSize::Variable, (*pPositions)[n] - nLastPos)); for (size_t nTmpLine = 0; nTmpLine < rLns.size(); ++nTmpLine)
{ // Have to do an Add here, because the BoxFormat // is still needed by the caller
pNewFormat->Add(*rLns[nTmpLine]->GetTabBoxes()[n]);
}
nLastPos = (*pPositions)[ n ];
}
// propagate size upwards from format, so the table gets the right size
SAL_WARN_IF(rBoxFormat.HasWriterListeners(), "sw.core", "who is still registered in the format?");
rBoxFormat.SetFormatAttr( SwFormatFrameSize( SwFrameSize::Variable, nLastPos ));
} else
{
size_t nWidth = nMaxBoxes ? USHRT_MAX / nMaxBoxes : USHRT_MAX;
rBoxFormat.SetFormatAttr(SwFormatFrameSize(SwFrameSize::Variable, nWidth));
}
}
// Get the separator's position from the first Node, in order for the Boxes to be set accordingly
SwTextFrameInfo aFInfo( static_cast<SwTextFrame*>(pTextNd->getLayoutFrame( pTextNd->GetDoc().getIDocumentLayoutAccess().GetCurrentLayout() )) ); if( aFInfo.IsOneLine() ) // only makes sense in this case
{
OUString const& rText(pTextNd->GetText()); for (sal_Int32 nChPos = 0; nChPos < rText.getLength(); ++nChPos)
{ if (rText[nChPos] == cCh)
{ // sw_redlinehide: no idea if this makes any sense...
TextFrameIndex const nPos(aFInfo.GetFrame()->MapModelToView(pTextNd, nChPos));
aPosArr.push_back( o3tl::narrowing<sal_uInt16>(
aFInfo.GetCharPos(nPos+TextFrameIndex(1), false)) );
}
}
// Set the TableNode as StartNode for all TextNodes in the Table const SwNodeIndex aTmpIdx( aCntPos.GetNode(), -1 );
pSttNd = new SwStartNode( aTmpIdx.GetNode(), SwNodeType::Start,
SwTableBoxStartNode ); new SwEndNode( aCntPos.GetNode(), *pSttNd );
pNewNd->m_pStartOfSection = pSttNd;
// Assign Section to the Box
pBox = new SwTableBox( pBoxFormat, *pSttNd, pLine );
pLine->GetTabBoxes().insert( pLine->GetTabBoxes().begin() + nBoxes++, pBox );
} else
{
++nChPos;
}
}
}
// Now for the last substring if( !pContentStore->Empty())
pContentStore->Restore( *pTextNd, pTextNd->GetText().getLength(), pTextNd->GetText().getLength()+1 );
/* Save first node in the selection if it is a content node. */
SwContentNode * pSttContentNd = rFirstRange.begin()->aStart.GetNode().GetContentNode();
boolconst bUndo(GetIDocumentUndoRedo().DoesUndo()); if (bUndo)
{ // Do not add splitting the TextNode to the Undo history
GetIDocumentUndoRedo().DoUndo(false);
}
::PaMCorrAbs( aOriginal, *pEnd );
// make sure that the range is on Node Edges
SwNodeRange aRg( pStart->GetNode(), pEnd->GetNode() ); if( pStart->GetContentIndex() )
getIDocumentContentOperations().SplitNode( *pStart, false );
bool bEndContent = 0 != pEnd->GetContentIndex();
// Do not split at the End of a Line (except at the End of the Doc) if( bEndContent )
{ if( pEnd->GetNode().GetContentNode()->Len() != pEnd->GetContentIndex()
|| pEnd->GetNodeIndex() >= GetNodes().GetEndOfContent().GetIndex()-1 )
{
getIDocumentContentOperations().SplitNode( *pEnd, false );
pEnd->Adjust(SwNodeOffset(-1)); // A Node and at the End? if( pStart->GetNodeIndex() >= pEnd->GetNodeIndex() )
--aRg.aStart;
} else
++aRg.aEnd;
}
{ // TODO: this is not Undo-able - only good enough for file import
IDocumentRedlineAccess & rIDRA(getIDocumentRedlineAccess());
SwNodeIndex const prev(rTableNodes.begin()->begin()->aStart, -1);
SwNodeIndex const* pPrev(&prev); // pPrev could point to non-textnode now for (constauto& rRow : rTableNodes)
{ for (constauto& rCell : rRow)
{
assert(SwNodeIndex(*pPrev, +1) == rCell.aStart);
SwPaM pam(rCell.aStart, 0, *pPrev,
(pPrev->GetNode().IsContentNode())
? pPrev->GetNode().GetContentNode()->Len() : 0);
rIDRA.SplitRedline(pam);
pPrev = &rCell.aEnd;
}
} // another one to break between last cell and node after table
SwPaM pam(pPrev->GetNode(), SwNodeOffset(+1), 0,
pPrev->GetNode(), SwNodeOffset(0),
(pPrev->GetNode().IsContentNode())
? pPrev->GetNode().GetContentNode()->Len() : 0);
rIDRA.SplitRedline(pam);
// Paragraph formatting results in overlapping elements, split of redlines then can result // in an unsorted redline table, fix it up.
SwRedlineTable& rRedlineTable = rIDRA.GetRedlineTable(); if (rRedlineTable.HasOverlappingElements())
{
rIDRA.GetRedlineTable().Resort();
}
}
// We always use Upper to insert the Table
SwNode2LayoutSaveUpperFrames aNode2Layout( aRg.aStart.GetNode() );
// All Lines have a left-to-right Fill Order
pLineFormat->SetFormatAttr( SwFormatFillOrder( ATT_LEFT_TO_RIGHT )); // The Table's SSize is USHRT_MAX
pTableFormat->SetFormatAttr( SwFormatFrameSize( SwFrameSize::Variable, USHRT_MAX ));
/* If the first node in the selection is a context node and if it has an item FRAMEDIR set (no default) propagate the item to the
replacing table. */ if (pSttContentNd)
{ const SwAttrSet & aNdSet = pSttContentNd->GetSwAttrSet(); if (const SvxFrameDirectionItem* pItem = aNdSet.GetItemIfSet( RES_FRAMEDIR ))
{
pTableFormat->SetFormatAttr( *pItem );
}
}
//Resolves: tdf#87977, tdf#78599, disable broadcasting modifications //until after RegisterToFormat is completed bool bEnableSetModified = getIDocumentState().IsEnableSetModified();
getIDocumentState().SetEnableSetModified(false);
if( !pBoxFormat->HasWriterListeners() )
{ // The Box's Formats already have the right size, we must only set // the right Border/AutoFormat.
pTableFormat->SetFormatAttr( pBoxFormat->GetFrameSize() ); delete pBoxFormat;
}
SwTableNode * pTableNd = new SwTableNode( rTableNodes.begin()->begin()->aStart.GetNode() ); //insert the end node after the last text node
SwNodeIndex aInsertIndex( rTableNodes.rbegin()->rbegin()->aEnd );
++aInsertIndex;
//!! ownership will be transferred in c-tor to SwNodes array. //!! Thus no real problem here... new SwEndNode( aInsertIndex.GetNode(), *pTableNd );
/** * Table to Text
*/ bool SwDoc::TableToText( const SwTableNode* pTableNd, sal_Unicode cCh )
{ if( !pTableNd ) returnfalse;
// #i34471# // If this is triggered by SwUndoTableToText::Repeat() nobody ever deleted // the table cursor.
SwEditShell* pESh = GetEditShell(); if (pESh && pESh->IsTableMode())
pESh->ClearMark();
/** * Use the ForEach method from PtrArray to recreate Text from a Table. * The Boxes can also contain Lines!
*/ struct DelTabPara
{
SwTextNode* pLastNd;
SwNodes& rNds;
SwUndoTableToText* pUndo;
sal_Unicode cCh;
// Do not take over the NumberFormatting's adjustment if( pDelPara->pLastNd && pDelPara->pLastNd->HasSwAttrSet() )
pDelPara->pLastNd->ResetAttr( RES_PARATR_ADJUST );
}
}
bool SwNodes::TableToText( const SwNodeRange& rRange, sal_Unicode cCh,
SwUndoTableToText* pUndo )
{ // Is a Table selected? if (rRange.aStart.GetIndex() >= rRange.aEnd.GetIndex()) returnfalse;
SwTableNode *const pTableNd(rRange.aStart.GetNode().GetTableNode()); if (nullptr == pTableNd ||
&rRange.aEnd.GetNode() != pTableNd->EndOfSectionNode() ) returnfalse;
// If the Table was alone in a Section, create the Frames via the Table's Upper
std::optional<SwNode2LayoutSaveUpperFrames> oNode2Layout;
SwNode* pFrameNd = FindPrvNxtFrameNode( rRange.aStart.GetNode(), &rRange.aEnd.GetNode() );
SwNodeIndex aFrameIdx( pFrameNd ? *pFrameNd: rRange.aStart.GetNode() ); if( !pFrameNd ) // Collect all Uppers
oNode2Layout.emplace(*pTableNd);
// Delete the Frames
pTableNd->DelFrames();
// "Delete" the Table and merge all Lines/Boxes
DelTabPara aDelPara( *this, cCh, pUndo ); for( SwTableLine *pLine : pTableNd->m_pTable->GetTabLines() )
lcl_DelLine( pLine, &aDelPara );
// We just created a TextNode with fitting separator for every TableLine. // Now we only need to delete the TableSection and create the Frames for the // new TextNode.
SwNodeRange aDelRg( rRange.aStart, rRange.aEnd );
// If the Table has PageDesc/Break Attributes, carry them over to the // first Text Node
{ // What about UNDO? const SfxItemSet& rTableSet = pTableNd->m_pTable->GetFrameFormat()->GetAttrSet(); const SvxFormatBreakItem* pBreak = rTableSet.GetItemIfSet( RES_BREAK, false ); const SwFormatPageDesc* pDesc = rTableSet.GetItemIfSet( RES_PAGEDESC, false );
// Remove the Cursor from the to-be-deleted Section. // The Cursor is placed after the table, except for // - when there's another Line, we place it in that one // - when a Line precedes it, we place it in that one
{
SwTableNode* pTableNd = rCursor.GetPointNode().FindTableNode();
if( !pNextBox ) // No succeeding Boxes? Then take the preceding one
{
pDelLine = pFndBox->GetLines().front()->GetLine();
pDelBox = pDelLine->GetTabBoxes()[ 0 ]; while( !pDelBox->GetSttNd() )
pDelBox = pDelBox->GetTabLines()[0]->GetTabBoxes()[0];
pNextBox = pDelLine->FindPreviousBox( pTableNd->GetTable(),
pDelBox ); while( pNextBox &&
pNextBox->GetFrameFormat()->GetProtect().IsContentProtected() )
pNextBox = pNextBox->FindPreviousBox( pTableNd->GetTable(), pNextBox );
}
SwNodeOffset nIdx; if( pNextBox ) // Place the Cursor here
nIdx = pNextBox->GetSttIdx() + 1; else// Else after the Table
nIdx = pTableNd->EndOfSectionIndex() + 1;
if( pCNd )
{ // Change the Shell's Cursor or the one passed?
SwPaM* pPam = const_cast<SwPaM*>(static_cast<SwPaM const *>(&rCursor));
pPam->GetPoint()->Assign(aIdx);
pPam->SetMark(); // Both want a part of it
pPam->DeleteMark();
}
}
void SwDoc::DeleteCol( const SwCursor& rCursor )
{ // Find the Boxes via the Layout
SwSelBoxes aBoxes;
GetTableSel( rCursor, aBoxes, SwTableSearchType::Col ); if( ::HasProtectedCells( aBoxes )) return;
// The Cursors need to be removed from the to-be-deleted range. // Always place them after/on top of the Table; they are always set // to the old position via the document position. if (SwEditShell* pESh = GetEditShell())
{ const SwNode* pNd = rCursor.GetPointNode().FindTableBoxStartNode();
pESh->ParkCursor( *pNd );
}
bool bNewTextNd = false; // Is it alone in a FlyFrame?
SwNodeIndex aIdx( *pTableNd, -1 ); const SwStartNode* pSttNd = aIdx.GetNode().GetStartNode(); if (pSttNd)
{ const SwNodeOffset nTableEnd = pTableNd->EndOfSectionIndex() + 1; const SwNodeOffset nSectEnd = pSttNd->EndOfSectionIndex(); if (nTableEnd == nSectEnd)
{ if (SwFlyStartNode == pSttNd->GetStartNodeType())
{
SwFrameFormat* pFormat = pSttNd->GetFlyFormat(); if (pFormat)
{ // That's the FlyFormat we're looking for
getIDocumentLayoutAccess().DelLayoutFormat( pFormat ); return;
}
} // No Fly? Thus Header or Footer: always leave a TextNode // We can forget about Undo then!
bNewTextNd = true;
}
}
// No Fly? Then it is a Header or Footer, so keep always a TextNode
++aIdx; if (GetIDocumentUndoRedo().DoesUndo())
{
GetIDocumentUndoRedo().ClearRedo();
SwPaM aPaM( *pTableNd->EndOfSectionNode(), aIdx.GetNode() );
// Save the cursors (UNO and otherwise)
SwPaM const* pSavePaM(nullptr);
SwPaM forwardPaM(*pTableNd->EndOfSectionNode()); if (forwardPaM.Move(fnMoveForward, GoInNode))
{
pSavePaM = &forwardPaM;
}
SwPaM backwardPaM(*pTableNd); if (backwardPaM.Move(fnMoveBackward, GoInNode))
{ if (pSavePaM == nullptr // try to stay in the same outer table cell
|| (forwardPaM.GetPoint()->GetNode().FindTableNode() != pTableNd->StartOfSectionNode()->FindTableNode()
&& forwardPaM.GetPoint()->GetNode().StartOfSectionIndex()
< backwardPaM.GetPoint()->GetNode().StartOfSectionIndex()))
{
pSavePaM = &backwardPaM;
}
}
assert(pSavePaM); // due to bNewTextNd this must succeed
{
SwPaM const tmpPaM(*pTableNd, *pTableNd->EndOfSectionNode());
::PaMCorrAbs(tmpPaM, *pSavePaM->GetPoint());
}
// Move hard PageBreaks to the succeeding Node bool bSavePageBreak = false, bSavePageDesc = false;
SwNodeOffset nNextNd = pTableNd->EndOfSectionIndex()+1;
SwContentNode* pNextNd = GetNodes()[ nNextNd ]->GetContentNode(); if (pNextNd)
{
SwFrameFormat* pTableFormat = pTableNd->GetTable().GetFrameFormat(); const SfxPoolItem *pItem; if (SfxItemState::SET == pTableFormat->GetItemState(RES_PAGEDESC, false, &pItem))
{
pNextNd->SetAttr( *pItem );
bSavePageDesc = true;
}
// Save the cursors (UNO and otherwise)
SwPaM const* pSavePaM(nullptr);
SwPaM forwardPaM(*pTableNd->EndOfSectionNode()); if (forwardPaM.Move(fnMoveForward, GoInNode))
{
pSavePaM = &forwardPaM;
}
SwPaM backwardPaM(*pTableNd); if (backwardPaM.Move(fnMoveBackward, GoInNode))
{ if (pSavePaM == nullptr // try to stay in the same outer table cell
|| (forwardPaM.GetPoint()->GetNode().FindTableNode() != pTableNd->StartOfSectionNode()->FindTableNode()
&& forwardPaM.GetPoint()->GetNode().StartOfSectionIndex()
< backwardPaM.GetPoint()->GetNode().StartOfSectionIndex()))
{
pSavePaM = &backwardPaM;
}
}
assert(pSavePaM); // due to bNewTextNd this must succeed
{
SwPaM const tmpPaM(*pTableNd, *pTableNd->EndOfSectionNode());
::PaMCorrAbs(tmpPaM, *pSavePaM->GetPoint());
}
// Move hard PageBreaks to the succeeding Node
SwContentNode* pNextNd = GetNodes()[ pTableNd->EndOfSectionIndex()+1 ]->GetContentNode(); if (pNextNd)
{
SwFrameFormat* pTableFormat = pTableNd->GetTable().GetFrameFormat(); const SfxPoolItem *pItem; if (SfxItemState::SET == pTableFormat->GetItemState(RES_PAGEDESC, false, &pItem))
{
pNextNd->SetAttr( *pItem );
}
if (bRet)
{ if (SwFEShell* pFEShell = GetDocShell()->GetFEShell())
{ if (officecfg::Office::Writer::Table::Change::ApplyTableAutoFormat::get())
{
pFEShell->UpdateTableStyleFormatting();
}
}
std::unique_ptr<SwUndoTableMerge> pUndo; if (GetIDocumentUndoRedo().DoesUndo())
pUndo.reset(new SwUndoTableMerge( rPam ));
// Find the Boxes via the Layout
SwSelBoxes aBoxes;
SwSelBoxes aMerged;
SwTableBox* pMergeBox;
if( !rTable.PrepareMerge( rPam, aBoxes, aMerged, &pMergeBox, pUndo.get() ) )
{ // No cells found to merge
getIDocumentRedlineAccess().SetRedlineFlags_intern( eOld ); if( pUndo )
{
pUndo.reset();
SwUndoId nLastUndoId(SwUndoId::EMPTY); if (GetIDocumentUndoRedo().GetLastUndoInfo(nullptr, & nLastUndoId)
&& (SwUndoId::REDLINE == nLastUndoId))
{ // FIXME: why is this horrible cleanup necessary?
SwUndoRedline *const pU = dynamic_cast<SwUndoRedline*>(
GetUndoManager().RemoveLastUndo()); if (pU && pU->GetRedlSaveCount())
{
SwEditShell *const pEditShell(GetEditShell());
assert(pEditShell);
::sw::UndoRedoContext context(*this, *pEditShell); static_cast<SfxUndoAction *>(pU)->UndoWithContext(context);
} delete pU;
}
}
} else
{ // The PaMs need to be removed from the to-be-deleted range. Thus always place // them at the end of/on top of the Table; it's always set to the old position via // the Document Position. // For a start remember an index for the temporary position, because we cannot // access it after GetMergeSel
{
rPam.DeleteMark();
rPam.GetPoint()->Assign(*pMergeBox->GetSttNd());
rPam.SetMark();
rPam.DeleteMark();
SwPaM* pTmp = &rPam; while( &rPam != ( pTmp = pTmp->GetNext() )) for( int i = 0; i < 2; ++i )
pTmp->GetBound( static_cast<bool>(i) ) = *rPam.GetPoint();
if (SwTableCursor* pTableCursor = dynamic_cast<SwTableCursor*>(&rPam))
{ // tdf#135098 update selection so rPam's m_SelectedBoxes is updated // to not contain the soon to-be-deleted SwTableBox so if the rPam // is queried via a11y it doesn't claim the deleted cell still // exists
pTableCursor->NewTableSelection();
}
}
// Merge them
pTableNd->GetTable().SwitchFormulasToInternalRepresentation();
SwTableNode::~SwTableNode()
{ // Notify UNO wrappers
GetTable().GetFrameFormat()->GetNotifier().Broadcast(SfxHint(SfxHintId::Dying));
DelFrames();
m_pTable->SetTableNode(this); // set this so that ~SwDDETable can read it!
m_pTable.reset();
}
/** * Creates all Views from the Document for the preceding Node. The resulting ContentFrames * are added to the corresponding Layout.
*/ void SwTableNode::MakeFramesForAdjacentContentNode(const SwNodeIndex & rIdx)
{ if( !GetTable().GetFrameFormat()->HasWriterListeners()) // Do we actually have Frame? return;
while( nullptr != (pFrame = aNode2Layout.NextFrame()) )
{ if ( ( pFrame->getRootFrame()->HasMergedParas() &&
!pNode->IsCreateFrameWhenHidingRedlines() ) || // tdf#153819 table deletion with change tracking: // table node without frames in Hide Changes mode
!pFrame->GetUpper() )
{ continue;
}
SwFrame *pNew = pNode->MakeFrame( pFrame ); // Will the Node receive Frames before or after? if ( bBefore ) // The new one precedes me
pNew->Paste( pFrame->GetUpper(), pFrame ); else // The new one succeeds me
pNew->Paste( pFrame->GetUpper(), pFrame->GetNext() );
}
}
/** * Create a TableFrame for every Shell and insert before the corresponding ContentFrame.
*/ void SwTableNode::MakeOwnFrames(SwPosition* pIdxBehind)
{
SwNode *pNd = GetNodes().FindPrvNxtFrameNode( *this, EndOfSectionNode() ); if( !pNd )
{ if (pIdxBehind)
pIdxBehind->Assign(*this); return;
} if (pIdxBehind)
pIdxBehind->Assign(*pNd);
void SwTableNode::DelFrames(SwRootFrame const*const pLayout)
{ /* For a start, cut out and delete the TabFrames (which will also delete the Columns and Rows) The TabFrames are attached to the FrameFormat of the SwTable.
We need to delete them in a more cumbersome way, for the Master to also delete the Follows. */
SwIterator<SwTabFrame,SwFormat> aIter( *(m_pTable->GetFrameFormat()) );
SwTabFrame *pFrame = aIter.First(); while ( pFrame )
{ bool bAgain = false;
{ if (!pFrame->IsFollow() && (!pLayout || pLayout == pFrame->getRootFrame()))
{ while ( pFrame->HasFollow() )
pFrame->JoinAndDelFollows(); // #i27138# // notify accessibility paragraphs objects about changed // CONTENT_FLOWS_FROM/_TO relation. // Relation CONTENT_FLOWS_FROM for current next paragraph will change // and relation CONTENT_FLOWS_TO for current previous paragraph will change. #if !ENABLE_WASM_STRIP_ACCESSIBILITY if (!GetDoc().IsInDtor())
{
SwViewShell* pViewShell( pFrame->getRootFrame()->GetCurrShell() ); if ( pViewShell && pViewShell->GetLayout() &&
pViewShell->GetLayout()->IsAnyShellAccessible() )
{ auto pNext = pFrame->FindNextCnt( true ); auto pPrev = pFrame->FindPrevCnt();
pViewShell->InvalidateAccessibleParaFlowRelation(
pNext ? pNext->DynCastTextFrame() : nullptr,
pPrev ? pPrev->DynCastTextFrame() : nullptr );
}
} #endif if (pFrame->GetUpper())
pFrame->Cut();
SwFrame::DestroyFrame(pFrame);
bAgain = true;
}
}
pFrame = bAgain ? aIter.First() : aIter.Next();
}
}
staticbool lcl_IsFrameInColumn( const SwCellFrame& rFrame, SwSelBoxes const & rBoxes )
{ for (size_t i = 0; i < rBoxes.size(); ++i)
{ if ( rFrame.GetTabBox() == rBoxes[ i ] ) returntrue;
}
returnfalse;
}
void SwDoc::GetTabRows( SwTabCols &rFill, const SwCellFrame* pBoxFrame )
{
OSL_ENSURE( pBoxFrame, "GetTabRows called without pBoxFrame" );
// Make code robust: if ( !pBoxFrame ) return;
// #i39552# Collection of the boxes of the current // column has to be done at the beginning of this function, because // the table may be formatted in ::GetTableSel.
SwDeletionChecker aDelCheck( pBoxFrame );
// delete first and last entry
OSL_ENSURE( rFill.Count(), "Deleting from empty vector. Fasten your seatbelts!" ); // #i60818# There may be only one entry in rFill. Make // code robust by checking count of rFill. if ( rFill.Count() ) rFill.Remove( 0 ); if ( rFill.Count() ) rFill.Remove( rFill.Count() - 1 );
rFill.SetLastRowAllowedToChange( !pTab->HasFollowFlowLine() );
}
// If the Table is still using relative values (USHRT_MAX) // we need to switch to absolute ones.
SwTable& rTab = *pTab->GetTable(); const SwFormatFrameSize& rTableFrameSz = rTab.GetFrameFormat()->GetFrameSize();
SwRectFnSet aRectFnSet(pTab); // #i17174# - With fix for #i9040# the shadow size is taken // from the table width. Thus, add its left and right size to current table // printing area width in order to get the correct table size attribute.
SwTwips nPrtWidth = aRectFnSet.GetWidth(pTab->getFramePrintArea());
{
SvxShadowItem aShadow( rTab.GetFrameFormat()->GetShadow() );
nPrtWidth += aShadow.CalcShadowSpace( SvxShadowItemSide::LEFT ) +
aShadow.CalcShadowSpace( SvxShadowItemSide::RIGHT );
} if( nPrtWidth != rTableFrameSz.GetWidth() )
{
SwFormatFrameSize aSz( rTableFrameSz );
aSz.SetWidth( nPrtWidth );
rTab.GetFrameFormat()->SetFormatAttr( aSz );
}
// If the Table is still using relative values (USHRT_MAX) // we need to switch to absolute ones.
SwRectFnSet aRectFnSet(pTab);
SwTabCols aOld( rNew.Count() );
// Set fixed points, LeftMin in Document coordinates, all others relative const SwPageFrame* pPage = pTab->FindPageFrame();
const tools::Long nDiff = nNewRowHeight - nOldRowHeight; if ( std::abs( nDiff ) >= ROWFUZZY )
{ // For the old table model pTextFrame and pLine will be set for every box. // For the new table model pTextFrame will be set if the box is not covered, // but the pLine will be set if the box is not an overlapping box // In the new table model the row height can be adjusted, // when both variables are set. const SwTextFrame* pTextFrame = nullptr; const SwTableLine* pLine = nullptr;
if ( pContent && pContent->IsTextFrame() )
{ const SwTableBox* pBox = static_cast<const SwCellFrame*>(pFrame)->GetTabBox(); const sal_Int32 nRowSpan = pBox->getRowSpan(); if( nRowSpan > 0 ) // Not overlapped
pTextFrame = static_cast<const SwTextFrame*>(pContent); if( nRowSpan < 2 ) // Not overlapping for row height
pLine = pBox->GetUpper(); if( pLine && pTextFrame ) // always for old table model
{ // The new row height must not to be calculated from an overlapping box
SwFormatFrameSize aNew( pLine->GetFrameFormat()->GetFrameSize() ); const tools::Long nNewSize = aRectFnSet.GetHeight(pFrame->getFrameArea()) + nDiff; if( nNewSize != aNew.GetHeight() )
{
aNew.SetHeight( nNewSize ); if ( SwFrameSize::Variable == aNew.GetHeightSizeType() )
aNew.SetHeightSizeType( SwFrameSize::Minimum ); // This position must not be in an overlapped box const SwPosition aPos(*static_cast<const SwTextFrame*>(pContent)->GetTextNodeFirst()); const SwCursor aTmpCursor( aPos, nullptr );
SetRowHeight( aTmpCursor, aNew ); // For the new table model we're done, for the old one // there might be another (sub)row to adjust... if( pTable->IsNewModel() ) break;
}
pLine = nullptr;
}
}
}
}
}
pFrame = pFrame->GetNextLayoutLeaf();
}
}
}
// If the Node is alone in the Section if( SwNodeOffset(2) == pDNd->EndOfSectionIndex() -
pDNd->StartOfSectionIndex() )
{
pSplPara->AddToUndoHistory( *pDNd );
pDNd->ChgFormatColl( pCNd->GetFormatColl() );
}
}
/** * Splits a Table in the top-level Line which contains the Index. * All succeeding top-level Lines go into a new Table/Node. * * @param bCalcNewSize true * Calculate the new Size for both from the * Boxes' Max; but only if Size is using absolute * values (USHRT_MAX)
*/ void SwDoc::SplitTable( const SwPosition& rPos, SplitTable_HeadlineOption eHdlnMode, bool bCalcNewSize )
{
SwNode* pNd = &rPos.GetNode();
SwTableNode* pTNd = pNd->FindTableNode(); if( !pTNd || pNd->IsTableNode() ) return;
switch( eHdlnMode )
{ // Set the lower Border of the preceding Line to // the upper Border of the current one case SplitTable_HeadlineOption::BorderCopy:
{
SwCollectTableLineBoxes aPara( false, eHdlnMode );
SwTableLine* pLn = rTable.GetTabLines()[
rTable.GetTabLines().size() - 1 ]; for( constauto& rpBox : pLn->GetTabBoxes() )
sw_Box_CollectBox(rpBox, &aPara );
// Switch off repeating Header
pNew->GetTable().SetRowsToRepeat( 0 );
} break;
// Take over the Attributes of the first Line to the new one case SplitTable_HeadlineOption::BoxAttrCopy: case SplitTable_HeadlineOption::BoxAttrAllCopy:
{
SwHistory* pHst = nullptr; if( SplitTable_HeadlineOption::BoxAttrAllCopy == eHdlnMode && pUndo )
pHst = pUndo->GetHistory();
case SplitTable_HeadlineOption::NONE: // Switch off repeating the Header
pNew->GetTable().SetRowsToRepeat( 0 ); break;
}
// And insert Frames
pNew->MakeOwnFrames();
// Insert a paragraph between the Table
GetNodes().MakeTextNode( *pNew,
getIDocumentStylePoolAccess().GetTextCollFromPool( RES_POOLCOLL_TEXT ) );
}
// Update Layout
aFndBox.MakeFrames( rTable );
// TL_CHART2: need to inform chart of probably changed cell names
UpdateCharts( rTable.GetFrameFormat()->GetName() );
// update table style formatting of both the tables if (SwFEShell* pFEShell = GetDocShell()->GetFEShell())
{ if (officecfg::Office::Writer::Table::Change::ApplyTableAutoFormat::get())
{
pFEShell->UpdateTableStyleFormatting(pTNd);
pFEShell->UpdateTableStyleFormatting(pNew);
}
}
staticbool lcl_ChgTableSize( SwTable& rTable )
{ // The Attribute must not be set via the Modify or else all Boxes are // set back to 0. // So lock the Format.
SwFrameFormat* pFormat = rTable.GetFrameFormat();
SwFormatFrameSize aTableMaxSz( pFormat->GetFrameSize() );
// pLine now contains the top-level line
sal_uInt16 nLinePos = rTable.GetTabLines().GetPos( pLine ); if( USHRT_MAX == nLinePos ||
( bAfter ? ++nLinePos >= rTable.GetTabLines().size() : !nLinePos )) return nullptr; // Not found or last Line!
// Find the first Box of the succeeding Line
SwTableLine* pNextLine = rTable.GetTabLines()[ nLinePos ];
pBox = pNextLine->GetTabBoxes()[0]; while( !pBox->GetSttNd() )
pBox = pBox->GetTabLines()[0]->GetTabBoxes()[0];
// Insert an EndNode and TableNode into the Nodes Array
SwTableNode * pNewTableNd;
{
SwEndNode* pOldTableEndNd = pTNd->EndOfSectionNode()->GetEndNode();
assert(pOldTableEndNd && "Where is the EndNode?");
new SwEndNode( *pBox->GetSttNd(), *pTNd );
pNewTableNd = new SwTableNode( *pBox->GetSttNd() );
pNewTableNd->GetTable().SetTableModel( rTable.IsNewModel() );
/* From the back (bottom right) to the front (top left) deregister all Boxes from the Chart Data Provider. The Modify event is triggered in the calling function.
TL_CHART2: */
SwChartDataProvider *pPCD = rTable.GetFrameFormat()->getIDocumentChartDataProviderAccess().GetChartDataProvider(); if( pPCD )
{ for (SwTableLines::size_type k = nLinePos; k < rTable.GetTabLines().size(); ++k)
{ const SwTableLines::size_type nLineIdx = (rTable.GetTabLines().size() - 1) - k + nLinePos; const SwTableBoxes::size_type nBoxCnt = rTable.GetTabLines()[ nLineIdx ]->GetTabBoxes().size(); for (SwTableBoxes::size_type j = 0; j < nBoxCnt; ++j)
{ const SwTableBoxes::size_type nIdx = nBoxCnt - 1 - j;
pPCD->DeleteBox( &rTable, *rTable.GetTabLines()[ nLineIdx ]->GetTabBoxes()[nIdx] );
}
}
}
// Calculate a new Size? // lcl_ChgTableSize: Only execute the second call if the first call was // successful, thus has an absolute Size if( bCalcNewSize && lcl_ChgTableSize( rTable ) )
lcl_ChgTableSize( pNewTableNd->GetTable() );
}
// TL_CHART2: need to inform chart of probably changed cell names
rTable.UpdateCharts();
return pNewTableNd; // That's it!
}
/** * rPos needs to be in the Table that remains * * @param bWithPrev merge the current Table with the preceding * or succeeding one
*/ bool SwDoc::MergeTable( const SwPosition& rPos, bool bWithPrev )
{
SwTableNode* pTableNd = rPos.GetNode().FindTableNode(), *pDelTableNd; if( !pTableNd ) returnfalse;
// Delete HTML Layout
pTableNd->GetTable().SetHTMLTableLayout(std::shared_ptr<SwHTMLTableLayout>());
pDelTableNd->GetTable().SetHTMLTableLayout(std::shared_ptr<SwHTMLTableLayout>());
// Both Tables are present; we can start
SwUndoMergeTable* pUndo = nullptr;
std::unique_ptr<SwHistory> pHistory; if (GetIDocumentUndoRedo().DoesUndo())
{
pUndo = new SwUndoMergeTable( *pTableNd, *pDelTableNd, bWithPrev );
GetIDocumentUndoRedo().AppendUndo(std::unique_ptr<SwUndo>(pUndo));
pHistory.reset(new SwHistory);
}
// Adapt all "TableFormulas"
pTableNd->GetTable().Merge(pDelTableNd->GetTable(), pHistory.get());
// The actual merge bool bRet = rNds.MergeTable( bWithPrev ? *pTableNd : *pDelTableNd, !bWithPrev );
// Find Lines for the Layout update
FndBox_ aFndBox( nullptr, nullptr );
aFndBox.SetTableLines( rTable );
aFndBox.DelFrames( rTable );
// TL_CHART2: // tell the charts about the table to be deleted and have them use their own data
GetDoc().getIDocumentChartDataProviderAccess().CreateChartInternalDataProviders( &rDelTable );
if( !bWithPrev )
{ // Transfer all Attributes of the succeeding Table to the preceding one // We do this, because the succeeding one is deleted when deleting the Node
rTable.SetRowsToRepeat( rDelTable.GetRowsToRepeat() );
rTable.SetTableChgMode( rDelTable.GetTableChgMode() );
rTable.GetFrameFormat()->LockModify();
*rTable.GetFrameFormat() = *rDelTable.GetFrameFormat(); // Also switch the Name
rTable.GetFrameFormat()->SetFormatName( rDelTable.GetFrameFormat()->GetName() );
rTable.GetFrameFormat()->UnlockModify();
}
// Move the Lines and Boxes
SwTableLines::size_type nOldSize = rTable.GetTabLines().size();
rTable.GetTabLines().insert( rTable.GetTabLines().begin() + nOldSize,
rDelTable.GetTabLines().begin(), rDelTable.GetTabLines().end() );
rDelTable.GetTabLines().clear();
// The preceding Table always remains, while the succeeding one is deleted
SwEndNode* pTableEndNd = pDelTableNd->EndOfSectionNode();
pTableNd->m_pEndOfSection = pTableEndNd;
SwNodeIndex aIdx( *pDelTableNd, 1 );
SwNode* pBoxNd = aIdx.GetNode().GetStartNode(); do {
OSL_ENSURE( pBoxNd->IsStartNode(), "This needs to be a StartNode!" );
pBoxNd->m_pStartOfSection = pTableNd;
pBoxNd = (*this)[ pBoxNd->EndOfSectionIndex() + 1 ];
} while( pBoxNd != pTableEndNd );
pBoxNd->m_pStartOfSection = pTableNd;
// tweak the conditional styles at the first inserted Line const SwTableLine* pFirstLn = rTable.GetTabLines()[ nOldSize ];
sw_LineSetHeadCondColl( pFirstLn );
// Forward declare so that the Lines and Boxes can use recursion staticbool lcl_SetAFormatBox(FndBox_ &, SetAFormatTabPara *pSetPara, bool bResetDirect); staticbool lcl_SetAFormatLine(FndLine_ &, SetAFormatTabPara *pPara, bool bResetDirect);
if (rBox.GetBox()->GetSttNd())
{
SwTableBox* pSetBox = rBox.GetBox(); if (!pSetBox->HasDirectFormatting() || bResetDirect)
{ if (bResetDirect)
pSetBox->SetDirectFormatting(false);
if (aCharSet.Count())
{
SwNodeOffset nSttNd = pSetBox->GetSttIdx()+1;
SwNodeOffset nEndNd = pSetBox->GetSttNd()->EndOfSectionIndex(); for (; nSttNd < nEndNd; ++nSttNd)
{
SwContentNode* pNd = rDoc.GetNodes()[ nSttNd ]->GetContentNode(); if (pNd)
pNd->SetAttr(aCharSet);
}
}
if (aBoxSet.Count())
{ if (pSetPara->pUndo && SfxItemState::SET == aBoxSet.GetItemState(RES_BOXATR_FORMAT))
pSetPara->pUndo->SaveBoxContent( *pSetBox );
pSetBox->ClaimFrameFormat()->SetFormatAttr(aBoxSet);
}
}
} else
{ // Not sure how this situation can occur, but apparently we have some kind of table in table. // I am guessing at how to best handle singlerow in this situation. constbool bOrigSingleRowTable = pSetPara->bSingleRowTable;
pSetPara->bSingleRowTable = rBox.GetLines().size() == 1; for (autoconst& rpFndLine : rBox.GetLines())
{
lcl_SetAFormatLine(*rpFndLine, pSetPara, bResetDirect);
}
pSetPara->bSingleRowTable = bOrigSingleRowTable;
}
if (!rBox.GetUpper()->GetUpper()) // a BaseLine
++pSetPara->nCurBox; returntrue;
}
// if the user forced a number format in this cell previously, // keep it, unless the user set that she wants the full number // format recognition if( pNumFormatItem && !bForceNumberFormat )
{
sal_uLong nOldNumFormat = pNumFormatItem->GetValue();
SvNumberFormatter* pNumFormatr = GetNumberFormatter();
SvNumFormatType nFormatType = pNumFormatr->GetType( nFormatIdx ); if( nFormatType == pNumFormatr->GetType( nOldNumFormat ) || SvNumFormatType::NUMBER == nFormatType )
{ // Current and specified NumFormat match // -> keep old Format
nFormatIdx = nOldNumFormat;
bSetNumberFormat = true;
} else
{ // Current and specified NumFormat do not match // -> insert as Text
bLockModify = bSetNumberFormat = false;
}
}
// It's not enough to only reset the Formula. // Make sure that the Text is formatted accordingly if( !bSetNumberFormat && !bIsEmptyTextNd && pNumFormatItem )
{ // Just resetting Attributes is not enough // Make sure that the Text is formatted accordingly
pBoxFormat->SetFormatAttr( *GetDfltAttr( RES_BOXATR_FORMAT ));
}
// Remove all number formats
sal_uInt16 nWhich1 = RES_BOXATR_FORMULA; if( !bIsEmptyTextNd )
{
nWhich1 = RES_BOXATR_FORMAT;
// Just resetting Attributes is not enough // Make sure that the Text is formatted accordingly
pBoxFormat->SetFormatAttr( *GetDfltAttr( nWhich1 ));
}
pBoxFormat->ResetFormatAttr( nWhich1, RES_BOXATR_VALUE );
} else
bChgd = false;
}
// Keep TextFormats!
sal_uInt16 nWhich1 = RES_BOXATR_FORMAT; if( GetNumberFormatter()->IsTextFormat(
pFormatItem->GetValue() ))
nWhich1 = RES_BOXATR_FORMULA; else // Just resetting Attributes is not enough // Make sure that the Text is formatted accordingly
pBoxFormat->SetFormatAttr( *GetDfltAttr( RES_BOXATR_FORMAT ));
/** * Copies a Table from the same or another Doc into itself * We create a new Table or an existing one is filled with the Content. * We either fill in the Content from a certain Box or a certain TableSelection * * This method is called by edglss.cxx/fecopy.cxx
*/ bool SwDoc::InsCopyOfTable( SwPosition& rInsPos, const SwSelBoxes& rBoxes, const SwTable* pCpyTable, bool bCpyName, bool bCorrPos, const TableStyleName& rStyleName )
{ bool bRet;
// no complex into complex, but copy into or from new model is welcome if( ( !pSrcTableNd->GetTable().IsTableComplex() || pInsTableNd->GetTable().IsNewModel() )
&& ( bDelCpyDoc || !rBoxes.empty() ) )
{ // Copy the Table "relatively" const SwSelBoxes* pBoxes;
SwSelBoxes aBoxes;
if( bDelCpyDoc )
{
SwTableBox* pBox = pInsTableNd->GetTable().GetTableBox(
pSttNd->GetIndex() );
OSL_ENSURE( pBox, "Box is not in this Table" );
aBoxes.insert( pBox );
pBoxes = &aBoxes;
} else
pBoxes = &rBoxes;
if( pUndo )
{ // If the Table could not be copied, delete the Undo object
GetIDocumentUndoRedo().DoUndo(bUndo); if( bRet || !pUndo->IsEmpty() )
{
GetIDocumentUndoRedo().AppendUndo(std::move(pUndo));
}
}
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.