summaryrefslogtreecommitdiff
path: root/configmgr/source/treemgr/nodeimplobj.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'configmgr/source/treemgr/nodeimplobj.cxx')
-rw-r--r--configmgr/source/treemgr/nodeimplobj.cxx1165
1 files changed, 1165 insertions, 0 deletions
diff --git a/configmgr/source/treemgr/nodeimplobj.cxx b/configmgr/source/treemgr/nodeimplobj.cxx
new file mode 100644
index 000000000000..57958c82771b
--- /dev/null
+++ b/configmgr/source/treemgr/nodeimplobj.cxx
@@ -0,0 +1,1165 @@
+/*************************************************************************
+ *
+ * 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 "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(sharable::GroupNode * const& _aNodeRef)
+: GroupNodeImpl(_aNodeRef)
+, m_aChanges()
+{
+}
+//-----------------------------------------------------------------------------
+
+DeferredGroupNodeImpl::~DeferredGroupNodeImpl()
+{
+}
+//-----------------------------------------------------------------------------
+
+ValueMemberNode DeferredGroupNodeImpl::makeValueMember(rtl::OUString const& _aName, bool _bForUpdate)
+{
+ MemberChanges::iterator it = m_aChanges.find(_aName);
+
+ if (it != m_aChanges.end())
+ {
+ if (!it->second.is())
+ OSL_ENSURE(_aName.getLength() == 0, "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
+ }
+
+ sharable::ValueNode * original = getOriginalValueNode(_aName);
+
+ if (_bForUpdate) // create a new change
+ {
+ if (original != 0)
+ {
+ rtl::Reference<ValueMemberNode::DeferredImpl> aNewChange(new ValueMemberNode::DeferredImpl(original));
+ m_aChanges[_aName] = aNewChange;
+
+ return ValueMemberNode(aNewChange);
+ }
+ }
+
+ return GroupNodeImpl::makeValueMember(original);
+}
+//-----------------------------------------------------------------------------
+
+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.getLength() == 0);
+ return true;
+ }
+
+ if (it->second->isChange())
+ return true;
+ }
+
+ return false;
+}
+//-----------------------------------------------------------------------------
+
+void DeferredGroupNodeImpl::collectValueChanges(NodeChanges& rChanges, Tree* pParentTree, unsigned int nNode) const
+{
+ for (MemberChanges::const_iterator it = m_aChanges.begin(); it != m_aChanges.end(); ++it)
+ {
+ if (it->second.is())
+ {
+ OSL_ASSERT(it->first.getLength() != 0);
+ 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.getLength() == 0);
+ }
+}
+//-----------------------------------------------------------------------------
+
+rtl::Reference<ValueMemberNode::DeferredImpl> DeferredGroupNodeImpl::findValueChange(rtl::OUString const& aName)
+{
+ rtl::Reference<ValueMemberNode::DeferredImpl> 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.getLength() == 0, "ERROR: Found empty change reference");
+ }
+
+ return aResult;
+}
+
+//-----------------------------------------------------------------------------
+
+std::auto_ptr<SubtreeChange> DeferredGroupNodeImpl::preCommitValueChanges()
+{
+ std::auto_ptr<SubtreeChange> aRet;
+
+ if (!m_aChanges.empty())
+ {
+ sharable::Node * originalData = this->getOriginalNodeAccess();
+ aRet.reset( new SubtreeChange( originalData->getName(),
+ originalData->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.getLength() == 0);
+ }
+ 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)
+ {
+ rtl::OUString aValueName(it->getNodeName());
+
+ MemberChanges::iterator itStoredChange = m_aChanges.find(aValueName);
+
+ if (itStoredChange != m_aChanges.end())
+ {
+ ValueChange * valueChange = dynamic_cast< ValueChange * >(&*it);
+ OSL_ENSURE(valueChange != 0, "Unexpected type of element change");
+ if (valueChange == 0) throw Exception("Unexpected type of element change");
+
+ rtl::Reference<ValueMemberNode::DeferredImpl> aStoredChange = itStoredChange->second;
+ OSL_ENSURE( aStoredChange.is(), "Found empty change object for Member value change");
+
+ if (aStoredChange.is())
+ {
+ aStoredChange->finishCommit(*valueChange);
+ OSL_ENSURE(!aStoredChange->isChange(),"ValueChange is not moot after finishCommit");
+ }
+
+ m_aChanges.erase( itStoredChange ); // remove finished change
+ }
+ else
+ OSL_ENSURE(dynamic_cast< ValueChange * >(&*it) == 0, "Value member change has no change data representation");
+
+ }
+
+ OSL_DEBUG_ONLY( m_aChanges.erase( rtl::OUString() ) ); // 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)
+ {
+ rtl::OUString aValueName(it->getNodeName());
+
+ MemberChanges::iterator itStoredChange = m_aChanges.find(aValueName);
+
+ if (itStoredChange != m_aChanges.end())
+ {
+ ValueChange * valueChange = dynamic_cast< ValueChange * >(&*it);
+ OSL_ENSURE(valueChange != 0, "Unexpected type of element change");
+ if (valueChange == 0) continue;
+
+ rtl::Reference<ValueMemberNode::DeferredImpl> aStoredChange = itStoredChange->second;
+ OSL_ENSURE( aStoredChange.is(), "Cannot restore change: found empty change object for Member value change");
+
+ if (aStoredChange.is())
+ {
+ aStoredChange->revertCommit(*valueChange);
+ 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(dynamic_cast< ValueChange * >(&*it) == 0, "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)
+ {
+ rtl::OUString aValueName(it->getNodeName());
+
+ MemberChanges::iterator itStoredChange = m_aChanges.find(aValueName);
+
+ if (itStoredChange != m_aChanges.end())
+ {
+ ValueChange * valueChange = dynamic_cast< ValueChange * >(&*it);
+ OSL_ENSURE(valueChange != 0, "Unexpected type of element change");
+ if (valueChange == 0) continue;
+
+ rtl::Reference<ValueMemberNode::DeferredImpl> 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(*valueChange);
+ {
+ if (!aStoredChange->isChange())
+ m_aChanges.erase( itStoredChange ); // remove change if it is moot
+ }
+ }
+ else
+ OSL_ENSURE(dynamic_cast< ValueChange * >(&*it) == 0, "Value member change has no change data representation");
+ }
+
+ OSL_DEBUG_ONLY( m_aChanges.erase( rtl::OUString() ) ); // 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 rtl::Reference<ValueMemberNode::DeferredImpl> at empty name
+ m_aChanges.insert( MemberChanges::value_type() );
+}
+//-----------------------------------------------------------------------------
+
+// Set nodes
+//-----------------------------------------------------------------------------
+
+
+//-----------------------------------------------------------------------------
+// class DeferredTreeSetNodeImpl
+//-----------------------------------------------------------------------------
+
+DeferredSetNodeImpl::DeferredSetNodeImpl(sharable::SetNode * 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::Data::const_iterator it = SetNodeImpl::beginElementSet(), stop = SetNodeImpl::endElementSet();
+ it != stop;
+ ++it)
+ {
+ if (!m_aChangedData.hasElement(it->first)) return false;
+ }}
+
+ return true;
+}
+//-----------------------------------------------------------------------------
+
+ElementTree* DeferredSetNodeImpl::doFindElement(rtl::OUString const& aName)
+{
+ ElementTreeData* 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::Data::const_iterator 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::Data::const_iterator it = m_aChangedData.beginNative(), stop = m_aChangedData.endNative();
+ it != stop;
+ ++it)
+ {
+ ElementTreeData 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::Data::const_iterator 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.get());
+
+ 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::Data::const_iterator 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::Data::const_iterator it = m_aChangedData.beginNative();
+ ElementSet::Data::const_iterator 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(rtl::OUString const& _aName, ElementTreeData const& _aElement)
+{
+ Tree* pContext = this->getParentTree();
+ OSL_ENSURE(pContext, "Context tree must be set before rebuilding");
+
+ rtl::Reference<view::ViewStrategy> xContextBehavior = pContext->getViewBehavior();
+
+ sharable::TreeFragment * elementAccessor = this->getDataAccess()->getElement(_aName);
+ OSL_ENSURE(elementAccessor != 0, "Element Tree not found in data");
+
+ OSL_ENSURE(_aElement.isValid(), "Element not found in view");
+ _aElement->rebuild(xContextBehavior, elementAccessor);
+}
+
+//-----------------------------------------------------------------------------
+std::auto_ptr<SubtreeChange> DeferredSetNodeImpl::preCommitChanges(std::vector< rtl::Reference<ElementTree> >& _rRemovedElements)
+{
+ sharable::Node * originalData = this->getOriginalNodeAccess();
+ // now first get the name of this node
+ rtl::OUString sSetName = originalData->getName();
+
+ // and make a SubtreeChange
+ std::auto_ptr<SubtreeChange> pSetChange( new SubtreeChange(sSetName,
+ getElementTemplate()->getName(),
+ getElementTemplate()->getModule(),
+ originalData->getAttributes() ) );
+
+ // commit preexisting nodes
+ {
+ for(ElementSet::Data::const_iterator 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.get());
+ 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::Data::const_iterator it = m_aChangedData.beginNative();
+ ElementSet::Data::const_iterator const stop = m_aChangedData.endNative();
+
+ while(it != stop)
+ {
+ rtl::OUString aName = it->first;
+ ElementTreeData aNewElement = it->second;
+
+ ElementTreeData* pOriginal = SetNodeImpl::getStoredElement(aName);
+
+ if (aNewElement.isValid())
+ {
+ rtl::Reference< 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, 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,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(),
+ "ERROR: Element template of change does not match the template of the set");
+ OSL_ENSURE( rChanges.getElementTemplateModule() == getElementTemplate()->getModule(),
+ "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)
+ {
+ rtl::OUString aElementName(it->getNodeName());
+
+ ElementTreeData* pOriginal = getStoredElement(aElementName);
+
+ if (ElementTreeData* pNewElement = m_aChangedData.getElement(aElementName))
+ {
+ ElementTreeData aOriginal;
+ if (pOriginal)
+ {
+ aOriginal = *pOriginal;
+ OSL_ASSERT(aOriginal.isValid());
+ }
+ else
+ OSL_ASSERT(!aOriginal.isValid());
+
+ // handle a added, replaced or deleted node
+ rtl::Reference< data::TreeSegment > aRemovedTree;
+
+ if (pNewElement->isValid())
+ {
+ AddNode * addNode = dynamic_cast< AddNode * >(&*it);
+ OSL_ENSURE(addNode != 0, "Unexpected type of element change");
+ if (addNode == 0) throw Exception("Unexpected type of element change");
+
+ aRemovedTree = addNode->getReplacedTree();
+ OSL_ASSERT( addNode->isReplacing() == (0!=pOriginal) );
+ OSL_ASSERT( addNode->isReplacing() == (bool) aRemovedTree.is() );
+
+ if (aOriginal.isValid())
+ SetNodeImpl::replaceElement(aElementName,*pNewElement);
+
+ else
+ SetNodeImpl::insertElement(aElementName,*pNewElement);
+
+ this->rebuildElement(aElementName,*pNewElement);
+ }
+ else
+ {
+ RemoveNode * removeNode = dynamic_cast< RemoveNode * >(&*it);
+ OSL_ENSURE(removeNode != 0, "Unexpected type of element change");
+ if (removeNode == 0) throw Exception("Unexpected type of element change");
+
+ aRemovedTree = removeNode->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");
+ SubtreeChange * subtreeChange = dynamic_cast< SubtreeChange * >(&*it);
+ OSL_ENSURE(subtreeChange != 0, "Unexpected type of element change");
+
+ if (subtreeChange == 0) throw Exception("Unexpected set element change");
+
+ if (pOriginal && pOriginal->isValid())
+ view::ViewTreeAccess(pOriginal->get()).finishCommit(*subtreeChange);
+ }
+ }
+ 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(),
+ "ERROR: Element template of change does not match the template of the set");
+ OSL_ENSURE( rChanges.getElementTemplateModule() == getElementTemplate()->getModule(),
+ "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)
+ {
+ rtl::OUString aElementName(it->getNodeName());
+
+ ElementTreeData* pOriginal = getStoredElement(aElementName);
+
+ if (ElementTreeData* pNewElement = m_aChangedData.getElement(aElementName))
+ {
+ // handle a added, replaced or deleted node
+ rtl::Reference< data::TreeSegment > pRemovedTree;
+
+ if (pNewElement->isValid())
+ {
+ AddNode * addNode = dynamic_cast< AddNode * >(&*it);
+ OSL_ENSURE(addNode != 0, "Unexpected type of element change");
+ if (addNode == 0) throw Exception("Unexpected type of element change");
+
+ pRemovedTree = addNode->getReplacedTree();
+ OSL_ASSERT( addNode->isReplacing() == (0!=pOriginal) );
+ OSL_ASSERT( addNode->isReplacing() == (0!=pRemovedTree.is()) );
+
+ OSL_ENSURE(!addNode->wasInserted(), "Cannot retract new node: Change was integrated");
+
+ rtl::Reference< data::TreeSegment > aAddedTree = addNode->getNewTree();
+ OSL_ENSURE(aAddedTree.is(), "Cannot restore new node: Change lost ownership");
+
+ // restore the tree
+ (*pNewElement)->takeTreeBack(aAddedTree);
+ }
+ else
+ {
+ RemoveNode * removeNode = dynamic_cast< RemoveNode * >(&*it);
+ OSL_ENSURE(removeNode != 0, "Unexpected type of element change");
+ if (removeNode == 0) throw Exception("Unexpected type of element change");
+
+ pRemovedTree = removeNode->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)
+ {
+ 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");
+ SubtreeChange * subtreeChange = dynamic_cast< SubtreeChange * >(&*it);
+ OSL_ENSURE(subtreeChange != 0, "Unexpected set element change");
+
+ if (subtreeChange == 0) throw Exception("Unexpected set element change");
+
+ if (pOriginal && pOriginal->isValid())
+ view::ViewTreeAccess(pOriginal->get()).revertCommit(*subtreeChange);
+ }
+ }
+}
+//-----------------------------------------------------------------------------
+
+void DeferredSetNodeImpl::failedCommit(SubtreeChange& rChanges)
+{
+ OSL_ENSURE(rChanges.isSetNodeChange(),"ERROR: Change type GROUP does not match set");
+ OSL_ENSURE( rChanges.getElementTemplateName() == getElementTemplate()->getName(),
+ "ERROR: Element template of change does not match the template of the set");
+ OSL_ENSURE( rChanges.getElementTemplateModule() == getElementTemplate()->getModule(),
+ "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)
+ {
+ rtl::OUString aElementName(it->getNodeName());
+
+ ElementTreeData* pOriginal = getStoredElement(aElementName);
+
+ if (ElementTreeData* pNewElement = m_aChangedData.getElement(aElementName))
+ {
+ ElementTreeData aOriginal;
+ if (pOriginal)
+ {
+ aOriginal = *pOriginal;
+ OSL_ASSERT(aOriginal.isValid());
+ }
+ else
+ OSL_ASSERT(!aOriginal.isValid());
+
+ // handle a added, replaced or deleted node
+ rtl::Reference< data::TreeSegment > aRemovedTree;
+
+ if (pNewElement->isValid())
+ {
+ AddNode * addNode = dynamic_cast< AddNode * >(&*it);
+ OSL_ENSURE(addNode != 0, "Unexpected type of element change");
+ if (addNode == 0) throw Exception("Unexpected type of element change");
+
+ aRemovedTree = addNode->getReplacedTree();
+ OSL_ASSERT( addNode->isReplacing() == (0!=pOriginal) );
+ OSL_ASSERT( addNode->isReplacing() == (bool) aRemovedTree.is() );
+
+ if (addNode->wasInserted())
+ { // it has been integrated into the master tree
+ OSL_ENSURE(getDataAccess()->getElement(aElementName) == addNode->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)
+ {
+ rtl::Reference< data::TreeSegment > aAddedTree = addNode->getNewTree();
+
+ OSL_ENSURE(aAddedTree.is(), "Unexpected: added node is gone, but where ? May cause invalid references");
+ (*pNewElement)->takeTreeBack(aAddedTree);
+ detach(*pNewElement);
+ }
+ }
+ else
+ {
+ RemoveNode * removeNode = dynamic_cast< RemoveNode * >(&*it);
+ OSL_ENSURE(removeNode != 0, "Unexpected type of element change");
+ if (removeNode == 0) throw Exception("Unexpected type of element change");
+
+ aRemovedTree = removeNode->getRemovedTree();
+
+ OSL_ASSERT(aOriginal.isValid());
+ if (aRemovedTree.is() && getDataAccess()->getElement(aElementName) == 0)
+ {
+ // 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");
+ SubtreeChange * subtreeChange = dynamic_cast< SubtreeChange * >(&*it);
+ OSL_ENSURE(subtreeChange != 0, "Unexpected set element change");
+
+ if (subtreeChange == 0) throw Exception("Unexpected set element change");
+
+ if (pOriginal && pOriginal->isValid())
+ view::ViewTreeAccess(pOriginal->get()).recoverFailedCommit(*subtreeChange);
+ }
+ }
+ m_bChanged = false;
+ m_bDefault = false;
+
+ OSL_ENSURE(m_aChangedData.isEmpty(), "ERROR: Uncommitted changes left in set node");
+}
+//-----------------------------------------------------------------------------
+
+void DeferredSetNodeImpl::insertNewElement(rtl::OUString const& aName, ElementTreeData const& aNewElement)
+{
+ attach(aNewElement,aName);
+ try
+ {
+ // put the new element into the changed set
+ ElementTreeData* 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(rtl::OUString const& aName)
+{
+ // put an empty (dummy) element into the changed set
+ ElementTreeData* pAddedElement = m_aChangedData.getElement(aName);
+ if (pAddedElement)
+ {
+ OSL_ENSURE(pAddedElement->isValid(),"WARNING: Element being removed was already removed");
+ detach(m_aChangedData.replaceElement(aName, ElementTreeData()));
+ m_bChanged = true;
+ m_bDefault = false;
+ }
+ else
+ {
+ m_aChangedData.insertElement(aName, ElementTreeData());
+ }
+
+ // now check the original one
+ ElementTreeData* 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, rtl::OUString const& aName, Change const& aChange)
+{
+ if (ElementTreeData* pLocalElement = m_aChangedData.getElement(aName))
+ {
+ if (ElementTreeData* pElement = getStoredElement(aName))
+ {
+ OSL_ASSERT(pElement->isValid());
+
+ if (SubtreeChange const * subtreeChange = dynamic_cast< SubtreeChange const * >(&aChange))
+ {
+ // recurse to element tree - but do not notify those changes (?)
+ Tree * elementTree = pElement->get();
+
+ NodeChangesInformation aIgnoredChanges;
+ view::getViewBehavior(elementTree)->adjustToChanges(aIgnoredChanges, view::getRootNode(elementTree), *subtreeChange);
+ }
+ else
+ {
+ OSL_ENSURE(dynamic_cast<ValueChange const * >(&aChange) != 0, "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
+ ElementTreeData 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(rtl::OUString const& aName, AddNode const& aAddNodeChange, ElementTreeData const& aNewElement)
+{
+ m_bDefault = false;
+ if (ElementTreeData* 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
+ {
+ ElementTreeData 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(rtl::OUString const& aName, RemoveNode const& /*aRemoveNodeChange*/)
+{
+ m_bDefault = false;
+ if (ElementTreeData* pLocalElement = m_aChangedData.getElement(aName))
+ {
+ if (hasStoredElement(aName))
+ {
+ // take away the original
+ this->removeElement(aName);
+ }
+
+ if (pLocalElement->isValid()) // remains a valid replacement
+ {
+ ElementTreeData 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::Data::const_iterator it = m_aChangedData.beginNative();
+ ElementSet::Data::const_iterator const stop = m_aChangedData.endNative();
+
+ while(it != stop)
+ {
+ rtl::OUString aName = it->first;
+ ElementTreeData aElement = it->second;
+
+ Change* pChange = _rChangeToDefault.getChange( aName );
+ OSL_ENSURE(pChange == NULL || dynamic_cast< AddNode * >(pChange) != 0 || dynamic_cast< RemoveNode * >(pChange) != 0,
+ "Unexpected change type found in difference to default tree");
+
+ if (pChange == NULL)
+ {
+ std::auto_ptr<INode> aDefaultNode = _rDefaultTree.removeChild(aName);
+ OSL_ENSURE( aDefaultNode.get(), "Error: unused Default tree not found after SetNodeImpl::implDifferenceToDefaultState");
+
+ rtl::OUString aElementTypeName = _rDefaultTree.getElementTemplateName();
+ OSL_ENSURE( _rDefaultTree.isSetNode(), "Error: missing set template information in default data");
+
+ rtl::Reference< data::TreeSegment > aDefaultTree = data::TreeSegment::create(aDefaultNode,aElementTypeName);
+ OSL_ENSURE(aDefaultTree.is(), "Error: unused Default tree not accessible after SetNodeImpl::implDifferenceToDefaultState");
+
+ AddNode* pAddIt = new AddNode(aDefaultTree, aName, 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 (AddNode * addNode = dynamic_cast< AddNode * >(pChange))
+ {
+ // adjust the AddNode - remove the original expected node
+ addNode->clearReplacedTree();
+
+ if (aElement.isValid())
+ {
+ if (aElement.inDefault)
+ {
+ // change already done locally
+ _rChangeToDefault.removeChange(aName);
+ }
+ else // adjust here
+ addNode->setReplacing();
+ }
+
+ else
+ OSL_ENSURE(!addNode->isReplacing(),"Could not unmark the 'replacing' state of an AddNode");
+ }
+ else if (RemoveNode * removeNode = dynamic_cast< RemoveNode * >(pChange))
+ {
+ if (aElement.isValid())
+ {
+ OSL_ENSURE(!aElement.inDefault, "Default element replaced by default");
+ // adjust the RemoveNode - remove the original expected node
+ removeNode->clearRemovedTree();
+ }
+ else
+ {
+ // change already done locally
+ _rChangeToDefault.removeChange(aName);
+ }
+ // TODO: mark local removal as to-default
+ }
+ }
+ }
+}
+//-----------------------------------------------------------------------------
+ }
+}