You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
653 lines
21 KiB
653 lines
21 KiB
/*
|
|
* Copyright (c) 2011-2015, Intel Corporation
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without modification,
|
|
* are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
|
* list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation and/or
|
|
* other materials provided with the distribution.
|
|
*
|
|
* 3. Neither the name of the copyright holder nor the names of its contributors
|
|
* may be used to endorse or promote products derived from this software without
|
|
* specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
|
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
#include "ConfigurableElement.h"
|
|
#include "MappingData.h"
|
|
#include "SyncerSet.h"
|
|
#include "ConfigurableDomain.h"
|
|
#include "ConfigurationAccessContext.h"
|
|
#include "ConfigurableElementAggregator.h"
|
|
#include "AreaConfiguration.h"
|
|
#include "Iterator.hpp"
|
|
#include "Utility.h"
|
|
#include "XmlParameterSerializingContext.h"
|
|
#include <assert.h>
|
|
|
|
#define base CElement
|
|
|
|
CConfigurableElement::CConfigurableElement(const std::string &strName) : base(strName)
|
|
{
|
|
}
|
|
|
|
bool CConfigurableElement::fromXml(const CXmlElement &xmlElement,
|
|
CXmlSerializingContext &serializingContext)
|
|
{
|
|
auto &context = static_cast<CXmlParameterSerializingContext &>(serializingContext);
|
|
auto &accessContext = context.getAccessContext();
|
|
|
|
if (accessContext.serializeSettings()) {
|
|
// As serialization and deserialisation are handled through the *same* function
|
|
// the (de)serialize object can not be const in `serializeXmlSettings` signature.
|
|
// As a result a const_cast is unavoidable :(.
|
|
// Fixme: split serializeXmlSettings in two functions (in and out) to avoid the `const_cast`
|
|
return serializeXmlSettings(const_cast<CXmlElement &>(xmlElement),
|
|
static_cast<CConfigurationAccessContext &>(accessContext));
|
|
}
|
|
return structureFromXml(xmlElement, serializingContext);
|
|
}
|
|
|
|
void CConfigurableElement::toXml(CXmlElement &xmlElement,
|
|
CXmlSerializingContext &serializingContext) const
|
|
{
|
|
auto &context = static_cast<CXmlParameterSerializingContext &>(serializingContext);
|
|
auto &accessContext = context.getAccessContext();
|
|
if (accessContext.serializeSettings()) {
|
|
|
|
serializeXmlSettings(xmlElement, static_cast<CConfigurationAccessContext &>(accessContext));
|
|
} else {
|
|
|
|
structureToXml(xmlElement, serializingContext);
|
|
}
|
|
}
|
|
|
|
// XML configuration settings parsing
|
|
bool CConfigurableElement::serializeXmlSettings(
|
|
CXmlElement &xmlConfigurationSettingsElementContent,
|
|
CConfigurationAccessContext &configurationAccessContext) const
|
|
{
|
|
size_t uiNbChildren = getNbChildren();
|
|
|
|
if (!configurationAccessContext.serializeOut()) {
|
|
// Just do basic checks and propagate to children
|
|
CXmlElement::CChildIterator it(xmlConfigurationSettingsElementContent);
|
|
|
|
CXmlElement xmlChildConfigurableElementSettingsElement;
|
|
|
|
// Propagate to children
|
|
for (size_t index = 0; index < uiNbChildren; index++) {
|
|
|
|
// Get child
|
|
const CConfigurableElement *pChildConfigurableElement =
|
|
static_cast<const CConfigurableElement *>(getChild(index));
|
|
|
|
if (!it.next(xmlChildConfigurableElementSettingsElement)) {
|
|
|
|
// Structure error
|
|
configurationAccessContext.setError(
|
|
"Configuration settings parsing: missing child node " +
|
|
pChildConfigurableElement->getXmlElementName() + " (name:" +
|
|
pChildConfigurableElement->getName() + ") in " + getName());
|
|
|
|
return false;
|
|
}
|
|
|
|
// Check element type matches in type
|
|
if (xmlChildConfigurableElementSettingsElement.getType() !=
|
|
pChildConfigurableElement->getXmlElementName()) {
|
|
|
|
// "Component" tag has been renamed to "ParameterBlock", but retro-compatibility
|
|
// shall be ensured.
|
|
//
|
|
// So checking if this case occurs, i.e. element name is "ParameterBlock"
|
|
// but xml setting name is "Component".
|
|
bool compatibilityCase =
|
|
(pChildConfigurableElement->getXmlElementName() == "ParameterBlock") &&
|
|
(xmlChildConfigurableElementSettingsElement.getType() == "Component");
|
|
|
|
// Error if the compatibility case does not occur.
|
|
if (!compatibilityCase) {
|
|
|
|
// Type error
|
|
configurationAccessContext.setError(
|
|
"Configuration settings parsing: Settings "
|
|
"for configurable element " +
|
|
pChildConfigurableElement->getQualifiedPath() +
|
|
" does not match expected type: " +
|
|
xmlChildConfigurableElementSettingsElement.getType() + " instead of " +
|
|
pChildConfigurableElement->getKind());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// Check element type matches in name
|
|
if (xmlChildConfigurableElementSettingsElement.getNameAttribute() !=
|
|
pChildConfigurableElement->getName()) {
|
|
|
|
// Name error
|
|
configurationAccessContext.setError(
|
|
"Configuration settings parsing: Under configurable element " +
|
|
getQualifiedPath() + ", expected element name " +
|
|
pChildConfigurableElement->getName() + " but found " +
|
|
xmlChildConfigurableElementSettingsElement.getNameAttribute() + " instead");
|
|
|
|
return false;
|
|
}
|
|
|
|
// Parse child configurable element's settings
|
|
if (!pChildConfigurableElement->serializeXmlSettings(
|
|
xmlChildConfigurableElementSettingsElement, configurationAccessContext)) {
|
|
|
|
return false;
|
|
}
|
|
}
|
|
// There should remain no configurable element to parse
|
|
if (it.next(xmlChildConfigurableElementSettingsElement)) {
|
|
|
|
// Structure error
|
|
configurationAccessContext.setError(
|
|
"Configuration settings parsing: Unexpected xml element node " +
|
|
xmlChildConfigurableElementSettingsElement.getType() + " in " + getQualifiedPath());
|
|
|
|
return false;
|
|
}
|
|
} else {
|
|
// Handle element name attribute
|
|
xmlConfigurationSettingsElementContent.setNameAttribute(getName());
|
|
|
|
// Propagate to children
|
|
for (size_t index = 0; index < uiNbChildren; index++) {
|
|
|
|
const CConfigurableElement *pChildConfigurableElement =
|
|
static_cast<const CConfigurableElement *>(getChild(index));
|
|
|
|
// Create corresponding child element
|
|
CXmlElement xmlChildConfigurableElementSettingsElement;
|
|
|
|
xmlConfigurationSettingsElementContent.createChild(
|
|
xmlChildConfigurableElementSettingsElement,
|
|
pChildConfigurableElement->getXmlElementName());
|
|
|
|
// Propagate
|
|
pChildConfigurableElement->serializeXmlSettings(
|
|
xmlChildConfigurableElementSettingsElement, configurationAccessContext);
|
|
}
|
|
}
|
|
// Done
|
|
return true;
|
|
}
|
|
|
|
// AreaConfiguration creation
|
|
CAreaConfiguration *CConfigurableElement::createAreaConfiguration(
|
|
const CSyncerSet *pSyncerSet) const
|
|
{
|
|
return new CAreaConfiguration(this, pSyncerSet);
|
|
}
|
|
|
|
// Parameter access
|
|
bool CConfigurableElement::accessValue(CPathNavigator &pathNavigator, std::string &strValue,
|
|
bool bSet,
|
|
CParameterAccessContext ¶meterAccessContext) const
|
|
{
|
|
std::string *pStrChildName = pathNavigator.next();
|
|
|
|
if (!pStrChildName) {
|
|
|
|
parameterAccessContext.setError((bSet ? "Can't set " : "Can't get ") +
|
|
pathNavigator.getCurrentPath() +
|
|
" because it is not a parameter");
|
|
|
|
return false;
|
|
}
|
|
|
|
const CConfigurableElement *pChild =
|
|
static_cast<const CConfigurableElement *>(findChild(*pStrChildName));
|
|
|
|
if (!pChild) {
|
|
|
|
parameterAccessContext.setError("Path not found: " + pathNavigator.getCurrentPath());
|
|
|
|
return false;
|
|
}
|
|
|
|
return pChild->accessValue(pathNavigator, strValue, bSet, parameterAccessContext);
|
|
}
|
|
|
|
// Whole element access
|
|
void CConfigurableElement::getSettingsAsBytes(std::vector<uint8_t> &bytes,
|
|
CParameterAccessContext ¶meterAccessContext) const
|
|
{
|
|
bytes.resize(getFootPrint());
|
|
|
|
parameterAccessContext.getParameterBlackboard()->readBytes(
|
|
bytes, getOffset() - parameterAccessContext.getBaseOffset());
|
|
}
|
|
|
|
bool CConfigurableElement::setSettingsAsBytes(const std::vector<uint8_t> &bytes,
|
|
CParameterAccessContext ¶meterAccessContext) const
|
|
{
|
|
CParameterBlackboard *pParameterBlackboard = parameterAccessContext.getParameterBlackboard();
|
|
|
|
// Size
|
|
size_t size = getFootPrint();
|
|
|
|
// Check sizes match
|
|
if (size != bytes.size()) {
|
|
|
|
parameterAccessContext.setError(std::string("Wrong size: Expected: ") +
|
|
std::to_string(size) + " Provided: " +
|
|
std::to_string(bytes.size()));
|
|
|
|
return false;
|
|
}
|
|
|
|
// Write bytes
|
|
pParameterBlackboard->writeBytes(bytes, getOffset() - parameterAccessContext.getBaseOffset());
|
|
|
|
if (not parameterAccessContext.getAutoSync()) {
|
|
// Auto sync is not activated, sync will be defered until an explicit request
|
|
return true;
|
|
}
|
|
|
|
CSyncerSet syncerSet;
|
|
fillSyncerSet(syncerSet);
|
|
core::Results res;
|
|
if (not syncerSet.sync(*parameterAccessContext.getParameterBlackboard(), false, &res)) {
|
|
|
|
parameterAccessContext.setError(utility::asString(res));
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
std::list<const CConfigurableElement *> CConfigurableElement::getConfigurableElementContext() const
|
|
{
|
|
std::list<const CConfigurableElement *> configurableElementPath;
|
|
|
|
const CElement *element = this;
|
|
while (element != nullptr and isOfConfigurableElementType(element)) {
|
|
auto configurableElement = static_cast<const CConfigurableElement *>(element);
|
|
|
|
configurableElementPath.push_back(configurableElement);
|
|
element = element->getParent();
|
|
}
|
|
|
|
return configurableElementPath;
|
|
}
|
|
|
|
// Used for simulation and virtual subsystems
|
|
void CConfigurableElement::setDefaultValues(CParameterAccessContext ¶meterAccessContext) const
|
|
{
|
|
// Propagate to children
|
|
size_t uiNbChildren = getNbChildren();
|
|
|
|
for (size_t index = 0; index < uiNbChildren; index++) {
|
|
|
|
const CConfigurableElement *pConfigurableElement =
|
|
static_cast<const CConfigurableElement *>(getChild(index));
|
|
|
|
pConfigurableElement->setDefaultValues(parameterAccessContext);
|
|
}
|
|
}
|
|
|
|
// Element properties
|
|
void CConfigurableElement::showProperties(std::string &strResult) const
|
|
{
|
|
base::showProperties(strResult);
|
|
|
|
strResult += "Total size: " + getFootprintAsString() + "\n";
|
|
}
|
|
|
|
std::string CConfigurableElement::logValue(utility::ErrorContext &context) const
|
|
{
|
|
return logValue(static_cast<CParameterAccessContext &>(context));
|
|
}
|
|
|
|
std::string CConfigurableElement::logValue(CParameterAccessContext & /*ctx*/) const
|
|
{
|
|
// By default, an element does not have a value. Only leaf elements have
|
|
// one. This method could be pure virtual but then, several derived classes
|
|
// would need to implement it in order to simply return an empty string.
|
|
return "";
|
|
}
|
|
|
|
// Offset
|
|
void CConfigurableElement::setOffset(size_t offset)
|
|
{
|
|
// Assign offset locally
|
|
_offset = offset;
|
|
|
|
// Propagate to children
|
|
size_t uiNbChildren = getNbChildren();
|
|
|
|
for (size_t index = 0; index < uiNbChildren; index++) {
|
|
|
|
CConfigurableElement *pConfigurableElement =
|
|
static_cast<CConfigurableElement *>(getChild(index));
|
|
|
|
pConfigurableElement->setOffset(offset);
|
|
|
|
offset += pConfigurableElement->getFootPrint();
|
|
}
|
|
}
|
|
|
|
size_t CConfigurableElement::getOffset() const
|
|
{
|
|
return _offset;
|
|
}
|
|
|
|
// Memory
|
|
size_t CConfigurableElement::getFootPrint() const
|
|
{
|
|
size_t uiSize = 0;
|
|
size_t uiNbChildren = getNbChildren();
|
|
|
|
for (size_t index = 0; index < uiNbChildren; index++) {
|
|
|
|
const CConfigurableElement *pConfigurableElement =
|
|
static_cast<const CConfigurableElement *>(getChild(index));
|
|
|
|
uiSize += pConfigurableElement->getFootPrint();
|
|
}
|
|
|
|
return uiSize;
|
|
}
|
|
|
|
// Browse parent path to find syncer
|
|
ISyncer *CConfigurableElement::getSyncer() const
|
|
{
|
|
// Check parent
|
|
const CElement *pParent = getParent();
|
|
|
|
if (isOfConfigurableElementType(pParent)) {
|
|
|
|
return static_cast<const CConfigurableElement *>(pParent)->getSyncer();
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
// Syncer set (me, ascendant or descendant ones)
|
|
void CConfigurableElement::fillSyncerSet(CSyncerSet &syncerSet) const
|
|
{
|
|
// Try me or ascendants
|
|
ISyncer *pMineOrAscendantSyncer = getSyncer();
|
|
|
|
if (pMineOrAscendantSyncer) {
|
|
|
|
// Provide found syncer object
|
|
syncerSet += pMineOrAscendantSyncer;
|
|
|
|
// Done
|
|
return;
|
|
}
|
|
// Fetch descendant ones
|
|
fillSyncerSetFromDescendant(syncerSet);
|
|
}
|
|
|
|
// Syncer set (descendant)
|
|
void CConfigurableElement::fillSyncerSetFromDescendant(CSyncerSet &syncerSet) const
|
|
{
|
|
// Dig
|
|
size_t uiNbChildren = getNbChildren();
|
|
|
|
for (size_t index = 0; index < uiNbChildren; index++) {
|
|
|
|
const CConfigurableElement *pConfigurableElement =
|
|
static_cast<const CConfigurableElement *>(getChild(index));
|
|
|
|
pConfigurableElement->fillSyncerSetFromDescendant(syncerSet);
|
|
}
|
|
}
|
|
|
|
// Configurable domain association
|
|
void CConfigurableElement::addAttachedConfigurableDomain(
|
|
const CConfigurableDomain *pConfigurableDomain)
|
|
{
|
|
_configurableDomainList.push_back(pConfigurableDomain);
|
|
}
|
|
|
|
void CConfigurableElement::removeAttachedConfigurableDomain(
|
|
const CConfigurableDomain *pConfigurableDomain)
|
|
{
|
|
_configurableDomainList.remove(pConfigurableDomain);
|
|
}
|
|
|
|
// Belonging domain
|
|
bool CConfigurableElement::belongsTo(const CConfigurableDomain *pConfigurableDomain) const
|
|
{
|
|
if (containsConfigurableDomain(pConfigurableDomain)) {
|
|
|
|
return true;
|
|
}
|
|
return belongsToDomainAscending(pConfigurableDomain);
|
|
}
|
|
|
|
// Belonging domains
|
|
void CConfigurableElement::getBelongingDomains(
|
|
std::list<const CConfigurableDomain *> &configurableDomainList) const
|
|
{
|
|
configurableDomainList.insert(configurableDomainList.end(), _configurableDomainList.begin(),
|
|
_configurableDomainList.end());
|
|
|
|
// Check parent
|
|
const CElement *pParent = getParent();
|
|
|
|
if (isOfConfigurableElementType(pParent)) {
|
|
|
|
static_cast<const CConfigurableElement *>(pParent)->getBelongingDomains(
|
|
configurableDomainList);
|
|
}
|
|
}
|
|
|
|
void CConfigurableElement::listBelongingDomains(std::string &strResult, bool bVertical) const
|
|
{
|
|
// Get belonging domain list
|
|
std::list<const CConfigurableDomain *> configurableDomainList;
|
|
|
|
getBelongingDomains(configurableDomainList);
|
|
|
|
// Fill list
|
|
listDomains(configurableDomainList, strResult, bVertical);
|
|
}
|
|
|
|
// Elements with no domains
|
|
void CConfigurableElement::listRogueElements(std::string &strResult) const
|
|
{
|
|
// Get rogue element aggregate list (no associated domain)
|
|
std::list<const CConfigurableElement *> rogueElementList;
|
|
|
|
CConfigurableElementAggregator configurableElementAggregator(
|
|
rogueElementList, &CConfigurableElement::hasNoDomainAssociated);
|
|
|
|
configurableElementAggregator.aggegate(this);
|
|
|
|
// Build list as std::string
|
|
std::list<const CConfigurableElement *>::const_iterator it;
|
|
|
|
for (it = rogueElementList.begin(); it != rogueElementList.end(); ++it) {
|
|
|
|
const CConfigurableElement *pConfigurableElement = *it;
|
|
|
|
strResult += pConfigurableElement->getPath() + "\n";
|
|
}
|
|
}
|
|
|
|
bool CConfigurableElement::isRogue() const
|
|
{
|
|
// Check not belonging to any domin from current level and towards ascendents
|
|
if (getBelongingDomainCount() != 0) {
|
|
|
|
return false;
|
|
}
|
|
|
|
// Get a list of elements (current + descendants) with no domains associated
|
|
std::list<const CConfigurableElement *> rogueElementList;
|
|
|
|
CConfigurableElementAggregator agregator(rogueElementList,
|
|
&CConfigurableElement::hasNoDomainAssociated);
|
|
|
|
agregator.aggegate(this);
|
|
|
|
// Check only one element found which ought to be current one
|
|
return (rogueElementList.size() == 1) && (rogueElementList.front() == this);
|
|
}
|
|
|
|
// Footprint as string
|
|
std::string CConfigurableElement::getFootprintAsString() const
|
|
{
|
|
// Get size as string
|
|
return std::to_string(getFootPrint()) + " byte(s)";
|
|
}
|
|
|
|
// Matching check for no domain association
|
|
bool CConfigurableElement::hasNoDomainAssociated() const
|
|
{
|
|
return _configurableDomainList.empty();
|
|
}
|
|
|
|
// Matching check for no valid associated domains
|
|
bool CConfigurableElement::hasNoValidDomainAssociated() const
|
|
{
|
|
if (_configurableDomainList.empty()) {
|
|
|
|
// No domains associated
|
|
return true;
|
|
}
|
|
|
|
ConfigurableDomainListConstIterator it;
|
|
|
|
// Browse all configurable domains for validity checking
|
|
for (it = _configurableDomainList.begin(); it != _configurableDomainList.end(); ++it) {
|
|
|
|
const CConfigurableDomain *pConfigurableDomain = *it;
|
|
|
|
if (pConfigurableDomain->isApplicableConfigurationValid(this)) {
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// Owning domains
|
|
void CConfigurableElement::listAssociatedDomains(std::string &strResult, bool bVertical) const
|
|
{
|
|
// Fill list
|
|
listDomains(_configurableDomainList, strResult, bVertical);
|
|
}
|
|
|
|
size_t CConfigurableElement::getBelongingDomainCount() const
|
|
{
|
|
// Get belonging domain list
|
|
std::list<const CConfigurableDomain *> configurableDomainList;
|
|
|
|
getBelongingDomains(configurableDomainList);
|
|
|
|
return configurableDomainList.size();
|
|
}
|
|
|
|
void CConfigurableElement::listDomains(
|
|
const std::list<const CConfigurableDomain *> &configurableDomainList, std::string &strResult,
|
|
bool bVertical) const
|
|
{
|
|
// Fill list
|
|
ConfigurableDomainListConstIterator it;
|
|
bool bFirst = true;
|
|
|
|
// Browse all configurable domains for comparison
|
|
for (it = configurableDomainList.begin(); it != configurableDomainList.end(); ++it) {
|
|
|
|
const CConfigurableDomain *pConfigurableDomain = *it;
|
|
|
|
if (!bVertical && !bFirst) {
|
|
|
|
strResult += ", ";
|
|
}
|
|
|
|
strResult += pConfigurableDomain->getName();
|
|
|
|
if (bVertical) {
|
|
|
|
strResult += "\n";
|
|
} else {
|
|
|
|
bFirst = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool CConfigurableElement::containsConfigurableDomain(
|
|
const CConfigurableDomain *pConfigurableDomain) const
|
|
{
|
|
ConfigurableDomainListConstIterator it;
|
|
|
|
// Browse all configurable domains for comparison
|
|
for (it = _configurableDomainList.begin(); it != _configurableDomainList.end(); ++it) {
|
|
|
|
if (pConfigurableDomain == *it) {
|
|
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Belonging domain ascending search
|
|
bool CConfigurableElement::belongsToDomainAscending(
|
|
const CConfigurableDomain *pConfigurableDomain) const
|
|
{
|
|
// Check parent
|
|
const CElement *pParent = getParent();
|
|
|
|
if (isOfConfigurableElementType(pParent)) {
|
|
|
|
return static_cast<const CConfigurableElement *>(pParent)->belongsTo(pConfigurableDomain);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Belonging subsystem
|
|
const CSubsystem *CConfigurableElement::getBelongingSubsystem() const
|
|
{
|
|
const CElement *pParent = getParent();
|
|
|
|
// Stop at system class
|
|
if (!pParent->getParent()) {
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
return static_cast<const CConfigurableElement *>(pParent)->getBelongingSubsystem();
|
|
}
|
|
|
|
// Check element is a parameter
|
|
bool CConfigurableElement::isParameter() const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Check parent is still of current type (by structure knowledge)
|
|
bool CConfigurableElement::isOfConfigurableElementType(const CElement *pParent) const
|
|
{
|
|
assert(pParent);
|
|
|
|
// Up to system class
|
|
return !!pParent->getParent();
|
|
}
|