570 lines
18 KiB
C++
570 lines
18 KiB
C++
/*************************************************************************
|
|
*
|
|
* $RCSfile: node.cxx,v $
|
|
*
|
|
* $Revision: 1.3 $
|
|
*
|
|
* last change: $Author: jb $ $Date: 2002-06-07 14:14:56 $
|
|
*
|
|
* 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 "node.hxx"
|
|
|
|
#ifndef INCLUDED_SHARABLE_ANYDATA_HXX
|
|
#include "anydata.hxx"
|
|
#endif
|
|
#ifndef INCLUDED_SHARABLE_TREEFRAGMENT_HXX
|
|
#include "treefragment.hxx"
|
|
#endif
|
|
#ifndef CONFIGMGR_ACCESSOR_HXX
|
|
#include "accessor.hxx"
|
|
#endif
|
|
#ifndef CONFIGMGR_UPDATEACCESSOR_HXX
|
|
#include "updateaccessor.hxx"
|
|
#endif
|
|
#ifndef CONFIGMGR_CONFIGURATION_ATTRIBUTES_HXX_
|
|
#include "attributes.hxx"
|
|
#endif
|
|
|
|
#ifndef _RTL_USTRING_HXX_
|
|
#include <rtl/ustring.hxx>
|
|
#endif
|
|
#ifndef _COM_SUN_STAR_UNO_ANY_HXX_
|
|
#include <com/sun/star/uno/Any.hxx>
|
|
#endif
|
|
|
|
#ifndef INCLUDED_CSTDDEF
|
|
#include <cstddef>
|
|
#define INCLUDED_CSTDDEF
|
|
#endif
|
|
|
|
namespace configmgr
|
|
{
|
|
//-----------------------------------------------------------------------------
|
|
namespace sharable
|
|
{
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Name name;
|
|
// Offset parent; // always counts backwards
|
|
// Flags::Field flags;
|
|
// Type ::Field type; // contains discriminator for union
|
|
|
|
rtl::OUString NodeInfo::getName(memory::Accessor const & _aAccessor) const
|
|
{
|
|
return readString(_aAccessor,this->name);
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
configmgr::node::Attributes NodeInfo::getAttributes() const
|
|
{
|
|
configmgr::node::Attributes aResult;
|
|
|
|
aResult.bWritable = ! (flags & Flags::readonly);
|
|
aResult.bFinalized = !!(flags & Flags::finalized);
|
|
|
|
aResult.bNullable = !!(flags & Flags::nullable);
|
|
aResult.bLocalized = !!(flags & Flags::localized);
|
|
|
|
// aResult.bNotified = !!(flags & Flags::notified);
|
|
// aResult.bConstrained= !!(flags & Flags::constrained);
|
|
|
|
configmgr::node::State state = (flags & Flags::defaulted) ? configmgr::node::isDefault :
|
|
(flags & Flags::defaultable) ? configmgr::node::isMerged :
|
|
configmgr::node::isReplaced;
|
|
aResult.setState(state);
|
|
|
|
return aResult;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool NodeInfo::isDefault() const
|
|
{
|
|
return !!(this->flags & Flags::defaulted);
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool NodeInfo::isLocalized() const
|
|
{
|
|
return !!(this->flags & Flags::localized);
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void NodeInfo::markAsDefault(bool bDefault)
|
|
{
|
|
if (bDefault)
|
|
{
|
|
OSL_ENSURE(flags & Flags::defaultable,"Marking a non-defaultable node as default");
|
|
this->flags |= Flags::defaulted;
|
|
}
|
|
else
|
|
this->flags &= ~Flags::defaulted;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool GroupNode::hasDefaultsAvailable() const
|
|
{
|
|
if (this->info.isDefault())
|
|
return true;
|
|
|
|
if (node(this)->getTreeFragment()->hasDefaultsAvailable())
|
|
return true;
|
|
|
|
#if 0 // extended check for default state
|
|
for (Node const * pChild = getFirstChild(); pChild != NULL; pChild = getNextChild(pChild))
|
|
if (! pChild->isDefault() )
|
|
return false;
|
|
|
|
return true;
|
|
#endif
|
|
|
|
return false;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
Node * GroupNode::getFirstChild()
|
|
{
|
|
OSL_ENSURE(numDescendants, "Groups MUST have at least one child");
|
|
return node(this) + 1;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
Node const * GroupNode::getFirstChild() const
|
|
{
|
|
OSL_ENSURE(numDescendants, "Groups MUST have at least one child");
|
|
return node(this) + 1;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
static
|
|
Offset implGetNextChildOffset(GroupNode const * _pParent, Node const * _pChild)
|
|
{
|
|
OSL_PRECOND(_pChild, "getNextChild: previous child must not be NULL");
|
|
OSL_PRECOND(_pChild->getParentNode() == node(_pParent), "getNextChild: not a child of this node");
|
|
|
|
|
|
OSL_ENSURE( node(_pParent) < _pChild && _pChild <= node(_pParent) + _pParent->numDescendants,
|
|
"getNextChild: child out of descendants range");
|
|
|
|
// offset to child's next sibling
|
|
Offset next = 1;
|
|
if ( _pChild->isGroup())
|
|
{
|
|
next += _pChild->group.numDescendants;
|
|
}
|
|
|
|
if (_pChild->node.info.parent + next > _pParent->numDescendants)
|
|
{
|
|
OSL_ENSURE(_pChild->node.info.parent + next == _pParent->numDescendants+1, "Next child candidate should match next sibling here");
|
|
return 0;
|
|
}
|
|
|
|
OSL_POSTCOND( (_pChild+next)->getParentNode() == node(_pParent), "getNextChild: not a child of this node");
|
|
return next;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
Node * GroupNode::getNextChild(Node * _pChild)
|
|
{
|
|
if (Offset next = implGetNextChildOffset(this, _pChild))
|
|
return _pChild + next;
|
|
|
|
else
|
|
return NULL;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
Node const * GroupNode::getNextChild(Node const * _pChild) const
|
|
{
|
|
if (Offset next = implGetNextChildOffset(this, _pChild))
|
|
return _pChild + next;
|
|
|
|
else
|
|
return NULL;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool SetNode::isLocalizedValue() const
|
|
{
|
|
return info.isLocalized();
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// TODO: optimize this - keep a list of such structs ....
|
|
struct SetNodeTemplateData
|
|
{
|
|
Name name;
|
|
Name module;
|
|
};
|
|
//-----------------------------------------------------------------------------
|
|
static inline
|
|
SetNodeTemplateData * readTemplateData(memory::Allocator const & _anAllocator, Address _aTemplateData)
|
|
{
|
|
return static_cast<SetNodeTemplateData *>( _anAllocator.access(_aTemplateData) );
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
static inline
|
|
SetNodeTemplateData const * readTemplateData(memory::Accessor const & _anAccessor, Address _aTemplateData)
|
|
{
|
|
return static_cast<SetNodeTemplateData const*>( _anAccessor.access(memory::Pointer(_aTemplateData)) );
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
Address SetNode::allocTemplateData(memory::Allocator const & _anAllocator, NameChar const * pName, NameChar const * pModule)
|
|
{
|
|
rtl::OUString aName(pName), aModule(pModule);
|
|
|
|
Address aData = _anAllocator.allocate(sizeof(SetNodeTemplateData));
|
|
|
|
if (aData)
|
|
{
|
|
SetNodeTemplateData * pData = readTemplateData(_anAllocator,aData);
|
|
|
|
OSL_ENSURE(pData, "Creating template data: unexpected NULL data");
|
|
|
|
pData->name = allocName(_anAllocator,aName);
|
|
pData->module = allocName(_anAllocator,aModule);
|
|
}
|
|
return aData;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void SetNode::releaseTemplateData(memory::Allocator const & _anAllocator, Address _aTemplateData)
|
|
{
|
|
if (!_aTemplateData) return;
|
|
|
|
SetNodeTemplateData const * pData = readTemplateData(_anAllocator,_aTemplateData);
|
|
|
|
OSL_ENSURE(pData, "Freeing template data: unexpected NULL data");
|
|
|
|
freeName(_anAllocator,pData->name);
|
|
freeName(_anAllocator,pData->module);
|
|
|
|
_anAllocator.deallocate(_aTemplateData);
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NameChar const * SetNode::getTemplateDataName(memory::Accessor const & _anAccessor, Address _aTemplateData)
|
|
{
|
|
OSL_PRECOND(_aTemplateData, "Reading template data: unexpected NULL pointer");
|
|
|
|
SetNodeTemplateData const * pData = readTemplateData(_anAccessor,_aTemplateData);
|
|
|
|
OSL_ENSURE(pData, "Reading template data: unexpected NULL data");
|
|
|
|
return accessName(_anAccessor,pData->name);
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
NameChar const * SetNode::getTemplateDataModule(memory::Accessor const & _anAccessor, Address _aTemplateData)
|
|
{
|
|
OSL_PRECOND(_aTemplateData, "Reading template data: unexpected NULL pointer");
|
|
|
|
SetNodeTemplateData const * pData = readTemplateData(_anAccessor,_aTemplateData);
|
|
|
|
OSL_ENSURE(pData, "Reading template data: unexpected NULL data");
|
|
|
|
return accessName(_anAccessor,pData->module);
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
rtl::OUString SetNode::getElementTemplateName(memory::Accessor const & _anAccessor) const
|
|
{
|
|
SetNodeTemplateData const * pData = readTemplateData(_anAccessor,this->elementType);
|
|
|
|
OSL_ENSURE(pData, "ERROR: No template data found for set");
|
|
|
|
return readName(_anAccessor,pData->name);
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
rtl::OUString SetNode::getElementTemplateModule(memory::Accessor const & _anAccessor) const
|
|
{
|
|
SetNodeTemplateData const * pData = readTemplateData(_anAccessor,this->elementType);
|
|
|
|
OSL_ENSURE(pData, "ERROR: No template data found for set");
|
|
|
|
return readName(_anAccessor,pData->module);
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
static inline
|
|
TreeFragment const * implGetFragmentFromList(memory::Accessor const & _anAccessor, List _aListEntry)
|
|
{
|
|
return static_cast<TreeFragment const *>(_anAccessor.access(memory::Pointer(_aListEntry)));
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
TreeFragment const * SetNode::getFirstElement(memory::Accessor const & _anAccessor) const
|
|
{
|
|
return implGetFragmentFromList(_anAccessor, this->elements);
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
TreeFragment const * SetNode::getNextElement(memory::Accessor const & _anAccessor, TreeFragment const * _pElement) const
|
|
{
|
|
OSL_PRECOND(_pElement, "getNextElement: previous element must not be NULL");
|
|
OSL_PRECOND(_pElement->header.parent == _anAccessor.address(this).value(),
|
|
"getNextElement: not an element of this node");
|
|
|
|
return implGetFragmentFromList(_anAccessor, _pElement->header.next);
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool ValueNode::isEmpty() const
|
|
{
|
|
Type::Field const empty_value_type = Type::value_any | Type::nodetype_value;
|
|
|
|
return info.type == empty_value_type;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool ValueNode::isNull() const
|
|
{
|
|
Flags::Type availmask = (info.flags & Flags::defaulted) ?
|
|
Flags::defaultAvailable :
|
|
Flags::valueAvailable;
|
|
|
|
return !(info.flags & availmask);
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool ValueNode::hasUsableDefault() const
|
|
{
|
|
return (info.flags & Flags::defaultable) &&
|
|
(info.flags & (Flags::defaultAvailable| Flags::nullable));
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
uno::Type ValueNode::getValueType() const
|
|
{
|
|
AnyData::TypeCode aType = info.type & Type::mask_valuetype;
|
|
|
|
return getUnoType(aType);
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
uno::Any ValueNode::getValue(memory::Accessor const & _aAccessor) const
|
|
{
|
|
if (info.flags & Flags::defaulted)
|
|
return getDefaultValue(_aAccessor);
|
|
|
|
else
|
|
return getUserValue(_aAccessor);
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
uno::Any ValueNode::getUserValue(memory::Accessor const & _aAccessor) const
|
|
{
|
|
if (info.flags & Flags::valueAvailable)
|
|
{
|
|
AnyData::TypeCode aType = info.type & Type::mask_valuetype;
|
|
|
|
return readData(_aAccessor,aType,this->value);
|
|
}
|
|
else
|
|
return uno::Any();
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
uno::Any ValueNode::getDefaultValue(memory::Accessor const & _aAccessor) const
|
|
{
|
|
if (info.flags & Flags::defaultAvailable)
|
|
{
|
|
AnyData::TypeCode aType = info.type & Type::mask_valuetype;
|
|
|
|
return readData(_aAccessor,aType,this->defaultValue);
|
|
}
|
|
else
|
|
return uno::Any();
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool Node::isNamed(rtl::OUString const & _aName, memory::Accessor const & _aAccessor) const
|
|
{
|
|
// TODO: optimize comparison
|
|
return !!(this->getName(_aAccessor) == _aName);
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
rtl::OUString Node::getName(memory::Accessor const & _aAccessor) const
|
|
{
|
|
return node.info.getName(_aAccessor);
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
configmgr::node::Attributes Node::getAttributes() const
|
|
{
|
|
return node.info.getAttributes();
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool Node::isDefault() const
|
|
{
|
|
return node.info.isDefault();
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool Node::isLocalized() const
|
|
{
|
|
return node.info.isLocalized();
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool Node::isGroup() const
|
|
{
|
|
return (node.info.type & Type::mask_nodetype) == Type::nodetype_group;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool Node::isSet() const
|
|
{
|
|
return (node.info.type & Type::mask_nodetype) == Type::nodetype_set;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool Node::isValue() const
|
|
{
|
|
return (node.info.type & Type::mask_nodetype) == Type::nodetype_value;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
GroupNode * Node::groupData()
|
|
{
|
|
return isGroup() ? &this->group : NULL;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
GroupNode const * Node::groupData() const
|
|
{
|
|
return isGroup() ? &this->group : NULL;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
SetNode * Node::setData()
|
|
{
|
|
return isSet() ? &this->set : NULL;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
SetNode const * Node::setData() const
|
|
{
|
|
return isSet() ? &this->set : NULL;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
ValueNode * Node::valueData()
|
|
{
|
|
return isValue() ? &this->value : NULL;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
ValueNode const * Node::valueData() const
|
|
{
|
|
return isValue() ? &this->value : NULL;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool Node::isFragmentRoot() const
|
|
{
|
|
return ! node.info.parent;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
Node * Node::getParentNode()
|
|
{
|
|
return node.info.parent ? this - node.info.parent : NULL;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
Node const * Node::getParentNode() const
|
|
{
|
|
return node.info.parent ? this - node.info.parent : NULL;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
static Offset getFragmentIndex(Node const * pNode)
|
|
{
|
|
Offset result = 0;
|
|
while (Offset step = pNode->node.info.parent)
|
|
{
|
|
result += step;
|
|
pNode -= step;
|
|
}
|
|
return result;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
TreeFragment * Node::getTreeFragment()
|
|
{
|
|
void * pRoot = this - getFragmentIndex(this);
|
|
|
|
void * pFrag = static_cast<char*>(pRoot) - offsetof(TreeFragment,nodes);
|
|
|
|
return static_cast<TreeFragment *>(pFrag);
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
|
|
TreeFragment const * Node::getTreeFragment() const
|
|
{
|
|
void const * pRoot = this - getFragmentIndex(this);
|
|
|
|
void const * pFrag = static_cast<char const*>(pRoot) - offsetof(TreeFragment,nodes);
|
|
|
|
return static_cast<TreeFragment const *>(pFrag);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
} // namespace sharable
|
|
//-----------------------------------------------------------------------------
|
|
} // namespace configmgr
|
|
|
|
|