From 8e45fc95efaf00a22e223ecbba721e30b5a17f4b Mon Sep 17 00:00:00 2001 From: sbh Date: Fri, 27 Feb 2015 13:12:47 +0300 Subject: [PATCH] Processing of "case" xml nodes for paiged containers (toolbox, switchcase) --- src/Config/Config_AttributeMessage.cpp | 15 +++++- src/Config/Config_AttributeMessage.h | 10 +++- src/Config/Config_Common.cpp | 72 ++++++++++++++++++++++++-- src/Config/Config_Common.h | 24 ++++++++- src/Config/Config_FeatureReader.cpp | 64 +++++++++++++++++++---- src/Config/Config_FeatureReader.h | 7 +++ src/Config/Config_XMLReader.cpp | 6 +++ src/Config/Config_XMLReader.h | 6 +++ 8 files changed, 185 insertions(+), 19 deletions(-) diff --git a/src/Config/Config_AttributeMessage.cpp b/src/Config/Config_AttributeMessage.cpp index 3b37a27bd..8009b12e4 100644 --- a/src/Config/Config_AttributeMessage.cpp +++ b/src/Config/Config_AttributeMessage.cpp @@ -5,10 +5,11 @@ Config_AttributeMessage::Config_AttributeMessage(const Events_ID theId, const void* theParent) : Events_Message(theId, theParent) { - myAttributeId = ""; // Attribute unique id - myFeatureId = ""; // Feature unique id + myAttributeId = std::string(); // Attribute unique id + myFeatureId = std::string(); // Feature unique id myIsObligatory = true; myIsConcealment = false; + myCaseId = std::string(); } Config_AttributeMessage::~Config_AttributeMessage() @@ -55,3 +56,13 @@ void Config_AttributeMessage::setObligatory(bool theObligatory) { this->myIsObligatory = theObligatory; } + +const std::string& Config_AttributeMessage::caseId() const +{ + return myCaseId; +} + +void Config_AttributeMessage::setCaseId(const std::string& theId) +{ + this->myCaseId = theId; +} diff --git a/src/Config/Config_AttributeMessage.h b/src/Config/Config_AttributeMessage.h index bfb9b64b1..7b2bd12b6 100644 --- a/src/Config/Config_AttributeMessage.h +++ b/src/Config/Config_AttributeMessage.h @@ -22,6 +22,7 @@ class Config_AttributeMessage : public Events_Message std::string myFeatureId; ///< Attribute's feature's unique id bool myIsObligatory; ///< Required to be set by user, else it's feature is invalid. bool myIsConcealment; ///< If true, conceals features used as input + std::string myCaseId; ///< Attribute's case's id, if it placed inside a paged containers public: /// Same event as Config_FeatureMessage::MODEL_EVENT() @@ -45,15 +46,20 @@ class Config_AttributeMessage : public Events_Message CONFIG_EXPORT bool isObligatory() const; /// Returns true if attribute should conceal input features CONFIG_EXPORT bool isConcealment() const; + /// Returns id of a case which contain the attribute + CONFIG_EXPORT const std::string& caseId() const; /// Set attribute's unique id CONFIG_EXPORT void setAttributeId(const std::string& theId); /// Set attribute's feature's unique id CONFIG_EXPORT void setFeatureId(const std::string& id); - /// Returns attribute's concealment state + /// Set attribute's concealment state CONFIG_EXPORT void setConcealment(bool isConcealment); - /// Returns attribute's obligatory state + /// Set attribute's obligatory state CONFIG_EXPORT void setObligatory(bool isObligatory); + /// Set attribute's case + CONFIG_EXPORT void setCaseId(const std::string& id); + }; #endif // ATTRIBUTE_MESSAGE_H diff --git a/src/Config/Config_Common.cpp b/src/Config/Config_Common.cpp index 9c4df7f57..8ffc9e126 100644 --- a/src/Config/Config_Common.cpp +++ b/src/Config/Config_Common.cpp @@ -27,7 +27,6 @@ bool isElementNode(xmlNodePtr theNode) bool isNode(xmlNodePtr theNode, const char* theNodeName, ...) { - bool result = false; const xmlChar* aName = theNode->name; if (!aName || !isElementNode(theNode)) { return false; @@ -50,19 +49,44 @@ bool isNode(xmlNodePtr theNode, const char* theNodeName, ...) return false; } +bool isAttributeNode(xmlNodePtr theNode) +{ + if(!isElementNode(theNode)) + return false; + // it's parent is "feature" or "source" or page ("case" or "box") + if(!hasParent(theNode, NODE_FEATURE, NODE_SOURCE, + WDG_TOOLBOX_BOX, WDG_SWITCH_CASE, NULL)) + return false; + + //it should not be a "source" or a "validator" node + bool isLogical = isNode(theNode, NODE_SOURCE, NODE_VALIDATOR, NODE_SELFILTER, NULL); + bool isPagedContainer = isNode(theNode, WDG_TOOLBOX, WDG_TOOLBOX_BOX, + WDG_SWITCH, WDG_SWITCH_CASE, NULL); + return !isLogical && !isPagedContainer; +} + bool isWidgetNode(xmlNodePtr theNode) { if(!isElementNode(theNode)) return false; // it's parent is "feature" or "source" - xmlNodePtr aParentNode = theNode->parent; - if(!isNode(aParentNode, NODE_FEATURE, NODE_SOURCE, NULL)) + if(!hasParent(theNode, NODE_FEATURE, NODE_SOURCE, + WDG_TOOLBOX_BOX, WDG_SWITCH_CASE, NULL)) return false; //it should not be a "source" or a "validator" node return !isNode(theNode, NODE_SOURCE, NODE_VALIDATOR, NODE_SELFILTER, NULL); } +// widget api? +bool isCaseNode(xmlNodePtr theNode) +{ + if(!isElementNode(theNode)) + return false; + + return isNode(theNode, WDG_SWITCH_CASE, WDG_TOOLBOX_BOX, NULL); +} + bool hasChild(xmlNodePtr theNode) { xmlNodePtr aNode = theNode->children; @@ -74,6 +98,48 @@ bool hasChild(xmlNodePtr theNode) return false; } +bool hasParent(xmlNodePtr theNode) +{ + xmlNodePtr aNode = theNode->parent; + if (!aNode) { + return false; + } + for (; aNode; aNode = aNode->next) { + if (isElementNode(theNode)) { + return true; + } + } + return false; +} + +bool hasParent(xmlNodePtr theNode, const char* theNodeName, ...) +{ + if (!hasParent(theNode)) { + return false; // have no parents at all + } + xmlNodePtr aNode = theNode->parent; + const xmlChar* aName = aNode->name; + if (!aName || !isElementNode(aNode)) { + return false; + } + if (!xmlStrcmp(aName, (const xmlChar *) theNodeName)) { + return true; + } + va_list args; // define argument list variable + va_start(args, theNodeName); // init list; point to last defined argument + while (true) { + char *anArg = va_arg (args, char*); // get next argument + if (anArg == NULL) + break; + if (!xmlStrcmp(aName, (const xmlChar *) anArg)) { + va_end(args); // cleanup the system stack + return true; + } + } + va_end(args); // cleanup the system stack + return false; +} + bool getParametersInfo(xmlNodePtr theNode, std::string& outPropertyId, std::list& outValidatorParameters) { diff --git a/src/Config/Config_Common.h b/src/Config/Config_Common.h index c53586eb5..52fc1e172 100644 --- a/src/Config/Config_Common.h +++ b/src/Config/Config_Common.h @@ -44,10 +44,21 @@ CONFIG_EXPORT bool isElementNode(xmlNodePtr theNode); CONFIG_EXPORT bool isNode(xmlNodePtr theNode, const char* theNodeName, ...); /*! - * Checks is the given node is attribute (widget) node. + * Checks if the given node is attribute node. + * Attribute node represents a widget, that is able to store/restore + * values from the model. Actually it's every widget, displayed + * in the XGUI_PropertyPanel, except paged containers (toolbox, switch/case). + */ +CONFIG_EXPORT bool isAttributeNode(xmlNodePtr theNode); + +/*! + * Checks if the given node is widget node. + * Widget nodes are attribute node + paged containers nodes. */ CONFIG_EXPORT bool isWidgetNode(xmlNodePtr theNode); +CONFIG_EXPORT bool isCaseNode(xmlNodePtr theNode); + /*! * Every xml node has child. Even if there is no explicit * child nodes libxml gives the "Text node" as child. @@ -57,6 +68,17 @@ CONFIG_EXPORT bool isWidgetNode(xmlNodePtr theNode); */ CONFIG_EXPORT bool hasChild(xmlNodePtr theNode); + +/*! + * Checks if the given node has a valid parent. + */ +CONFIG_EXPORT bool hasParent(xmlNodePtr theNode); + +/*! + * Checks if the given node has a valid parent with any of the given node names. + */ +CONFIG_EXPORT bool hasParent(xmlNodePtr theNode, const char* theNodeName, ...); + /*! * Returns named property for an id node as std::string and the parameters of the node. */ diff --git a/src/Config/Config_FeatureReader.cpp b/src/Config/Config_FeatureReader.cpp index 7f51d34ab..adf8f5e7a 100644 --- a/src/Config/Config_FeatureReader.cpp +++ b/src/Config/Config_FeatureReader.cpp @@ -61,27 +61,49 @@ void Config_FeatureReader::processNode(xmlNodePtr theNode) } else if (isNode(theNode, NODE_WORKBENCH, NODE_GROUP, NULL)) { storeAttribute(theNode, _ID); storeAttribute(theNode, WORKBENCH_DOC); - } else if (myIsProcessWidgets && isWidgetNode(theNode)) { - std::shared_ptr aMessage(new Config_AttributeMessage(aMenuItemEvent, this)); - aMessage->setFeatureId(restoreAttribute(NODE_FEATURE, _ID)); - std::string anAttributeID = getProperty(theNode, _ID); - if (!anAttributeID.empty()) { - aMessage->setAttributeId(anAttributeID); - aMessage->setObligatory(getBooleanAttribute(theNode, ATTR_OBLIGATORY, true)); - aMessage->setConcealment(getBooleanAttribute(theNode, ATTR_CONCEALMENT, false)); - //aMessage->setCaseId - Events_Loop::loop()->send(aMessage); + } else if (myIsProcessWidgets) { + // widgets, like shape_selector or containers, like toolbox + if (isAttributeNode(theNode)) { + std::shared_ptr aMessage(new Config_AttributeMessage(aMenuItemEvent, this)); + aMessage->setFeatureId(restoreAttribute(NODE_FEATURE, _ID)); + std::string anAttributeID = getProperty(theNode, _ID); + if (!anAttributeID.empty()) { + aMessage->setAttributeId(anAttributeID); + aMessage->setObligatory(getBooleanAttribute(theNode, ATTR_OBLIGATORY, true)); + aMessage->setConcealment(getBooleanAttribute(theNode, ATTR_CONCEALMENT, false)); + // nested "paged" widgets are not allowed, this issue may be resolved here: + if (hasParent(theNode, WDG_SWITCH_CASE, WDG_TOOLBOX_BOX, NULL)) { + const char* kWdgCase = hasParent(theNode, WDG_SWITCH_CASE, NULL) + ? WDG_SWITCH_CASE + : WDG_TOOLBOX_BOX; + aMessage->setCaseId(restoreAttribute(kWdgCase, _ID)); + } + Events_Loop::loop()->send(aMessage); + } + // container pages, like "case" or "box" + } else if (isCaseNode(theNode)) { + storeAttribute(theNode, _ID); // save case:caseId (or box:boxId) } } //Process SOURCE, VALIDATOR nodes. Config_XMLReader::processNode(theNode); } +void Config_FeatureReader::cleanup(xmlNodePtr theNode) +{ + if (isCaseNode(theNode)) { + // cleanup id of cases when leave case node + cleanupAttribute(theNode, _ID); + } +} + bool Config_FeatureReader::processChildren(xmlNodePtr theNode) { bool result = isNode(theNode, NODE_WORKBENCH, NODE_GROUP, NULL); if(!result && myIsProcessWidgets) { - result = isNode(theNode, NODE_FEATURE, NULL); + result = isNode(theNode, NODE_FEATURE, + WDG_TOOLBOX, WDG_TOOLBOX_BOX, + WDG_SWITCH, WDG_SWITCH_CASE, NULL); } return result; } @@ -139,3 +161,23 @@ std::string Config_FeatureReader::restoreAttribute(const char* theNodeName, } return result; } + +bool Config_FeatureReader::cleanupAttribute(xmlNodePtr theNode, + const char* theNodeAttribute) +{ + return cleanupAttribute(getNodeName(theNode).c_str(), theNodeAttribute); +} + +bool Config_FeatureReader::cleanupAttribute(const char* theNodeName, + const char* theNodeAttribute) +{ + std::string aKey = std::string(theNodeName) + ":" + std::string(theNodeAttribute); + bool result = false; + std::map::iterator anEntry = myParentAttributes.find(aKey); + if( anEntry != myParentAttributes.end()) { + myParentAttributes.erase(anEntry); + result = true; + } + return result; +} + diff --git a/src/Config/Config_FeatureReader.h b/src/Config/Config_FeatureReader.h index 7f7889aaa..75eb376e5 100644 --- a/src/Config/Config_FeatureReader.h +++ b/src/Config/Config_FeatureReader.h @@ -39,6 +39,10 @@ class Config_FeatureReader : public Config_XMLReader protected: /// Overloaded method. Defines how to process each node virtual void processNode(xmlNodePtr aNode); + + /// Overloaded method. Clears attribute cache on extit from attribute's node + virtual void cleanup(xmlNodePtr aNode); + /// Overloaded method. Defines if the given node should be parsed recursively virtual bool processChildren(xmlNodePtr aNode); @@ -54,6 +58,9 @@ class Config_FeatureReader : public Config_XMLReader /// Restores an attribute from internal map. std::string restoreAttribute(const char* theNodeName, const char* theNodeAttribute); + bool cleanupAttribute(xmlNodePtr theNode, const char* theNodeAttribute); + bool cleanupAttribute(const char* theNodeName, const char* theNodeAttribute); + private: /// A map to store all parent's attributes. /// The key has from "Node_Name:Node_Attribute" diff --git a/src/Config/Config_XMLReader.cpp b/src/Config/Config_XMLReader.cpp index 03af8f4c7..768232b74 100644 --- a/src/Config/Config_XMLReader.cpp +++ b/src/Config/Config_XMLReader.cpp @@ -86,6 +86,11 @@ void Config_XMLReader::processNode(xmlNodePtr theNode) } } +void Config_XMLReader::cleanup(xmlNodePtr) +{ + // do nothing; +} + bool Config_XMLReader::processChildren(xmlNodePtr aNode) { return true; @@ -126,6 +131,7 @@ void Config_XMLReader::readRecursively(xmlNodePtr theParent) if (processChildren(aNode)) { readRecursively(aNode); } + cleanup(aNode); } } diff --git a/src/Config/Config_XMLReader.h b/src/Config/Config_XMLReader.h index 01e64c394..603ce7d1f 100644 --- a/src/Config/Config_XMLReader.h +++ b/src/Config/Config_XMLReader.h @@ -61,6 +61,12 @@ class Config_XMLReader * "selection_filter" nodes. */ virtual void processNode(xmlNodePtr aNode); + + /*! + * This method gives an ability to finalize processing of a node, + * when reader is about to leave the node (node and all it's children are processed) + */ + virtual void cleanup(xmlNodePtr aNode); /*! * \brief Defines which nodes should be processed recursively. Virtual. * The default impl is to read all nodes. -- 2.39.2