/* -*- 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 .
*/
switch (m_pAttr->Which())
{ case RES_BREAK: switch (static_cast<SvxFormatBreakItem &>(*m_pAttr).GetBreak())
{ case SvxBreak::PageBefore: case SvxBreak::PageAfter: case SvxBreak::PageBoth:
aResult = SwResId(STR_UNDO_PAGEBREAKS);
break; case SvxBreak::ColumnBefore: case SvxBreak::ColumnAfter: case SvxBreak::ColumnBoth:
aResult = SwResId(STR_UNDO_COLBRKS);
SwHistorySetText::SwHistorySetText( SwTextAttr* pTextHt, SwNodeOffset nNodePos )
: SwHistoryHint( HSTRY_SETTXTHNT )
, m_nNodeIndex( nNodePos )
, m_nStart( pTextHt->GetStart() )
, m_nEnd( pTextHt->GetAnyEnd() )
, m_bFormatIgnoreStart(pTextHt->IsFormatIgnoreStart())
, m_bFormatIgnoreEnd (pTextHt->IsFormatIgnoreEnd ())
{ // Caution: the following attributes generate no format attributes: // - NoLineBreak, NoHyphen, Inserted, Deleted // These cases must be handled separately !!!
// a little bit complicated but works: first assign a copy of the // default value and afterwards the values from text attribute if ( RES_TXTATR_CHARFMT == pTextHt->Which() )
{
m_pAttr.reset( new SwFormatCharFormat( pTextHt->GetCharFormat().GetCharFormat() ) );
} else
{
m_pAttr.reset( pTextHt->GetAttr().Clone() );
}
}
SwHistorySetText::~SwHistorySetText()
{
}
void SwHistorySetText::SetInDoc( SwDoc& rDoc, bool )
{ if (!m_pAttr) return;
if ( RES_TXTATR_CHARFMT == m_pAttr->Which() )
{ // ask the Doc if the CharFormat still exists if (!rDoc.GetCharFormats()->ContainsFormat(static_cast<SwFormatCharFormat&>(*m_pAttr).GetCharFormat())) return; // do not set, format does not exist
}
SwTextNode * pTextNd = rDoc.GetNodes()[ m_nNodeIndex ]->GetTextNode();
OSL_ENSURE( pTextNd, "SwHistorySetText::SetInDoc: not a TextNode" );
if ( !pTextNd ) return;
SwTextAttr *const pAttr = pTextNd->InsertItem(*m_pAttr, m_nStart, m_nEnd,
SetAttrMode::NOTXTATRCHR |
SetAttrMode::NOHINTADJUST ); // shouldn't be possible to hit any error/merging path from here
assert(pAttr); if (m_bFormatIgnoreStart)
{
pAttr->SetFormatIgnoreStart(true);
} if (m_bFormatIgnoreEnd)
{
pAttr->SetFormatIgnoreEnd(true);
}
}
// if a reference mark without an end already exists here: must not insert! if ( m_nStart != m_nEnd ||
!pTextNd->GetTextAttrForCharAt( m_nStart, RES_TXTATR_REFMARK ) )
{
pTextNd->InsertItem( aRefMark, m_nStart, m_nEnd,
SetAttrMode::NOTXTATRCHR );
}
}
// keep the old NodePos (because who knows what later will be saved/deleted // in SaveSection)
SwDoc& rDoc = const_cast<SwDoc&>(pTextFootnote->GetTextNode().GetDoc());
SwNode* pSaveNd = rDoc.GetNodes()[ m_nNodeIndex ];
// keep pointer to StartNode of FootnoteSection and reset its attribute for now // (as a result, its/all Frames will be deleted automatically)
SwNodeIndex aSttIdx( *pTextFootnote->GetStartNode() );
pTextFootnote->SetStartNode( nullptr, false );
if (m_pUndo)
{ // set the footnote in the TextNode
SwFormatFootnote aNew( m_bEndNote ); if ( !m_FootnoteNumber.isEmpty() )
{
aNew.SetNumStr( m_FootnoteNumber );
}
SwTextFootnote* pTextFootnote = new SwTextFootnote(
SfxPoolItemHolder(rDoc.GetAttrPool(), &aNew),
m_nStart );
// create the section of the Footnote
SwNodeIndex aIdx( *pTextNd );
m_pUndo->RestoreSection( rDoc, &aIdx, SwFootnoteStartNode );
pTextFootnote->SetStartNode( &aIdx ); if ( m_pUndo->GetHistory() )
{ // create frames only now
m_pUndo->GetHistory()->Rollback( rDoc );
}
// before setting the format, check if it is still available in the // document. if it has been deleted, there is no undo! if ( !(pContentNd && m_nNodeType == pContentNd->GetNodeType()) ) return;
// now the situation is that m_bSavePos and m_bSaveOtherPos don't determine // whether the mark was deleted if (autoconst iter = pMarkAccess->findMark(m_aName); iter != pMarkAccess->getAllMarksEnd())
{
pMark = *iter;
} if(m_bSavePos)
{
SwContentNode* const pContentNd = rNds[m_nNode]->GetContentNode();
assert(pContentNd);
oPam.emplace(*pContentNd, m_nContent);
} else
{
assert(pMark);
oPam.emplace(pMark->GetMarkPos());
}
assert(oPam);
SwHistorySetAttrSet::SwHistorySetAttrSet( const SfxItemSet& rSet,
SwNodeOffset nNodePos, const o3tl::sorted_vector<sal_uInt16> &rSetArr)
: SwHistoryHint(HSTRY_SETATTRSET)
, m_OldSet(*rSet.GetPool(), rSet.GetRanges())
, m_ResetArray(0, 4)
, m_nNodeIndex(nNodePos)
{ // ITEM: Analyzed this one, it originally iterated using two SfxItemIter at the // same time to iterate rSet and m_OldSet. m_OldSet was copied from rSet before // in the var init above. It then *removed* Items again or manipulated them. // The problem with that is that this implies that the two iterators will advance // on the same WhichIDs step by step. Even after copying and with the former // organization of the Items in ItemSet as fixed array of pointers that is a // 'wild' assumption, besides that deleting Items while a iterator is used is // bad in general, too. // I re-designed this to iterate over the source ItemSet (rSet) and add Items // as needed to the target ItemSet m_OldSet. This is tricky since some NonShareable // 'special' Items get special treatment. for (SfxItemIter aIter(rSet); !aIter.IsAtEnd(); aIter.NextItem())
{ // check if Item is intended to be contained if (rSetArr.count(aIter.GetCurWhich()))
{ // do include item, but take care of some 'special' cases switch (aIter.GetCurWhich())
{ case RES_PAGEDESC:
{ // SwFormatPageDesc - NonShareable Item
SwFormatPageDesc* pNew(new SwFormatPageDesc(*static_cast<const SwFormatPageDesc*>(aIter.GetCurItem())));
pNew->ChgDefinedIn(nullptr);
m_OldSet.Put(std::unique_ptr<SwFormatPageDesc>(pNew)); break;
} case RES_PARATR_DROP:
{ // SwFormatDrop - NonShareable Item
SwFormatDrop* pNew(new SwFormatDrop(*static_cast<const SwFormatDrop*>(aIter.GetCurItem())));
pNew->ChgDefinedIn(nullptr);
m_OldSet.Put(std::unique_ptr<SwFormatDrop>(pNew)); break;
} case RES_BOXATR_FORMULA:
{ // When a formula is set, never save the value. It // possibly must be recalculated! // Save formulas always in plain text // RES_BOXATR_FORMULA: SwTableBoxFormula - NonShareable Item // CAUTION: also is connected to RES_BOXATR_VALUE which was hard deleted before
SwTableBoxFormula* pNew(static_cast<const SwTableBoxFormula*>(aIter.GetCurItem())->Clone());
if (pNew->IsIntrnlName())
{ const SwTableBoxFormula& rOld(rSet.Get(RES_BOXATR_FORMULA)); const SwNode* pNd(rOld.GetNodeOfFormula());
if (nullptr != pNd)
{ const SwTableNode* pTableNode(pNd->FindTableNode());
pNew->ChgDefinedIn(nullptr);
m_OldSet.Put(std::unique_ptr<SwTableBoxFormula>(pNew)); break;
} case RES_BOXATR_VALUE:
{ // If RES_BOXATR_FORMULA is set, do *not* set RES_BOXATR_VALUE - SwTableBoxValue - that IS a Shareable Item (!) // If RES_BOXATR_FORMULA is not set, also no reason to set RES_BOXATR_VALUE // -> so just ignore it here (?) break;
} default:
{ // all other Items: add to m_OldSet
m_OldSet.Put(*aIter.GetCurItem()); break;
}
}
} else
{ // do not include item, additionally remember in // m_ResetArray
m_ResetArray.push_back(aIter.GetCurWhich());
}
}
}
// One would expect m_rFormat to only contain FlyFormats, given the name of // this class, but apparently it is also used for DrawFormats. if (!rDoc.GetSpzFrameFormats()->IsAlive(&m_rFormat)) // Format does still exist return;
// so the Layout does not get confused if (!pCNd->getLayoutFrame(rDoc.getIDocumentLayoutAccess().GetCurrentLayout(), nullptr, nullptr))
{
m_rFormat.DelFrames();
}
// no default Attribute?
std::unique_ptr<SwHistoryHint> pHt;
// To be able to include the DrawingLayer FillItems something more // general has to be done to check if an Item is default than to check // if its pointer equals that in Writer's global PoolDefaults (held in // aAttrTab and used to fill the pool defaults in Writer - looks as if // Writer is *older* than the SfxItemPool ?). I checked the possibility to // get the SfxItemPool here (works), but decided to use the SfxPoolItem's // global tooling aka IsDefaultItem(const SfxPoolItem*) for now if(pOldValue && !IsDefaultItem(pOldValue))
{
pHt.reset( new SwHistorySetFormat( pOldValue, nNodeIdx ) );
} else
{
pHt.reset( new SwHistoryResetFormat( pNewValue, nNodeIdx ) );
}
m_SwpHstry.push_back( std::move(pHt) );
}
// FIXME: refactor the following "Add" methods (DRY)? void SwHistory::AddTextAttr(SwTextAttr *const pHint,
SwNodeOffset const nNodeIdx, boolconst bNewAttr)
{
OSL_ENSURE( !m_nEndDiff, "History was not deleted after REDO" );
std::unique_ptr<SwHistoryHint> pHt; if( !bNewAttr )
{ switch ( pHint->Which() )
{ case RES_TXTATR_FTN:
pHt.reset( new SwHistorySetFootnote( static_cast<SwTextFootnote*>(pHint), nNodeIdx ) ); break; case RES_TXTATR_FLYCNT:
pHt.reset( new SwHistoryTextFlyCnt( static_cast<SwTextFlyCnt*>(pHint)
->GetFlyCnt().GetFrameFormat() ) ); break; case RES_TXTATR_FIELD: case RES_TXTATR_ANNOTATION:
pHt.reset( new SwHistorySetTextField(
static_txtattr_cast<SwTextField*>(pHint), nNodeIdx) ); break; case RES_TXTATR_TOXMARK:
pHt.reset( new SwHistorySetTOXMark(
static_txtattr_cast<SwTextTOXMark*>(pHint), nNodeIdx) ); break; case RES_TXTATR_REFMARK:
pHt.reset( new SwHistorySetRefMark(
static_txtattr_cast<SwTextRefMark*>(pHint), nNodeIdx) ); break; default:
pHt.reset( new SwHistorySetText( pHint, nNodeIdx ) );
}
} else
{
pHt.reset( new SwHistoryResetText( pHint->Which(), pHint->GetStart(),
pHint->GetAnyEnd(), nNodeIdx ) );
}
m_SwpHstry.push_back( std::move(pHt) );
}
void SwHistory::AddColl(SwFormatColl *const pColl, SwNodeOffset const nNodeIdx,
SwNodeType const nWhichNd)
{
OSL_ENSURE( !m_nEndDiff, "History was not deleted after REDO" );
// for every SwHistoryFlyCnt, call the Redo of its UndoObject. // this saves the formats of the flys! for ( sal_uInt16 n = nOld; n < nNewTmpEnd; n++ )
{ if ( HSTRY_FLYCNT == (*this)[ n ]->Which() )
{ static_cast<SwHistoryTextFlyCnt*>((*this)[ n ])
->GetUDelLFormat()->RedoForRollback();
}
}
// copy all attributes of the TextNode in the area from nStart to nEnd
SwTextAttr* pHt; for( size_t n = 0; n < pHts->Count(); ++n )
{ // nAttrStt must even be set when !pEndIdx
pHt = pHts->Get(n); const sal_Int32 nAttrStt = pHt->GetStart(); const sal_Int32 * pEndIdx = pHt->GetEnd(); if( nullptr != pEndIdx && nAttrStt > nEnd ) break;
// never copy Flys and Footnote !! bool bNextAttr = false; switch( pHt->Which() )
{ case RES_TXTATR_FIELD: case RES_TXTATR_ANNOTATION: case RES_TXTATR_INPUTFIELD: if( !bCopyFields )
bNextAttr = true; break; case RES_TXTATR_FLYCNT: case RES_TXTATR_FTN:
bNextAttr = true; break;
}
if( bNextAttr ) continue;
// save all attributes that are somehow in this area if ( nStart <= nAttrStt )
{ if ( nEnd > nAttrStt )
{
AddTextAttr(pHt, nNodeIdx, false);
}
} elseif ( pEndIdx && nStart < *pEndIdx )
{
AddTextAttr(pHt, nNodeIdx, false);
}
}
}
// Class to register the history at a Node, Format, HintsArray, ...
SwRegHistory::SwRegHistory( SwHistory* pHst )
: SwClient( nullptr )
, m_pHistory( pHst )
, m_nNodeIndex( NODE_OFFSET_MAX )
{
MakeSetWhichIds();
}
// Caution: The array can be deleted when inserting an attribute! // This can happen when the value that should be added first deletes // an existing attribute but does not need to be added itself because // the paragraph attributes are identical // ( -> bForgetAttr in SwpHints::Insert ) if ( pTextNode->GetpSwpHints() && m_pHistory )
{
pTextNode->GetpSwpHints()->DeRegister();
}
#ifndef NDEBUG if ( m_pHistory && bInserted )
{
SfxItemIter aIter(rSet); for (SfxPoolItem const* pItem = aIter.GetCurItem(); pItem; pItem = aIter.NextItem())
{ // check that the history recorded a hint to reset every item
sal_uInt16 const nWhich(pItem->Which());
sal_uInt16 const nExpected(
(isCHRATR(nWhich) || RES_TXTATR_UNKNOWN_CONTAINER == nWhich)
? RES_TXTATR_AUTOFMT
: nWhich); if (RES_TXTATR_AUTOFMT == nExpected) continue; // special case, may get set on text node itself // tdf#105077 even worse, node's set could cause // nothing at all to be inserted
assert(std::any_of(
m_pHistory->m_SwpHstry.begin(), m_pHistory->m_SwpHstry.end(),
[nExpected](std::unique_ptr<SwHistoryHint> const& pHint) -> bool {
SwHistoryResetText const*const pReset( dynamic_cast<SwHistoryResetText const*>(pHint.get())); return pReset && (pReset->GetWhich() == nExpected);
}));
}
} #endif
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.