office-gobmx/configmgr/source/tree/mergehelper.cxx
Oliver Bolte 267744e7a9 INTEGRATION: CWS pchfix02 (1.6.60); FILE MERGED
2006/09/01 17:20:42 kaib 1.6.60.1: #i68856# Added header markers and pch files
2006-09-16 14:21:19 +00:00

493 lines
17 KiB
C++

/*************************************************************************
*
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: mergehelper.cxx,v $
*
* $Revision: 1.7 $
*
* last change: $Author: obo $ $Date: 2006-09-16 15:21:19 $
*
* The Contents of this file are made available subject to
* the terms of GNU Lesser General Public License Version 2.1.
*
*
* GNU Lesser General Public License Version 2.1
* =============================================
* Copyright 2005 by Sun Microsystems, Inc.
* 901 San Antonio Road, Palo Alto, CA 94303, USA
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
*
* This library 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 for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
************************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_configmgr.hxx"
#include <stdio.h>
#include "mergehelper.hxx"
#ifndef CONFIGMGR_NODECONVERTER_HXX
#include "nodeconverter.hxx"
#endif
#ifndef CONFIGMGR_TREEPROVIDER_HXX
#include "treeprovider.hxx"
#endif
#ifndef CONFIGMGR_TREE_NODEFACTORY_HXX
#include "treenodefactory.hxx"
#endif
#ifndef CONFIGMGR_TREE_CHANGEFACTORY_HXX
#include "treechangefactory.hxx"
#endif
#ifndef CONFIGMGR_CONFIGPATH_HXX_
#include "configpath.hxx"
#endif
#ifndef _CONFIGMGR_TRACER_HXX_
#include "tracer.hxx"
#endif
#ifndef _OSL_DIAGNOSE_H_
#include <osl/diagnose.h>
#endif
//..........................................................................
namespace configmgr
{
namespace
{
//==========================================================================
//= OCleanupLayerAction
//==========================================================================
//= This class cleans up a layer to be merged into an existing tree
//==========================================================================
class OCleanupLayerAction : ChangeTreeModification
{
SubtreeChange& m_rResultTree; // list which containes changes merged with the existing nodes
ISubtree const & m_rTargetTree; // reference node needed for merging
OTreeNodeConverter m_aNodeConverter;
public:
static bool adjust(SubtreeChange& _rResultTree, SubtreeChange& _aLayerTree, ISubtree const& _aTargetTree)
{
return OCleanupLayerAction(_rResultTree,_aTargetTree).impl_cleanup(_aLayerTree);
}
static bool adjust(SubtreeChange& _rResultTree, SubtreeChange& _aLayerTree, ISubtree const& _aTargetTree, OTreeNodeFactory& _rNodeFactory)
{
return OCleanupLayerAction(_rResultTree,_aTargetTree,_rNodeFactory).impl_cleanup(_aLayerTree);
}
private:
OCleanupLayerAction(SubtreeChange& _rResult, ISubtree const& _rTree)
:m_rResultTree(_rResult)
,m_rTargetTree(_rTree)
,m_aNodeConverter()
{}
OCleanupLayerAction(SubtreeChange& _rResult, ISubtree const& _rTree, OTreeNodeFactory& _rNodeFactory)
:m_rResultTree(_rResult)
,m_rTargetTree(_rTree)
,m_aNodeConverter(_rNodeFactory)
{}
void handle(ValueChange& aValueNode);
void handle(AddNode& aAddNode);
void handle(RemoveNode& aRemoveNode);
void handle(SubtreeChange& aSubtree);
bool impl_cleanup(SubtreeChange& _aUpdateTree);
void add(std::auto_ptr<Change> _pChange);
void addReplacedNode(data::TreeSegment const & _aReplacedTree);
void addReplacedNode(std::auto_ptr<INode> _aReplacedNode);
};
// --------------------------------- MergeLayerToTree ---------------------------------
class MergeLayerToTree : ChangeTreeModification
{
ISubtree& m_rTree;
public:
explicit
MergeLayerToTree(ISubtree& _rTree):m_rTree(_rTree) {}
MergeLayerToTree& merge(SubtreeChange & _rLayerTree);
private:
void handle(ValueChange& aValueNode);
void handle(AddNode& aAddNode);
void handle(RemoveNode& aRemoveNode);
void handle(SubtreeChange& aSubtree);
static void mergeAttributes(INode& _rNode, node::Attributes const& _aChangeAttributes);
};
// --------------------------------- AttributeSetter ---------------------------------
class AttributeSetter : NodeModification
{
node::State m_state;
bool m_bPromoteFinalized;
public:
explicit
AttributeSetter(node::State _state, bool _bPromoteFinalized)
: m_state(_state)
, m_bPromoteFinalized(_bPromoteFinalized)
{}
void setNodeAttributes(INode& _rNode);
using NodeModification::applyToNode;
private:
void handle(ValueNode& _rValueNode);
void handle(ISubtree& _rSubtree);
};
// -----------------------------------------------------------------------------
} // anon namepsace
// -----------------------------------------------------------------------------
// this is our 'exported' function
void mergeLayerToTree(SubtreeChange & _aLayerTree,ISubtree& _aTree)
{
// coarse: _aTree += _aLayerTree;
AttributeSetter(node::isDefault, true).applyToNode(_aTree);
SubtreeChange aMergeChange(_aLayerTree, SubtreeChange::NoChildCopy());
if (OCleanupLayerAction::adjust(aMergeChange,_aLayerTree,_aTree))
MergeLayerToTree(_aTree).merge(aMergeChange);
}
// -----------------------------------------------------------------------------
namespace
{
//==========================================================================
//= OCleanupLayerAction
//==========================================================================
static inline bool isFinal(node::Attributes const& _aAttributes)
{
return _aAttributes.isFinalized() || _aAttributes.isReadonly();
}
//==========================================================================
bool OCleanupLayerAction::impl_cleanup(SubtreeChange& _aUpdateTree)
{
OSL_ENSURE(!_aUpdateTree.isReplacedNode(), "Layer cleanup: A replaced tree should not be merged");
if (isFinal(m_rTargetTree.getAttributes()))
{
CFG_TRACE_WARNING("Layer cleanup : Ignoring change to write-protected tree '%s'",OUSTRING2ASCII(m_rTargetTree.getName()));
return false;
}
// first check the changes
this->applyToChildren(_aUpdateTree);
return m_rResultTree.size() != 0;
}
//--------------------------------------------------------------------------
inline void OCleanupLayerAction::add(std::auto_ptr<Change> _aChange)
{
m_rResultTree.addChange(_aChange);
}
//--------------------------------------------------------------------------
void OCleanupLayerAction::handle(ValueChange& _rChange)
{
OUString const sNodeName = _rChange.getNodeName();
OSL_ENSURE(!_rChange.isToDefault(),"Found change to default in layer being merged");
// replaced state -> should be a full (added/replaced) node
//if (_rChange.isReplacedNode() && m_rTargetTree.isSetNodeChange())
if ( _rChange.isReplacedValue() )
{
std::auto_ptr<ValueNode> pNode( m_aNodeConverter.createCorrespondingNode(_rChange) );
this->addReplacedNode( base_ptr(pNode) );
}
else if (INode const * const pTargetNode = m_rTargetTree.getChild(sNodeName))
{
// this mismatch is not discarded here (should be ignored while merging though)
OSL_ENSURE(pTargetNode->asValueNode(), "Layer cleanup : Node type mismatch: Value change applied to non-value node !");
if (!isFinal(pTargetNode->getAttributes()))
{
std::auto_ptr<Change> pResult( new ValueChange(_rChange) );
this->add(pResult);
}
else
{
CFG_TRACE_WARNING("Layer cleanup : Ignoring change to write-protected value '%s'",OUSTRING2ASCII(sNodeName));
}
}
else
{
OSL_TRACE("Layer cleanup : Found orphaned node (value) '%s'",OUSTRING2ASCII(sNodeName));
CFG_TRACE_INFO("Layer cleanup : Found orphaned node (value) '%s'",OUSTRING2ASCII(sNodeName));
OSL_ENSURE(false, "Layer cleanup : Found orphaned Value");
}
}
//--------------------------------------------------------------------------
void OCleanupLayerAction::handle(SubtreeChange& _rChange)
{
OUString const sNodeName = _rChange.getNodeName();
OSL_ENSURE(!_rChange.isToDefault(),"Found change to default in layer being merged");
// replaced state -> should be a full (added/replaced) node
if (_rChange.isReplacedNode())
{
std::auto_ptr<ISubtree> pNode = m_aNodeConverter.createCorrespondingTree(_rChange);
// mark as complete with defaults)
pNode->setLevels(treeop::ALL_LEVELS,treeop::ALL_LEVELS);
this->addReplacedNode( base_ptr(pNode) );
}
else if ( INode const * const pTargetNode = m_rTargetTree.getChild(sNodeName) )
{
ISubtree const * pTargetTree = pTargetNode->asISubtree();
if (pTargetTree)
{
// generate a new change
std::auto_ptr<SubtreeChange> pResult( new SubtreeChange(_rChange, SubtreeChange::NoChildCopy()) );
// recurse
if ( adjust(*pResult,_rChange,*pTargetTree,m_aNodeConverter.nodeFactory()) )
this->add(base_ptr(pResult));
else
CFG_TRACE_INFO("Layer cleanup : Found void modification tree '%s'",OUSTRING2ASCII(sNodeName));
}
else
{
OSL_ENSURE(false, "Layer cleanup : Node type mismatch: Tree change applied to non-tree node !");
CFG_TRACE_ERROR("Layer cleanup : Discarding schema violation for node '%s'",OUSTRING2ASCII(sNodeName));
//throw Whatever();
}
}
else
{
OSL_TRACE("Layer cleanup : Found orphaned node (subtree) '%s'",OUSTRING2ASCII(sNodeName));
CFG_TRACE_INFO("Layer cleanup : Found orphaned node (subtree) '%s'",OUSTRING2ASCII(sNodeName));
}
}
//--------------------------------------------------------------------------
void OCleanupLayerAction::handle(RemoveNode& _rChange)
{
OUString const sNodeName = _rChange.getNodeName();
OSL_ENSURE(!_rChange.isToDefault(),"Found change to default in layer being merged");
OSL_ENSURE(m_rTargetTree.isSetNode(),"Found RemoveNode for non-set-element in layer being merged");
// look up the corresponding node
INode const * const pTargetNode = m_rTargetTree.getChild(sNodeName);
if (pTargetNode)
{
// generate the same change
std::auto_ptr<Change> pResult( new RemoveNode(sNodeName,false) );
this->add(pResult);
}
else
{
OSL_TRACE("Layer cleanup : Found orphaned node (removal) '%s'",OUSTRING2ASCII(sNodeName));
CFG_TRACE_INFO("Layer cleanup : Found orphaned node (removal) '%s'",OUSTRING2ASCII(sNodeName));
}
}
//--------------------------------------------------------------------------
void OCleanupLayerAction::handle(AddNode& _rChange)
{
OSL_ENSURE(!_rChange.isToDefault(),"Found change to default in layer being merged");
// generate the same change
this->addReplacedNode( _rChange.getNewTree() );
}
//--------------------------------------------------------------------------
void OCleanupLayerAction::addReplacedNode(std::auto_ptr<INode> _aReplacedNode)
{
OSL_ENSURE(m_rTargetTree.isSetNode(),"Found replaced node for non-set-element in layer being merged");
OSL_ASSERT(_aReplacedNode.get());
OUString sTypeName = m_rTargetTree.getElementTemplateName();
this->addReplacedNode( data::TreeSegment::createNew(_aReplacedNode,sTypeName) );
}
//--------------------------------------------------------------------------
void OCleanupLayerAction::addReplacedNode(data::TreeSegment const & _aReplacedTree)
{
OSL_ENSURE(m_rTargetTree.isSetNode(),"Found replaced node for non-set-element in layer being merged");
OSL_ASSERT(_aReplacedTree.is());
OUString sNodeName = _aReplacedTree.getName().toString();
// add the tree to the change list
std::auto_ptr<AddNode> pResult( new AddNode(_aReplacedTree,sNodeName, false) );
// look up the corresponding existing node
INode const * const pTargetNode = m_rTargetTree.getChild(sNodeName);
if (pTargetNode) pResult->setReplacing();
this->add( base_ptr(pResult) );
}
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
void MergeLayerToTree::mergeAttributes(INode& _rNode, node::Attributes const& _aChangeAttributes)
{
OSL_ENSURE(!isFinal(_rNode.getAttributes()),"Layer merge: Node being merged is READONLY - cleanup broken");
OSL_ENSURE(_aChangeAttributes.state() == node::isMerged,"Layer merge: Found unexpected state for change being merged");
_rNode.modifyState(node::isMerged);
_rNode.modifyAccess(_aChangeAttributes.getAccess());
}
//--------------------------------------------------------------------------
MergeLayerToTree& MergeLayerToTree::merge(SubtreeChange & _rLayerTree)
{
OSL_ENSURE(_rLayerTree.getNodeName() == m_rTree.getName(),"Layer merge: change does not match tree");
this->applyToChildren(_rLayerTree);
mergeAttributes(m_rTree,_rLayerTree.getAttributes());
return *this;
}
//--------------------------------------------------------------------------
void MergeLayerToTree::handle(ValueChange& _rChange)
{
OSL_ENSURE(!_rChange.isToDefault(),"Layer merge: Found change to default - cleanup broken");
OUString const sNodeName = _rChange.getNodeName();
INode * const pTargetNode = m_rTree.getChild(sNodeName);
OSL_ENSURE(pTargetNode,"Layer merge: Found NULL value - cleanup broken");
OSL_ENSURE(!isFinal(pTargetNode->getAttributes()),"Layer merge: Found READONLY value - cleanup broken");
if (ValueNode* pTargetValue = pTargetNode->asValueNode() )
{
_rChange.applyChangeNoRecover(*pTargetValue);
mergeAttributes(*pTargetValue,_rChange.getAttributes());
}
else
{
OSL_ENSURE(false, "Layer merge : Node type mismatch: Value change applied to non-value node !");
CFG_TRACE_ERROR("Layer merge : Discarding schema violation for value '%s'",OUSTRING2ASCII(sNodeName));
//throw Whatever();
}
}
//--------------------------------------------------------------------------
void MergeLayerToTree::handle(AddNode& _rChange)
{
OUString const sNodeName = _rChange.getNodeName();
node::State eNodeState = node::isAdded;
if (_rChange.isReplacing())
{
OSL_VERIFY( m_rTree.removeChild(sNodeName).get() );
eNodeState = node::isReplaced;
}
OSL_ENSURE( !m_rTree.getChild(sNodeName),"Layer merge: Found conflicting data on insert - cleanup broken");
data::TreeSegment aAddedTree = _rChange.getNewTree();
OSL_ENSURE( aAddedTree.is(),"Layer merge: Found empty data on insert - cleanup broken");
// clean up the attributes of the added node
data::TreeSegment::RawTreeData aAddedData = aAddedTree.cloneData(true);
AttributeSetter(eNodeState,false).applyToNode(*aAddedData);
m_rTree.addChild(aAddedData);
}
//--------------------------------------------------------------------------
void MergeLayerToTree::handle(RemoveNode& _rChange)
{
OUString const sNodeName = _rChange.getNodeName();
// should have such a node when removing
OSL_VERIFY( m_rTree.removeChild(sNodeName).get() );
}
//--------------------------------------------------------------------------
void MergeLayerToTree::handle(SubtreeChange& _rChange)
{
OSL_ENSURE(!_rChange.isToDefault(),"Layer merge: Found change to default - cleanup broken");
OUString const sNodeName = _rChange.getNodeName();
INode * const pTargetNode = m_rTree.getChild(sNodeName);
OSL_ENSURE(pTargetNode,"Layer merge: Found NULL subtree - cleanup broken");
OSL_ENSURE(!isFinal(pTargetNode->getAttributes()),"Layer merge: Found READONLY subtree - cleanup broken");
ISubtree * const pTargetTree = pTargetNode->asISubtree();
OSL_ENSURE(pTargetTree,"Layer merge: Found non-tree for SubtreeChange - cleanup broken");
// recurse
MergeLayerToTree(*pTargetTree).merge(_rChange);
}
//--------------------------------------------------------------------------
void AttributeSetter::setNodeAttributes(INode& _rNode)
{
node::Attributes const aOldAttributes = _rNode.getAttributes();
_rNode.modifyState(m_state);
if (m_bPromoteFinalized && isFinal(aOldAttributes))
_rNode.modifyAccess(node::accessReadonly);
}
// -----------------------------------------------------------------------------
void AttributeSetter::handle(ValueNode& _rValueNode)
{
setNodeAttributes(_rValueNode);
}
// -----------------------------------------------------------------------------
void AttributeSetter::handle(ISubtree& _rSubtree)
{
setNodeAttributes(_rSubtree);
this->applyToChildren(_rSubtree);
}
//--------------------------------------------------------------------------
} // anonymous namespace
//..........................................................................
} // namespace configmgr
//..........................................................................