Salome HOME
Dump Python in the High Level Parameterized Geometry API (issue #1648)
[modules/shaper.git] / src / Model / Model_Validator.cpp
1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
2
3 // File:        Model_Validator.cpp
4 // Created:     2 Jul 2014
5 // Author:      Mikhail PONIKAROV
6
7 #include "Model_Validator.h"
8
9 #include "Model_AttributeValidator.h"
10 #include "Model_FeatureValidator.h"
11
12 #include <ModelAPI_Attribute.h>
13 #include <ModelAPI_AttributeString.h>
14 #include <ModelAPI_AttributeValidator.h>
15 #include <ModelAPI_Feature.h>
16 #include <ModelAPI_Result.h>
17 #include <Model_Data.h>
18
19 #include <Events_InfoMessage.h>
20
21 void Model_ValidatorsFactory::registerValidator(const std::string& theID,
22   ModelAPI_Validator* theValidator)
23 {
24   if (myIDs.find(theID) != myIDs.end()) {
25     Events_InfoMessage("Model_Validator", "Validator %1 is already registered").arg(theID).send();
26   } else {
27     myIDs[theID] = theValidator;
28   }
29 }
30
31 void Model_ValidatorsFactory::assignValidator(const std::string& theID,
32   const std::string& theFeatureID)
33 {
34   if (myFeatures.find(theFeatureID) == myFeatures.end()) {
35     myFeatures[theFeatureID] = AttrValidators();
36   }
37   if (myFeatures[theFeatureID].find(theID) != myFeatures[theFeatureID].end()) {
38     //Events_Error::send(std::string("Validator ") + theID + 
39     //  " for feature " + theFeatureID + "is already registered");
40   } else {
41     myFeatures[theFeatureID][theID] = std::list<std::string>();
42   }
43 }
44
45 void Model_ValidatorsFactory::assignValidator(const std::string& theID,
46   const std::string& theFeatureID,
47   const std::list<std::string>& theArguments)
48 {
49   if (myFeatures.find(theFeatureID) == myFeatures.end()) {
50     myFeatures[theFeatureID] = AttrValidators();
51   }
52
53   if (myFeatures[theFeatureID].find(theID) != myFeatures[theFeatureID].end()) {
54     //Events_Error::send(std::string("Validator ") + theID + 
55     //  " for feature " + theFeatureID + "is already registered");
56   } else {
57     myFeatures[theFeatureID][theID] = theArguments;
58   }
59 }
60
61 void Model_ValidatorsFactory::assignValidator(const std::string& theID,
62   const std::string& theFeatureID,
63   const std::string& theAttrID,
64   const std::list<std::string>& theArguments)
65 {
66   // create feature-structures if not exist
67   std::map<std::string, std::map<std::string, AttrValidators> >::iterator aFeature = myAttrs.find(
68     theFeatureID);
69   if (aFeature == myAttrs.end()) {
70     myAttrs[theFeatureID] = std::map<std::string, AttrValidators>();
71     aFeature = myAttrs.find(theFeatureID);
72   }
73   // add attr-structure if not exist, or generate error if already exist
74   std::map<std::string, AttrValidators>::iterator anAttr = aFeature->second.find(theAttrID);
75   if (anAttr == aFeature->second.end()) {
76     aFeature->second[theAttrID] = AttrValidators();
77   }
78   aFeature->second[theAttrID][theID] = theArguments;
79 }
80
81 void Model_ValidatorsFactory::validators(const std::string& theFeatureID,
82                                          Validators& theValidators) const
83 {
84   std::map<std::string, AttrValidators>::const_iterator aFeatureIt = 
85       myFeatures.find(theFeatureID);
86   if (aFeatureIt != myFeatures.cend()) {
87     AttrValidators::const_iterator aValidatorsIt = aFeatureIt->second.cbegin();
88     for (; aValidatorsIt != aFeatureIt->second.cend(); aValidatorsIt++) {
89       if (!validator(aValidatorsIt->first)) {
90         Events_InfoMessage("Model_Validator", "Validator %1 was not registered")
91           .arg(aValidatorsIt->first).send();
92       } else {
93         theValidators.push_back(std::make_pair(aValidatorsIt->first, aValidatorsIt->second));
94       }
95     }
96   }
97   addDefaultValidators(theValidators);
98 }
99
100 void Model_ValidatorsFactory::validators(const std::string& theFeatureID, const std::string& theAttrID,
101                                          Validators& theValidators) const
102 {
103   std::map<std::string, std::map<std::string, AttrValidators> >::const_iterator aFeatureIt = 
104       myAttrs.find(theFeatureID);
105   if (aFeatureIt != myAttrs.cend()) {
106     std::map<std::string, AttrValidators>::const_iterator anAttrIt = aFeatureIt->second.find(theAttrID);
107     if (anAttrIt != aFeatureIt->second.end()) {
108       AttrValidators::const_iterator aValidatorsIt = anAttrIt->second.cbegin();
109       for (; aValidatorsIt != anAttrIt->second.cend(); aValidatorsIt++) {
110         if (!validator(aValidatorsIt->first)) {
111           Events_InfoMessage("Model_Validator", "Validator %1 was not registered")
112             .arg(aValidatorsIt->first).send();
113         } else {
114           theValidators.push_back(std::make_pair(aValidatorsIt->first, aValidatorsIt->second));
115         }
116       }
117     }
118   }
119   addDefaultAttributeValidators(theValidators);
120 }
121
122 Model_ValidatorsFactory::Model_ValidatorsFactory()
123   : ModelAPI_ValidatorsFactory()
124 {
125   registerValidator("Model_FeatureValidator", new Model_FeatureValidator);
126   registerValidator("Model_AttributeValidator", new Model_AttributeValidator);
127 }
128
129 const ModelAPI_Validator* Model_ValidatorsFactory::validator(const std::string& theID) const
130 {
131   std::map<std::string, ModelAPI_Validator*>::const_iterator aIt = myIDs.find(theID);
132   if (aIt != myIDs.end()) {
133     return aIt->second;
134   }
135   return NULL;
136 }
137
138 void Model_ValidatorsFactory::addDefaultValidators(Validators& theValidators) const
139 {
140   const static std::string kDefaultId = "Model_FeatureValidator";
141   if (!validator(kDefaultId))
142     return;
143   theValidators.push_back(std::make_pair(kDefaultId, std::list<std::string>()));
144 }
145
146 void Model_ValidatorsFactory::addDefaultAttributeValidators(Validators& theValidators) const
147 {
148   const static std::string kDefaultId = "Model_AttributeValidator";
149   if (!validator(kDefaultId))
150     return;
151   theValidators.push_back(std::make_pair(kDefaultId, std::list<std::string>()));
152 }
153
154 bool Model_ValidatorsFactory::validate(const std::shared_ptr<ModelAPI_Feature>& theFeature) const
155 {
156   std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theFeature->data());
157   if (aData.get() && aData->isValid()) {
158     if (aData->execState() == ModelAPI_StateDone)
159       aData->eraseErrorString(); // no error => erase the information string
160   } else {
161     return false; // feature is broken, already not presented in the data structure
162   }
163
164   // check feature validators first
165   Validators aValidators;
166   validators(theFeature->getKind(), aValidators);
167
168   if (!aValidators.empty()) {
169     Validators::const_iterator aValidatorIt = aValidators.cbegin();
170     for(; aValidatorIt != aValidators.cend(); aValidatorIt++) {
171       const std::string& aValidatorID = aValidatorIt->first;
172       const std::list<std::string>& anArguments = aValidatorIt->second;
173       // validators() checks invalid validator names
174       //if (!aValidator) {
175       //  Events_Error::send(std::string("Validator ") + aValidatorID + " was not registered");
176       //  continue;
177       //}
178       const ModelAPI_FeatureValidator* aFValidator = 
179         dynamic_cast<const ModelAPI_FeatureValidator*>(validator(aValidatorID));
180       if (aFValidator) {
181         Events_InfoMessage anError;
182         if (!aFValidator->isValid(theFeature, anArguments, anError)) {
183           if (anError.empty())
184             anError = "Unknown error.";
185           anError = aValidatorID + ": " + anError.messageString();
186           theFeature->setError(anError.messageString(), false);
187           theFeature->data()->execState(ModelAPI_StateInvalidArgument);
188           return false;
189         }
190       }
191     }
192   }
193   // The default validator was retrned by validators() and was checked in previous cycle
194   //// check default validator
195   //std::map<std::string, ModelAPI_Validator*>::const_iterator aDefaultVal = myIDs.find(kDefaultId);
196   //if(aDefaultVal != myIDs.end()) {
197   //  static const std::list<std::string> anEmptyArgList;
198   //  const ModelAPI_FeatureValidator* aFValidator = 
199   //    dynamic_cast<const ModelAPI_FeatureValidator*>(aDefaultVal->second);
200   //  if (aFValidator) {
201   //    std::string anError;
202   //    if (!aFValidator->isValid(theFeature, anEmptyArgList, anError)) {
203   //      if (anError.empty())
204   //        anError = "Unknown error.";
205   //      anError = "Feature invalidated by \"" + kDefaultId + "\" with error: " + anError;
206   //      theFeature->setError(anError, false);
207   //      theFeature->data()->execState(ModelAPI_StateInvalidArgument);
208   //      return false;
209   //    }
210   //  }
211   //}
212
213   // check all attributes for validity
214   // Validity of data is checked by "Model_FeatureValidator" (kDefaultId)
215   // if (!aData || !aData->isValid())
216   //   return false;
217   static const std::string kAllTypes = "";
218   std::list<std::string> aLtAttributes = aData->attributesIDs(kAllTypes);
219   std::list<std::string>::const_iterator anAttrIt = aLtAttributes.cbegin();
220   for (; anAttrIt != aLtAttributes.cend(); anAttrIt++) {
221     const std::string& anAttributeID = *anAttrIt; 
222     AttributePtr anAttribute = theFeature->data()->attribute(anAttributeID);
223
224     std::string aValidatorID;
225     Events_InfoMessage anError;
226     if (!validate(anAttribute, aValidatorID, anError)) {
227       if (anError.empty())
228         anError = "Unknown error.";
229       anError = anAttributeID + " - " + aValidatorID + ": " + anError.messageString();
230       theFeature->setError(anError.messageString(), false);
231       theFeature->data()->execState(ModelAPI_StateInvalidArgument);
232       return false;
233     } 
234   }
235
236   return true;
237 }
238
239 bool Model_ValidatorsFactory::validate(const std::shared_ptr<ModelAPI_Attribute>& theAttribute,
240                                        std::string& theValidator,
241                                        Events_InfoMessage& theError) const
242 {
243   FeaturePtr aFeature = ModelAPI_Feature::feature(theAttribute->owner());
244   if (!aFeature.get()) {
245     theValidator = "Model_ValidatorsFactory";
246     theError = "Attribute has no feature.";
247     return false;
248   }
249
250   // skip not-case attributes, that really may be invalid (issue 671)
251   if (!const_cast<Model_ValidatorsFactory*>(this)->isCase(aFeature, theAttribute->id()))
252     return true;
253
254   Validators aValidators;
255   validators(aFeature->getKind(), theAttribute->id(), aValidators);
256
257   Validators::iterator aValidatorIt = aValidators.begin();
258   for (; aValidatorIt != aValidators.end(); ++aValidatorIt) {
259     const std::string& aValidatorID = aValidatorIt->first;
260     const std::list<std::string>& anArguments = aValidatorIt->second;
261     const ModelAPI_AttributeValidator* anAttrValidator =
262         dynamic_cast<const ModelAPI_AttributeValidator*>(validator(aValidatorID));
263     if (!anAttrValidator)
264       continue;
265     if (!anAttrValidator->isValid(theAttribute, anArguments, theError)) {
266       theValidator = aValidatorID;
267       return false;
268     } 
269   }
270
271   return true;
272 }
273
274 void Model_ValidatorsFactory::registerNotObligatory(std::string theFeature, std::string theAttribute)
275 {
276   const static std::string kDefaultId = "Model_FeatureValidator";
277   std::map<std::string, ModelAPI_Validator*>::const_iterator it = myIDs.find(kDefaultId);
278   if (it != myIDs.end()) {
279     Model_FeatureValidator* aValidator = dynamic_cast<Model_FeatureValidator*>(it->second);
280     if (aValidator) {
281       aValidator->registerNotObligatory(theFeature, theAttribute);
282     }
283   }
284 }
285
286 bool Model_ValidatorsFactory::isNotObligatory(std::string theFeature, std::string theAttribute)
287 {
288   const static std::string kDefaultId = "Model_FeatureValidator";
289   std::map<std::string, ModelAPI_Validator*>::const_iterator it = myIDs.find(kDefaultId);
290   if (it != myIDs.end()) {
291     Model_FeatureValidator* aValidator = dynamic_cast<Model_FeatureValidator*>(it->second);
292     if (aValidator) {
293       return aValidator->isNotObligatory(theFeature, theAttribute);
294     }
295   }
296   return false; // default
297 }
298
299 void Model_ValidatorsFactory::registerConcealment(std::string theFeature, std::string theAttribute)
300 {
301   std::map<std::string, std::set<std::string> >::iterator aFind = myConcealed.find(theFeature);
302   if (aFind == myConcealed.end()) {
303     std::set<std::string> aNewSet;
304     aNewSet.insert(theAttribute);
305     myConcealed[theFeature] = aNewSet;
306   } else {
307     aFind->second.insert(theAttribute);
308   }
309 }
310
311 bool Model_ValidatorsFactory::isConcealed(std::string theFeature, std::string theAttribute)
312 {
313   std::map<std::string, std::set<std::string> >::iterator aFind = myConcealed.find(theFeature);
314   return aFind != myConcealed.end() && aFind->second.find(theAttribute) != aFind->second.end();
315 }
316
317 void Model_ValidatorsFactory::registerUnconcealment(std::shared_ptr<ModelAPI_Result> theUnconcealed,
318     std::shared_ptr<ModelAPI_Feature> theCanceledFeat)
319 {
320   if (myUnconcealed.find(theUnconcealed) == myUnconcealed.end()) {
321     myUnconcealed[theUnconcealed] = std::list<std::shared_ptr<ModelAPI_Feature> >();
322   }
323   myUnconcealed[theUnconcealed].push_back(theCanceledFeat);
324   std::dynamic_pointer_cast<Model_Data>(theUnconcealed->data())->updateConcealmentFlag();
325 }
326
327 void Model_ValidatorsFactory::disableUnconcealment(std::shared_ptr<ModelAPI_Result> theUnconcealed,
328     std::shared_ptr<ModelAPI_Feature> theCanceledFeat)
329 {
330   std::map<std::shared_ptr<ModelAPI_Result>, std::list<std::shared_ptr<ModelAPI_Feature> > >
331     ::iterator aResFound = myUnconcealed.find(theUnconcealed);
332   if (aResFound != myUnconcealed.end()) {
333     std::list<std::shared_ptr<ModelAPI_Feature> >::iterator anIter = aResFound->second.begin();
334     for(; anIter != aResFound->second.end(); anIter++) {
335       if (*anIter == theCanceledFeat) {
336         aResFound->second.erase(anIter);
337         std::dynamic_pointer_cast<Model_Data>(theUnconcealed->data())->updateConcealmentFlag();
338         break;
339       }
340     }
341   }
342 }
343
344 bool Model_ValidatorsFactory::isUnconcealed(std::shared_ptr<ModelAPI_Result> theUnconcealed,
345     std::shared_ptr<ModelAPI_Feature> theCanceledFeat)
346 {
347   std::map<std::shared_ptr<ModelAPI_Result>, std::list<std::shared_ptr<ModelAPI_Feature> > >
348     ::iterator aResFound = myUnconcealed.find(theUnconcealed);
349   if (aResFound != myUnconcealed.end()) {
350     std::list<std::shared_ptr<ModelAPI_Feature> >::iterator aFeatIter = aResFound->second.begin();
351     for(; aFeatIter != aResFound->second.end(); aFeatIter++) {
352       if (aFeatIter->get()) {
353         if ((*aFeatIter)->isDisabled()) continue;
354         if (*aFeatIter == theCanceledFeat)
355           return true; // this is exactly canceled
356         if (theCanceledFeat->document()->isLater(*aFeatIter, theCanceledFeat))
357           return true; // if unconcealed feature (from the list) is later than concealed
358       } else
359         return true; // empty attribute means that everything is canceled
360     }
361   }
362   return false;
363 }
364
365 void Model_ValidatorsFactory::registerCase(std::string theFeature, std::string theAttribute,
366                             const std::list<std::pair<std::string, std::string> >& theCases)
367 {
368   std::map<std::string, std::map<std::string, std::map<std::string, std::set<std::string> > > >
369     ::iterator aFindFeature = myCases.find(theFeature);
370   if (aFindFeature == myCases.end()) {
371     myCases[theFeature] = std::map<std::string, std::map<std::string, std::set<std::string> > >();
372     aFindFeature = myCases.find(theFeature);
373   }
374   std::map<std::string, std::map<std::string, std::set<std::string> > >::iterator aFindAttrID =
375     aFindFeature->second.find(theAttribute);
376
377   if (aFindAttrID == aFindFeature->second.end()) {
378     aFindFeature->second[theAttribute] =
379       std::map<std::string, std::set<std::string> >();
380     aFindAttrID = aFindFeature->second.find(theAttribute);
381   }
382   std::list<std::pair<std::string, std::string> >::const_iterator aCasesIt = theCases.begin(),
383                                                                        aCasesLast = theCases.end();
384   std::map<std::string, std::set<std::string> > aFindCases = aFindAttrID->second;
385   for (; aCasesIt != aCasesLast; aCasesIt++) {
386     std::pair<std::string, std::string> aCasePair = *aCasesIt;
387     std::string aSwitch = aCasePair.first;
388     if (aFindAttrID->second.find(aSwitch) == aFindAttrID->second.end()) {
389       aFindAttrID->second[aSwitch] = std::set<std::string>();
390     }
391     aFindAttrID->second[aSwitch].insert(aCasePair.second);
392   }
393 }
394
395 bool Model_ValidatorsFactory::isCase(FeaturePtr theFeature, std::string theAttribute)
396 {
397   bool anInCase = true;
398   std::map<std::string, std::map<std::string, std::map<std::string, std::set<std::string> > > >
399     ::iterator aFindFeature = myCases.find(theFeature->getKind());
400   if (aFindFeature != myCases.end()) {
401     std::map<std::string, std::map<std::string, std::set<std::string> > >::iterator
402       aFindAttrID = aFindFeature->second.find(theAttribute);
403     if (aFindAttrID != aFindFeature->second.end()) {
404       std::map<std::string, std::set<std::string> >::iterator
405               aCasesIt = aFindAttrID->second.begin(), aCasesLast = aFindAttrID->second.end();
406       for (; aCasesIt != aCasesLast && anInCase; aCasesIt++) {
407         // the the switch-attribute that contains the case value
408         AttributeStringPtr aSwitch = theFeature->string(aCasesIt->first);
409         if (aSwitch.get()) {
410           // the second has the case identifier
411           anInCase =  aCasesIt->second.find(aSwitch->value()) != aCasesIt->second.end();
412         }
413       }
414     }
415   }
416   return anInCase; // if no additional conditions, this attribute is the case to be validated
417 }