/************************************************************************* * * OpenOffice.org - a multi-platform office productivity suite * * $RCSfile: viewstrategy.cxx,v $ * * $Revision: 1.11 $ * * last change: $Author: ihi $ $Date: 2007-11-23 14:50:09 $ * * 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 "viewstrategy.hxx" #ifndef CONFIGMGR_VALUENODEBEHAVIOR_HXX_ #include "valuenodeimpl.hxx" #endif #ifndef CONFIGMGR_GROUPNODEBEHAVIOR_HXX_ #include "groupnodeimpl.hxx" #endif #ifndef CONFIGMGR_SETNODEBEHAVIOR_HXX_ #include "setnodeimpl.hxx" #endif #ifndef CONFIGMGR_CHANGE_HXX #include "change.hxx" #endif #ifndef CONFIGMGR_NODEVISITOR_HXX #include "nodevisitor.hxx" #endif #ifndef CONFIGMGR_GROUPNODEACCESS_HXX #include "groupnodeaccess.hxx" #endif #ifndef CONFIGMGR_SETNODEACCESS_HXX #include "setnodeaccess.hxx" #endif #ifndef CONFIGMGR_CONFIGCHANGE_HXX_ #include "nodechange.hxx" #endif #ifndef CONFIGMGR_CONFIGCHANGEIMPL_HXX_ #include "nodechangeimpl.hxx" #endif #ifndef CONFIGMGR_NODECONVERTER_HXX #include "nodeconverter.hxx" #endif //----------------------------------------------------------------------------- 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 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 ViewStrategy::doPreCommitChanges(Tree const& _aTree, configuration::ElementList& ) { { (void)_aTree; } OSL_ENSURE(!hasChanges(getRootNode(_aTree)),"Unexpected changes in View"); return std::auto_ptr(); } 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(rElementChange); SetNodeElement aNewElement = pSetData->makeAdditionalElement(this,aAddNode,nDepth); pThisChange = pSetData->doAdjustToAddedElement(aName, aAddNode,aNewElement); } else if (rElementChange.ISA(RemoveNode)) { RemoveNode const& aRemoveNode = static_cast(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(*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(*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 makeChangeToDefault(data::SetNodeAccess const & _aSetNode) { return std::auto_ptr( new SubtreeChange( _aSetNode.getName().toString(), _aSetNode.getElementTemplateName().toString(), _aSetNode.getElementTemplateModule().toString(), _aSetNode.getAttributes(), true // to default ) ); } std::auto_ptr ViewStrategy::differenceToDefaultState(SetNode const& _aNode, ISubtree& _rDefaultTree) const { checkInstance(_aNode.tree()); std::auto_ptr 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); } //----------------------------------------------------------------------------- } //----------------------------------------------------------------------------- }