/* -*- 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 .
*/
void DelBoxNode( SwTableSortBoxes const & rSortCntBoxes )
{ for (size_t n = 0; n < rSortCntBoxes.size(); ++n)
{
rSortCntBoxes[ n ]->m_pStartNode = nullptr;
}
}
SwTable::~SwTable()
{ if( m_xRefObj.is() )
{
SwDoc& rDoc = GetFrameFormat()->GetDoc(); if( !rDoc.IsInDtor() ) // then remove from the list
rDoc.getIDocumentLinksAdministration().GetLinkManager().RemoveServer( m_xRefObj.get() );
m_xRefObj->Closed();
}
// the table can be deleted if it's the last client of the FrameFormat
SwTableFormat* pFormat = GetFrameFormat();
pFormat->Remove(*this); // remove
if( !pFormat->HasWriterListeners() )
pFormat->GetDoc().DelTableFrameFormat( pFormat ); // and delete
// Delete the pointers from the SortArray of the boxes. The objects // are preserved and are deleted by the lines/boxes arrays dtor. // Note: unfortunately not enough, pointers to the StartNode of the // section need deletion.
DelBoxNode(m_TabSortContentBoxes);
m_TabSortContentBoxes.clear();
}
// The value for the left edge of the box is calculated from the // widths of the previous boxes.
tools::Long nPos = 0;
tools::Long nLeftMin = 0;
tools::Long nRightMax = 0; if (nWish != 0) //fdo#33012 0 width frmfmt
{
SwTwips nSum = 0; const SwTableBox *pCur = pBox; const SwTableLine *pLine = pBox->GetUpper(); const tools::Long nAct = rToFill.GetRight() - rToFill.GetLeft(); // +1 why?
while ( pLine )
{ const SwTableBoxes &rBoxes = pLine->GetTabBoxes(); for ( size_t i = 0; i < rBoxes.size(); ++i )
{ const SwTwips nWidth = rBoxes[i]->GetFrameFormat()->GetFrameSize().GetWidth();
nSum += nWidth; const tools::Long nTmp = lcl_MulDiv64<tools::Long>(nSum, nAct, nWish);
void SwTable::GetTabCols( SwTabCols &rToFill, const SwTableBox *pStart, bool bRefreshHidden, bool bCurRowOnly ) const
{ // Optimization: if bHidden is set, we only update the Hidden Array. if ( bRefreshHidden )
{ // remove corrections for ( size_t i = 0; i < rToFill.Count(); ++i )
{
SwTabColsEntry& rEntry = rToFill.GetEntry( i );
rEntry.nPos -= rToFill.GetLeft();
rEntry.nMin -= rToFill.GetLeft();
rEntry.nMax -= rToFill.GetLeft();
}
// All are hidden, so add the visible ones. for ( size_t i = 0; i < rToFill.Count(); ++i )
rToFill.SetHidden( i, true );
} else
{
rToFill.Remove( 0, rToFill.Count() );
}
// Insertion cases: // 1. All boxes which are inferior to Line which is superior to the Start, // as well as their inferior boxes if present. // 2. Starting from the Line, the superior box plus its neighbours; but no inferiors. // 3. Apply 2. to the Line superior to the chain of boxes, // until the Line's superior is not a box but the table. // Only those boxes are inserted that don't contain further rows. The insertion // function takes care to avoid duplicates. In order to achieve this, we work // with some degree of fuzzyness (to avoid rounding errors). // Only the left edge of the boxes are inserted. // Finally, the first entry is removed again, because it's already // covered by the border. // 4. Scan the table again and insert _all_ boxes, this time as hidden.
for ( size_t i = 0; i < rBoxes.size(); ++i )
::lcl_ProcessBoxGet( rBoxes[i], rToFill, pTabFormat, bRefreshHidden );
// 2. and 3. const SwTableLine *pLine = pStart->GetUpper()->GetUpper() ?
pStart->GetUpper()->GetUpper()->GetUpper() : nullptr; while ( pLine )
{ const SwTableBoxes &rBoxes2 = pLine->GetTabBoxes(); for ( size_t k = 0; k < rBoxes2.size(); ++k )
::lcl_SortedTabColInsert( rToFill, rBoxes2[k],
pTabFormat, false, bRefreshHidden );
pLine = pLine->GetUpper() ? pLine->GetUpper()->GetUpper() : nullptr;
}
if ( !bRefreshHidden )
{ // 4. if ( !bCurRowOnly )
{ for ( size_t i = 0; i < m_aLines.size(); ++i )
::lcl_ProcessLineGet( m_aLines[i], rToFill, pTabFormat );
}
rToFill.Remove( 0 );
}
// Now the coordinates are relative to the left table border - i.e. // relative to SwTabCols.nLeft. However, they are expected // relative to the left document border, i.e. SwTabCols.nLeftMin. // So all values need to be extended by nLeft. for ( size_t i = 0; i < rToFill.Count(); ++i )
{
SwTabColsEntry& rEntry = rToFill.GetEntry( i );
rEntry.nPos += rToFill.GetLeft();
rEntry.nMin += rToFill.GetLeft();
rEntry.nMax += rToFill.GetLeft();
}
}
staticvoid lcl_ProcessLine( SwTableLine *pLine, Parm &rParm )
{
SwTableBoxes &rBoxes = pLine->GetTabBoxes(); for ( size_t i = rBoxes.size(); i > 0; )
{
--i;
::lcl_ProcessBoxSet( rBoxes[i], rParm );
}
}
staticvoid lcl_ProcessBoxSet( SwTableBox *pBox, Parm &rParm )
{ if ( !pBox->GetTabLines().empty() )
{
SwTableLines &rLines = pBox->GetTabLines(); for ( size_t i = rLines.size(); i > 0; )
{
--i;
lcl_ProcessLine( rLines[i], rParm );
}
} else
{ // Search the old TabCols for the current position (calculate from // left and right edge). Adjust the box if the values differ from // the new TabCols. If the adjusted edge has no neighbour we also // adjust all superior boxes.
// The value for the left edge of the box is calculated from the // widths of the previous boxes plus the left edge.
tools::Long nLeft = rParm.rOld.GetLeft(); const SwTableBox *pCur = pBox; const SwTableLine *pLine = pBox->GetUpper();
while ( pLine )
{ const SwTableBoxes &rBoxes = pLine->GetTabBoxes(); for ( size_t i = 0; (i < rBoxes.size()) && (rBoxes[i] != pCur); ++i)
{
nLeft += lcl_MulDiv64<tools::Long>(
rBoxes[i]->GetFrameFormat()->GetFrameSize().GetWidth(),
nOldAct, rParm.nOldWish);
}
pCur = pLine->GetUpper();
pLine = pCur ? pCur->GetUpper() : nullptr;
}
tools::Long nLeftDiff = 0;
tools::Long nRightDiff = 0; if ( nLeft != rParm.rOld.GetLeft() ) // There are still boxes before this.
{ // Right edge is left edge plus width. const tools::Long nWidth = lcl_MulDiv64<tools::Long>(
pBox->GetFrameFormat()->GetFrameSize().GetWidth(),
nOldAct, rParm.nOldWish); const tools::Long nRight = nLeft + nWidth;
size_t nLeftPos = 0;
size_t nRightPos = 0; bool bFoundLeftPos = false; bool bFoundRightPos = false; for ( size_t i = 0; i < rParm.rOld.Count(); ++i )
{ if ( nLeft >= (rParm.rOld[i] - COLFUZZY) &&
nLeft <= (rParm.rOld[i] + COLFUZZY) )
{
nLeftPos = i;
bFoundLeftPos = true;
} elseif ( nRight >= (rParm.rOld[i] - COLFUZZY) &&
nRight <= (rParm.rOld[i] + COLFUZZY) )
{
nRightPos = i;
bFoundRightPos = true;
}
}
nLeftDiff = bFoundLeftPos ?
rParm.rOld[nLeftPos] - rParm.rNew[nLeftPos] : 0;
nRightDiff= bFoundRightPos ?
rParm.rNew[nRightPos] - rParm.rOld[nRightPos] : 0;
} else// The first box.
{
nLeftDiff = rParm.rOld.GetLeft() - rParm.rNew.GetLeft(); if ( rParm.rOld.Count() )
{ // Calculate the difference to the edge touching the first box. const tools::Long nWidth = lcl_MulDiv64<tools::Long>(
pBox->GetFrameFormat()->GetFrameSize().GetWidth(),
nOldAct, rParm.nOldWish); const tools::Long nTmp = nWidth + rParm.rOld.GetLeft(); for ( size_t i = 0; i < rParm.rOld.Count(); ++i )
{ if ( nTmp >= (rParm.rOld[i] - COLFUZZY) &&
nTmp <= (rParm.rOld[i] + COLFUZZY) )
{
nRightDiff = rParm.rNew[i] - rParm.rOld[i]; break;
}
}
}
}
if ( nLeftDiff || nRightDiff )
{ // The difference is the actual difference amount. For stretched // tables, it does not make sense to adjust the attributes of the // boxes by this amount. The difference amount needs to be converted // accordingly.
tools::Long nTmp = rParm.rNew.GetRight() - rParm.rNew.GetLeft(); // +1 why?
nLeftDiff *= rParm.nNewWish;
nLeftDiff /= nTmp;
nRightDiff *= rParm.nNewWish;
nRightDiff /= nTmp;
tools::Long nDiff = nLeftDiff + nRightDiff;
// Adjust the box and all superiors by the difference amount. while ( pBox )
{
SwFormatFrameSize aFormatFrameSize( pBox->GetFrameFormat()->GetFrameSize() );
aFormatFrameSize.SetWidth( aFormatFrameSize.GetWidth() + nDiff ); if ( aFormatFrameSize.GetWidth() < 0 )
aFormatFrameSize.SetWidth( -aFormatFrameSize.GetWidth() );
rParm.aShareFormats.SetSize( *pBox, aFormatFrameSize );
// The outer cells of the last row are responsible to adjust a surrounding cell. // Last line check: if ( pBox->GetUpper()->GetUpper() &&
pBox->GetUpper() != pBox->GetUpper()->GetUpper()->GetTabLines().back())
{
pBox = nullptr;
} else
{ // Middle cell check: if ( pBox != pBox->GetUpper()->GetTabBoxes().front() )
nDiff = nRightDiff;
if ( pBox != pBox->GetUpper()->GetTabBoxes().back() )
nDiff -= nRightDiff;
// FME: Made rOld const. The caller is responsible for passing correct // values of rOld. Therefore we do not have to call GetTabCols anymore: //GetTabCols( rOld, pStart );
Parm aParm( rNew, rOld );
OSL_ENSURE( rOld.Count() == rNew.Count(), "Number of columns changed.");
// Convert the edges. We need to adjust the size of the table and some boxes. // For the size adjustment, we must not make use of the Modify, since that'd // adjust all boxes, which we really don't want.
SwFrameFormat *pFormat = GetFrameFormat();
aParm.nOldWish = aParm.nNewWish = pFormat->GetFrameSize().GetWidth(); if ( (rOld.GetLeft() != rNew.GetLeft()) ||
(rOld.GetRight()!= rNew.GetRight()) )
{
LockModify();
{
SvxLRSpaceItem aLR( pFormat->GetLRSpace() );
SvxShadowItem aSh( pFormat->GetShadow() );
// Adjust the size of the table, watch out for stretched tables. if ( nTabDiff )
{
aParm.nNewWish += nTabDiff; if ( aParm.nNewWish < 0 )
aParm.nNewWish = USHRT_MAX; // Oops! Have to roll back.
SwFormatFrameSize aSz( pFormat->GetFrameSize() ); if ( aSz.GetWidth() != aParm.nNewWish )
{
aSz.SetWidth( aParm.nNewWish );
aSz.SetWidthPercent( 0 );
pFormat->SetFormatAttr( aSz );
}
}
UnlockModify();
}
if( IsNewModel() )
NewSetTabCols( aParm, rNew, rOld, pStart, bCurRowOnly ); else
{ if ( bCurRowOnly )
{ // To adjust the current row, we need to process all its boxes, // similar to the filling of the TabCols (see GetTabCols()). // Unfortunately we again have to take care to adjust the boxes // from back to front, respectively from outer to inner. // The best way to achieve this is probably to track the boxes // in a PtrArray. const SwTableBoxes &rBoxes = pStart->GetUpper()->GetTabBoxes(); for ( size_t i = 0; i < rBoxes.size(); ++i )
::lcl_ProcessBoxPtr( rBoxes[i], aParm.aBoxArr, false );
const SwTableLine *pLine = pStart->GetUpper()->GetUpper() ?
pStart->GetUpper()->GetUpper()->GetUpper() : nullptr; const SwTableBox *pExcl = pStart->GetUpper()->GetUpper(); while ( pLine )
{ const SwTableBoxes &rBoxes2 = pLine->GetTabBoxes(); bool bBefore = true; for ( size_t i = 0; i < rBoxes2.size(); ++i )
{ if ( rBoxes2[i] != pExcl )
::lcl_ProcessBoxPtr( rBoxes2[i], aParm.aBoxArr, bBefore ); else
bBefore = false;
}
pExcl = pLine->GetUpper();
pLine = pLine->GetUpper() ? pLine->GetUpper()->GetUpper() : nullptr;
} // After we've inserted a bunch of boxes (hopefully all and in // correct order), we just need to process them in reverse order. for ( int j = aParm.aBoxArr.size()-1; j >= 0; --j )
{
SwTableBox *pBox = aParm.aBoxArr[j];
::lcl_ProcessBoxSet( pBox, aParm );
}
} else
{ // Adjusting the entire table is 'easy'. All boxes without lines are // adjusted, as are their superiors. Of course we need to process // in reverse order to prevent fooling ourselves!
SwTableLines &rLines = GetTabLines(); for ( size_t i = rLines.size(); i > 0; )
{
--i;
::lcl_ProcessLine( rLines[i], aParm );
}
}
}
// check if the box found has any contents if( pBox && !pBox->GetSttNd() )
{
OSL_FAIL( "Box without content, looking for the next one!" ); // "drop this" until the first box while( !pBox->GetTabLines().empty() )
pBox = pBox->GetTabLines().front()->GetTabBoxes().front();
} return pBox;
}
SwTableBox* SwTable::GetTableBox( SwNodeOffset nSttIdx )
{ // For optimizations, don't always process the entire SortArray. // Converting text to table, tries certain conditions // to ask for a table box of a table that is not yet having a format if(!GetFrameFormat()) return nullptr;
SwTableBox* pRet = nullptr;
SwNodes& rNds = GetFrameFormat()->GetDoc().GetNodes();
SwNodeOffset nIndex = nSttIdx + 1;
SwContentNode* pCNd = nullptr;
SwTableNode* pTableNd = nullptr;
while ( nIndex < rNds.Count() )
{
pTableNd = rNds[ nIndex ]->GetTableNode(); if ( pTableNd ) break;
pCNd = rNds[ nIndex ]->GetContentNode(); if ( pCNd ) break;
++nIndex;
}
if ( pCNd || pTableNd )
{
sw::BroadcastingModify* pModify = pCNd; // #144862# Better handling of table in table if ( pTableNd && pTableNd->GetTable().GetFrameFormat() )
pModify = pTableNd->GetTable().GetFrameFormat();
SwFrame* pFrame = pModify ? SwIterator<SwFrame,sw::BroadcastingModify>(*pModify).First() : nullptr; while ( pFrame && !pFrame->IsCellFrame() )
pFrame = pFrame->GetUpper(); if ( pFrame )
pRet = const_cast<SwTableBox*>(static_cast<SwCellFrame*>(pFrame)->GetTabBox());
}
// In case the layout doesn't exist yet or anything else goes wrong. if ( !pRet )
{ for (size_t n = m_TabSortContentBoxes.size(); n; )
{ if (m_TabSortContentBoxes[ --n ]->GetSttIdx() == nSttIdx)
{ return m_TabSortContentBoxes[ n ];
}
}
} return pRet;
}
bool SwTable::IsTableComplex() const
{ // Returns true for complex tables, i.e. tables that contain nestings, // like containing boxes not part of the first line, e.g. results of // splits/merges which lead to more complex structures. for (size_t n = 0; n < m_TabSortContentBoxes.size(); ++n)
{ if (m_TabSortContentBoxes[ n ]->GetUpper()->GetUpper())
{ returntrue;
}
} returnfalse;
}
SwTableLine::~SwTableLine()
{ for (size_t i = 0; i < m_aBoxes.size(); ++i)
{ delete m_aBoxes[i];
} // the TabelleLine can be deleted if it's the last client of the FrameFormat
sw::BroadcastingModify* pMod = GetFrameFormat();
pMod->Remove(*this); // remove, if( !pMod->HasWriterListeners() ) delete pMod; // and delete
}
SwTableLineFormat* SwTableLine::ClaimFrameFormat()
{ // This method makes sure that this object is an exclusive SwTableLine client // of an SwTableLineFormat object // If other SwTableLine objects currently listen to the same SwTableLineFormat as // this one, something needs to be done
SwTableLineFormat *pRet = GetFrameFormat();
SwIterator<SwTableLine,SwFormat> aIter( *pRet ); for( SwTableLine* pLast = aIter.First(); pLast; pLast = aIter.Next() )
{ if ( pLast != this )
{ // found another SwTableLine that is a client of the current Format // create a new Format as a copy and use it for this object
SwTableLineFormat *pNewFormat = pRet->GetDoc().MakeTableLineFormat();
*pNewFormat = *pRet;
// register SwRowFrames that know me as clients at the new Format
SwIterator<SwRowFrame,SwFormat> aFrameIter( *pRet ); for( SwRowFrame* pFrame = aFrameIter.First(); pFrame; pFrame = aFrameIter.Next() ) if( pFrame->GetTabLine() == this )
pFrame->RegisterToFormat( *pNewFormat );
// register myself
pNewFormat->Add(*this);
pRet = pNewFormat; break;
}
}
SwTwips SwTableLine::GetTableLineHeight( bool& bLayoutAvailable ) const
{
SwTwips nRet = 0;
bLayoutAvailable = false;
SwIterator<SwRowFrame,SwFormat> aIter( *GetFrameFormat() ); // A row could appear several times in headers/footers so only one chain of master/follow tables // will be accepted... const SwTabFrame* pChain = nullptr; // My chain for( SwRowFrame* pLast = aIter.First(); pLast; pLast = aIter.Next() )
{ if (pLast->GetTabLine() != this) continue;
const SwTabFrame* pTab = pLast->FindTabFrame(); if (!pTab) continue;
// The first one defines the chain, if a chain is defined, only members of the chain // will be added. if (!pChain || pChain->IsAnFollow( pTab ) || pTab->IsAnFollow(pChain))
{
pChain = pTab; // defines my chain (even it is already) if( pTab->IsVertical() )
nRet += pLast->getFrameArea().Width(); else
nRet += pLast->getFrameArea().Height(); // Optimization, if there are no master/follows in my chain, nothing more to add if( !pTab->HasFollow() && !pTab->IsFollow() ) break; // This is not an optimization, this is necessary to avoid double additions of // repeating rows if( pTab->IsInHeadline(*pLast) ) break;
}
} return nRet;
}
bool SwTableLine::IsEmpty() const
{ for (size_t i = 0; i < m_aBoxes.size(); ++i)
{ if ( !m_aBoxes[i]->IsEmpty() ) returnfalse;
} returntrue;
}
bool SwTable::IsEmpty() const
{ for (size_t i = 0; i < m_aLines.size(); ++i)
{ if ( !m_aLines[i]->IsEmpty() ) returnfalse;
} returntrue;
}
SwRedlineTable::size_type nRedlinePos = 0; for (size_t i = 0; i < m_aLines.size(); ++i)
{ // has a deleted row if ( m_aLines[i]->IsDeleted(nRedlinePos) ) returntrue;
// has a deleted cell in the not deleted row
SwTableBoxes& rBoxes = m_aLines[i]->GetTabBoxes(); for( size_t j = 0; j < rBoxes.size(); ++j )
{ if ( RedlineType::Delete == rBoxes[j]->GetRedlineType() ) returntrue;
}
} returnfalse;
}
void SwTable::UpdateFields(TableFormulaUpdateFlags eFlags)
{
SwDoc& rDoc = GetFrameFormat()->GetDoc(); auto pFieldType = rDoc.getIDocumentFieldsAccess().GetFieldType(SwFieldIds::Table, OUString(), false); if(!pFieldType) return;
std::vector<SwFormatField*> vFields;
pFieldType->GatherFields(vFields); for(auto pFormatField : vFields)
{
SwTableField* pField = static_cast<SwTableField*>(pFormatField->GetField()); // table where this field is located const SwTableNode* pTableNd; const SwTextNode& rTextNd = pFormatField->GetTextField()->GetTextNode();
pTableNd = rTextNd.FindTableNode(); if(pTableNd == nullptr || &pTableNd->GetTable() != this) continue;
switch(eFlags)
{ case TBL_BOXNAME: // to the external representation
pField->PtrToBoxNm(this); break; case TBL_RELBOXNAME: // to the relative representation
pField->ToRelBoxNm(this); break; case TBL_BOXPTR: // to the internal representation // JP 17.06.96: internal representation on all formulas // (reference to other table!!!)
pField->BoxNmToPtr( &pTableNd->GetTable() ); break; default:
assert(false); // Only TBL_BOXNAME, TBL_RELBOXNAME and TBL_BOXPTR are supported break;
}
}
// process all table box formulas
SwTableLines& rTableLines = GetTabLines(); for (SwTableLine* pTableLine : rTableLines)
{
SwTableBoxes& rTableBoxes = pTableLine->GetTabBoxes(); for (SwTableBox* pTableBox : rTableBoxes)
{
SwTableBoxFormat* pTableBoxFormat = pTableBox->GetFrameFormat(); if (const SwTableBoxFormula* pItem = pTableBoxFormat->GetItemIfSet( RES_BOXATR_FORMULA, false ))
{ // SwTableBoxFormula is non-shareable, so const_cast is somewhat OK auto & rBoxFormula = const_cast<SwTableBoxFormula&>(*pItem); if(eFlags == TBL_BOXPTR)
rBoxFormula.TryBoxNmToPtr(); elseif(eFlags == TBL_RELBOXNAME)
rBoxFormula.TryRelBoxNm(); else
rBoxFormula.ChangeState();
}
}
}
}
// TODO Set HasTextChangesOnly=true, if needed based on the redlines in the cells. // At tracked row deletion, return with the newest deletion of the row or // at tracked row insertion, return with the oldest insertion in the row, which // contain the change data of the row change. // If the return value is SwRedlineTable::npos, there is no tracked row change.
SwRedlineTable::size_type SwTableLine::UpdateTextChangesOnly(
SwRedlineTable::size_type& rRedlinePos, bool bUpdateProperty ) const
{
SwRedlineTable::size_type nRet = SwRedlineTable::npos; const SwRedlineTable& aRedlineTable = GetFrameFormat()->GetDoc().getIDocumentRedlineAccess().GetRedlineTable();
// check table row property "HasTextChangesOnly", if it's defined and its // value is false, and all text content is in delete redlines, the row is deleted const SvxPrintItem *pHasTextChangesOnlyProp =
GetFrameFormat()->GetAttrSet().GetItem<SvxPrintItem>(RES_PRINT); if ( pHasTextChangesOnlyProp && !pHasTextChangesOnlyProp->GetValue() )
{ const SwTableBoxes & rBoxes = GetTabBoxes();
size_t nBoxes = rBoxes.size(); bool bInsertion = false; bool bPlainTextInLine = false;
SwRedlineTable::size_type nOldestRedline = SwRedlineTable::npos;
SwRedlineTable::size_type nNewestRedline = SwRedlineTable::npos; for (size_t nBoxIndex = 0; nBoxIndex < nBoxes && rRedlinePos < aRedlineTable.size(); ++nBoxIndex)
{ auto pBox = rBoxes[nBoxIndex]; if ( pBox->IsEmpty( /*bWithRemainingNestedTable =*/ false ) )
{ // no text content, check the next cells continue;
}
if ( pRedline->Start()->GetNodeIndex() > pEndNodeIndex.GetIndex() )
{ // no more redlines in the actual cell, // check the next ones break;
}
// redline in the cell if ( aCellStart <= *pRedline->Start() )
{ if ( !bHasRedlineInBox )
{
bHasRedlineInBox = true; // plain text before the first redline in the text if ( pRedline->Start()->GetContentIndex() > 0 )
bPlainTextInLine = true;
}
RedlineType nType = pRedline->GetType();
// first insert redline if ( !bInsertion )
{ if ( RedlineType::Insert == nType )
{
bInsertion = true;
} else
{ // plain text between the delete redlines
--> --------------------
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.