1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: viewstrategy.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_configmgr.hxx"
34 #include "viewstrategy.hxx"
35 #include "valuenodeimpl.hxx"
36 #include "groupnodeimpl.hxx"
37 #include "setnodeimpl.hxx"
39 #include "nodevisitor.hxx"
40 #include "nodechange.hxx"
41 #include "nodechangeimpl.hxx"
42 #include "nodeconverter.hxx"
43 //-----------------------------------------------------------------------------
46 //-----------------------------------------------------------------------------
49 //-----------------------------------------------------------------------------
52 sharable::ValueNode
* getMemberValueAccess( GroupNode
const & _aGroupNode
, rtl::OUString
const & _aName
)
54 configuration::GroupNodeImpl
* pGroupData
= _aGroupNode
.get_impl();
55 return pGroupData
->getOriginalValueNode(_aName
);
58 //-----------------------------------------------------------------------------
59 void ViewStrategy::checkInstance(configuration::Tree
* tree
) const
61 (void) tree
; // avoid warnings
62 OSL_ENSURE( getViewBehavior(tree
).get() == this,
63 "Tree operation dispatched to wrong strategy instance");
65 //-----------------------------------------------------------------------------
66 void ViewStrategy::collectChanges(configuration::Tree
* tree
, configuration::NodeChanges
& rChanges
) const
69 doCollectChanges( getRootNode(tree
), rChanges
);
72 bool ViewStrategy::hasChanges(configuration::Tree
* tree
) const
75 return hasChanges( getRootNode(tree
) );
78 // mark the given node and all its ancestors (we can stop when we hit a node that already is marked)
79 void ViewStrategy::markChanged(Node
const& _aNode
)
81 configuration::Tree
* tree
= _aNode
.tree();
89 this->doMarkChanged(aNode
);
91 aNode
= aNode
.getParent();
93 while (aNode
.is() && !this->hasChanges( aNode
));
96 if (!aNode
.is()) // just marked the root
98 configuration::Tree
* pContext
= tree
->getContextTree();
99 unsigned int nContext
= tree
->getContextNode();
102 OSL_ASSERT(pContext
->isValidNode(nContext
));
104 view::Node
aContextNode(pContext
,nContext
);
105 pContext
->getViewBehavior()->markChanged(aContextNode
);
110 //-----------------------------------------------------------------------------
111 std::auto_ptr
<SubtreeChange
> ViewStrategy::preCommitChanges(configuration::Tree
* tree
, std::vector
< rtl::Reference
<configuration::ElementTree
> >& _rRemovedElements
)
114 return doPreCommitChanges( tree
, _rRemovedElements
);
117 void ViewStrategy::finishCommit(configuration::Tree
* tree
, SubtreeChange
& rRootChange
)
120 doFinishCommit(tree
, rRootChange
);
123 void ViewStrategy::revertCommit(configuration::Tree
* tree
, SubtreeChange
& rRootChange
)
126 doRevertCommit(tree
, rRootChange
);
129 void ViewStrategy::recoverFailedCommit(configuration::Tree
* tree
, SubtreeChange
& rRootChange
)
132 doFailedCommit(tree
, rRootChange
);
135 //-----------------------------------------------------------------------------
136 void ViewStrategy::adjustToChanges(configuration::NodeChangesInformation
& rLocalChanges
, Node
const& _aNode
, SubtreeChange
const& aExternalChange
)
138 OSL_PRECOND( isValidNode(_aNode
), "ERROR: Valid node required for adjusting to changes" );
139 OSL_PRECOND( getSimpleNodeName(_aNode
) == aExternalChange
.getNodeName(), "name of change does not match actual node" );
141 checkInstance(_aNode
.tree());
143 configuration::Tree
* pTreeData
= _aNode
.tree();
145 if (_aNode
.isSetNode())
147 OSL_ENSURE(aExternalChange
.isSetNodeChange(),"ERROR: Change type GROUP does not match set");
149 unsigned int nDepth
= pTreeData
->getRemainingDepth(_aNode
.get_offset());
151 implAdjustToElementChanges( rLocalChanges
, SetNode(_aNode
), aExternalChange
, nDepth
);
153 else if (_aNode
.isGroupNode())
155 OSL_ENSURE(!aExternalChange
.isSetNodeChange(),"ERROR: Change type SET does not match group");
157 GroupNode
aGroupNode(_aNode
);
159 implAdjustToValueChanges(rLocalChanges
, aGroupNode
, aExternalChange
);
160 implAdjustToSubChanges( rLocalChanges
, aGroupNode
, aExternalChange
);
162 else // might occur on external change (?)
164 OSL_ENSURE(_aNode
.isValueNode(), "Tree: Unknown node type to adjust to changes");
166 OSL_ENSURE(_aNode
.get_offset() == configuration::Tree::ROOT
, "Tree: Unexpected node type - non-root value element");
168 OSL_ENSURE(false,"ERROR: Change type does not match node: Trying to apply subtree change to value element.");
172 //-----------------------------------------------------------------------------
174 void ViewStrategy::addLocalChangeHelper( configuration::NodeChangesInformation
& rLocalChanges_
, configuration::NodeChange
const& aChange_
)
176 aChange_
.getChangeInfos(rLocalChanges_
);
179 //-----------------------------------------------------------------------------
180 // TO DO: create CommitAction class, which is returned by precommit (if applicable)
182 std::auto_ptr
<SubtreeChange
> ViewStrategy::doPreCommitChanges(configuration::Tree
* tree
, std::vector
< rtl::Reference
<configuration::ElementTree
> >& )
184 (void) tree
; // avoid warnings
185 OSL_ENSURE(!hasChanges(getRootNode(tree
)),"Unexpected changes in View");
186 return std::auto_ptr
<SubtreeChange
>();
189 void ViewStrategy::doFinishCommit(configuration::Tree
* tree
, SubtreeChange
& )
191 (void) tree
; // avoid warnings
192 OSL_ENSURE(!hasChanges(getRootNode(tree
)),"Unexpected changes in View");
193 OSL_ENSURE(false,"ERROR: Cannot finish commit for unexpected changes");
196 void ViewStrategy::doRevertCommit(configuration::Tree
* tree
, SubtreeChange
& )
198 (void) tree
; // avoid warnings
199 OSL_ENSURE(!hasChanges(getRootNode(tree
)),"Unexpected changes in View");
200 OSL_ENSURE(false,"ERROR: Cannot revert commit for unexpected changes");
203 void ViewStrategy::doFailedCommit(configuration::Tree
* tree
, SubtreeChange
& )
205 (void) tree
; // avoid warnings
206 OSL_ENSURE(!hasChanges(getRootNode(tree
)),"Unexpected changes in View");
207 OSL_ENSURE(false,"ERROR: Cannot recover commit for unexpected changes");
210 //-----------------------------------------------------------------------------
211 void ViewStrategy::implAdjustToElementChange(configuration::NodeChangesInformation
& rLocalChanges
, SetNode
const& _aSetNode
, Change
const& rElementChange
, unsigned int nDepth
)
213 configuration::SetNodeImpl
* pSetData
= _aSetNode
.get_impl();
215 OSL_ENSURE( pSetData
->implHasLoadedElements() , "Unexpected call: Processing element change in uninitialized set");
217 rtl::OUString
aName( rElementChange
.getNodeName() );
219 configuration::SetElementChangeImpl
* pThisChange
= 0;
220 if (AddNode
const * addNode
= dynamic_cast< AddNode
const *>(&rElementChange
))
222 configuration::ElementTreeData aNewElement
= pSetData
->makeAdditionalElement(this, *addNode
, nDepth
);
224 pThisChange
= pSetData
->doAdjustToAddedElement(aName
, *addNode
, aNewElement
);
226 else if (RemoveNode
const * removeNode
= dynamic_cast< RemoveNode
const * >(&rElementChange
))
228 pThisChange
= pSetData
->doAdjustToRemovedElement(aName
, *removeNode
);
232 if (nDepth
> 0 || (NULL
!= pSetData
->doFindElement(aName
)) )// found even beyond nDepth ?
234 pThisChange
= pSetData
->doAdjustChangedElement(rLocalChanges
,aName
, rElementChange
);
240 addLocalChangeHelper( rLocalChanges
, configuration::NodeChange(pThisChange
) );
244 void ViewStrategy::implAdjustToElementChanges(configuration::NodeChangesInformation
& rLocalChanges
, SetNode
const& _aSetNode
, SubtreeChange
const& rExternalChanges
, unsigned int nDepth
)
249 configuration::SetNodeImpl
* pSetData
= _aSetNode
.get_impl();
251 OSL_ENSURE( pSetData
->getTemplateProvider().isValid(), "Cannot adjust SetNode to changes - node was never initialized" );
253 if (pSetData
->implHasLoadedElements())
255 unsigned int const nElementDepth
= configuration::childDepth(nDepth
);
256 for (SubtreeChange::ChildIterator it
= rExternalChanges
.begin(); it
!= rExternalChanges
.end(); ++it
)
258 this->implAdjustToElementChange(rLocalChanges
, _aSetNode
, *it
, nElementDepth
);
263 OSL_ENSURE( !hasChanges(_aSetNode
.node()),"Cannot have changes to consider when no elements are loaded");
265 pSetData
->convertChanges( rLocalChanges
, rExternalChanges
, nDepth
);
270 configuration::ValueChangeImpl
* ViewStrategy::doAdjustToValueChange(GroupNode
const& _aGroupNode
, rtl::OUString
const& _aName
, ValueChange
const& _rExternalChange
)
272 configuration::ValueChangeImpl
* pChangeImpl
= NULL
;
274 sharable::ValueNode
* localNode
= getMemberValueAccess(_aGroupNode
,_aName
);
277 switch( _rExternalChange
. getMode() )
279 case ValueChange::wasDefault
:
280 case ValueChange::changeValue
:
281 pChangeImpl
= new configuration::ValueReplaceImpl( _rExternalChange
.getNewValue(), _rExternalChange
.getOldValue() );
284 case ValueChange::setToDefault
:
285 pChangeImpl
= new configuration::ValueResetImpl( _rExternalChange
.getNewValue(), _rExternalChange
.getOldValue() );
288 default: OSL_ENSURE(false, "Unknown change mode");
289 // fall thru to next case for somewhat meaningful return value
290 case ValueChange::changeDefault
:
292 com::sun::star::uno::Any aLocalValue
= localNode
->getValue();
294 pChangeImpl
= new configuration::ValueReplaceImpl( aLocalValue
, aLocalValue
);
298 OSL_ASSERT( pChangeImpl
);
302 OSL_ENSURE(false, "ERROR: Notification tries to change nonexistent value within group");
308 void ViewStrategy::implAdjustToValueChanges(configuration::NodeChangesInformation
& rLocalChanges
, GroupNode
const& _aGroupNode
, SubtreeChange
const& rExternalChanges
)
310 for (SubtreeChange::ChildIterator it
= rExternalChanges
.begin(); it
!= rExternalChanges
.end(); ++it
)
312 if (ValueChange
const * valueChange
= dynamic_cast< ValueChange
const * >(&*it
))
314 rtl::OUString
aValueName( valueChange
->getNodeName() );
316 if (configuration::ValueChangeImpl
* pThisChange
= doAdjustToValueChange(_aGroupNode
, aValueName
, *valueChange
))
318 pThisChange
->setTarget(_aGroupNode
,aValueName
);
319 addLocalChangeHelper(rLocalChanges
, configuration::NodeChange(pThisChange
));
322 OSL_TRACE("WARNING: Configuration: derived class hides an external value member change from listeners");
325 OSL_ENSURE(dynamic_cast< SubtreeChange
const * >(&*it
) != 0, "Unexpected change type within group");
329 void ViewStrategy::implAdjustToSubChanges(configuration::NodeChangesInformation
& rLocalChanges
, GroupNode
const& _aGroupNode
, SubtreeChange
const& rExternalChanges
)
331 #if (OSL_DEBUG_LEVEL > 0)
332 configuration::Tree
* pTreeData
= _aGroupNode
.tree();
334 for(SubtreeChange::ChildIterator it
= rExternalChanges
.begin(); it
!= rExternalChanges
.end(); ++it
)
336 if (SubtreeChange
const * subtreeChange
= dynamic_cast< SubtreeChange
const * >(&*it
))
338 Node aSubNode
= _aGroupNode
.findChild( it
->getNodeName() );
339 OSL_ENSURE( aSubNode
.is() || pTreeData
->depthTo(_aGroupNode
.node().get_offset()) >= pTreeData
->getAvailableDepth(), "Changed node not found in tree");
343 OSL_ENSURE( pTreeData
->getRemainingDepth(_aGroupNode
.node().get_offset()) > 0, "Depth is smaller than expected for tree");
344 this->adjustToChanges(rLocalChanges
, aSubNode
, *subtreeChange
);
349 OSL_ENSURE(dynamic_cast< ValueChange
const * >(&*it
) != 0, "Unexpected change type for child of group node; change is ignored");
350 OSL_ENSURE( !_aGroupNode
.findChild(it
->getNodeName()).is(),
351 "Found sub(tree) node where a value was expected");
355 //-----------------------------------------------------------------------------
356 void ViewStrategy::doCollectChanges(Node
const& _aNode
, configuration::NodeChanges
& ) const
359 // no-op: there are no changes to collect
360 OSL_ENSURE(!hasChanges(_aNode
),"Unexpected changes in View");
364 //-----------------------------------------------------------------------------
365 com::sun::star::uno::Any
ViewStrategy::getValue(ValueNode
const& _aNode
) const
367 checkInstance(_aNode
.tree());
368 return _aNode
.get_impl()->getValue();
370 #if OSL_DEBUG_LEVEL > 0
371 com::sun::star::uno::Type
ViewStrategy::getValueType(ValueNode
const& _aNode
) const
373 checkInstance(_aNode
.tree());
374 return _aNode
.get_impl()->getValueType();
377 //-----------------------------------------------------------------------------
378 // group member access
380 //-----------------------------------------------------------------------------
381 namespace { // helpers
382 struct GroupMemberDispatch
: data::NodeVisitor
384 GroupMemberDispatch(ViewStrategy
& _rStrategy
, GroupNode
const& _aGroup
, configuration::GroupMemberVisitor
& rVisitor
)
385 : m_rStrategy(_rStrategy
)
387 , m_rVisitor(rVisitor
)
390 static bool mapResult(configuration::GroupMemberVisitor::Result _aResult
)
392 return _aResult
== configuration::GroupMemberVisitor::DONE
;
395 static configuration::GroupMemberVisitor::Result
unmapResult(bool done
)
398 ? configuration::GroupMemberVisitor::DONE
399 : configuration::GroupMemberVisitor::CONTINUE
;
402 using NodeVisitor::handle
;
403 virtual bool handle(sharable::Node
* node
);
404 virtual bool handle(sharable::ValueNode
* node
);
405 #if (OSL_DEBUG_LEVEL > 0)
406 bool test_value(sharable::Node
* node
) const;
408 ViewStrategy
& m_rStrategy
;
410 configuration::GroupMemberVisitor
& m_rVisitor
;
412 configuration::GroupMemberVisitor::Result m_aResult
;
415 #if (OSL_DEBUG_LEVEL > 0)
416 bool GroupMemberDispatch::test_value(sharable::Node
* node
) const
418 return m_rStrategy
.hasValue(m_aGroup
, node
->getName());
422 bool GroupMemberDispatch::handle(sharable::ValueNode
* node
)
424 OSL_ENSURE( test_value(sharable::node(node
)), "ERROR: Group MemberDispatch:Did not find a ValueMember for a value child.");
426 rtl::OUString aValueName
= node
->info
.getName();
428 return mapResult( m_rVisitor
.visit( m_rStrategy
.getValue(m_aGroup
,aValueName
) ) );
431 bool GroupMemberDispatch::handle(sharable::Node
* node
)
433 (void) node
; // avoid warnings
434 OSL_ENSURE( !test_value(node
), "ERROR: Group MemberDispatch:Found a ValueMember for a subtree child.");
439 //-----------------------------------------------------------------------------
440 configuration::ValueMemberNode
ViewStrategy::doGetValueMember(GroupNode
const& _aNode
, rtl::OUString
const& _aName
, bool ) const
442 sharable::ValueNode
* valueData
= getMemberValueAccess(_aNode
,_aName
);
443 return _aNode
.get_impl()->makeValueMember(valueData
);
446 bool ViewStrategy::hasValue(GroupNode
const& _aNode
, rtl::OUString
const& _aName
) const
448 checkInstance(_aNode
.tree());
449 return getMemberValueAccess(_aNode
,_aName
) != 0;
452 bool ViewStrategy::hasValue(GroupNode
const& _aNode
) const
454 checkInstance(_aNode
.tree());
455 configuration::GroupNodeImpl
* pGroupNode
=_aNode
.get_impl();
456 sharable::GroupNode
* group
= pGroupNode
->getDataAccess();
457 return group
->numDescendants
> 0;
461 bool ViewStrategy::areValueDefaultsAvailable(GroupNode
const& _aNode
) const
463 checkInstance(_aNode
.tree());
465 return _aNode
.get_impl()->areValueDefaultsAvailable();
468 configuration::ValueMemberNode
ViewStrategy::getValue(GroupNode
const& _aNode
, rtl::OUString
const& _aName
) const
470 checkInstance(_aNode
.tree());
471 return doGetValueMember(_aNode
,_aName
,false);
474 configuration::ValueMemberUpdate
ViewStrategy::getValueForUpdate(GroupNode
const & _aNode
, rtl::OUString
const& _aName
)
476 checkInstance(_aNode
.tree());
477 return configuration::ValueMemberUpdate( doGetValueMember(_aNode
,_aName
,true), *this );
480 configuration::GroupMemberVisitor::Result
ViewStrategy::dispatchToValues(GroupNode
const& _aNode
, configuration::GroupMemberVisitor
& _aVisitor
)
482 checkInstance(_aNode
.tree());
484 GroupMemberDispatch
aDispatch(*this,_aNode
,_aVisitor
);
486 bool done
= aDispatch
.visitChildren( _aNode
.getAccess() );
488 return aDispatch
.unmapResult(done
);
491 //-----------------------------------------------------------------------------
492 configuration::ElementTreeData
ViewStrategy::implMakeElement(SetNode
const& _aNode
, configuration::SetEntry
const& anEntry
) const
494 configuration::SetNodeImpl
* pNodeData
= _aNode
.get_impl();
495 return pNodeData
->implValidateElement(pNodeData
->entryToElement(anEntry
));
497 //-----------------------------------------------------------------------------
498 configuration::SetEntry
ViewStrategy::implFindElement(SetNode
const& _aNode
, rtl::OUString
const& aName
) const
500 configuration::SetNodeImpl
* pNodeData
= _aNode
.get_impl();
502 OSL_ENSURE(pNodeData
->implHasLoadedElements(),"Cannot find elements in set that is not loaded");
503 configuration::ElementTree
* pElement
= pNodeData
->doFindElement(aName
);
505 return configuration::SetEntry(pElement
);
508 configuration::SetEntry
ViewStrategy::findElement(SetNode
const& _aNode
, rtl::OUString
const& aName
) const
510 checkInstance(_aNode
.tree());
511 _aNode
.get_impl()->implEnsureElementsLoaded();
512 return implFindElement(_aNode
,aName
);
515 configuration::SetEntry
ViewStrategy::findAvailableElement(SetNode
const& _aNode
, rtl::OUString
const& aName
) const
517 checkInstance(_aNode
.tree());
518 if (_aNode
.get_impl()->implHasLoadedElements())
519 return implFindElement(_aNode
,aName
);
521 return configuration::SetEntry(0);
526 std::auto_ptr
<SubtreeChange
> makeChangeToDefault(sharable::SetNode
* setNode
)
528 return std::auto_ptr
<SubtreeChange
>(
530 setNode
->info
.getName(),
531 setNode
->getElementTemplateName(),
532 setNode
->getElementTemplateModule(),
533 sharable::node(setNode
)->getAttributes(),
538 std::auto_ptr
<SubtreeChange
> ViewStrategy::differenceToDefaultState(SetNode
const& _aNode
, ISubtree
& _rDefaultTree
) const
540 checkInstance(_aNode
.tree());
541 std::auto_ptr
<SubtreeChange
> aResult
;
543 sharable::SetNode
* originalSetNode
= _aNode
.getAccess();
544 OSL_ASSERT(originalSetNode
!= 0);
545 if (!originalSetNode
->info
.isDefault())
547 aResult
= makeChangeToDefault(originalSetNode
);
549 configuration::SetNodeImpl
* pNodeData
= _aNode
.get_impl();
550 if (this->hasChanges(_aNode
.node()))
552 OSL_ENSURE(pNodeData
->implHasLoadedElements(),"Unexpected: Found set with changes but elements are not loaded");
553 pNodeData
->doDifferenceToDefaultState(*aResult
,_rDefaultTree
);
556 pNodeData
->implDifferenceToDefaultState(*aResult
,_rDefaultTree
);
561 rtl::Reference
<configuration::Template
> ViewStrategy::getElementTemplate(SetNode
const& _aNode
) const
563 checkInstance(_aNode
.tree());
564 return _aNode
.get_impl()->getElementTemplate();
567 configuration::TemplateProvider
ViewStrategy::getTemplateProvider(SetNode
const& _aNode
) const
569 checkInstance(_aNode
.tree());
570 return _aNode
.get_impl()->getTemplateProvider();
573 node::Attributes
ViewStrategy::getNodeAttributes(Node
const& _aNode
) const
575 checkInstance(_aNode
.tree());
576 return _aNode
.getAccessRef()->getAttributes();
579 //-----------------------------------------------------------------------------
580 configuration::SetNodeVisitor::Result
ViewStrategy::dispatchToElements(SetNode
const& _aNode
, configuration::SetNodeVisitor
& _aVisitor
)
582 checkInstance(_aNode
.tree());
584 configuration::SetNodeImpl
* pNodeData
= _aNode
.get_impl();
586 if (pNodeData
->implLoadElements())
587 return pNodeData
->doDispatchToElements(_aVisitor
);
590 return configuration::SetNodeVisitor::CONTINUE
;
593 bool ViewStrategy::isEmpty(SetNode
const& _aNode
) const
595 checkInstance(_aNode
.tree());
597 configuration::SetNodeImpl
* pNodeData
= _aNode
.get_impl();
599 return !pNodeData
->implLoadElements() || pNodeData
->doIsEmpty();
601 //-----------------------------------------------------------------------------
603 void ViewStrategy::insertElement(SetNode
const& _aNode
, rtl::OUString
const& _aName
, configuration::SetEntry
const& _aNewEntry
)
605 // cannot insert, if we cannot check for collisions
606 checkInstance(_aNode
.tree());
607 _aNode
.get_impl()->implEnsureElementsLoaded();
608 doInsertElement(_aNode
,_aName
,_aNewEntry
);
611 void ViewStrategy::removeElement(SetNode
const& _aNode
, rtl::OUString
const& _aName
)
613 // cannot remove, if we cannot check for existance
614 checkInstance(_aNode
.tree());
615 _aNode
.get_impl()->implEnsureElementsLoaded();
616 doRemoveElement(_aNode
,_aName
);
619 //-----------------------------------------------------------------------------
621 //-----------------------------------------------------------------------------