office-gobmx/configmgr/source/treemgr/viewstrategy.cxx
Rüdiger Timm fcac1fc2ac INTEGRATION: CWS changefileheader (1.11.16); FILE MERGED
2008/04/01 12:27:39 thb 1.11.16.2: #i85898# Stripping all external header guards
2008/03/31 12:22:57 rt 1.11.16.1: #i87441# Change license header to LPGL v3.
2008-04-11 12:59:54 +00:00

669 lines
27 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: viewstrategy.cxx,v $
* $Revision: 1.12 $
*
* 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 "viewstrategy.hxx"
#include "valuenodeimpl.hxx"
#include "groupnodeimpl.hxx"
#include "setnodeimpl.hxx"
#include "change.hxx"
#include "nodevisitor.hxx"
#include "groupnodeaccess.hxx"
#include "setnodeaccess.hxx"
#include "nodechange.hxx"
#include "nodechangeimpl.hxx"
#include "nodeconverter.hxx"
//-----------------------------------------------------------------------------
namespace configmgr
{
//-----------------------------------------------------------------------------
namespace view
{
//-----------------------------------------------------------------------------
using configuration::SetEntry;
using configuration::ElementList;
using configuration::GroupMemberVisitor;
using configuration::SetNodeVisitor;
static
inline
data::ValueNodeAccess getMemberValueAccess( GroupNode const & _aGroupNode, Name const & _aName )
{
configuration::GroupNodeImpl* pGroupData = _aGroupNode.get_impl();
return pGroupData->getOriginalValueNode(_aName);
}
//-----------------------------------------------------------------------------
void ViewStrategy::checkInstance(Tree const& _aTreeForThis) const
{
{ (void)_aTreeForThis; }
OSL_ENSURE( getViewBehavior(_aTreeForThis).get() == this,
"Tree operation dispatched to wrong strategy instance");
}
//-----------------------------------------------------------------------------
void ViewStrategy::collectChanges(Tree const& _aTree, NodeChanges& rChanges) const
{
checkInstance(_aTree);
doCollectChanges( getRootNode(_aTree), rChanges );
}
bool ViewStrategy::hasChanges(Tree const& _aTree) const
{
checkInstance(_aTree);
return hasChanges( getRootNode(_aTree) );
}
// mark the given node and all its ancestors (we can stop when we hit a node that already is marked)
void ViewStrategy::markChanged(Node const& _aNode)
{
Tree aTree = _aNode.tree();
checkInstance(aTree);
Node aNode = _aNode;
if (aNode.is())
{
do
{
this->doMarkChanged(aNode);
aNode = aNode.getParent();
}
while (aNode.is() && !this->hasChanges( aNode ));
}
if (!aNode.is()) // just marked the root
{
configuration::TreeImpl* pTreeData = aTree.get_impl();
configuration::TreeImpl* pContext = pTreeData->getContextTree();
NodeOffset nContext = pTreeData->getContextNode();
if (pContext)
{
OSL_ASSERT(pContext->isValidNode(nContext));
view::Node aContextNode(*pContext,nContext);
pContext->getViewBehavior()->markChanged(aContextNode);
}
}
}
//-----------------------------------------------------------------------------
std::auto_ptr<SubtreeChange> ViewStrategy::preCommitChanges(Tree const& _aTree, ElementList& _rRemovedElements)
{
checkInstance(_aTree);
return doPreCommitChanges( _aTree, _rRemovedElements);
}
void ViewStrategy::finishCommit(Tree const& _aTree, SubtreeChange& rRootChange)
{
checkInstance(_aTree);
doFinishCommit(_aTree, rRootChange);
}
void ViewStrategy::revertCommit(Tree const& _aTree, SubtreeChange& rRootChange)
{
checkInstance(_aTree);
doRevertCommit(_aTree, rRootChange);
}
void ViewStrategy::recoverFailedCommit(Tree const& _aTree, SubtreeChange& rRootChange)
{
checkInstance(_aTree);
doFailedCommit(_aTree, rRootChange);
}
//-----------------------------------------------------------------------------
void ViewStrategy::adjustToChanges(NodeChangesInformation& rLocalChanges, Node const& _aNode, SubtreeChange const& aExternalChange)
{
OSL_PRECOND( isValidNode(_aNode), "ERROR: Valid node required for adjusting to changes" );
OSL_PRECOND( getSimpleNodeName(_aNode).toString() == aExternalChange.getNodeName(), "Name of change does not match actual node" );
checkInstance(_aNode.tree());
configuration::TreeImpl * pTreeData = _aNode.tree().get_impl();
if (_aNode.isSetNode())
{
OSL_ENSURE(aExternalChange.isSetNodeChange(),"ERROR: Change type GROUP does not match set");
TreeDepth nDepth = pTreeData->getRemainingDepth(_aNode.get_offset());
implAdjustToElementChanges( rLocalChanges, SetNode(_aNode), aExternalChange, nDepth);
}
else if (_aNode.isGroupNode())
{
OSL_ENSURE(!aExternalChange.isSetNodeChange(),"ERROR: Change type SET does not match group");
GroupNode aGroupNode(_aNode);
implAdjustToValueChanges(rLocalChanges, aGroupNode, aExternalChange);
implAdjustToSubChanges( rLocalChanges, aGroupNode, aExternalChange);
}
else // might occur on external change (?)
{
OSL_ENSURE(_aNode.isValueNode(), "TreeImpl: Unknown node type to adjust to changes");
OSL_ENSURE(_aNode.get_offset() == pTreeData->root_(), "TreeImpl: Unexpected node type - non-root value element");
OSL_ENSURE(false,"ERROR: Change type does not match node: Trying to apply subtree change to value element.");
}
}
//-----------------------------------------------------------------------------
void ViewStrategy::addLocalChangeHelper( NodeChangesInformation& rLocalChanges_, configuration::NodeChange const& aChange_)
{
aChange_.getChangeInfos(rLocalChanges_);
}
//-----------------------------------------------------------------------------
// TO DO: create CommitAction class, which is returned by precommit (if applicable)
std::auto_ptr<SubtreeChange> ViewStrategy::doPreCommitChanges(Tree const& _aTree, configuration::ElementList& )
{
{ (void)_aTree; }
OSL_ENSURE(!hasChanges(getRootNode(_aTree)),"Unexpected changes in View");
return std::auto_ptr<SubtreeChange>();
}
void ViewStrategy::doFinishCommit(Tree const& _aTree, SubtreeChange& )
{
{ (void)_aTree; }
OSL_ENSURE(!hasChanges(getRootNode(_aTree)),"Unexpected changes in View");
OSL_ENSURE(false,"ERROR: Cannot finish commit for unexpected changes");
}
void ViewStrategy::doRevertCommit(Tree const& _aTree, SubtreeChange& )
{
{ (void)_aTree; }
OSL_ENSURE(!hasChanges(getRootNode(_aTree)),"Unexpected changes in View");
OSL_ENSURE(false,"ERROR: Cannot revert commit for unexpected changes");
}
void ViewStrategy::doFailedCommit(Tree const& _aTree, SubtreeChange& )
{
{ (void)_aTree; }
OSL_ENSURE(!hasChanges(getRootNode(_aTree)),"Unexpected changes in View");
OSL_ENSURE(false,"ERROR: Cannot recover commit for unexpected changes");
}
//-----------------------------------------------------------------------------
void ViewStrategy::implAdjustToElementChange(NodeChangesInformation& rLocalChanges, SetNode const& _aSetNode, Change const& rElementChange, TreeDepth nDepth)
{
using namespace configuration;
SetNodeImpl * pSetData = _aSetNode.get_impl();
OSL_ENSURE( pSetData->implHasLoadedElements() , "Unexpected call: Processing element change in uninitialized set");
Name aName = makeElementName( rElementChange.getNodeName(), Name::NoValidate() );
SetElementChangeImpl* pThisChange = 0;
if (rElementChange.ISA(AddNode))
{
AddNode const& aAddNode = static_cast<AddNode const&>(rElementChange);
SetNodeElement aNewElement = pSetData->makeAdditionalElement(this,aAddNode,nDepth);
pThisChange = pSetData->doAdjustToAddedElement(aName, aAddNode,aNewElement);
}
else if (rElementChange.ISA(RemoveNode))
{
RemoveNode const& aRemoveNode = static_cast<RemoveNode const&>(rElementChange);
pThisChange = pSetData->doAdjustToRemovedElement(aName, aRemoveNode);
}
else
{
if (nDepth > 0 || (NULL != pSetData->doFindElement(aName)) )// found even beyond nDepth ?
{
pThisChange = pSetData->doAdjustChangedElement(rLocalChanges,aName, rElementChange);
}
}
if (pThisChange)
{
addLocalChangeHelper( rLocalChanges, NodeChange(pThisChange) );
}
}
void ViewStrategy::implAdjustToElementChanges(NodeChangesInformation& rLocalChanges, SetNode const& _aSetNode, SubtreeChange const& rExternalChanges, TreeDepth nDepth)
{
if (nDepth > 0)
{
configuration::SetNodeImpl * pSetData = _aSetNode.get_impl();
OSL_ENSURE( pSetData->getTemplateProvider().isValid(), "Cannot adjust SetNode to changes - node was never initialized" );
if (pSetData->implHasLoadedElements())
{
TreeDepth const nElementDepth = configuration::childDepth(nDepth);
for (SubtreeChange::ChildIterator it = rExternalChanges.begin(); it != rExternalChanges.end(); ++it)
{
this->implAdjustToElementChange(rLocalChanges, _aSetNode, *it, nElementDepth);
}
}
else
{
OSL_ENSURE( !hasChanges(_aSetNode.node()),"Cannot have changes to consider when no elements are loaded");
pSetData->convertChanges( rLocalChanges, rExternalChanges, nDepth);
}
}
}
configuration::ValueChangeImpl* ViewStrategy::doAdjustToValueChange(GroupNode const& _aGroupNode, Name const& _aName, ValueChange const& _rExternalChange)
{
using namespace configuration;
ValueChangeImpl* pChangeImpl = NULL;
data::ValueNodeAccess aLocalNode = getMemberValueAccess(_aGroupNode,_aName);
if (aLocalNode.isValid())
{
switch( _rExternalChange. getMode() )
{
case ValueChange::wasDefault:
case ValueChange::changeValue:
pChangeImpl = new ValueReplaceImpl( _rExternalChange.getNewValue(), _rExternalChange.getOldValue() );
break;
case ValueChange::setToDefault:
pChangeImpl = new ValueResetImpl( _rExternalChange.getNewValue(), _rExternalChange.getOldValue() );
break;
default: OSL_ENSURE(false, "Unknown change mode");
// fall thru to next case for somewhat meaningful return value
case ValueChange::changeDefault:
{
UnoAny aLocalValue = aLocalNode.getValue();
pChangeImpl = new ValueReplaceImpl( aLocalValue, aLocalValue );
}
break;
}
OSL_ASSERT( pChangeImpl );
}
else
{
OSL_ENSURE(false, "ERROR: Notification tries to change nonexistent value within group");
}
return pChangeImpl;
}
void ViewStrategy::implAdjustToValueChanges(NodeChangesInformation& rLocalChanges, GroupNode const& _aGroupNode, SubtreeChange const& rExternalChanges)
{
for (SubtreeChange::ChildIterator it = rExternalChanges.begin(); it != rExternalChanges.end(); ++it)
{
using namespace configuration;
if (it->ISA(ValueChange))
{
ValueChange const& rValueChange = static_cast<ValueChange const&>(*it);
Name aValueName = makeNodeName( rValueChange.getNodeName(), Name::NoValidate() );
if (ValueChangeImpl* pThisChange = doAdjustToValueChange(_aGroupNode, aValueName, rValueChange))
{
pThisChange->setTarget(_aGroupNode,aValueName);
addLocalChangeHelper(rLocalChanges, NodeChange(pThisChange));
}
else
OSL_TRACE("WARNING: Configuration: derived class hides an external value member change from listeners");
}
else
OSL_ENSURE(it->ISA(SubtreeChange), "Unexpected change type within group");
}
}
void ViewStrategy::implAdjustToSubChanges(NodeChangesInformation& rLocalChanges, GroupNode const& _aGroupNode, SubtreeChange const& rExternalChanges)
{
using namespace configuration;
#if (OSL_DEBUG_LEVEL > 0)
TreeImpl * pTreeData = _aGroupNode.tree().get_impl();
#endif
for(SubtreeChange::ChildIterator it = rExternalChanges.begin(); it != rExternalChanges.end(); ++it)
{
if ( it->ISA(SubtreeChange) )
{
Node aSubNode = _aGroupNode.findChild( makeNodeName(it->getNodeName(), Name::NoValidate()) );
OSL_ENSURE( aSubNode.is() || pTreeData->depthTo(_aGroupNode.node().get_offset()) >= pTreeData->getAvailableDepth(), "Changed node not found in tree");
if (aSubNode.is())
{
OSL_ENSURE( pTreeData->getRemainingDepth(_aGroupNode.node().get_offset()) > 0, "Depth is smaller than expected for tree");
this->adjustToChanges(rLocalChanges, aSubNode, static_cast<SubtreeChange const&>(*it));
}
}
else
{
OSL_ENSURE(it->ISA(ValueChange), "Unexpected change type for child of group node; change is ignored");
OSL_ENSURE( !_aGroupNode.findChild(makeNodeName(it->getNodeName(), Name::NoValidate())).is(),
"Found sub(tree) node where a value was expected");
}
}
}
//-----------------------------------------------------------------------------
void ViewStrategy::doCollectChanges(Node const& _aNode, NodeChanges& ) const
{
{ (void)_aNode; }
// no-op: there are no changes to collect
OSL_ENSURE(!hasChanges(_aNode),"Unexpected changes in View");
}
//-----------------------------------------------------------------------------
UnoAny ViewStrategy::getValue(ValueNode const& _aNode) const
{
checkInstance(_aNode.tree());
return _aNode.get_impl()->getValue();
}
UnoType ViewStrategy::getValueType(ValueNode const& _aNode) const
{
checkInstance(_aNode.tree());
return _aNode.get_impl()->getValueType();
}
//-----------------------------------------------------------------------------
// group member access
//-----------------------------------------------------------------------------
namespace { // helpers
using configuration::GroupMemberVisitor;
struct GroupMemberDispatch : data::NodeVisitor
{
GroupMemberDispatch(ViewStrategy& _rStrategy, GroupNode const& _aGroup, GroupMemberVisitor& rVisitor)
: m_rStrategy(_rStrategy)
, m_aGroup(_aGroup)
, m_rVisitor(rVisitor)
{}
static Result mapResult(GroupMemberVisitor::Result _aResult)
{
OSL_ASSERT( DONE == Result(GroupMemberVisitor::DONE) );
OSL_ASSERT( CONTINUE == Result(GroupMemberVisitor::CONTINUE) );
return Result(_aResult);
}
static GroupMemberVisitor::Result unmapResult(Result _aResult)
{
OSL_ASSERT( DONE == Result(GroupMemberVisitor::DONE) );
OSL_ASSERT( CONTINUE == Result(GroupMemberVisitor::CONTINUE) );
return GroupMemberVisitor::Result(_aResult);
}
virtual Result handle(data::ValueNodeAccess const& _aValue);
virtual Result handle(data::NodeAccess const& _aNonValue);
bool test_value(data::NodeAccess const & _aNode) const;
ViewStrategy& m_rStrategy;
GroupNode m_aGroup;
GroupMemberVisitor& m_rVisitor;
GroupMemberVisitor::Result m_aResult;
protected:
using NodeVisitor::handle;
};
bool GroupMemberDispatch::test_value(data::NodeAccess const& _aNode) const
{
Name aName = _aNode.getName();
return m_rStrategy.hasValue( m_aGroup, aName );
}
GroupMemberDispatch::Result GroupMemberDispatch::handle(data::ValueNodeAccess const& _aValue)
{
OSL_ENSURE( test_value(_aValue), "ERROR: Group MemberDispatch:Did not find a ValueMember for a value child.");
Name aValueName = _aValue.getName();
return mapResult( m_rVisitor.visit( m_rStrategy.getValue(m_aGroup,aValueName) ) );
}
GroupMemberDispatch::Result GroupMemberDispatch::handle(data::NodeAccess const& _aNonValue)
{
{ (void)_aNonValue; }
OSL_ENSURE( !test_value(_aNonValue), "ERROR: Group MemberDispatch:Found a ValueMember for a subtree child.");
return CONTINUE;
}
}
//-----------------------------------------------------------------------------
configuration::ValueMemberNode ViewStrategy::doGetValueMember(GroupNode const& _aNode, Name const& _aName, bool ) const
{
using data::ValueNodeAccess;
ValueNodeAccess aValueData = getMemberValueAccess(_aNode,_aName);
return _aNode.get_impl()->makeValueMember( aValueData );
}
bool ViewStrategy::hasValue(GroupNode const& _aNode, Name const& _aName) const
{
checkInstance(_aNode.tree());
return getMemberValueAccess(_aNode,_aName).isValid();
}
bool ViewStrategy::hasValue(GroupNode const& _aNode) const
{
checkInstance(_aNode.tree());
configuration::GroupNodeImpl* pGroupNode=_aNode.get_impl();
data::GroupNodeAccess aGroupNodeAccess = pGroupNode->getDataAccess();
return aGroupNodeAccess.hasChildren();
}
bool ViewStrategy::areValueDefaultsAvailable(GroupNode const& _aNode) const
{
checkInstance(_aNode.tree());
return _aNode.get_impl()->areValueDefaultsAvailable();
}
configuration::ValueMemberNode ViewStrategy::getValue(GroupNode const& _aNode, Name const& _aName) const
{
checkInstance(_aNode.tree());
return doGetValueMember(_aNode,_aName,false);
}
configuration::ValueMemberUpdate ViewStrategy::getValueForUpdate(GroupNode const & _aNode, Name const& _aName)
{
checkInstance(_aNode.tree());
return ValueMemberUpdate( doGetValueMember(_aNode,_aName,true), *this );
}
GroupMemberVisitor::Result ViewStrategy::dispatchToValues(GroupNode const& _aNode, GroupMemberVisitor& _aVisitor)
{
checkInstance(_aNode.tree());
GroupMemberDispatch aDispatch(*this,_aNode,_aVisitor);
GroupMemberDispatch::Result eResult = aDispatch.visitChildren( _aNode.getAccess() );
return aDispatch.unmapResult(eResult);
}
//-----------------------------------------------------------------------------
ViewStrategy::SetNodeElement ViewStrategy::implMakeElement(SetNode const& _aNode, SetNodeEntry const& anEntry) const
{
configuration::SetNodeImpl * pNodeData = _aNode.get_impl();
return pNodeData->implValidateElement(pNodeData->entryToElement(anEntry));
}
//-----------------------------------------------------------------------------
SetEntry ViewStrategy::implFindElement(SetNode const& _aNode, Name const& aName) const
{
configuration::SetNodeImpl * pNodeData = _aNode.get_impl();
OSL_ENSURE(pNodeData->implHasLoadedElements(),"Cannot find elements in set that is not loaded");
configuration::ElementTreeImpl * pElement = pNodeData->doFindElement(aName);
return SetEntry(pElement);
}
SetEntry ViewStrategy::findElement(SetNode const& _aNode, Name const& aName) const
{
checkInstance(_aNode.tree());
_aNode.get_impl()->implEnsureElementsLoaded();
return implFindElement(_aNode,aName);
}
SetEntry ViewStrategy::findAvailableElement(SetNode const& _aNode, Name const& aName) const
{
checkInstance(_aNode.tree());
if (_aNode.get_impl()->implHasLoadedElements())
return implFindElement(_aNode,aName);
else
return SetEntry(0);
}
static
inline
std::auto_ptr<SubtreeChange> makeChangeToDefault(data::SetNodeAccess const & _aSetNode)
{
return std::auto_ptr<SubtreeChange>(
new SubtreeChange(
_aSetNode.getName().toString(),
_aSetNode.getElementTemplateName().toString(),
_aSetNode.getElementTemplateModule().toString(),
_aSetNode.getAttributes(),
true // to default
) );
}
std::auto_ptr<SubtreeChange> ViewStrategy::differenceToDefaultState(SetNode const& _aNode, ISubtree& _rDefaultTree) const
{
checkInstance(_aNode.tree());
std::auto_ptr<SubtreeChange> aResult;
data::SetNodeAccess aOriginalSetNode = _aNode.getAccess();
if (!aOriginalSetNode.isDefault())
{
OSL_ASSERT(aOriginalSetNode.isValid());
aResult = makeChangeToDefault( aOriginalSetNode );
configuration::SetNodeImpl * pNodeData = _aNode.get_impl();
if (this->hasChanges(_aNode.node()))
{
OSL_ENSURE(pNodeData->implHasLoadedElements(),"Unexpected: Found set with changes but elements are not loaded");
pNodeData->doDifferenceToDefaultState(*aResult,_rDefaultTree);
}
else
pNodeData->implDifferenceToDefaultState(*aResult,_rDefaultTree);
}
return aResult;
}
configuration::TemplateHolder ViewStrategy::getElementTemplate(SetNode const& _aNode) const
{
checkInstance(_aNode.tree());
return _aNode.get_impl()->getElementTemplate();
}
configuration::TemplateProvider ViewStrategy::getTemplateProvider(SetNode const& _aNode) const
{
checkInstance(_aNode.tree());
return _aNode.get_impl()->getTemplateProvider();
}
//-----------------------------------------------------------------------------
data::NodeAccess ViewStrategy::getNodeAccess(Node const& _aNode) const
{
checkInstance(_aNode.tree());
return _aNode.getAccessRef();
}
Name ViewStrategy::getNodeName(Node const& _aNode) const
{
checkInstance(_aNode.tree());
return _aNode.data().getName();
}
node::Attributes ViewStrategy::getNodeAttributes(Node const& _aNode) const
{
checkInstance(_aNode.tree());
return _aNode.getAccessRef()->getAttributes();
}
//-----------------------------------------------------------------------------
SetNodeVisitor::Result ViewStrategy::dispatchToElements(SetNode const& _aNode, SetNodeVisitor& _aVisitor)
{
checkInstance(_aNode.tree());
configuration::SetNodeImpl * pNodeData = _aNode.get_impl();
if (pNodeData->implLoadElements())
return pNodeData->doDispatchToElements(_aVisitor);
else
return SetNodeVisitor::CONTINUE;
}
bool ViewStrategy::isEmpty(SetNode const& _aNode) const
{
checkInstance(_aNode.tree());
configuration::SetNodeImpl * pNodeData = _aNode.get_impl();
return !pNodeData->implLoadElements() || pNodeData->doIsEmpty();
}
//-----------------------------------------------------------------------------
void ViewStrategy::insertElement(SetNode const& _aNode, Name const& _aName, SetEntry const& _aNewEntry)
{
// cannot insert, if we cannot check for collisions
checkInstance(_aNode.tree());
_aNode.get_impl()->implEnsureElementsLoaded();
doInsertElement(_aNode,_aName,_aNewEntry);
}
void ViewStrategy::removeElement(SetNode const& _aNode, Name const& _aName)
{
// cannot remove, if we cannot check for existance
checkInstance(_aNode.tree());
_aNode.get_impl()->implEnsureElementsLoaded();
doRemoveElement(_aNode,_aName);
}
//-----------------------------------------------------------------------------
}
//-----------------------------------------------------------------------------
}