diff options
author | Lars Langhans <lla@openoffice.org> | 2001-01-17 14:02:34 +0000 |
---|---|---|
committer | Lars Langhans <lla@openoffice.org> | 2001-01-17 14:02:34 +0000 |
commit | c34914cf86fdab6162e754a128c45012c3e326d9 (patch) | |
tree | f5fff5f704e5440a757649e897e1d73fe30acca5 /configmgr | |
parent | efb3ac864d869f573b0fa0091931d091c319fb2f (diff) |
#82734# lasy writing
Diffstat (limited to 'configmgr')
-rw-r--r-- | configmgr/source/api2/broadcaster.cxx | 9 | ||||
-rw-r--r-- | configmgr/source/api2/providerimpl.cxx | 12 | ||||
-rw-r--r-- | configmgr/source/inc/change.hxx | 23 | ||||
-rw-r--r-- | configmgr/source/inc/mergechange.hxx | 156 | ||||
-rw-r--r-- | configmgr/source/inc/rttimacros.hxx | 6 | ||||
-rw-r--r-- | configmgr/source/inc/treeprovider.hxx | 24 | ||||
-rw-r--r-- | configmgr/source/misc/makefile.mk | 5 | ||||
-rw-r--r-- | configmgr/source/misc/mergechange.cxx | 949 | ||||
-rw-r--r-- | configmgr/source/tree/changes.cxx | 41 | ||||
-rw-r--r-- | configmgr/source/tree/cmtreemodel.cxx | 26 | ||||
-rw-r--r-- | configmgr/source/treecache/disposetimer.cxx | 189 | ||||
-rw-r--r-- | configmgr/source/treecache/disposetimer.hxx | 81 |
12 files changed, 1479 insertions, 42 deletions
diff --git a/configmgr/source/api2/broadcaster.cxx b/configmgr/source/api2/broadcaster.cxx index ea80de7317c8..ead33c1bcb1c 100644 --- a/configmgr/source/api2/broadcaster.cxx +++ b/configmgr/source/api2/broadcaster.cxx @@ -2,9 +2,9 @@ * * $RCSfile: broadcaster.cxx,v $ * - * $Revision: 1.5 $ + * $Revision: 1.6 $ * - * last change: $Author: jb $ $Date: 2000-12-07 14:09:32 $ + * last change: $Author: lla $ $Date: 2001-01-17 15:02:27 $ * * The Contents of this file are made available subject to the terms of * either of the following licenses @@ -986,7 +986,10 @@ namespace configmgr } } - if( !aNewChange.resolveObjects(rFactory) ) OSL_TRACE("Cannot find affected elements of Change"); + if( !aNewChange.resolveObjects(rFactory) ) + { + OSL_TRACE("Cannot find affected elements of Change"); + } } diff --git a/configmgr/source/api2/providerimpl.cxx b/configmgr/source/api2/providerimpl.cxx index c5c02a4ef431..5897be0fed43 100644 --- a/configmgr/source/api2/providerimpl.cxx +++ b/configmgr/source/api2/providerimpl.cxx @@ -2,9 +2,9 @@ * * $RCSfile: providerimpl.cxx,v $ * - * $Revision: 1.16 $ + * $Revision: 1.17 $ * - * last change: $Author: jb $ $Date: 2000-12-19 17:35:00 $ + * last change: $Author: lla $ $Date: 2001-01-17 15:02:27 $ * * The Contents of this file are made available subject to the terms of * either of the following licenses @@ -188,7 +188,7 @@ namespace configmgr // m_pTreeMgr->releaseSubtree(ssUserProfile, m_xDefaultOptions); } } - catch (container::NoSuchElementException&) + catch (uno::Exception&) { // could not read default locale // default locale is en-US @@ -224,7 +224,7 @@ namespace configmgr // ITreeProvider /ITreeManager //----------------------------------------------------------------------------- ISubtree* OProviderImpl::requestSubtree( OUString const& aSubtreePath, const vos::ORef < OOptions >& _xOptions, - sal_Int16 nMinLevels) throw (container::NoSuchElementException) + sal_Int16 nMinLevels) throw (uno::Exception) { return m_pTreeMgr->requestSubtree(aSubtreePath, _xOptions, nMinLevels); } @@ -359,7 +359,7 @@ namespace configmgr OSL_ASSERT(sal_Int16(nMinLevels) == nMinLevels); pTree = requestSubtree(_rAccessor,_xOptions, sal_Int16(nMinLevels)); } - catch(container::NoSuchElementException&e) + catch(uno::Exception&e) { sErrorMessage = e.Message; } @@ -401,7 +401,7 @@ namespace configmgr OSL_ASSERT(sal_Int16(nMinLevels) == nMinLevels); pTree = requestSubtree(_rAccessor, _xOptions, sal_Int16(nMinLevels)); } - catch(container::NoSuchElementException&e) + catch(uno::Exception &e) { sErrorMessage = e.Message; } diff --git a/configmgr/source/inc/change.hxx b/configmgr/source/inc/change.hxx index c33a3f282154..24bf26919558 100644 --- a/configmgr/source/inc/change.hxx +++ b/configmgr/source/inc/change.hxx @@ -2,9 +2,9 @@ * * $RCSfile: change.hxx,v $ * - * $Revision: 1.6 $ + * $Revision: 1.7 $ * - * last change: $Author: jb $ $Date: 2000-12-04 09:14:33 $ + * last change: $Author: lla $ $Date: 2001-01-17 15:02:30 $ * * The Contents of this file are made available subject to the terms of * either of the following licenses @@ -141,6 +141,7 @@ namespace configmgr // some kind of simple rtti RTTI_BASE(Change); + virtual Change* clone() const = 0; private: virtual Change* doGetChild(rtl::OUString const& ) const { return 0; } @@ -164,9 +165,10 @@ namespace configmgr public: ValueChange(rtl::OUString const& _rName, uno::Any aNewValue, const configuration::Attributes& _rAttributes, Mode aMode = changeValue, uno::Any aOldValue = uno::Any()); - ValueChange(const ValueChange&); ValueChange(uno::Any aNewValue, ValueNode const& aOldValue); ValueChange(SetToDefault, ValueNode const& aOldValue); + ValueChange(const ValueChange&); + virtual Change* clone() const; uno::Any getNewValue() const { return m_aValue; } uno::Any getOldValue() const { return m_aOldValue; } @@ -206,12 +208,13 @@ namespace configmgr bool m_bReplacing; // don't create CopyCTor automatically - AddNode(AddNode const&); void operator=(AddNode const&); public: AddNode(std::auto_ptr<INode> aNewNode_,rtl::OUString const& _rName); ~AddNode(); + AddNode(AddNode const&); + virtual Change* clone() const; /// marks this as not merely adding a node but replacing another void setReplacing() { m_bReplacing = true; } @@ -275,8 +278,11 @@ namespace configmgr std::auto_ptr<INode> m_aOwnOldNode; public: - RemoveNode(rtl::OUString const& _rName) ; - ~RemoveNode() ; + RemoveNode(rtl::OUString const& _rName); + ~RemoveNode(); + RemoveNode(const RemoveNode&); + virtual Change* clone() const; + virtual void dispatch(ChangeTreeAction& anAction) const { anAction.handle(*this); } virtual void dispatch(ChangeTreeModification& anAction) { anAction.handle(*this); } @@ -320,7 +326,6 @@ namespace configmgr configuration::Attributes m_aAttributes; // don't create CopyCTor automatically - SubtreeChange(SubtreeChange&); void operator=(SubtreeChange&); public: @@ -356,6 +361,9 @@ namespace configmgr ~SubtreeChange(); + SubtreeChange(const SubtreeChange&); + virtual Change* clone() const; + void swap(SubtreeChange& aOther); bool isReplacing() const {return m_aAttributes.bReplacing;} @@ -457,6 +465,7 @@ namespace configmgr //========================================================================== /** a specialized SubtreeChange, which, upon desctruction, does not delete the changes it holds + <BR> This implies that when using this class, you have to beware of the lifetime of the involved objects */ diff --git a/configmgr/source/inc/mergechange.hxx b/configmgr/source/inc/mergechange.hxx new file mode 100644 index 000000000000..e83b5b4beb7d --- /dev/null +++ b/configmgr/source/inc/mergechange.hxx @@ -0,0 +1,156 @@ +/************************************************************************* + * + * $RCSfile: mergechange.hxx,v $ + * + * $Revision: 1.1 $ + * + * last change: $Author: lla $ $Date: 2001-01-17 15:02:30 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 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 + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include "change.hxx" +#include "treeprovider.hxx" + +namespace configmgr +{ + + class ONameCreator + { + std::vector<rtl::OUString> m_aNameList; + public: + ONameCreator(){} + void init(const ConfigurationName &_aName); + rtl::OUString createName(const rtl::OUString &aPlusName); + void pushName(const rtl::OUString &aName); + void popName(); + }; + + // ----------------------------------------------------------------------------- + + // Helperclass to search a change in a given changetree + class OMergeSearchChange : private ChangeTreeModification, public ONameCreator + { + rtl::OUString m_aSearchName; + bool m_bFound; + Change* m_pFoundChange; + + protected: + bool isFound() { return m_bFound; } + virtual void handle(ValueChange& _rValueNode); + virtual void handle(AddNode& _rAddNode); + virtual void handle(RemoveNode& _rRemoveNode); + virtual void handle(SubtreeChange& _rSubtree); + + public: + OMergeSearchChange(const rtl::OUString &_aName); + Change* searchForChange(Change &aChange); + }; + + // ----------------------------------------------------------------------------- + class OMergeTreeChangeList : private ChangeTreeAction, public ONameCreator + { + TreeChangeList &m_aTreeChangeList; // ChangeList, which will be grown + SubtreeChange *m_pCurrentParent; // our current position + vector<SubtreeChange*> m_aTreePathStack; // how the name says, a stack for the given path + + + // ------- Helper for Path stack ------- + void pushTree(SubtreeChange* _pTree); + void popTree(); + public: + // CTor + OMergeTreeChangeList(TreeChangeList& _aTree); + SubtreeChange* check(const ConfigurationName &_aName); + + // start function, with the Change we want to do. + // WARNING this could be a big tree, because a change can contain subtreechanges! + void handleChange(TreeChangeList &_rList); + + + private: + virtual void handle(ValueChange const& _rValueNode); + virtual void handle(AddNode const& _rAddNode); + virtual void handle(RemoveNode const& _rRemoveNode); + virtual void handle(SubtreeChange const& _rSubtree); + }; + + // ----------------------------------------------------------------------------- + class OMergeChanges : private ChangeTreeAction, public ONameCreator + { + SubtreeChange &m_aSubtreeChange; // ChangeList, which will be grown + SubtreeChange *m_pCurrentParent; // our current position + vector<SubtreeChange*> m_aTreePathStack; // how the name says, a stack for the given path + + // ------- Helper for Path stack ------- + void pushTree(SubtreeChange* _pTree); + void popTree(); + + public: + // CTor + OMergeChanges(SubtreeChange& _aTree); + + SubtreeChange* check(const ConfigurationName &_aName); + + // start function, with the Change we want to do. + // WARNING this could be a big tree, because a change can contain subtreechanges! + void handleChange(const SubtreeChange &_rList, const rtl::OUString &_aPathToRoot); + + private: + virtual void handle(ValueChange const& _rValueNode); + virtual void handle(AddNode const& _rAddNode); + virtual void handle(RemoveNode const& _rRemoveNode); + virtual void handle(SubtreeChange const& _rSubtree); + + }; +} // namespace configmgr diff --git a/configmgr/source/inc/rttimacros.hxx b/configmgr/source/inc/rttimacros.hxx index 74ab8f5fec70..6e95e4d62259 100644 --- a/configmgr/source/inc/rttimacros.hxx +++ b/configmgr/source/inc/rttimacros.hxx @@ -2,9 +2,9 @@ * * $RCSfile: rttimacros.hxx,v $ * - * $Revision: 1.1 $ + * $Revision: 1.2 $ * - * last change: $Author: lla $ $Date: 2000-11-15 07:14:58 $ + * last change: $Author: lla $ $Date: 2001-01-17 15:02:30 $ * * The Contents of this file are made available subject to the terms of * either of the following licenses @@ -70,7 +70,7 @@ { \ return 0 == strcmp(_pName, getStaticType()); \ } \ - const sal_Char* getType() const { return #classname; } \ + virtual const sal_Char* getType() const { return #classname; } \ static const sal_Char* getStaticType() { return #classname; } #define RTTI(classname, baseclassname) \ diff --git a/configmgr/source/inc/treeprovider.hxx b/configmgr/source/inc/treeprovider.hxx index eaec0b905589..a41f06d3f25f 100644 --- a/configmgr/source/inc/treeprovider.hxx +++ b/configmgr/source/inc/treeprovider.hxx @@ -2,9 +2,9 @@ * * $RCSfile: treeprovider.hxx,v $ * - * $Revision: 1.5 $ + * $Revision: 1.6 $ * - * last change: $Author: jb $ $Date: 2000-12-14 16:11:19 $ + * last change: $Author: lla $ $Date: 2001-01-17 15:02:30 $ * * The Contents of this file are made available subject to the terms of * either of the following licenses @@ -129,6 +129,17 @@ namespace configmgr SubtreeChange root; // changes made within this sub tree // TreeChangeList(): root(::rtl::OUString(), configuration::Attributes()){} + TreeChangeList(const vos::ORef < OOptions >& _xOptions, const rtl::OUString& _rPathToRoot, const SubtreeChange& _aSubtree) + : m_xOptions(_xOptions), + pathToRoot(_rPathToRoot), + root(_aSubtree) /* EXPENSIVE!!! (deep copy) */ + {} + + TreeChangeList(const vos::ORef < OOptions >& _xOptions, const rtl::OUString& _rPathToRoot, auto_ptr<SubtreeChange> _pSubtreeChange) + : m_xOptions(_xOptions), + pathToRoot(_rPathToRoot), + root(*_pSubtreeChange.release()) /* EXPENSIVE!!! (deep copy) */ + {} /** ctor @param _rPathToRoot path to the root of the whole to-be-updated subtree @param _rLocalName relative path within the to-be-updated subtree @@ -153,7 +164,9 @@ namespace configmgr : m_xOptions(_xOptions) , pathToRoot(_rPathToRoot) , root(_rTree) - {} + { + OSL_ENSHURE(false, "Test only, because deep copy of subtreechange is very expensive."); + } /** ctor @param _rTreeList list to initialize the path, no childs are copied @@ -163,6 +176,7 @@ namespace configmgr , pathToRoot(_rTree.pathToRoot) , root(_rTree.root, _rNoCopy) {} + }; //========================================================================== @@ -175,8 +189,8 @@ namespace configmgr virtual ISubtree * requestSubtree(OUString const& aSubtreePath, const vos::ORef < OOptions >& _xOptions, - sal_Int16 nMinLevels = ALL_LEVELS) throw (container::NoSuchElementException) = 0; - virtual void updateTree(TreeChangeList& aChanges) throw (lang::WrappedTargetException, uno::RuntimeException) = 0; + sal_Int16 nMinLevels = ALL_LEVELS) throw (uno::Exception) = 0; + virtual void updateTree(TreeChangeList& aChanges) throw (uno::Exception) = 0; }; diff --git a/configmgr/source/misc/makefile.mk b/configmgr/source/misc/makefile.mk index 84c7283ae60d..e9c466919d62 100644 --- a/configmgr/source/misc/makefile.mk +++ b/configmgr/source/misc/makefile.mk @@ -2,9 +2,9 @@ # # $RCSfile: makefile.mk,v $ # -# $Revision: 1.3 $ +# $Revision: 1.4 $ # -# last change: $Author: fs $ $Date: 2000-12-01 14:06:03 $ +# last change: $Author: lla $ $Date: 2001-01-17 15:02:32 $ # # The Contents of this file are made available subject to the terms of # either of the following licenses @@ -96,6 +96,7 @@ SLOFILES= \ $(SLO)$/strimpl.obj \ $(SLO)$/strconverter.obj \ $(SLO)$/treemap.obj \ + $(SLO)$/mergechange.obj \ # --- Targets ---------------------------------- diff --git a/configmgr/source/misc/mergechange.cxx b/configmgr/source/misc/mergechange.cxx new file mode 100644 index 000000000000..8e253b8ac8b3 --- /dev/null +++ b/configmgr/source/misc/mergechange.cxx @@ -0,0 +1,949 @@ +/************************************************************************* + * + * $RCSfile: mergechange.cxx,v $ + * + * $Revision: 1.1 $ + * + * last change: $Author: lla $ $Date: 2001-01-17 15:02:33 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 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 + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (the "License"); You may not use this file + * except in compliance with the License. You may obtain a copy of the + * License at http://www.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#include <stdio.h> + +#ifndef CONFIGMGR_CONFNAME_HXX_ +#include "confname.hxx" +#endif + + +#include "mergechange.hxx" + +#include "change.hxx" +#include "treeprovider.hxx" +#include "treeactions.hxx" +#include "tracer.hxx" + +#ifndef _COM_SUN_STAR_UNO_ANY_H_ +#include <com/sun/star/uno/Any.h> +#endif + +#define ASCII(x) rtl::OUString::createFromAscii(x) + +namespace configmgr +{ + using namespace com::sun::star::uno; + + void ONameCreator::init(const ConfigurationName &_aName) + { + // HACK! + if (!(_aName.fullName().equals(ASCII("/")))) + { + // initial Name + for(ConfigurationName::Iterator it = _aName.begin(); + it != _aName.end(); + ++it) + { + m_aNameList.push_back(*it); + } + } + } + + rtl::OUString ONameCreator::createName(const rtl::OUString &aPlusName) + { + // create a name + OUString aName; + for (vector<OUString>::const_iterator it = m_aNameList.begin(); + it != m_aNameList.end(); + it++) + { + aName += *it; + aName += OUString::createFromAscii("/"); + } + if (aPlusName.getLength() == 0) + { + aName = aName.copy(0, aName.getLength() - 1); + } + else + { + aName += aPlusName; + } + + return aName; + } + void ONameCreator::pushName(const rtl::OUString &aName) + { + m_aNameList.push_back(aName); + } + void ONameCreator::popName() + { + m_aNameList.pop_back(); + } + + + // ----------------------------------------------------------------------------- + + // Helperclass to search a change in a given changetree + OMergeSearchChange::OMergeSearchChange(const rtl::OUString &_aName) + : m_aSearchName(_aName), m_bFound(false), m_pFoundChange(NULL) {} + + void OMergeSearchChange::handle(ValueChange& _rValueNode) + { + rtl::OUString aName = createName(_rValueNode.getNodeName()); + if (aName.equals(m_aSearchName)) + { + m_bFound = true; + m_pFoundChange = &_rValueNode; + } + } + + void OMergeSearchChange::handle(AddNode& _rAddNode) + { + rtl::OUString aName = createName(_rAddNode.getNodeName()); + if (aName.equals(m_aSearchName)) + { + m_bFound = true; + m_pFoundChange = &_rAddNode; + } + } + + void OMergeSearchChange::handle(RemoveNode& _rRemoveNode) + { + rtl::OUString aName = createName(_rRemoveNode.getNodeName()); + if (aName.equals(m_aSearchName)) + { + m_bFound = true; + m_pFoundChange = &_rRemoveNode; + } + } + + void OMergeSearchChange::handle(SubtreeChange& _rSubtree) + { + rtl::OUString aName = createName(_rSubtree.getNodeName()); + if (aName.equals(m_aSearchName)) + { + m_bFound = true; + m_pFoundChange = &_rSubtree; + } + if (!m_bFound) + { + // recursive descent + pushName(_rSubtree.getNodeName()); + _rSubtree.forEachChange(*this); + popName(); + } + } + + Change* OMergeSearchChange::searchForChange(Change &aChange) + { + applyToChange(aChange); + if (isFound()) + { + return m_pFoundChange; + } + return NULL; + } + // ----------------------------------------------------------------------------- + class OMergeValueChange : private ChangeTreeModification + { + const ValueChange& m_aValueChange; + public: + OMergeValueChange(const ValueChange& _aValueChange) + :m_aValueChange(_aValueChange) + { + + } + void handleChange(Change &_rNode) + { + applyToChange(_rNode); + } + private: + virtual void handle(ValueChange& _rValueChange) + { + // POST: Handle ValueChange + _rValueChange.setNewValue(m_aValueChange.getNewValue(), m_aValueChange.getMode()); + } + virtual void handle(RemoveNode& _rRemoveNode) + { + OSL_ENSHURE(false, "OMergeValueChange::handle(ValueChange): have a ValueChange for a removed node!"); + // should never happen. How did the user change a value for a node which is obviously flagged as removed? + } + virtual void handle(AddNode& _rAddNode) + { + // POST: Handle ValueChange in AddNode + INode* pINode = _rAddNode.getAddedNode(); + ValueNode *pValueNode = pINode->asValueNode(); + if (pValueNode) + pValueNode->setValue(m_aValueChange.getNewValue()); + else + OSL_ENSURE(sal_False, "OMergeValueChange:handle(AddNode): have a ValueChange a for non-value node!"); + } + virtual void handle(SubtreeChange& _rSubtree) + { + OSL_ENSHURE(false, "OMergeValueChange:handle(SubtreeChange): have a ValueChange for a sub tree!"); + } + }; + + // ----------------------------------------------------------------------------- + class OMergeRemoveNode : private ChangeTreeModification + { + public: + // actions to take with the remove node change + enum Action + { + RemoveCompletely, + FlagDeleted, + Undetermined + }; + + protected: + Action m_eAction; + + public: + OMergeRemoveNode() : m_eAction(Undetermined) { } + + Action getAction() const { return m_eAction; } + + void handleChange(Change* _pChange) + { + if (_pChange) + applyToChange(*_pChange); + else + // no change -> flag as deleted + m_eAction = FlagDeleted; + } + + private: + virtual void handle(ValueChange& aValueChange) + { + OSL_ENSHURE(false, "OMergeRemoveNode::handle(ValueChange): remove a value node?"); + } + + virtual void handle(RemoveNode& _rRemoveNode) + { + OSL_ENSHURE(false, "OMergeRemoveNode::handle(RemoveNode): should never happen!"); + // how can a RemoveNode change exist if in the file we're merging it into + // there already is such a RemoveNode change (_rRemoveNode)? + } + + virtual void handle(AddNode& _rAddNode) + { + // though this is suspicious, as currently no AddNode changes are created ... + m_eAction = RemoveCompletely; + } + + virtual void handle(SubtreeChange& _rSubtree) + { + m_eAction = FlagDeleted; + // TODO: need an extra state to distinguish between nodes which are overwritten in the user layer + // and nodes which are added to the user layer, but not existent in the share layer + // In the latter case m_eAction could be set to RemoveCompletely + } + }; + + + // ----------------------------------------------------------------------------- + // ----------------------------------------------------------------------------- + class OMergeSubtreeChange : private ChangeTreeModification,public ONameCreator + { + const SubtreeChange& m_aSubtreeChange; + public: + OMergeSubtreeChange(const SubtreeChange& _aSubtreeChange) + :m_aSubtreeChange(_aSubtreeChange) + { + + } + void handleChange(Change& _pChange) + { + applyToChange(_pChange); + } + + private: + virtual void handle(ValueChange& aValueChange) + { + OSL_ENSHURE(false, "OMergeSubtreeChange::handle(ValueChange): remove a value node?"); + } + + virtual void handle(RemoveNode& _rRemoveNode) + { + OSL_ENSHURE(false, "OMergeSubtreeChange::handle(RemoveNode): should never happen!"); + } + + virtual void handle(AddNode& _rAddNode) + { + } + + virtual void handle(SubtreeChange& _rSubtree) + { + // we will run through the exist tree and insert the new one. + pushName(_rSubtree.getNodeName()); + _rSubtree.forEachChange(*this); + popName(); + } + }; + + // ----------------------------------------------------------------------------- + // Main class for merging treechangelists + + // ------- Helper for Path stack ------- + void OMergeTreeChangeList::pushTree(SubtreeChange* _pTree) + { + m_pCurrentParent = _pTree; + OSL_ENSHURE(m_pCurrentParent, "OMergeTreeChangeList::pushTree: must not be NULL!"); + m_aTreePathStack.push_back(_pTree); + } + void OMergeTreeChangeList::popTree() + { + m_aTreePathStack.pop_back(); + m_pCurrentParent = m_aTreePathStack.back(); + } + + // CTor + OMergeTreeChangeList::OMergeTreeChangeList(TreeChangeList& _aTree) + :m_aTreeChangeList(_aTree), m_pCurrentParent(NULL) + { + } + + SubtreeChange* OMergeTreeChangeList::check(const ConfigurationName &_aName) + { + // First check, if the aName is in the treechangelist + ONameCreator aNameCreator; + + SubtreeChange* pCurrentParent = &m_aTreeChangeList.root; + + if (!(_aName.fullName().equals(ASCII("/")))) + { + for(ConfigurationName::Iterator it = _aName.begin(); + it != _aName.end(); + ++it) + { + aNameCreator.pushName(*it); + rtl::OUString aSearchName = aNameCreator.createName(OUString()); + OMergeSearchChange a(aSearchName); + Change *pChange = a.searchForChange(m_aTreeChangeList.root); + + if (!pChange) + { + // create a correspondens for the name, we not found. + auto_ptr<SubtreeChange> pNewChange(new SubtreeChange(*it, OUString(), configuration::Attributes())); + pCurrentParent->addChange(auto_ptr<Change>(pNewChange.release())); + + pChange = a.searchForChange(m_aTreeChangeList.root); + } + pCurrentParent = SAL_STATIC_CAST(SubtreeChange*, pChange); + } + } + return pCurrentParent; + } + + // start function, with the Change we want to do. + // WARNING this could be a big tree, because a change can contain subtreechanges! + void OMergeTreeChangeList::handleChange(TreeChangeList &_rList) + { + rtl::OUString aPath = _rList.pathToRoot; + ConfigurationName aName(aPath, ConfigurationName::Absolute()); + init(aName); // our Name start with pathToRoot + m_pCurrentParent = check(aName); // pathToRoot must exist or will be created + + applyToChange(_rList.root); + } + + // Algorithm: search the actual path in the out m_aTreeChangeList + // if we found something, we must merge/convert the Node with our Node + // if we found nothing, we must create a new Node with our change + // thats it. + + // the merge is contructed with helper classes because, it's possible that we + // are a ValueChange but in the TreeChangeList this change is an AddNode, so + // we have something to do. + + void OMergeTreeChangeList::handle(ValueChange const& _rValueNode) + { + // Handle a ValueChange, + rtl::OUString aSearchName = createName(_rValueNode.getNodeName()); // this construct is only for better debugging + OMergeSearchChange a(aSearchName); + Change *pChange = a.searchForChange(m_aTreeChangeList.root); + if (pChange) + { + // Value found, merge content + OMergeValueChange a(_rValueNode); + a.handleChange(*pChange); + } + else + { + // there is no ValueChange in the List, insert new one + auto_ptr<Change> pNewChange(new ValueChange(_rValueNode)); + m_pCurrentParent->addChange(pNewChange); + } + } + + void OMergeTreeChangeList::handle(AddNode const& _rAddNode) + { + // Handle an AddNode + rtl::OUString aSearchName = createName(_rAddNode.getNodeName()); + OMergeSearchChange a(aSearchName); + Change *pChange = a.searchForChange(m_aTreeChangeList.root); + + if (pChange) + { + OSL_ENSURE(pChange->ISA(RemoveNode) || _rAddNode.isReplacing(), "OMergeTreeChangeList::handle(AddNode): the changes tree given already contains a change for this!"); + + m_pCurrentParent->removeChange(pChange->getNodeName()); + } + // insert manually + auto_ptr<INode> pNode = auto_ptr<INode>(_rAddNode.getAddedNode()->clone()); + auto_ptr<Change> pNewChange(new AddNode(pNode, _rAddNode.getNodeName())); + m_pCurrentParent->addChange(pNewChange); + } + + void OMergeTreeChangeList::handle(RemoveNode const& _rRemoveNode) + { + // Handle a RemoveNode + rtl::OUString aSearchName = createName(_rRemoveNode.getNodeName()); + OMergeSearchChange a(aSearchName); + Change *pChange = a.searchForChange(m_aTreeChangeList.root); + + // examine what to do with this change + OMergeRemoveNode aExaminer; + aExaminer.handleChange(pChange); + + // remove the change from it's parent (may it's re-inserted in another form below) + if (pChange) + m_pCurrentParent->removeChange(pChange->getNodeName()); + + // insert a new change if necessary + switch (aExaminer.getAction()) + { + case OMergeRemoveNode::RemoveCompletely: + // nothing to do, we already removed it + break; + default: + OSL_ENSURE(sal_False, "OMergeTreeChangeList::handle(RemoveNode): don't know what to do with this!"); + // NO BREAK. + // defaulting this so that the node will be marked as deleted + case OMergeRemoveNode::FlagDeleted: + { + auto_ptr<Change> pNewChange(new RemoveNode(_rRemoveNode.getNodeName())); + m_pCurrentParent->addChange(pNewChange); + } + break; + } + } + + void OMergeTreeChangeList::handle(SubtreeChange const& _rSubtree) + { + // Handle a SubtreeChange + // we must check if exact this SubtreeChange is in the TreeChangeList, if not, + // we must add this SubtreeChange to the TreeChangeList + // with the pointer m_pCurrentParent we remember our SubtreeChange in witch we + // add all other Changes. + + rtl::OUString aSearchName = createName(_rSubtree.getNodeName()); + OMergeSearchChange a(aSearchName); + Change *pChange = a.searchForChange(m_aTreeChangeList.root); + /* + if (pChange) + { + // Value found, merge content + OMergeSubtreeChange a(_rSubtree); + a.handleChange(*pChange); + } + else + { + // Value not found, create a new SubtreeChange + auto_ptr<SubtreeChange> pNewChange(new SubtreeChange(_rSubtree, SubtreeChange::NoChildCopy())); + // add the new SubtreeChange in m_aTreeChangeList + m_pCurrentParent->addChange(auto_ptr<Change>(pNewChange.release())); + } + */ + + // const sal_Char* pType = pChange ? pChange->getType() : NULL; + SubtreeChange* pSubtreeChange = NULL; + if (pChange == NULL || pChange->ISA(SubtreeChange)) + { + // hard cast(!) to SubtreeChange because we are a SubtreeChange + pSubtreeChange = SAL_STATIC_CAST(SubtreeChange*, pChange); + if (pSubtreeChange) + { + // Value found, nothing to be done, because we are a SubtreeChange + // we only must go downstairs + } + else + { + // create a new SubtreeChange + auto_ptr<SubtreeChange> pNewChange(new SubtreeChange(_rSubtree, SubtreeChange::NoChildCopy())); + // add the new SubtreeChange in m_aTreeChangeList + m_pCurrentParent->addChange(auto_ptr<Change>(pNewChange.release())); + // check list and get this new SubtreeChange + pChange = a.searchForChange(m_aTreeChangeList.root); + pSubtreeChange = SAL_STATIC_CAST(SubtreeChange*, pChange); + } + // save this SubtreeChange so we allways have the last Subtree + pushTree(pSubtreeChange); // remember the SubtreeChange Pointer + pushName(_rSubtree.getNodeName()); // pathstack + _rSubtree.forEachChange(*this); + popName(); + popTree(); + } + else if (pChange->ISA(AddNode)) + { + AddNode* pAddNode = SAL_STATIC_CAST(AddNode*, pChange); + INode* pNode = pAddNode->getAddedNode(); + ISubtree* pSubtree = pNode ? pNode->asISubtree() : 0; + + OSL_ENSURE(pSubtree, "BLA"); + if (pSubtree) + { + OSL_ENSHURE(false, "DANGER, THIS CODE IS WRONG!"); + // because, the important Node is the _rSubtree, which will not insert anywhere + + // Merge _rSubtree into pSubtree using a TreeUpdate object + TreeUpdate aTreeUpdate(pSubtree); + TreeChangeList aMergeChangeList(m_aTreeChangeList, SubtreeChange::NoChildCopy()); + OMergeTreeAction aChangeHandler(aMergeChangeList.root, pSubtree); + m_aTreeChangeList.root.forEachChange(aChangeHandler); + // now check the real modifications + OChangeActionCounter aChangeCounter; + aChangeCounter.handle(aMergeChangeList.root); + CFG_TRACE_INFO("cache manager: counted changes from notification : additions: %i , removes: %i, value changes: %i", aChangeCounter.nAdds, aChangeCounter.nRemoves, aChangeCounter.nValues); + if (aChangeCounter.hasChanges()) + { + // aTree.updateTree(aMergeChangeList); + aMergeChangeList.root.forEachChange(aTreeUpdate); + } + } + else + { + /* wrong type of node found: bse ASSERTEN/WERFEN */; + } + + } + else + { + /* wrong type of node found: bse ASSERTEN/WERFEN */; + } + } + + + + // ----------------------------------------------------------------------------- + + // ------- Helper for Path stack ------- + void OMergeChanges::pushTree(SubtreeChange* _pTree) + { + m_pCurrentParent = _pTree; + OSL_ENSHURE(m_pCurrentParent, "OMergeChanges::pushTree: must not be NULL!"); + m_aTreePathStack.push_back(_pTree); + } + void OMergeChanges::popTree() + { + m_aTreePathStack.pop_back(); + m_pCurrentParent = m_aTreePathStack.back(); + } + + // CTor + OMergeChanges::OMergeChanges(SubtreeChange& _aTree) + :m_aSubtreeChange(_aTree), m_pCurrentParent(NULL) + { + } + + SubtreeChange* OMergeChanges::check(const ConfigurationName &_aName) + { + // First check, if the aName is in the subtreechange + ONameCreator aNameCreator; + + SubtreeChange* pCurrentParent = &m_aSubtreeChange; + + if (!(_aName.fullName().equals(ASCII("/")))) + { + for(ConfigurationName::Iterator it = _aName.begin(); + it != _aName.end(); + ++it) + { + aNameCreator.pushName(*it); + rtl::OUString aSearchName = aNameCreator.createName(OUString()); + OMergeSearchChange a(aSearchName); + Change *pChange = a.searchForChange(m_aSubtreeChange); + + if (!pChange) + { + // create a correspondens for the name, we not found. + auto_ptr<SubtreeChange> pNewChange(new SubtreeChange(*it, OUString(), configuration::Attributes())); + pCurrentParent->addChange(auto_ptr<Change>(pNewChange.release())); + + pChange = a.searchForChange(m_aSubtreeChange); + } + pCurrentParent = SAL_STATIC_CAST(SubtreeChange*, pChange); + + // HACK! + // no descent to anything, we are flat! + break; + } + } + return pCurrentParent; + } + + // start function, with the Change we want to do. + // WARNING this could be a big tree, because a change can contain subtreechanges! + void OMergeChanges::handleChange(const SubtreeChange &_rList, const rtl::OUString &_aPathToRoot) + { + rtl::OUString aPath = _aPathToRoot; + ConfigurationName aName(aPath, ConfigurationName::Absolute()); + // try to use an empty List. + // init(aName); // our Name start with pathToRoot + m_pCurrentParent = check(aName); // pathToRoot must exist or will be created + + applyToChange(_rList); + } + + // Algorithm: search the actual path in the out m_aSubtreeChange + // if we found something, we must merge/convert the Node with our Node + // if we found nothing, we must create a new Node with our change + // thats it. + + // the merge is contructed with helper classes because, it's possible that we + // are a ValueChange but in the TreeChangeList this change is an AddNode, so + // we have something to do. + + void OMergeChanges::handle(ValueChange const& _rValueNode) + { + // Handle a ValueChange, + rtl::OUString aSearchName = createName(_rValueNode.getNodeName()); // this construct is only for better debugging + OMergeSearchChange a(aSearchName); + Change *pChange = a.searchForChange(m_aSubtreeChange); + if (pChange) + { + // Value found, merge content + OMergeValueChange a(_rValueNode); + a.handleChange(*pChange); + } + else + { + // there is no ValueChange in the List, insert new one + auto_ptr<Change> pNewChange(new ValueChange(_rValueNode)); + m_pCurrentParent->addChange(pNewChange); + } + } + + void OMergeChanges::handle(AddNode const& _rAddNode) + { + // Handle an AddNode + rtl::OUString aSearchName = createName(_rAddNode.getNodeName()); + OMergeSearchChange a(aSearchName); + Change *pChange = a.searchForChange(m_aSubtreeChange); + + if (pChange) + { + OSL_ENSURE(pChange->ISA(RemoveNode) || _rAddNode.isReplacing(), "OMergeTreeChangeList::handle(AddNode): the changes tree given already contains a change for this!"); + + m_pCurrentParent->removeChange(pChange->getNodeName()); + } + // insert manually + auto_ptr<INode> pNode = auto_ptr<INode>(_rAddNode.getAddedNode()->clone()); + auto_ptr<Change> pNewChange(new AddNode(pNode, _rAddNode.getNodeName())); + m_pCurrentParent->addChange(pNewChange); + } + + void OMergeChanges::handle(RemoveNode const& _rRemoveNode) + { + // Handle a RemoveNode + rtl::OUString aSearchName = createName(_rRemoveNode.getNodeName()); + OMergeSearchChange a(aSearchName); + Change *pChange = a.searchForChange(m_aSubtreeChange); + + // examine what to do with this change + OMergeRemoveNode aExaminer; + aExaminer.handleChange(pChange); + + // remove the change from it's parent (may it's re-inserted in another form below) + if (pChange) + m_pCurrentParent->removeChange(pChange->getNodeName()); + + // insert a new change if necessary + switch (aExaminer.getAction()) + { + case OMergeRemoveNode::RemoveCompletely: + // nothing to do, we already removed it + break; + default: + OSL_ENSURE(sal_False, "OMergeChanges::handle(RemoveNode): don't know what to do with this!"); + // NO BREAK. + // defaulting this so that the node will be marked as deleted + case OMergeRemoveNode::FlagDeleted: + { + auto_ptr<Change> pNewChange(new RemoveNode(_rRemoveNode.getNodeName())); + m_pCurrentParent->addChange(pNewChange); + } + break; + } + } + + +// ----------------------------------------------------------------------------- + class TreeUpdater : public ChangeTreeModification + { + ISubtree* m_pCurrentSubtree; +#if DEBUG + std::vector<rtl::OString> aLog; +#endif + + public: + TreeUpdater(ISubtree* pSubtree):m_pCurrentSubtree(pSubtree){} + + void handle(ValueChange& aValueNode); + void handle(AddNode& aAddNode); + void handle(RemoveNode& aRemoveNode); + void handle(SubtreeChange& aSubtree); + }; + +// ----------------------------------------------------------------------------- + + + void OMergeChanges::handle(SubtreeChange const& _rSubtreeChange) + { + // Handle a SubtreeChange + // we must check if exact this SubtreeChange is in the TreeChangeList, if not, + // we must add this SubtreeChange to the TreeChangeList + // with the pointer m_pCurrentParent we remember our SubtreeChange in witch we + // add all other Changes. + + rtl::OUString aSearchName = createName(_rSubtreeChange.getNodeName()); + OMergeSearchChange a(aSearchName); + Change *pChange = a.searchForChange(m_aSubtreeChange); + + SubtreeChange* pSubtreeChange = NULL; + if (pChange == NULL || pChange->ISA(SubtreeChange)) + { + // hard cast(!) to SubtreeChange because we are a SubtreeChange + pSubtreeChange = SAL_STATIC_CAST(SubtreeChange*, pChange); + if (pSubtreeChange) + { + // Value found, nothing to be done, because we are a SubtreeChange + // we only must go downstairs + } + else + { + // create a new SubtreeChange + auto_ptr<SubtreeChange> pNewChange(new SubtreeChange(_rSubtreeChange, SubtreeChange::NoChildCopy())); + // add the new SubtreeChange in m_aTreeChangeList + m_pCurrentParent->addChange(auto_ptr<Change>(pNewChange.release())); + // check list and get this new SubtreeChange + pChange = a.searchForChange(m_aSubtreeChange); + pSubtreeChange = SAL_STATIC_CAST(SubtreeChange*, pChange); + } + // save this SubtreeChange so we allways have the last Subtree + pushTree(pSubtreeChange); // remember the SubtreeChange Pointer + pushName(_rSubtreeChange.getNodeName()); // pathstack + _rSubtreeChange.forEachChange(*this); + popName(); + popTree(); + } + else if (pChange->ISA(AddNode)) + { + // OSL_ENSHURE(false, "sorry, no addnode in subtreechange! can't supported yet."); + + AddNode* pAddNode = SAL_STATIC_CAST(AddNode*, pChange); + INode* pNode = pAddNode->getAddedNode(); + ISubtree* pISubtree = pNode ? pNode->asISubtree() : 0; + + OSL_ENSURE(pISubtree, "Warning: there is no Subtree in the AddNode"); + if (pISubtree) + { + // ---------------------------- + // pISubtree += _rSubtreeChange + // ---------------------------- + + // Merge _rSubtreeChange into pSubtree using a TreeUpdate object + SubtreeChange *pSubtreeChange = SAL_STATIC_CAST(SubtreeChange*, _rSubtreeChange.clone()); + TreeUpdater aTreeUpdate(pISubtree); + pSubtreeChange->forEachChange(aTreeUpdate); + +// +// // auto_ptr<SubtreeChange> pNewChange(new SubtreeChange(_rSubtreeChange, SubtreeChange::NoChildCopy())); +// // OMergeTreeAction aChangeHandler(*pNewChange.get(), pISubtree); +// // pNewChange.get()->forEachChange(aChangeHandler); +// +// TreeChangeList aMergeChangeList(NULL, _rSubtreeChange.getNodeName(), _rSubtreeChange); +// +// OMergeTreeAction aChangeHandler(aMergeChangeList.root, pISubtree); +// m_aSubtreeChange.forEachChange(aChangeHandler); +// +// // now check the real modifications +// OChangeActionCounter aChangeCounter; +// // aChangeCounter.handle(*pNewChange.get()); +// aChangeCounter.handle(aMergeChangeList.root); +// +// CFG_TRACE_INFO("cache manager: counted changes from notification : additions: %i , removes: %i, value changes: %i", aChangeCounter.nAdds, aChangeCounter.nRemoves, aChangeCounter.nValues); +// if (aChangeCounter.hasChanges()) +// { +// // pNewChange.get()->forEachChange(aTreeUpdate); +// aMergeChangeList.root.forEachChange(aTreeUpdate); +// } + } + else + { + // wrong type of node found: bse ASSERTEN/WERFEN + } + } + else + { + // wrong type of node found: bse ASSERTEN/WERFEN + } + } + + + + // --------------------------------- updateTree --------------------------------- + void TreeUpdater::handle(ValueChange& aValueNode) + { + // Change a Value + OSL_ENSURE(m_pCurrentSubtree,"Cannot apply ValueChange without subtree"); + + INode* pBaseNode = m_pCurrentSubtree ? m_pCurrentSubtree->getChild(aValueNode.getNodeName()) : 0; + OSL_ENSURE(pBaseNode,"Cannot apply Change: No node to change"); + + ValueNode* pValue = pBaseNode ? pBaseNode->asValueNode() : 0; + OSL_ENSURE(pValue,"Cannot apply ValueChange: Node is not a value"); + + if (pValue) + aValueNode.applyTo(*pValue); +#ifdef DEBUG + else + { + ::rtl::OString aStr("TreeUpdater: Can't find value with name:="); + aStr += rtl::OUStringToOString(aValueNode.getNodeName(),RTL_TEXTENCODING_ASCII_US); + OSL_ENSHURE(pValue, aStr.getStr()); + aLog.push_back(aStr); + } +#endif + } + + void TreeUpdater::handle(AddNode& aAddNode) + { + // Add a new Value + if (m_pCurrentSubtree) + { + if (aAddNode.isReplacing()) + { + std::auto_ptr<INode> aOldNode = m_pCurrentSubtree->removeChild(aAddNode.getNodeName()); + +#ifdef DEBUG + OSL_ENSHURE(aOldNode.get(), "TreeUpdater:AddNode: can't recover node being replaced"); + if (aOldNode.get() == NULL) + aLog.push_back(rtl::OString("TreeUpdater: can't recover node being replaced (for AddNode)")); +#endif + if (aOldNode.get() != NULL) + { + OIdRemover::removeIds(*aOldNode); + } + + aAddNode.takeReplacedNode( aOldNode ); + } + + m_pCurrentSubtree->addChild(aAddNode.releaseAddedNode()); + + OIdPropagator::propagateIdToChildren(*m_pCurrentSubtree); + } +#ifdef DEBUG + else + aLog.push_back(rtl::OString("TreeUpdater: no CurrentSubtree for AddNode")); +#endif + + } + + void TreeUpdater::handle(RemoveNode& aRemoveNode) + { + // remove a Value + if (m_pCurrentSubtree) + { + std::auto_ptr<INode> aOldNode = m_pCurrentSubtree->removeChild(aRemoveNode.getNodeName()); + + sal_Bool bOk = (NULL != aOldNode.get()); + if (bOk) + { + OIdRemover::removeIds(*aOldNode); + } + aRemoveNode.takeRemovedNode( aOldNode ); + +#ifdef DEBUG + if (!bOk) + { + ::rtl::OString aStr("TreeUpdater: Can't remove child with name:="); + aStr += rtl::OUStringToOString(aRemoveNode.getNodeName(),RTL_TEXTENCODING_ASCII_US); + OSL_ENSHURE(bOk, aStr.getStr()); + aLog.push_back(aStr); + } +#endif + } + } + + void TreeUpdater::handle(SubtreeChange& _aSubtree) + { + // handle traversion + ISubtree *pOldSubtree = m_pCurrentSubtree; + rtl::OUString aNodeName = _aSubtree.getNodeName(); + OSL_ENSHURE(m_pCurrentSubtree->getChild(aNodeName), "TreeUpdater::handle : invalid subtree change ... this will crash !"); + m_pCurrentSubtree = m_pCurrentSubtree->getChild(aNodeName)->asISubtree(); + +#if DEBUG + ::rtl::OString aStr("TreeUpdater: there is no Subtree for name:="); + aStr += rtl::OUStringToOString(_aSubtree.getNodeName(),RTL_TEXTENCODING_ASCII_US); + OSL_ENSHURE(m_pCurrentSubtree, aStr.getStr()); + if (!m_pCurrentSubtree) + aLog.push_back(aStr); +#endif + + _aSubtree.forEachChange(*this); + m_pCurrentSubtree = pOldSubtree; + } + +} // namespace configmgr diff --git a/configmgr/source/tree/changes.cxx b/configmgr/source/tree/changes.cxx index 5cefc49c3e1e..dd90cca63298 100644 --- a/configmgr/source/tree/changes.cxx +++ b/configmgr/source/tree/changes.cxx @@ -2,9 +2,9 @@ * * $RCSfile: changes.cxx,v $ * - * $Revision: 1.4 $ + * $Revision: 1.5 $ * - * last change: $Author: dg $ $Date: 2000-11-30 08:31:49 $ + * last change: $Author: lla $ $Date: 2001-01-17 15:02:33 $ * * The Contents of this file are made available subject to the terms of * either of the following licenses @@ -108,6 +108,11 @@ ValueChange::ValueChange(const ValueChange& _rChange) ,m_aAttributes(_rChange.getAttributes()) {} +// ----------------------------------------------------------------------------- +Change* ValueChange::clone() const +{ + return new ValueChange(*this); +} // ------------------------------------------------------------------------- namespace tree_changes_internal { inline void doAdjust(uno::Any& aActual, uno::Any const& aTarget) @@ -204,6 +209,24 @@ AddNode::~AddNode() { } +// ----------------------------------------------------------------------------- +AddNode::AddNode(const AddNode& _aObj) + : Change(_aObj), m_bReplacing(_aObj.m_bReplacing) +{ + m_pNewNode = _aObj.m_pNewNode ? _aObj.m_pNewNode->clone() : NULL; + m_pOldNode = _aObj.m_pOldNode ? _aObj.m_pOldNode->clone() : NULL; + if (_aObj.m_aOwnNewNode.get()) + m_aOwnNewNode.reset(_aObj.m_aOwnNewNode.get()->clone()); + if (_aObj.m_aOwnOldNode.get()) + m_aOwnOldNode.reset(_aObj.m_aOwnOldNode.get()->clone()); +} + +// ----------------------------------------------------------------------------- +Change* AddNode::clone() const +{ + return new AddNode(*this); +} + //-------------------------------------------------------------------------- void AddNode::expectReplacedNode(INode* pOldNode) { @@ -238,6 +261,20 @@ RemoveNode::RemoveNode(OUString const& _rName) RemoveNode::~RemoveNode() { } +// ----------------------------------------------------------------------------- +RemoveNode::RemoveNode(const RemoveNode& _aObj) + :Change(_aObj) +{ + m_pOldNode = _aObj.m_pOldNode ? _aObj.m_pOldNode->clone() : NULL; + if (_aObj.m_aOwnOldNode.get()) + m_aOwnOldNode.reset(_aObj.m_aOwnOldNode.get()->clone()); +} + +// ----------------------------------------------------------------------------- +Change* RemoveNode::clone() const +{ + return new RemoveNode(*this); +} //-------------------------------------------------------------------------- void RemoveNode::expectRemovedNode(INode* pOldNode) diff --git a/configmgr/source/tree/cmtreemodel.cxx b/configmgr/source/tree/cmtreemodel.cxx index 7adbe4babadd..a3e1ea6c0dc4 100644 --- a/configmgr/source/tree/cmtreemodel.cxx +++ b/configmgr/source/tree/cmtreemodel.cxx @@ -2,9 +2,9 @@ * * $RCSfile: cmtreemodel.cxx,v $ * - * $Revision: 1.5 $ + * $Revision: 1.6 $ * - * last change: $Author: lla $ $Date: 2000-12-12 17:00:40 $ + * last change: $Author: lla $ $Date: 2001-01-17 15:02:33 $ * * The Contents of this file are made available subject to the terms of * either of the following licenses @@ -105,10 +105,32 @@ SubtreeChange::~SubtreeChange() } } +// ----------------------------------------------------------------------------- +SubtreeChange::SubtreeChange(const SubtreeChange& _aObj) + :Change(_aObj), + m_sTemplateName(_aObj.m_sTemplateName), + m_aAttributes(_aObj.m_aAttributes) +{ + for(Children::const_iterator aIter = _aObj.m_aChanges.begin(); + aIter != _aObj.m_aChanges.end(); + ++aIter) + { + OSL_ASSERT(aIter->second); + Children::value_type aCopy(aIter->first, aIter->second->clone()); + m_aChanges.insert(m_aChanges.end(), aCopy); + } +} + +// ----------------------------------------------------------------------------- +Change* SubtreeChange::clone() const +{ + return new SubtreeChange(*this); +} //-------------------------------------------------------------------------- void SubtreeChange::addChange(std::auto_ptr<Change> aChange) { OUString aNodeName(aChange->getNodeName()); + m_aChanges.find(aNodeName); OSL_ENSHURE(m_aChanges.end() == m_aChanges.find(aNodeName), "SubtreeChange::addChange : overwriting an existent change !"); delete m_aChanges[aNodeName]; diff --git a/configmgr/source/treecache/disposetimer.cxx b/configmgr/source/treecache/disposetimer.cxx index 75e28f89c93c..e3b121388eb3 100644 --- a/configmgr/source/treecache/disposetimer.cxx +++ b/configmgr/source/treecache/disposetimer.cxx @@ -2,9 +2,9 @@ * * $RCSfile: disposetimer.cxx,v $ * - * $Revision: 1.3 $ + * $Revision: 1.4 $ * - * last change: $Author: dg $ $Date: 2000-12-20 10:54:23 $ + * last change: $Author: lla $ $Date: 2001-01-17 15:02:34 $ * * The Contents of this file are made available subject to the terms of * either of the following licenses @@ -230,13 +230,13 @@ TimeStamp OTreeDisposeScheduler::runDisposer(TimeStamp const& _aActualTime) osl::ClearableMutexGuard aGuard( m_rTreeManager.m_aTreeListMutex ); - vos::ORef< OOptions > xTask = this->getTask( _aActualTime, aNextTime ); - if (xTask.isValid()) + vos::ORef< OOptions > xTaskOption = this->getTask( _aActualTime, aNextTime ); + if (xTaskOption.isValid()) { CFG_TRACE_INFO("Found cleanup task for user %s and locale %s", - OUSTRING2ASCII(xTask->getUser()), OUSTRING2ASCII(xTask->getLocale())); + OUSTRING2ASCII(xTaskOption->getUser()), OUSTRING2ASCII(xTaskOption->getLocale())); - if (TreeInfo* pInfo = m_rTreeManager.requestTreeInfo(xTask,false)) + if (TreeInfo* pInfo = m_rTreeManager.requestTreeInfo(xTaskOption,false)) { CFG_TRACE_INFO_NI("- Found matching data container (TreeInfo) - collecting data"); @@ -258,7 +258,7 @@ TimeStamp OTreeDisposeScheduler::runDisposer(TimeStamp const& _aActualTime) CFG_TRACE_INFO_NI("- Rescheduling current option set" ); - aNextTime = this->implAddTask(xTask,aNextTaskTime); + aNextTime = this->implAddTask(xTaskOption,aNextTaskTime); } else if (pInfo->isEmpty())// may have been the last one - check that @@ -268,7 +268,7 @@ TimeStamp OTreeDisposeScheduler::runDisposer(TimeStamp const& _aActualTime) // get rid of it - see TreeManager::disposeOne std::auto_ptr<TreeInfo> pDisposeInfo(pInfo); - m_rTreeManager.m_aTreeList.erase(xTask); + m_rTreeManager.m_aTreeList.erase(xTaskOption); // got it out of reachability - now dispose/notify without lock @@ -294,14 +294,14 @@ TimeStamp OTreeDisposeScheduler::runDisposer(TimeStamp const& _aActualTime) if (aNodeList.getLength() > 0) { CFG_TRACE_INFO_NI("- Stoping notifications for %d Nodes", int(aNodeList.getLength()) ); - m_rTreeManager.cancelNotify(aNodeList, xTask); + m_rTreeManager.cancelNotify(aNodeList, xTaskOption); } uno::Sequence< OUString > aCloseList = TreeInfo::collectNodeIds(aDisposeList); if (aCloseList.getLength() > 0) { CFG_TRACE_INFO_NI("- Closing %d NodeIds", int(aCloseList.getLength()) ); - m_rTreeManager.closeNodes(aCloseList,xTask); + m_rTreeManager.closeNodes(aCloseList,xTaskOption); } } CFG_TRACE_INFO_NI("- Now disposing %d module trees", int(aDisposeList.size()) ); @@ -373,5 +373,174 @@ TimeStamp OTreeDisposeScheduler::implAddTask(vos::ORef< OOptions > const& _xOpti } // ------------------------------------------------------------------------- + + + + + + + + + // ========================================================================= +OTreeCacheWriteScheduler::~OTreeCacheWriteScheduler() +{ + stopAndWriteCache(); +} + +void OTreeCacheWriteScheduler::stopAndWriteCache() +{ + osl::MutexGuard aOwnGuard( m_aMutex ); + + CFG_TRACE_INFO("Cancelling all cache writings, Stopping timer"); + + if (m_xTimer.isValid()) + { + m_xTimer->stop(); // just to be sure + m_xTimer.unbind(); // just to be sure + } + runDisposer(); +} +// ------------------------------------------------------------------------- +void OTreeCacheWriteScheduler::Timer::onShot() +{ + rParent.onTimerShot(); +} +// ----------------------------------------------------------------------------- +void OTreeCacheWriteScheduler::onTimerShot() +{ + //m_aTimer.stop(); + + CFG_TRACE_INFO("Cleanup Timer invoked - executing dispose task"); + + try + { + runDisposer(); + } + + catch (uno::Exception& ue) + { + OSL_ENSURE(false, "ERROR: UNO Exception left a disposer"); + ue; + } + catch (configuration::Exception& ce) + { + OSL_ENSURE(false, "ERROR: configuration::Exception left a disposer"); + ce; + } + catch (...) + { + OSL_ENSURE(false, "ERROR: Unknown Exception left a disposer"); + } + + TimeStamp aNewTime = implGetCleanupTime(TimeStamp::getCurrentTime(), m_aCleanupInterval); + + osl::MutexGuard aGuard(m_aMutex); + implStartBefore(aNewTime); +} +// ------------------------------------------------------------------------- +void OTreeCacheWriteScheduler::runDisposer() +{ + // Write Cache + CFG_TRACE_INFO("Starting lasy write"); + osl::ClearableMutexGuard aGuard( m_rTreeManager.m_aUpdateMutex ); + + for (CacheWriteList::iterator it = m_aWriteList.begin(); + it != m_aWriteList.end(); + ++it) + { + vos::ORef< OOptions > xTaskOption = *it; + if (xTaskOption.isValid()) + { + if (TreeInfo* pInfo = m_rTreeManager.requestTreeInfo(xTaskOption,false)) + { + CFG_TRACE_INFO_NI("- Found matching data container (TreeInfo) - collecting data"); + + PendingList aList; + sal_Int32 nCount = pInfo->syncPending(xTaskOption, aList); + if (nCount > 0) + { + CFG_TRACE_INFO_NI("write down %d pendings", nCount); + for(PendingList::iterator it = aList.begin(); + it != aList.end(); + ++it) + { + rtl::OUString sName = it->first; + auto_ptr<SubtreeChange> aSubtreeChange = it->second; + ConfigurationName aName; // MUST be empty, we have the ptr to the root obj + m_rTreeManager.sessionUpdate(xTaskOption, aName, aSubtreeChange); + } + } + } + } + else + { + CFG_TRACE_WARNING_NI("runDisposer: TaskOption not valid"); + } + + } + m_aWriteList.clear(); +} + +// ----------------------------------------------------------------------------- +// should be called guarded only +void OTreeCacheWriteScheduler::implStartBefore(TimeStamp const& _aTime) +{ + // check if we were cleared + if (!m_aWriteList.empty()) + { + if (m_xTimer.isEmpty()) + m_xTimer = new Timer(*this); + + if (!m_xTimer->isTicking()) + { + m_xTimer->setAbsoluteTime(_aTime.getTimeValue()); + + if (!m_xTimer->isTicking()) + m_xTimer->start(); + + OSL_ASSERT( m_xTimer->isTicking() ); + } + CFG_TRACE_INFO_NI("- Cleanup timer running - next execution in %d seconds", int (m_xTimer->getRemainingTime().Seconds) ); + CFG_TRACE_INFO_NI("- %d cleanup tasks are pending", int(m_aWriteList.size()) ); + } + else + { + if (!m_xTimer.isEmpty()) + { + m_xTimer->stop(); + CFG_TRACE_INFO_NI("- Stopped timer - no more open cleanup tasks"); + } + } +} + +// ----------------------------------------------------------------------------- +void OTreeCacheWriteScheduler::scheduleWrite(vos::ORef< OOptions > const& _xOptions, bool _bSync) +{ + OSL_ASSERT(_xOptions.isValid()); + OSL_ENSURE(_xOptions->getLocale().getLength() >0, "ERROR: OTreeDisposeScheduler: cannot handle complete user scheduling"); + + osl::MutexGuard aGuard( m_aMutex ); + + CFG_TRACE_INFO("Scheduling cache write for user '%s' with locale '%s'", + OUSTRING2ASCII(_xOptions->getUser()), OUSTRING2ASCII(_xOptions->getLocale())); + + CFG_TRACE_INFO_NI("- cache write will be started in about %d seconds", int(m_aCleanupInterval.getTimeValue().Seconds)); + + m_aWriteList.push_back(_xOptions); + + + if (_bSync || m_bSyncron) + { + // write now! + runDisposer(); + } + else + { + // lasy writing + TimeStamp aNewTime = implGetCleanupTime(TimeStamp::getCurrentTime(), m_aCleanupInterval); + implStartBefore(aNewTime); + } +} + } // namespace diff --git a/configmgr/source/treecache/disposetimer.hxx b/configmgr/source/treecache/disposetimer.hxx index f65590a14971..f597526a523a 100644 --- a/configmgr/source/treecache/disposetimer.hxx +++ b/configmgr/source/treecache/disposetimer.hxx @@ -2,9 +2,9 @@ * * $RCSfile: disposetimer.hxx,v $ * - * $Revision: 1.1 $ + * $Revision: 1.2 $ * - * last change: $Author: jb $ $Date: 2000-12-15 16:14:03 $ + * last change: $Author: lla $ $Date: 2001-01-17 15:02:34 $ * * The Contents of this file are made available subject to the terms of * either of the following licenses @@ -74,6 +74,10 @@ namespace configmgr { class TreeManager; //////////////////////////////////////////////////////////////////////////////// +/* OTreeDisposeScheduler: + does something special???? +*/ + class OTreeDisposeScheduler { typedef std::multimap< TimeStamp, vos::ORef< OOptions >, ltTimeStamp > Agenda; @@ -187,6 +191,79 @@ namespace configmgr { return aBaseTime + aDelay; } }; + + // ----------------------------------------------------------------------------- + + // Write down the Cache, much less complex than caching Nodes + // (better control) + class OTreeCacheWriteScheduler + { + typedef std::vector<vos::ORef< OOptions > > CacheWriteList; // fire and forget! + + class Timer : public vos::OTimer + { + public: + OTreeCacheWriteScheduler& rParent; + + Timer(OTreeCacheWriteScheduler& _rParent) : rParent(_rParent) {}; + + // vos::OTimer + virtual void SAL_CALL onShot(); + }; + friend void Timer::onShot(); + private: + mutable osl::Mutex m_aMutex; + vos::ORef<Timer> m_xTimer; + TreeManager& m_rTreeManager; + + CacheWriteList m_aWriteList; + // TimeInterval m_aCleanupDelay; + TimeInterval m_aCleanupInterval; + + bool m_bSyncron; // if true, write syncron only, no timer thread + + public: + //-------- Construction and destruction ----------------------------------- + explicit + OTreeCacheWriteScheduler(TreeManager& _rTreeManager, TimeInterval const& _aCleanupDelay, bool _bSyncron) + : m_xTimer(0) + , m_rTreeManager(_rTreeManager) + , m_aCleanupInterval(_aCleanupDelay) + , m_bSyncron(_bSyncron) + {} + ~OTreeCacheWriteScheduler(); + + //-------- Delay and Interval --------------------------------------------- + /// retrieves the recurrance interval used for cleanup + TimeInterval const& getCleanupInterval() const + { + osl::MutexGuard aGuard(m_aMutex); + return m_aCleanupInterval; + } + /// calculate the time when to cleanup an pbject that became eligible at <var>aBaseTime</var>. + TimeStamp getCleanupTime(TimeStamp const& aBaseTime = TimeStamp::getCurrentTime()) + { + return implGetCleanupTime(aBaseTime, getCleanupInterval()); + } + static TimeStamp implGetCleanupTime(TimeStamp const& aBaseTime, TimeInterval const& aDelay) + { + return aBaseTime + aDelay; + } + //-------- Control of execution ------------------------------------------ + /// stop and discard pending activities for _xOptions + // void writeCache(vos::ORef< OOptions > const& _xOptions); + void scheduleWrite(vos::ORef< OOptions > const& _xOptions, bool _bSync = false); + + /// stop and discard pending activities + void stopAndWriteCache(); + private: + // vos::OTimer + void onTimerShot(); + + void runDisposer(); + void implStartBefore(TimeStamp const& _aTime); + + }; //////////////////////////////////////////////////////////////////////////////// } // namespace configmgr |