/* -*- 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 );
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.