Salome HOME
Update copyrights
[modules/shaper.git] / src / Config / Config_FeatureReader.cpp
1 // Copyright (C) 2014-2019  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include <Config_Keywords.h>
21 #include <Config_Common.h>
22 #include <Config_FeatureMessage.h>
23 #include <Config_AttributeMessage.h>
24 #include <Config_FeatureReader.h>
25 #include <Config_Translator.h>
26 #include <Events_Message.h>
27 #include <Events_Loop.h>
28
29 #include <libxml/parser.h>
30 #include <libxml/tree.h>
31 #include <libxml/xmlstring.h>
32
33 #include <string>
34 #include <algorithm>
35 #include <list>
36
37 #ifdef _DEBUG
38 #include <iostream>
39 #endif
40
41 Config_FeatureReader::Config_FeatureReader(const std::string& theXmlFile,
42                                            const std::string& theLibraryName,
43                                            const char* theEventGenerated)
44     : Config_XMLReader(theXmlFile),
45       myLibraryName(theLibraryName),
46       myEventGenerated(theEventGenerated ? theEventGenerated : Config_FeatureMessage::GUI_EVENT()),
47       myIsProcessWidgets(theEventGenerated != NULL)
48 {
49 }
50
51 Config_FeatureReader::~Config_FeatureReader()
52 {
53 }
54
55 std::list<std::string> Config_FeatureReader::features() const
56 {
57   return myFeatures;
58 }
59
60 void Config_FeatureReader::processNode(xmlNodePtr theNode)
61 {
62   Events_ID aMenuItemEvent = Events_Loop::eventByName(myEventGenerated);
63   if (isNode(theNode, NODE_FEATURE, NULL)) {
64     storeAttribute(theNode, _ID);
65     std::shared_ptr<Config_FeatureMessage>
66       aMessage(new Config_FeatureMessage(aMenuItemEvent, this));
67     fillFeature(theNode, aMessage);
68     myFeatures.push_back(getProperty(theNode, _ID));
69     //If a feature has xml definition for it's widget:
70     aMessage->setUseInput(hasChild(theNode));
71     Events_Loop::loop()->send(aMessage);
72     //The m_last* variables always defined before fillFeature() call. XML is a tree.
73   } else if (isNode(theNode, NODE_WORKBENCH, NODE_GROUP, NULL)) {
74     storeAttribute(theNode, _ID);
75     storeAttribute(theNode, GROUP_TOOLBAR);
76     storeAttribute(theNode, WORKBENCH_DOC, true);
77   } else if (myIsProcessWidgets) {
78     // widgets, like shape_selector or containers, like toolbox
79     if (isAttributeNode(theNode)) {
80       std::shared_ptr<Config_AttributeMessage>
81         aMessage(new Config_AttributeMessage(aMenuItemEvent, this));
82       aMessage->setFeatureId(restoreAttribute(NODE_FEATURE, _ID));
83       std::string anAttributeID = getProperty(theNode, _ID);
84       if (!anAttributeID.empty()) {
85         aMessage->setAttributeId(anAttributeID);
86         aMessage->setObligatory(getBooleanAttribute(theNode, ATTR_OBLIGATORY, true));
87         bool isConcealment = getBooleanAttribute(theNode, ATTR_CONCEALMENT, false);
88         aMessage->setConcealment(isConcealment);
89         bool isMainArg = isConcealment && getBooleanAttribute(theNode, ATTR_MAIN_ARG, false);
90         aMessage->setMainArgument(isMainArg);
91         aMessage->setGeometricalSelection(getBooleanAttribute(theNode,
92                                                               ATTR_GEOMETRICAL_SELECTION,
93                                                               false));
94
95         std::list<std::pair<std::string, std::string> > aCases;
96         xmlNodePtr aCaseNode = hasParentRecursive(theNode,
97           WDG_SWITCH_CASE, WDG_TOOLBOX_BOX, WDG_OPTIONALBOX, WDG_RADIOBOX_ITEM, NULL);
98         while(aCaseNode) {
99           std::string aCaseNodeID = getProperty(aCaseNode, _ID);
100           std::string aSwitchNodeID = "";
101           const xmlChar* aName = aCaseNode->name;
102           xmlNodePtr aSwitchNode;
103           if (!xmlStrcmp(aName, (const xmlChar *) WDG_SWITCH_CASE)) {
104             aSwitchNode = hasParentRecursive(aCaseNode, WDG_SWITCH, NULL);
105           }
106           else if (!xmlStrcmp(aName, (const xmlChar *) WDG_TOOLBOX_BOX)) {
107             aSwitchNode = hasParentRecursive(aCaseNode, WDG_TOOLBOX, NULL);
108           }
109           else if (!xmlStrcmp(aName, (const xmlChar *)WDG_RADIOBOX_ITEM)) {
110             aSwitchNode = hasParentRecursive(aCaseNode, WDG_RADIOBOX, NULL);
111           }
112           if (!xmlStrcmp(aName, (const xmlChar *) WDG_OPTIONALBOX)) {
113             /// the box is optional, attribute is in case
114             /// if the optional attribute value is not empty
115             aSwitchNode = aCaseNode;
116           }
117           if (aSwitchNode)
118             aSwitchNodeID = getProperty(aSwitchNode, _ID);
119
120           aCases.push_back(std::make_pair(aSwitchNodeID, aCaseNodeID));
121           aCaseNode = hasParentRecursive(aSwitchNode, WDG_SWITCH_CASE,
122             WDG_TOOLBOX_BOX, WDG_OPTIONALBOX, WDG_RADIOBOX_ITEM, NULL);
123         }
124         aMessage->setCases(aCases);
125         Events_Loop::loop()->send(aMessage);
126       }
127     // container pages, like "case" or "box"
128     } else if (isNode(theNode, WDG_OPTIONALBOX, WDG_SWITCH, WDG_SWITCH_CASE,
129                       WDG_TOOLBOX, WDG_TOOLBOX_BOX,
130                       WDG_RADIOBOX, WDG_RADIOBOX_ITEM, NULL)) {
131       storeAttribute(theNode, _ID); // save case:caseId (or box:boxId)
132     }
133   }
134   //Process SOURCE nodes.
135   Config_XMLReader::processNode(theNode);
136 }
137
138 void Config_FeatureReader::cleanup(xmlNodePtr theNode)
139 {
140   if (isNode(theNode, WDG_OPTIONALBOX, WDG_SWITCH, WDG_SWITCH_CASE,
141     WDG_TOOLBOX, WDG_TOOLBOX_BOX, WDG_RADIOBOX_ITEM, WDG_RADIOBOX, NULL)) {
142     // cleanup id of cases when leave case node
143     cleanupAttribute(theNode, _ID);
144   }
145 }
146
147 bool Config_FeatureReader::processChildren(xmlNodePtr theNode)
148 {
149   bool result = isNode(theNode, NODE_WORKBENCH, NODE_GROUP, NULL);
150   if(!result && myIsProcessWidgets) {
151     result = isNode(theNode, NODE_FEATURE,
152                              WDG_GROUP, WDG_OPTIONALBOX,
153                              WDG_TOOLBOX, WDG_TOOLBOX_BOX,
154                              WDG_RADIOBOX, WDG_RADIOBOX_ITEM,
155                              WDG_SWITCH, WDG_SWITCH_CASE, NULL);
156   }
157   return result;
158 }
159
160 void Config_FeatureReader::fillFeature(xmlNodePtr theFeatureNode,
161   const std::shared_ptr<Config_FeatureMessage>& outFeatureMessage)
162 {
163   std::string anId = getProperty(theFeatureNode, _ID);
164   outFeatureMessage->setId(anId);
165   outFeatureMessage->setPluginLibrary(myLibraryName);
166   outFeatureMessage->setNestedFeatures(getProperty(theFeatureNode, FEATURE_NESTED));
167   outFeatureMessage->setActionsWhenNested(getNormalizedProperty(theFeatureNode,
168                                           FEATURE_WHEN_NESTED));
169   outFeatureMessage->setModal(getBooleanAttribute(theFeatureNode, FEATURE_MODAL, false));
170   bool isAutoPreview = getBooleanAttribute(theFeatureNode, FEATURE_AUTO_PREVIEW, true);
171   outFeatureMessage->setAutoPreview(isAutoPreview);
172   outFeatureMessage->setApplyContinue(
173     getBooleanAttribute(theFeatureNode, FEATURE_APPLY_CONTINUE, false));
174
175   bool isInternal = getBooleanAttribute(theFeatureNode, ATTR_INTERNAL, false);
176   outFeatureMessage->setInternal(isInternal);
177   if (isInternal) {
178     //Internal feature has no visual representation.
179     return;
180   }
181
182   std::string aText = Config_Translator::translate(anId, getProperty(theFeatureNode, FEATURE_TEXT));
183   outFeatureMessage->setText(aText);
184   std::string aToolTip = Config_Translator::translate(anId,
185                                                       getProperty(theFeatureNode, FEATURE_TOOLTIP));
186   outFeatureMessage->setIcon(getProperty(theFeatureNode, FEATURE_ICON));
187   outFeatureMessage->setKeysequence(getProperty(theFeatureNode, FEATURE_KEYSEQUENCE));
188   std::string aHelpFile = getProperty(theFeatureNode, HELP_FILE);
189   if (!aHelpFile.empty())
190     outFeatureMessage->setHelpFileName(myLibraryName + "/" + aHelpFile);
191
192   std::string aGroupName = restoreAttribute(NODE_GROUP, _ID);
193   std::string aWBNName = restoreAttribute(NODE_WORKBENCH, _ID);
194   std::string isGroupToolbarId = restoreAttribute(NODE_GROUP, GROUP_TOOLBAR);
195   bool isGroupToolbar = false;
196   if (isGroupToolbarId.length() > 0)
197     isGroupToolbar = (isGroupToolbarId == "yes");
198   outFeatureMessage->setGroupId(aGroupName);
199   outFeatureMessage->setWorkbenchId(aWBNName);
200   outFeatureMessage->setToolBarId(isGroupToolbar ? aGroupName : aWBNName);
201
202   // Get document kind of a feature, if empty set workbench's kind (might be empty too)
203   std::string aDocKind = getProperty(theFeatureNode, FEATURE_DOC);
204   if(aDocKind.empty()) {
205     aDocKind = restoreAttribute(NODE_WORKBENCH, WORKBENCH_DOC);
206   }
207   outFeatureMessage->setDocumentKind(aDocKind);
208 }