b092668dfa
2008/04/01 12:27:37 thb 1.25.16.2: #i85898# Stripping all external header guards 2008/03/31 12:22:56 rt 1.25.16.1: #i87441# Change license header to LPGL v3.
1175 lines
42 KiB
C++
1175 lines
42 KiB
C++
/*************************************************************************
|
|
*
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* Copyright 2008 by Sun Microsystems, Inc.
|
|
*
|
|
* OpenOffice.org - a multi-platform office productivity suite
|
|
*
|
|
* $RCSfile: nodeimplobj.cxx,v $
|
|
* $Revision: 1.26 $
|
|
*
|
|
* This file is part of OpenOffice.org.
|
|
*
|
|
* OpenOffice.org is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU Lesser General Public License version 3
|
|
* only, as published by the Free Software Foundation.
|
|
*
|
|
* OpenOffice.org is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Lesser General Public License version 3 for more details
|
|
* (a copy is included in the LICENSE file that accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public License
|
|
* version 3 along with OpenOffice.org. If not, see
|
|
* <http://www.openoffice.org/license.html>
|
|
* for a copy of the LGPLv3 License.
|
|
*
|
|
************************************************************************/
|
|
|
|
// MARKER(update_precomp.py): autogen include statement, do not remove
|
|
#include "precompiled_configmgr.hxx"
|
|
#include <stdio.h>
|
|
#include "nodeimplobj.hxx"
|
|
|
|
|
|
#include "nodechange.hxx"
|
|
#include "nodechangeinfo.hxx"
|
|
#include "nodechangeimpl.hxx"
|
|
#include "setnodeaccess.hxx"
|
|
#include "valuenode.hxx"
|
|
#include "change.hxx"
|
|
#include "viewaccess.hxx"
|
|
#include "viewfactory.hxx"
|
|
|
|
namespace configmgr
|
|
{
|
|
namespace configuration
|
|
{
|
|
//-----------------------------------------------------------------------------
|
|
// Value Nodes
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// class DeferredValueElementNodeImpl
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Group Nodes
|
|
//-----------------------------------------------------------------------------
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// class DeferredGroupNodeImpl
|
|
//-----------------------------------------------------------------------------
|
|
|
|
DeferredGroupNodeImpl::DeferredGroupNodeImpl(data::GroupNodeAddress const& _aNodeRef)
|
|
: GroupNodeImpl(_aNodeRef)
|
|
, m_aChanges()
|
|
{
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
DeferredGroupNodeImpl::~DeferredGroupNodeImpl()
|
|
{
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
ValueMemberNode DeferredGroupNodeImpl::makeValueMember(Name const& _aName, bool _bForUpdate)
|
|
{
|
|
MemberChanges::iterator it = m_aChanges.find(_aName);
|
|
|
|
if (it != m_aChanges.end())
|
|
{
|
|
if (!it->second.is())
|
|
OSL_ENSURE(_aName.isEmpty(), "ERROR: Found empty change reference");
|
|
|
|
else if (_bForUpdate || it->second->isChange()) // found one
|
|
return ValueMemberNode(it->second);
|
|
|
|
else // leftover non-change
|
|
m_aChanges.erase(it);
|
|
|
|
// if not found continue with default
|
|
}
|
|
|
|
data::ValueNodeAccess aOriginal = getOriginalValueNode(_aName);
|
|
|
|
if (_bForUpdate) // create a new change
|
|
{
|
|
if (aOriginal.isValid())
|
|
{
|
|
MemberChange aNewChange(new ValueMemberNode::DeferredImpl(aOriginal));
|
|
m_aChanges[_aName] = aNewChange;
|
|
|
|
return ValueMemberNode(aNewChange);
|
|
}
|
|
}
|
|
|
|
return GroupNodeImpl::makeValueMember(aOriginal);
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool DeferredGroupNodeImpl::hasChanges() const
|
|
{
|
|
for (MemberChanges::const_iterator it = m_aChanges.begin(); it != m_aChanges.end(); ++it)
|
|
{
|
|
if (!it->second.is())
|
|
{
|
|
// empty element is present -> marked as changed
|
|
OSL_ASSERT(it->first.isEmpty());
|
|
return true;
|
|
}
|
|
|
|
if (it->second->isChange())
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void DeferredGroupNodeImpl::collectValueChanges(NodeChanges& rChanges, TreeImpl* pParentTree, NodeOffset nNode) const
|
|
{
|
|
for (MemberChanges::const_iterator it = m_aChanges.begin(); it != m_aChanges.end(); ++it)
|
|
{
|
|
if (it->second.is())
|
|
{
|
|
OSL_ASSERT(!it->first.isEmpty());
|
|
if (ValueChangeImpl* pValueChange = it->second->collectChange())
|
|
{
|
|
pValueChange->setTarget(pParentTree,nNode,it->first);
|
|
|
|
rChanges.add( NodeChange(pValueChange) );
|
|
}
|
|
else // leftover non-change
|
|
OSL_ENSURE(!it->second->isChange(), "Got no change from a changing value") ;
|
|
}
|
|
else
|
|
OSL_ASSERT(it->first.isEmpty());
|
|
}
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
DeferredGroupNodeImpl::MemberChange DeferredGroupNodeImpl::findValueChange(Name const& aName)
|
|
{
|
|
MemberChange aResult;
|
|
|
|
MemberChanges::iterator it = m_aChanges.find(aName);
|
|
|
|
if (it != m_aChanges.end())
|
|
{
|
|
if (it->second.is() )
|
|
{
|
|
if (it->second->isChange())
|
|
{
|
|
aResult = it->second;
|
|
}
|
|
|
|
else // leftover non-change -> drop
|
|
{
|
|
m_aChanges.erase(it);
|
|
}
|
|
}
|
|
else
|
|
OSL_ENSURE(aName.isEmpty(), "ERROR: Found empty change reference");
|
|
}
|
|
|
|
return aResult;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
std::auto_ptr<SubtreeChange> DeferredGroupNodeImpl::preCommitValueChanges()
|
|
{
|
|
std::auto_ptr<SubtreeChange> aRet;
|
|
|
|
if (!m_aChanges.empty())
|
|
{
|
|
data::NodeAccess aOriginalData = this->getOriginalNodeAccess();
|
|
aRet.reset( new SubtreeChange( aOriginalData.getName().toString(),
|
|
aOriginalData->getAttributes() ) );
|
|
|
|
for (MemberChanges::iterator pos = m_aChanges.begin(); pos != m_aChanges.end(); )
|
|
{
|
|
MemberChanges::iterator it = pos++; // this is used to allow erasing below
|
|
|
|
if (!it->second.is())
|
|
{
|
|
OSL_ASSERT(it->first.isEmpty());
|
|
}
|
|
else if (it->second->isChange())
|
|
{
|
|
std::auto_ptr<ValueChange> aValueChange = it->second->preCommitChange();
|
|
if (aValueChange.get())
|
|
{
|
|
std::auto_ptr<Change> aBaseChange(aValueChange.release());
|
|
aRet->addChange( aBaseChange );
|
|
}
|
|
else
|
|
OSL_ENSURE(false, "Got no change from a changed member");
|
|
}
|
|
else // found left-over non-change
|
|
m_aChanges.erase(it);
|
|
}
|
|
if (m_aChanges.empty()) aRet.reset();
|
|
}
|
|
|
|
return aRet;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void DeferredGroupNodeImpl::finishCommit(SubtreeChange& rChanges)
|
|
{
|
|
OSL_ENSURE(!rChanges.isSetNodeChange(),"ERROR: Change type SET does not match group");
|
|
|
|
for(SubtreeChange::MutatingChildIterator it = rChanges.begin_changes(), stop = rChanges.end_changes();
|
|
it != stop;
|
|
++it)
|
|
{
|
|
Name aValueName = makeNodeName(it->getNodeName(), Name::NoValidate());
|
|
|
|
MemberChanges::iterator itStoredChange = m_aChanges.find(aValueName);
|
|
|
|
if (itStoredChange != m_aChanges.end())
|
|
{
|
|
OSL_ENSURE( it->ISA(ValueChange) , "Unexpected type of element change");
|
|
if (!it->ISA(ValueChange)) throw Exception("Unexpected type of element change");
|
|
|
|
ValueChange & rValueChange = static_cast<ValueChange&>(*it);
|
|
|
|
MemberChange aStoredChange = itStoredChange->second;
|
|
OSL_ENSURE( aStoredChange.is(), "Found empty change object for Member value change");
|
|
|
|
if (aStoredChange.is())
|
|
{
|
|
aStoredChange->finishCommit(rValueChange);
|
|
OSL_ENSURE(!aStoredChange->isChange(),"ValueChange is not moot after finishCommit");
|
|
}
|
|
|
|
m_aChanges.erase( itStoredChange ); // remove finished change
|
|
}
|
|
else
|
|
OSL_ENSURE( !it->ISA(ValueChange) , "Value member change has no change data representation");
|
|
|
|
}
|
|
|
|
OSL_DEBUG_ONLY( m_aChanges.erase( Name() ) ); // remove change marker (if present)
|
|
OSL_ENSURE(m_aChanges.empty(), "Found unprocessed changes to values in group");
|
|
|
|
m_aChanges.clear(); // remove all pending stuff and marker
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void DeferredGroupNodeImpl::revertCommit(SubtreeChange& rChanges)
|
|
{
|
|
OSL_ENSURE(!rChanges.isSetNodeChange(),"ERROR: Change type SET does not match group");
|
|
|
|
for(SubtreeChange::MutatingChildIterator it = rChanges.begin_changes(), stop = rChanges.end_changes();
|
|
it != stop;
|
|
++it)
|
|
{
|
|
Name aValueName = makeNodeName(it->getNodeName(), Name::NoValidate());
|
|
|
|
MemberChanges::iterator itStoredChange = m_aChanges.find(aValueName);
|
|
|
|
if (itStoredChange != m_aChanges.end())
|
|
{
|
|
OSL_ENSURE( it->ISA(ValueChange) , "Unexpected type of element change");
|
|
if (!it->ISA(ValueChange)) continue;
|
|
|
|
ValueChange & rValueChange = static_cast<ValueChange&>(*it);
|
|
|
|
MemberChange aStoredChange = itStoredChange->second;
|
|
OSL_ENSURE( aStoredChange.is(), "Cannot restore change: found empty change object for Member value change");
|
|
|
|
if (aStoredChange.is())
|
|
{
|
|
aStoredChange->revertCommit(rValueChange);
|
|
OSL_ENSURE(!aStoredChange->isChange(),"ValueChange is not moot after reverting - will be discarded nevertheless");
|
|
}
|
|
m_aChanges.erase( itStoredChange ); // remove change if it is moot
|
|
}
|
|
else
|
|
OSL_ENSURE( !it->ISA(ValueChange) , "Value member change has no change data representation");
|
|
}
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void DeferredGroupNodeImpl::failedCommit(SubtreeChange& rChanges)
|
|
{
|
|
OSL_ENSURE(!rChanges.isSetNodeChange(),"ERROR: Change type SET does not match group");
|
|
|
|
for(SubtreeChange::MutatingChildIterator it = rChanges.begin_changes(), stop = rChanges.end_changes();
|
|
it != stop;
|
|
++it)
|
|
{
|
|
Name aValueName = makeNodeName(it->getNodeName(), Name::NoValidate());
|
|
|
|
MemberChanges::iterator itStoredChange = m_aChanges.find(aValueName);
|
|
|
|
if (itStoredChange != m_aChanges.end())
|
|
{
|
|
OSL_ENSURE( it->ISA(ValueChange) , "Unexpected type of element change");
|
|
if (!it->ISA(ValueChange)) continue;
|
|
|
|
ValueChange & rValueChange = static_cast<ValueChange&>(*it);
|
|
|
|
MemberChange aStoredChange = itStoredChange->second;
|
|
OSL_ENSURE( aStoredChange.is(), "Cannot recover from failed change: found empty change object for Member value change");
|
|
|
|
if (aStoredChange.is())
|
|
aStoredChange->failedCommit(rValueChange);
|
|
{
|
|
if (!aStoredChange->isChange())
|
|
m_aChanges.erase( itStoredChange ); // remove change if it is moot
|
|
}
|
|
}
|
|
else
|
|
OSL_ENSURE( !it->ISA(ValueChange) , "Value member change has no change data representation");
|
|
}
|
|
|
|
OSL_DEBUG_ONLY( m_aChanges.erase( Name() ) ); // remove change marker (if present)
|
|
OSL_ENSURE(m_aChanges.empty(), "RevertCommit: Found unprocessed changes to values in group");
|
|
|
|
m_aChanges.clear(); // discard all pending stuff and marker
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
void DeferredGroupNodeImpl::markChanged()
|
|
{
|
|
// special mark: a NULL DeferredImplRef at empty Name
|
|
m_aChanges.insert( MemberChanges::value_type() );
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Set nodes
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// class DeferredTreeSetNodeImpl
|
|
//-----------------------------------------------------------------------------
|
|
|
|
DeferredSetNodeImpl::DeferredSetNodeImpl(data::SetNodeAddress const& _aNodeRef, Template* pTemplate)
|
|
: SetNodeImpl(_aNodeRef,pTemplate)
|
|
, m_aChangedData()
|
|
, m_bChanged(false)
|
|
, m_bDefault(false)
|
|
{
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool DeferredSetNodeImpl::doIsEmpty() const
|
|
{
|
|
if (m_aChangedData.isEmpty())
|
|
return SetNodeImpl::doIsEmpty();
|
|
|
|
// look for added elements
|
|
{for(ElementSet::ConstIterator it = m_aChangedData.begin(), stop = m_aChangedData.end();
|
|
it != stop;
|
|
++it)
|
|
{
|
|
if (it->isValid()) return false;
|
|
}}
|
|
|
|
|
|
// look for elements in the base set that are not 'deleted' (the changes are all deletions here)
|
|
{for(ElementSet::PairIterator it = SetNodeImpl::beginElementSet(), stop = SetNodeImpl::endElementSet();
|
|
it != stop;
|
|
++it)
|
|
{
|
|
if (!m_aChangedData.hasElement(it->first)) return false;
|
|
}}
|
|
|
|
return true;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
ElementTreeImpl* DeferredSetNodeImpl::doFindElement(Name const& aName)
|
|
{
|
|
Element* pElement = m_aChangedData.getElement(aName);
|
|
if (!pElement)
|
|
pElement = SetNodeImpl::getStoredElement(aName);
|
|
|
|
return pElement ? pElement->get() : 0;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
SetNodeVisitor::Result DeferredSetNodeImpl::doDispatchToElements(SetNodeVisitor& aVisitor)
|
|
{
|
|
SetNodeVisitor::Result eRet = SetNodeVisitor::CONTINUE;
|
|
// look for elements in the base set that are not hidden by changes
|
|
{for(ElementSet::PairIterator it = SetNodeImpl::beginElementSet(), stop = SetNodeImpl::endElementSet();
|
|
it != stop && eRet != SetNodeVisitor::DONE;
|
|
++it)
|
|
{
|
|
if (m_aChangedData.getElement(it->first) == 0)
|
|
{
|
|
OSL_ASSERT(it->second.isValid());
|
|
eRet = aVisitor.visit(SetEntry(it->second.get()));
|
|
}
|
|
}}
|
|
|
|
// look for added elements
|
|
{for(ElementSet::ConstIterator it = m_aChangedData.begin(), stop = m_aChangedData.end();
|
|
it != stop && eRet != SetNodeVisitor::DONE;
|
|
++it)
|
|
{
|
|
if (it->isValid())
|
|
{
|
|
eRet = aVisitor.visit(SetEntry(it->get()));
|
|
}
|
|
}}
|
|
return eRet;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool DeferredSetNodeImpl::hasChanges() const
|
|
{
|
|
return m_bChanged || !m_aChangedData.isEmpty();
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void DeferredSetNodeImpl::collectElementChanges(NodeChanges& rChanges) const
|
|
{
|
|
// collect added and deleted nodes
|
|
{for(ElementSet::PairIterator it = m_aChangedData.beginNative(), stop = m_aChangedData.endNative();
|
|
it != stop;
|
|
++it)
|
|
{
|
|
Element const* pOriginal = SetNodeImpl::getStoredElement(it->first);
|
|
|
|
if (it->second.isValid()) // added one
|
|
{
|
|
if (pOriginal)
|
|
{
|
|
rChanges.add(NodeChange(implCreateReplace(it->first,it->second,*pOriginal)));
|
|
}
|
|
else
|
|
{
|
|
rChanges.add(NodeChange(implCreateInsert(it->first,it->second)));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pOriginal)
|
|
{
|
|
rChanges.add(NodeChange(implCreateRemove(it->first,*pOriginal)));
|
|
}
|
|
|
|
//else nothing to do
|
|
}
|
|
}}
|
|
|
|
// collect preexisting nodes
|
|
// if (!containsValues()) // value elements ar immutable !
|
|
{for(ElementSet::PairIterator it = SetNodeImpl::beginElementSet(), stop = SetNodeImpl::endElementSet();
|
|
it != stop;
|
|
++it)
|
|
{
|
|
if (m_aChangedData.getElement(it->first) == 0)
|
|
{
|
|
OSL_ASSERT(it->second.isValid());
|
|
view::ViewTreeAccess aElementView(*it->second);
|
|
|
|
if (aElementView.hasChanges())
|
|
aElementView.collectChanges(rChanges);
|
|
}
|
|
}}
|
|
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void DeferredSetNodeImpl::markChanged()
|
|
{
|
|
m_bChanged = true;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void DeferredSetNodeImpl::doTransferElements(ElementSet& rReplacement)
|
|
{
|
|
// transfer preexisting nodes (unless replaced/deleted)
|
|
{for(ElementSet::PairIterator it = SetNodeImpl::beginElementSet(), stop = SetNodeImpl::endElementSet();
|
|
it != stop;
|
|
++it)
|
|
{
|
|
if (m_aChangedData.getElement(it->first) == 0)
|
|
{
|
|
OSL_ASSERT(it->second.isValid());
|
|
|
|
rReplacement.insertElement(it->first,it->second);
|
|
}
|
|
}}
|
|
|
|
// commit added and deleted nodes
|
|
{
|
|
ElementSet::PairIterator it = m_aChangedData.beginNative();
|
|
ElementSet::PairIterator const stop = m_aChangedData.endNative();
|
|
|
|
while(it != stop)
|
|
{
|
|
if (it->second.isValid())
|
|
rReplacement.insertElement(it->first,it->second);
|
|
|
|
++it;
|
|
m_aChangedData.removeElement(it->first);
|
|
}
|
|
}
|
|
|
|
m_bChanged = false;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void DeferredSetNodeImpl::rebuildElement(Name const& _aName, Element const& _aElement)
|
|
{
|
|
TreeImpl* pContext = this->getParentTree();
|
|
OSL_ENSURE(pContext, "Context tree must be set before rebuilding");
|
|
|
|
rtl::Reference<view::ViewStrategy> xContextBehavior = pContext->getViewBehavior();
|
|
|
|
data::TreeAccessor aElementAccessor = this->getDataAccess().getElementTree(_aName);
|
|
OSL_ENSURE(aElementAccessor != NULL, "Element Tree not found in data");
|
|
|
|
OSL_ENSURE(_aElement.isValid(), "Element not found in view");
|
|
_aElement->rebuild(xContextBehavior,aElementAccessor);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
std::auto_ptr<SubtreeChange> DeferredSetNodeImpl::preCommitChanges(ElementList& _rRemovedElements)
|
|
{
|
|
data::NodeAccess aOriginalData = this->getOriginalNodeAccess();
|
|
// now first get the name of this node
|
|
Name sSetName = aOriginalData.getName();
|
|
|
|
// and make a SubtreeChange
|
|
std::auto_ptr<SubtreeChange> pSetChange( new SubtreeChange(sSetName.toString(),
|
|
getElementTemplate()->getName().toString(),
|
|
getElementTemplate()->getModule().toString(),
|
|
aOriginalData->getAttributes() ) );
|
|
|
|
// commit preexisting nodes
|
|
{
|
|
for(ElementSet::PairIterator it = SetNodeImpl::beginElementSet(), stop = SetNodeImpl::endElementSet();
|
|
it != stop;
|
|
++it)
|
|
{
|
|
if (m_aChangedData.getElement(it->first) == 0)
|
|
{
|
|
OSL_ASSERT(it->second.isValid());
|
|
OSL_ENSURE( !m_bDefault || it->second.inDefault, "m_bDefault is inconsistent");
|
|
|
|
view::ViewTreeAccess aElementView(*it->second);
|
|
std::auto_ptr<SubtreeChange> pNewChange = aElementView.preCommitChanges(_rRemovedElements);
|
|
if (pNewChange.get() != 0)
|
|
{
|
|
//OSL_ENSURE( !containsValues(), "Unexpected change generated by value set element");
|
|
std::auto_ptr<Change> pNewChangeBase( pNewChange.release() );
|
|
pSetChange->addChange(pNewChangeBase);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// commit added and deleted nodes
|
|
{
|
|
ElementSet::PairIterator it = m_aChangedData.beginNative();
|
|
ElementSet::PairIterator const stop = m_aChangedData.endNative();
|
|
|
|
while(it != stop)
|
|
{
|
|
Name aName = it->first;
|
|
Element aNewElement = it->second;
|
|
|
|
Element* pOriginal = SetNodeImpl::getStoredElement(aName);
|
|
|
|
if (aNewElement.isValid())
|
|
{
|
|
data::TreeSegment aAddedTree = aNewElement->releaseOwnedTree();
|
|
if (!aAddedTree.is())
|
|
{
|
|
throw Exception("INTERNAL ERROR: Could not find data for the added ElementTree");
|
|
}
|
|
|
|
OSL_ENSURE( !m_bDefault || aNewElement.inDefault, "m_bDefault is inconsistent");
|
|
|
|
AddNode* pAddNode = new AddNode(aAddedTree, aName.toString(), aNewElement.inDefault );
|
|
|
|
std::auto_ptr<Change> pNewChange( pAddNode );
|
|
|
|
if (pOriginal)
|
|
pAddNode->setReplacing();
|
|
|
|
pSetChange->addChange(pNewChange);
|
|
}
|
|
else
|
|
{
|
|
if (pOriginal)
|
|
{
|
|
OSL_ENSURE( !m_bDefault || aNewElement.inDefault, "m_bDefault is inconsistent");
|
|
|
|
std::auto_ptr<Change> pNewChange( new RemoveNode(aName.toString(),aNewElement.inDefault) );
|
|
|
|
pSetChange->addChange(pNewChange);
|
|
}
|
|
//else nothing to do
|
|
}
|
|
|
|
// collect removed or replaced element
|
|
if (pOriginal)
|
|
_rRemovedElements.push_back( pOriginal->tree );
|
|
|
|
++it;
|
|
}
|
|
}
|
|
return pSetChange;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void DeferredSetNodeImpl::finishCommit(SubtreeChange& rChanges)
|
|
{
|
|
OSL_ENSURE(rChanges.isSetNodeChange(),"ERROR: Change type GROUP does not match set");
|
|
OSL_ENSURE( rChanges.getElementTemplateName() == getElementTemplate()->getName().toString(),
|
|
"ERROR: Element template of change does not match the template of the set");
|
|
OSL_ENSURE( rChanges.getElementTemplateModule() == getElementTemplate()->getModule().toString(),
|
|
"ERROR: Element template module of change does not match the template of the set");
|
|
|
|
for(SubtreeChange::MutatingChildIterator it = rChanges.begin_changes(), stop = rChanges.end_changes();
|
|
it != stop;
|
|
++it)
|
|
{
|
|
Name aElementName = makeElementName(it->getNodeName(), Name::NoValidate());
|
|
|
|
Element* pOriginal = getStoredElement(aElementName);
|
|
|
|
if (Element* pNewElement = m_aChangedData.getElement(aElementName))
|
|
{
|
|
Element aOriginal;
|
|
if (pOriginal)
|
|
{
|
|
aOriginal = *pOriginal;
|
|
OSL_ASSERT(aOriginal.isValid());
|
|
}
|
|
else
|
|
OSL_ASSERT(!aOriginal.isValid());
|
|
|
|
// handle a added, replaced or deleted node
|
|
data::TreeSegment aRemovedTree;
|
|
|
|
if (pNewElement->isValid())
|
|
{
|
|
OSL_ENSURE( it->ISA(AddNode) , "Unexpected type of element change");
|
|
if (!it->ISA(AddNode)) throw Exception("Unexpected type of element change");
|
|
|
|
AddNode& rAddNode = static_cast<AddNode&>(*it);
|
|
|
|
aRemovedTree = rAddNode.getReplacedTree();
|
|
OSL_ASSERT( rAddNode.isReplacing() == (0!=pOriginal) );
|
|
OSL_ASSERT( rAddNode.isReplacing() == aRemovedTree.is() );
|
|
|
|
if (aOriginal.isValid())
|
|
SetNodeImpl::replaceElement(aElementName,*pNewElement);
|
|
|
|
else
|
|
SetNodeImpl::insertElement(aElementName,*pNewElement);
|
|
|
|
this->rebuildElement(aElementName,*pNewElement);
|
|
}
|
|
else
|
|
{
|
|
OSL_ENSURE( it->ISA(RemoveNode) , "Unexpected type of element change");
|
|
if (!it->ISA(RemoveNode)) throw Exception("Unexpected type of element change");
|
|
|
|
RemoveNode& rRemoveNode = static_cast<RemoveNode&>(*it);
|
|
aRemovedTree = rRemoveNode.getRemovedTree();
|
|
|
|
OSL_ASSERT(aOriginal.isValid());
|
|
if (aOriginal.isValid())
|
|
SetNodeImpl::removeElement(aElementName);
|
|
}
|
|
// handle a added or deleted node
|
|
if (aOriginal.isValid())
|
|
{
|
|
OSL_ENSURE(aRemovedTree.is(), "Cannot take over the removed node");
|
|
|
|
aOriginal->takeTreeAndRebuild(aRemovedTree);
|
|
}
|
|
m_aChangedData.removeElement(aElementName);
|
|
}
|
|
else
|
|
{
|
|
// handle preexisting nodes
|
|
//OSL_ENSURE(!containsValues(), "Unexpected change to value set element");
|
|
OSL_ENSURE(pOriginal && pOriginal->isValid(), "Changed Element is missing");
|
|
OSL_ENSURE(it->ISA(SubtreeChange), "Unexpected type of element change");
|
|
|
|
if (!it->ISA(SubtreeChange)) throw Exception("Unexpected set element change");
|
|
|
|
if (pOriginal && pOriginal->isValid())
|
|
view::ViewTreeAccess(**pOriginal).finishCommit(static_cast<SubtreeChange&>(*it));
|
|
}
|
|
}
|
|
m_bChanged = false;
|
|
|
|
OSL_ENSURE(m_aChangedData.isEmpty(), "ERROR: Uncommitted changes left in set node");
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void DeferredSetNodeImpl::revertCommit(SubtreeChange& rChanges)
|
|
{
|
|
OSL_ENSURE(rChanges.isSetNodeChange(),"ERROR: Change type GROUP does not match set");
|
|
OSL_ENSURE( rChanges.getElementTemplateName() == getElementTemplate()->getName().toString(),
|
|
"ERROR: Element template of change does not match the template of the set");
|
|
OSL_ENSURE( rChanges.getElementTemplateModule() == getElementTemplate()->getModule().toString(),
|
|
"ERROR: Element template module of change does not match the template of the set");
|
|
|
|
|
|
for(SubtreeChange::MutatingChildIterator it = rChanges.begin_changes(), stop = rChanges.end_changes();
|
|
it != stop;
|
|
++it)
|
|
{
|
|
Name aElementName = makeElementName(it->getNodeName(), Name::NoValidate());
|
|
|
|
Element* pOriginal = getStoredElement(aElementName);
|
|
|
|
if (Element* pNewElement = m_aChangedData.getElement(aElementName))
|
|
{
|
|
// handle a added, replaced or deleted node
|
|
data::TreeSegment pRemovedTree;
|
|
|
|
if (pNewElement->isValid())
|
|
{
|
|
OSL_ENSURE( it->ISA(AddNode) , "Unexpected type of element change");
|
|
if (!it->ISA(AddNode)) throw Exception("Unexpected type of element change");
|
|
|
|
AddNode& rAddNode = static_cast<AddNode&>(*it);
|
|
|
|
pRemovedTree = rAddNode.getReplacedTree();
|
|
OSL_ASSERT( rAddNode.isReplacing() == (0!=pOriginal) );
|
|
OSL_ASSERT( rAddNode.isReplacing() == (0!=pRemovedTree.is()) );
|
|
|
|
OSL_ENSURE(!rAddNode.wasInserted(), "Cannot retract new node: Change was integrated");
|
|
|
|
data::TreeSegment aAddedTree = rAddNode.getNewTree();
|
|
OSL_ENSURE(aAddedTree.is(), "Cannot restore new node: Change lost ownership");
|
|
|
|
// restore the tree
|
|
(*pNewElement)->takeTreeBack(aAddedTree);
|
|
}
|
|
else
|
|
{
|
|
OSL_ENSURE( it->ISA(RemoveNode) , "Unexpected type of element change");
|
|
if (!it->ISA(RemoveNode)) throw Exception("Unexpected type of element change");
|
|
|
|
RemoveNode& rRemoveNode = static_cast<RemoveNode&>(*it);
|
|
pRemovedTree = rRemoveNode.getRemovedTree();
|
|
|
|
OSL_ASSERT(pOriginal);
|
|
OSL_ASSERT((0 != pOriginal) == (0!=pRemovedTree.is()) );
|
|
}
|
|
OSL_ENSURE(pRemovedTree.is(), "Possible problems reverting removed node: Change took ownership");
|
|
// try handle a added or deleted node
|
|
if (pOriginal && pRemovedTree.is())
|
|
{
|
|
OSL_ASSERT(pOriginal->isValid());
|
|
(*pOriginal)->takeTreeAndRebuild(pRemovedTree);
|
|
OSL_DEBUG_ONLY(pRemovedTree.clear());
|
|
}
|
|
OSL_ENSURE(!pRemovedTree.is(), "Could not revert removed node: Nowhere to put ownership");
|
|
}
|
|
else
|
|
{
|
|
// handle preexisting nodes
|
|
//OSL_ENSURE(!containsValues(), "Unexpected change to value set element");
|
|
OSL_ENSURE(pOriginal && pOriginal->isValid(), "Changed Element is missing");
|
|
OSL_ENSURE(it->ISA(SubtreeChange), "Unexpected set element change");
|
|
|
|
if (!it->ISA(SubtreeChange)) throw Exception("Unexpected set element change");
|
|
|
|
if (pOriginal && pOriginal->isValid())
|
|
view::ViewTreeAccess(**pOriginal).revertCommit(static_cast<SubtreeChange&>(*it));
|
|
}
|
|
}
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void DeferredSetNodeImpl::failedCommit(SubtreeChange& rChanges)
|
|
{
|
|
OSL_ENSURE(rChanges.isSetNodeChange(),"ERROR: Change type GROUP does not match set");
|
|
OSL_ENSURE( rChanges.getElementTemplateName() == getElementTemplate()->getName().toString(),
|
|
"ERROR: Element template of change does not match the template of the set");
|
|
OSL_ENSURE( rChanges.getElementTemplateModule() == getElementTemplate()->getModule().toString(),
|
|
"ERROR: Element template module of change does not match the template of the set");
|
|
|
|
for(SubtreeChange::MutatingChildIterator it = rChanges.begin_changes(), stop = rChanges.end_changes();
|
|
it != stop;
|
|
++it)
|
|
{
|
|
Name aElementName = makeElementName(it->getNodeName(), Name::NoValidate());
|
|
|
|
Element* pOriginal = getStoredElement(aElementName);
|
|
|
|
if (Element* pNewElement = m_aChangedData.getElement(aElementName))
|
|
{
|
|
Element aOriginal;
|
|
if (pOriginal)
|
|
{
|
|
aOriginal = *pOriginal;
|
|
OSL_ASSERT(aOriginal.isValid());
|
|
}
|
|
else
|
|
OSL_ASSERT(!aOriginal.isValid());
|
|
|
|
// handle a added, replaced or deleted node
|
|
data::TreeSegment aRemovedTree;
|
|
|
|
if (pNewElement->isValid())
|
|
{
|
|
OSL_ENSURE( it->ISA(AddNode) , "Unexpected type of element change");
|
|
if (!it->ISA(AddNode)) throw Exception("Unexpected type of element change");
|
|
|
|
AddNode& rAddNode = static_cast<AddNode&>(*it);
|
|
|
|
aRemovedTree = rAddNode.getReplacedTree();
|
|
OSL_ASSERT( rAddNode.isReplacing() == (0!=pOriginal) );
|
|
OSL_ASSERT( rAddNode.isReplacing() == aRemovedTree.is() );
|
|
|
|
if (rAddNode.wasInserted())
|
|
{ // it has been integrated into the master tree
|
|
OSL_ENSURE(getDataAccess().getElementTree(aElementName) == rAddNode.getInsertedTree(),
|
|
"Internal Error: Inserted tree address does not match actual data");
|
|
|
|
// so add it
|
|
if (aOriginal.isValid())
|
|
SetNodeImpl::replaceElement(aElementName,*pNewElement);
|
|
|
|
else
|
|
SetNodeImpl::insertElement(aElementName,*pNewElement);
|
|
|
|
this->rebuildElement(aElementName,*pNewElement);
|
|
}
|
|
else // Change not done; need to restore new node (element will be released into the wild then)
|
|
{
|
|
data::TreeSegment aAddedTree = rAddNode.getNewTree();
|
|
|
|
OSL_ENSURE(aAddedTree.is(), "Unexpected: added node is gone, but where ? May cause invalid references");
|
|
if (aAddedTree.is())
|
|
(*pNewElement)->takeTreeBack(aAddedTree);
|
|
detach(*pNewElement);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
OSL_ENSURE( it->ISA(RemoveNode) , "Unexpected type of element change");
|
|
if (!it->ISA(RemoveNode)) throw Exception("Unexpected type of element change");
|
|
|
|
RemoveNode& rRemoveNode = static_cast<RemoveNode&>(*it);
|
|
aRemovedTree = rRemoveNode.getRemovedTree();
|
|
|
|
OSL_ASSERT(aOriginal.isValid());
|
|
if (aRemovedTree.is() && !getDataAccess().hasElement(aElementName))
|
|
{
|
|
// really removed - then remove the originel
|
|
if (aOriginal.isValid())
|
|
SetNodeImpl::removeElement(aElementName);
|
|
}
|
|
}
|
|
|
|
// handle a added or deleted node
|
|
if (aOriginal.isValid() && aRemovedTree.is())
|
|
{
|
|
aOriginal->takeTreeAndRebuild(aRemovedTree);
|
|
//aOriginal->getAccess().makeDirect();
|
|
OSL_DEBUG_ONLY(aRemovedTree.clear());
|
|
}
|
|
OSL_ENSURE(!aRemovedTree.is(), "Could not revert removed node: Nowhere to put ownership");
|
|
|
|
m_aChangedData.removeElement(aElementName);
|
|
}
|
|
else
|
|
{
|
|
// handle preexisting nodes
|
|
//OSL_ENSURE(!containsValues(), "Unexpected change to value set element");
|
|
OSL_ENSURE(pOriginal && pOriginal->isValid(), "Changed Element is missing");
|
|
OSL_ENSURE(it->ISA(SubtreeChange), "Unexpected set element change");
|
|
|
|
if (!it->ISA(SubtreeChange)) throw Exception("Unexpected set element change");
|
|
|
|
if (pOriginal && pOriginal->isValid())
|
|
view::ViewTreeAccess(**pOriginal).recoverFailedCommit(static_cast<SubtreeChange&>(*it));
|
|
}
|
|
}
|
|
m_bChanged = false;
|
|
m_bDefault = false;
|
|
|
|
OSL_ENSURE(m_aChangedData.isEmpty(), "ERROR: Uncommitted changes left in set node");
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void DeferredSetNodeImpl::insertNewElement(Name const& aName, Element const& aNewElement)
|
|
{
|
|
attach(aNewElement,aName);
|
|
try
|
|
{
|
|
// put the new element into the changed set
|
|
Element* pAddedElement = m_aChangedData.getElement(aName);
|
|
if (pAddedElement)
|
|
{
|
|
OSL_ENSURE(!pAddedElement->isValid(),"WARNING: Element being inserted was already there - replacing");
|
|
detach(m_aChangedData.replaceElement(aName,aNewElement));
|
|
}
|
|
else
|
|
{
|
|
m_aChangedData.insertElement(aName, aNewElement);
|
|
}
|
|
m_bChanged = true;
|
|
m_bDefault = false;
|
|
}
|
|
catch (std::exception&)
|
|
{
|
|
detach(aNewElement);
|
|
throw;
|
|
}
|
|
}
|
|
//-------------------------------------------------------------------------
|
|
|
|
void DeferredSetNodeImpl::removeOldElement(Name const& aName)
|
|
{
|
|
// put an empty (dummy) element into the changed set
|
|
Element* pAddedElement = m_aChangedData.getElement(aName);
|
|
if (pAddedElement)
|
|
{
|
|
OSL_ENSURE(pAddedElement->isValid(),"WARNING: Element being removed was already removed");
|
|
detach(m_aChangedData.replaceElement(aName, Element()));
|
|
m_bChanged = true;
|
|
m_bDefault = false;
|
|
}
|
|
else
|
|
{
|
|
m_aChangedData.insertElement(aName, Element());
|
|
}
|
|
|
|
// now check the original one
|
|
Element* pOldElement = getStoredElement(aName);
|
|
if (pOldElement)
|
|
{
|
|
OSL_ASSERT(pOldElement->isValid());
|
|
detach(*pOldElement);
|
|
m_bChanged = true;
|
|
m_bDefault = false;
|
|
}
|
|
else // just clear things out
|
|
{
|
|
m_aChangedData.removeElement(aName);
|
|
}
|
|
|
|
OSL_ENSURE(pOldElement || pAddedElement,"WARNING: Element being removed was not found in set");
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
SetElementChangeImpl* DeferredSetNodeImpl::doAdjustChangedElement(NodeChangesInformation& rLocalChanges, Name const& aName, Change const& aChange)
|
|
{
|
|
if (Element* pLocalElement = m_aChangedData.getElement(aName))
|
|
{
|
|
if (Element* pElement = getStoredElement(aName))
|
|
{
|
|
OSL_ASSERT(pElement->isValid());
|
|
|
|
if (aChange.ISA(SubtreeChange))
|
|
{
|
|
//OSL_ENSURE( !containsValues(), "Unexpected kind of change: Tree change applied to value set element" );
|
|
SubtreeChange const& aSubtreeChange = static_cast<SubtreeChange const&>(aChange);
|
|
|
|
// recurse to element tree - but do not notify those changes (?)
|
|
view::Tree aElementTree(**pElement);
|
|
|
|
NodeChangesInformation aIgnoredChanges;
|
|
view::getViewBehavior(aElementTree)->adjustToChanges(aIgnoredChanges,view::getRootNode(aElementTree),aSubtreeChange);
|
|
}
|
|
else
|
|
{
|
|
OSL_ENSURE( aChange.ISA(ValueChange), "Unexpected kind of change to value set element" );
|
|
//OSL_ENSURE( containsValues(), "Unexpected kind of change: Value change applied to tree set element" );
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// could be changed to do an insert instead (?)
|
|
OSL_ENSURE( false, "Changed Element didn't exist before it was removed/replaced" );
|
|
}
|
|
|
|
if (pLocalElement->isValid())
|
|
{
|
|
// we have a complete replacement for the changed node
|
|
Element aLocalElement = *pLocalElement;
|
|
|
|
// also signal something happened
|
|
return implCreateReplace(aName,aLocalElement,aLocalElement);
|
|
}
|
|
else
|
|
{
|
|
// already removed locally - should be notified by different route (if applicable)
|
|
return NULL;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return SetNodeImpl::doAdjustChangedElement( rLocalChanges,aName,aChange);
|
|
}
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
SetElementChangeImpl* DeferredSetNodeImpl::doAdjustToAddedElement(Name const& aName, AddNode const& aAddNodeChange, Element const& aNewElement)
|
|
{
|
|
m_bDefault = false;
|
|
if (Element* pLocalElement = m_aChangedData.getElement(aName))
|
|
{
|
|
// We have another element replacing ours - what do we do ?
|
|
if (hasStoredElement(aName))
|
|
{
|
|
OSL_ENSURE( aAddNodeChange.isReplacing(), "Added Element already exists - replacing" );
|
|
|
|
this->replaceElement(aName,aNewElement);
|
|
}
|
|
else
|
|
{
|
|
OSL_ENSURE( !aAddNodeChange.isReplacing(), "Replaced Element doesn't exist - simply adding" );
|
|
this->insertElement(aName,aNewElement);
|
|
}
|
|
|
|
|
|
if (pLocalElement->isValid()) // ours remains a valid replacement
|
|
{
|
|
Element aLocalElement = *pLocalElement;
|
|
|
|
// just signal something happened
|
|
return implCreateReplace(aName,aLocalElement,aLocalElement);
|
|
}
|
|
else // had been removed locally
|
|
{
|
|
// signal what happened
|
|
return implCreateInsert(aName,aNewElement);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return SetNodeImpl::implAdjustToAddedElement(aName,aNewElement,aAddNodeChange.isReplacing());
|
|
}
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
SetElementChangeImpl* DeferredSetNodeImpl::doAdjustToRemovedElement(Name const& aName, RemoveNode const& /*aRemoveNodeChange*/)
|
|
{
|
|
m_bDefault = false;
|
|
if (Element* pLocalElement = m_aChangedData.getElement(aName))
|
|
{
|
|
if (hasStoredElement(aName))
|
|
{
|
|
// take away the original
|
|
this->removeElement(aName);
|
|
}
|
|
|
|
if (pLocalElement->isValid()) // remains a valid replacement
|
|
{
|
|
Element aLocalElement = *pLocalElement;
|
|
|
|
// signal something happened
|
|
return implCreateReplace(aName,aLocalElement,aLocalElement);
|
|
}
|
|
else // already was removed locally
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return SetNodeImpl::implAdjustToRemovedElement(aName);
|
|
}
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void DeferredSetNodeImpl::doDifferenceToDefaultState(SubtreeChange& _rChangeToDefault, ISubtree& _rDefaultTree)
|
|
{
|
|
if (!m_bDefault)
|
|
{
|
|
implDifferenceToDefaultState(_rChangeToDefault,_rDefaultTree);
|
|
|
|
ElementSet::PairIterator it = m_aChangedData.beginNative();
|
|
ElementSet::PairIterator const stop = m_aChangedData.endNative();
|
|
|
|
while(it != stop)
|
|
{
|
|
Name aName = it->first;
|
|
Element aElement = it->second;
|
|
|
|
Change* pChange = _rChangeToDefault.getChange( aName.toString() );
|
|
OSL_ENSURE(pChange == NULL || pChange->ISA(AddNode) || pChange->ISA(RemoveNode),
|
|
"Unexpected change type found in difference to default tree");
|
|
|
|
if (pChange == NULL)
|
|
{
|
|
std::auto_ptr<INode> aDefaultNode = _rDefaultTree.removeChild(aName.toString());
|
|
OSL_ENSURE( aDefaultNode.get(), "Error: unused Default tree not found after SetNodeImpl::implDifferenceToDefaultState");
|
|
|
|
OUString aElementTypeName = _rDefaultTree.getElementTemplateName();
|
|
OSL_ENSURE( _rDefaultTree.isSetNode(), "Error: missing set template information in default data");
|
|
|
|
data::TreeSegment aDefaultTree = data::TreeSegment::createNew(aDefaultNode,aElementTypeName);
|
|
OSL_ENSURE( aDefaultTree.is(), "Error: unused Default tree not accessible after SetNodeImpl::implDifferenceToDefaultState");
|
|
|
|
AddNode* pAddIt = new AddNode(aDefaultTree, aName.toString(), true );
|
|
|
|
std::auto_ptr<Change> pNewChange( pAddIt );
|
|
|
|
if (aElement.isValid())
|
|
{
|
|
OSL_ENSURE(!aElement.inDefault, "Default element replaced by default");
|
|
pAddIt->setReplacing();
|
|
}
|
|
|
|
_rChangeToDefault.addChange(pNewChange);
|
|
|
|
}
|
|
else if ( pChange->ISA(AddNode) )
|
|
{
|
|
// adjust the AddNode - remove the original expected node
|
|
AddNode* pAddIt = static_cast<AddNode*>(pChange);
|
|
pAddIt->clearReplacedTree();
|
|
|
|
if (aElement.isValid())
|
|
{
|
|
if (aElement.inDefault)
|
|
{
|
|
// change already done locally
|
|
_rChangeToDefault.removeChange(aName.toString());
|
|
}
|
|
else // adjust here
|
|
pAddIt->setReplacing();
|
|
}
|
|
|
|
else
|
|
OSL_ENSURE(!pAddIt->isReplacing(),"Could not unmark the 'replacing' state of an AddNode");
|
|
}
|
|
else if ( pChange->ISA(RemoveNode) )
|
|
{
|
|
if (aElement.isValid())
|
|
{
|
|
OSL_ENSURE(!aElement.inDefault, "Default element replaced by default");
|
|
// adjust the RemoveNode - remove the original expected node
|
|
RemoveNode* pRemoveIt = static_cast<RemoveNode*>(pChange);
|
|
pRemoveIt->clearRemovedTree();
|
|
}
|
|
else
|
|
{
|
|
// change already done locally
|
|
_rChangeToDefault.removeChange(aName.toString());
|
|
}
|
|
// TODO: mark local removal as to-default
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
}
|
|
}
|