Salome HOME
Issue #2566: Resize boolean operations icons
[modules/shaper.git] / src / FeaturesPlugin / FeaturesPlugin_Validators.cpp
1 // Copyright (C) 2014-2017  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
18 // email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
19 //
20
21 #include "FeaturesPlugin_Validators.h"
22
23 #include "FeaturesPlugin_Boolean.h"
24 #include "FeaturesPlugin_BooleanFuse.h"
25 #include "FeaturesPlugin_BooleanCommon.h"
26 #include "FeaturesPlugin_BooleanSmash.h"
27 #include "FeaturesPlugin_Union.h"
28
29 #include <Events_InfoMessage.h>
30
31 #include <ModelAPI_Attribute.h>
32 #include <ModelAPI_AttributeInteger.h>
33 #include <ModelAPI_AttributeSelectionList.h>
34 #include <ModelAPI_AttributeString.h>
35 #include <ModelAPI_AttributeReference.h>
36 #include <ModelAPI_AttributeRefList.h>
37 #include <ModelAPI_Feature.h>
38 #include <ModelAPI_ResultBody.h>
39 #include <ModelAPI_ResultConstruction.h>
40 #include <ModelAPI_Tools.h>
41
42 #include <GeomValidators_BodyShapes.h>
43 #include <GeomValidators_Face.h>
44 #include <GeomValidators_FeatureKind.h>
45 #include <GeomValidators_ShapeType.h>
46
47 #include <GeomAPI_DataMapOfShapeShape.h>
48 #include <GeomAPI_Lin.h>
49 #include <GeomAPI_PlanarEdges.h>
50 #include <GeomAPI_Pln.h>
51 #include <GeomAPI_ShapeExplorer.h>
52 #include <GeomAPI_ShapeIterator.h>
53
54 #include <GeomAlgoAPI_CompoundBuilder.h>
55 #include <GeomAlgoAPI_ShapeBuilder.h>
56 #include <GeomAlgoAPI_ShapeTools.h>
57 #include <GeomAlgoAPI_WireBuilder.h>
58
59 #define _USE_MATH_DEFINES
60 #include <math.h>
61
62 //==================================================================================================
63 bool FeaturesPlugin_ValidatorPipePath::isValid(const AttributePtr& theAttribute,
64                                                const std::list<std::string>& theArguments,
65                                                Events_InfoMessage& theError) const
66 {
67   AttributeSelectionPtr aPathAttrSelection =
68     std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
69   if(!aPathAttrSelection.get()) {
70     theError = "Error: This validator can only work with path selector in \"Pipe\" feature.";
71     return false;
72   }
73
74   GeomShapePtr aPathShape = aPathAttrSelection->value();
75   ResultPtr aContext = aPathAttrSelection->context();
76   if(!aContext.get()) {
77     theError = "Error: Empty context.";
78     return false;
79   }
80   GeomShapePtr aContextShape = aContext->shape();
81   if(aPathShape.get() && aPathShape->shapeType() == GeomAPI_Shape::WIRE &&
82       !aPathShape->isEqual(aContextShape)) {
83     theError = "Error: Local selection of wires not allowed.";
84     return false;
85   }
86
87   return true;
88 }
89
90 //==================================================================================================
91 bool FeaturesPlugin_ValidatorPipeLocations::isValid(
92   const std::shared_ptr<ModelAPI_Feature>& theFeature,
93   const std::list<std::string>& theArguments,
94   Events_InfoMessage& theError) const
95 {
96   static const std::string aCreationMethodID = "creation_method";
97   static const std::string aBaseObjectsID = "base_objects";
98   static const std::string aLocationsID = "locations_objects";
99
100   if(theFeature->getKind() != "Pipe") {
101     theError = "Error: Feature \"%1\" does not supported by this validator.";
102     theError.arg(theFeature->getKind());
103     return false;
104   }
105
106   AttributeStringPtr aCreationMethodAttr = theFeature->string(aCreationMethodID);
107   if(!aCreationMethodAttr.get()) {
108     theError = "Error: Could not get \"%1\" attribute.";
109     theError.arg(aCreationMethodID);
110     return false;
111   }
112
113   if(aCreationMethodAttr->value() != "locations") {
114     return true;
115   }
116
117   AttributeSelectionListPtr aBaseObjectsSelectionList = theFeature->selectionList(aBaseObjectsID);
118   if(!aBaseObjectsSelectionList.get()) {
119     theError = "Error: Could not get \"%1\" attribute.";
120     theError.arg(aBaseObjectsID);
121     return false;
122   }
123
124   AttributeSelectionListPtr aLocationsSelectionList = theFeature->selectionList(aLocationsID);
125   if(!aLocationsSelectionList.get()) {
126     theError = "Error: Could not get \"%1\" attribute.";
127     theError.arg(aBaseObjectsID);
128     return false;
129   }
130
131   if(aLocationsSelectionList->size() > 0 &&
132      aLocationsSelectionList->size() != aBaseObjectsSelectionList->size()) {
133     theError = "Error: Number of locations should be the same as base objects.";
134     return false;
135   }
136
137   return true;
138 }
139
140 //==================================================================================================
141 bool FeaturesPlugin_ValidatorBaseForGeneration::isValid(const AttributePtr& theAttribute,
142                                                         const std::list<std::string>& theArguments,
143                                                         Events_InfoMessage& theError) const
144 {
145   if(theArguments.empty()) {
146     theError = "Error: Validator parameters is empty.";
147     return false;
148   }
149
150   // Checking attribute.
151   if(!isValidAttribute(theAttribute, theArguments, theError)) {
152     if(theError.empty()) {
153       theError = "Error: Attribute contains unacceptable shape.";
154     }
155     return false;
156   }
157
158   GeomAPI_DataMapOfShapeShape aSelectedWiresFromObjects;
159   std::string anAttributeType = theAttribute->attributeType();
160   if(anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
161     AttributeSelectionListPtr aListAttr =
162       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
163     for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
164       AttributeSelectionPtr aSelectionAttr = aListAttr->value(anIndex);
165       ResultPtr aContext = aSelectionAttr->context();
166       if(!aContext.get()) {
167         theError = "Error: Empty context.";
168         return false;
169       }
170
171       ResultConstructionPtr aResultConstruction =
172         std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
173       if(!aResultConstruction.get()) {
174         // It is not a result construction.
175         // If shape is compound check that it contains only faces and edges.
176         GeomShapePtr aShape = aSelectionAttr->value();
177         if(!aShape.get()) {
178           aShape = aContext->shape();
179         }
180
181         if(aShape->shapeType() == GeomAPI_Shape::COMPOUND) {
182           for(GeomAPI_ShapeIterator anIt(aShape); anIt.more(); anIt.next()) {
183             GeomShapePtr aSubShape = anIt.current();
184             if(aSubShape->shapeType() != GeomAPI_Shape::EDGE
185                 && aSubShape->shapeType() != GeomAPI_Shape::FACE) {
186               theError = "Error: Compound should contain only faces and edges.";
187               return false;
188             }
189           }
190         }
191
192         continue;
193       }
194
195       GeomShapePtr aShape = aSelectionAttr->value();
196       GeomShapePtr aContextShape = aResultConstruction->shape();
197       if(!aShape.get()) {
198         // Whole sketch selected.
199         continue;
200       } else {
201         // Object from sketch selected.
202         for(GeomAPI_ShapeExplorer anExp(aShape, GeomAPI_Shape::WIRE); anExp.more(); anExp.next()) {
203           GeomShapePtr aWire = anExp.current();
204           if(aWire->orientation() != GeomAPI_Shape::FORWARD) {
205             theError = "Error: Wire with wrong orientation selected.";
206             return false;
207           }
208
209           if(aSelectedWiresFromObjects.isBound(aWire)) {
210             theError =
211               "Error: Objects with such wire already selected. Don't allow to select this object.";
212             return false;
213           }
214
215           aSelectedWiresFromObjects.bind(aWire, aWire);
216         }
217       }
218     }
219   }
220
221   return true;
222 }
223
224 //==================================================================================================
225 bool FeaturesPlugin_ValidatorBaseForGenerationSketchOrSketchObjects::isValid(
226   const std::shared_ptr<ModelAPI_Feature>& theFeature,
227   const std::list<std::string>& theArguments,
228   Events_InfoMessage& theError) const
229 {
230   const std::string aBaseObjectsID = theArguments.front();
231
232   AttributeSelectionListPtr aListAttr = theFeature->selectionList(aBaseObjectsID);
233   if(!aListAttr.get()) {
234     theError = "Error: Could not get \"%1\" attribute.";
235     theError.arg(aBaseObjectsID);
236     return false;
237   }
238
239   std::set<ResultConstructionPtr> aSelectedSketches;
240   std::set<ResultConstructionPtr> aSelectedSketchesFromObjects;
241
242   for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
243     AttributeSelectionPtr aSelectionAttr = aListAttr->value(anIndex);
244     ResultPtr aContext = aSelectionAttr->context();
245     if(!aContext.get()) {
246       theError = "Error: Empty context.";
247       return false;
248     }
249
250     ResultConstructionPtr aResultConstruction =
251       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
252     if(!aResultConstruction.get()) {
253       // It is not a result construction.
254       continue;
255     }
256
257     GeomShapePtr aShape = aSelectionAttr->value();
258     GeomShapePtr aContextShape = aResultConstruction->shape();
259     if(!aShape.get()) {
260       // Whole sketch selected.
261       aSelectedSketches.insert(aResultConstruction);
262     } else {
263       // Object from sketch selected.
264       aSelectedSketchesFromObjects.insert(aResultConstruction);
265     }
266   }
267
268
269   for(std::set<ResultConstructionPtr>::const_iterator anIt = aSelectedSketches.cbegin();
270       anIt != aSelectedSketches.cend();
271       ++anIt) {
272     ResultConstructionPtr aResultConstruction = *anIt;
273     if(aSelectedSketchesFromObjects.find(aResultConstruction) !=
274         aSelectedSketchesFromObjects.cend()) {
275       theError = "Sketch and objects from it can not be selected at the same time.";
276       return false;
277     }
278   }
279
280   return true;
281 }
282
283 //==================================================================================================
284 bool FeaturesPlugin_ValidatorBaseForGeneration::isValidAttribute(const AttributePtr& theAttribute,
285                                                         const std::list<std::string>& theArguments,
286                                                         Events_InfoMessage& theError) const
287 {
288   if(!theAttribute.get()) {
289     theError = "Error: Empty attribute.";
290     return false;
291   }
292
293   std::string anAttributeType = theAttribute->attributeType();
294   if(anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
295     AttributeSelectionListPtr aListAttr =
296       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
297     for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
298       // If at least one attribute is invalid, the result is false.
299       if(!isValidAttribute(aListAttr->value(anIndex), theArguments, theError)) {
300         return false;
301       }
302     }
303   } else if(anAttributeType == ModelAPI_AttributeSelection::typeId()) {
304     // Getting context.
305     AttributeSelectionPtr anAttr =
306       std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
307     ResultPtr aContext = anAttr->context();
308     if(!aContext.get()) {
309       theError = "Error: Attribute have empty context.";
310       return false;
311     }
312
313     GeomShapePtr aShape = anAttr->value();
314     GeomShapePtr aContextShape = aContext->shape();
315     if(!aShape.get()) {
316       aShape = aContextShape;
317     }
318     if(!aShape.get()) {
319       theError = "Error: Empty shape selected";
320       return false;
321     }
322
323     ResultConstructionPtr aConstruction =
324       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
325     if(aConstruction.get()) {
326       // Construciotn selected. Check that is is not infinite.
327       if(aConstruction->isInfinite()) {
328         theError = "Error: Infinite constructions is not allowed as base.";
329         return false;
330       }
331
332       if(aShape->isEqual(aContextShape)) {
333         // Whole construction selected. Check that it have faces.
334         if(aConstruction->facesNum() > 0) {
335           return true;
336         }
337       } else {
338         // Shape on construction selected. Check that it is a face or wire.
339         if(aShape->shapeType() == GeomAPI_Shape::WIRE ||
340            aShape->shapeType() == GeomAPI_Shape::FACE) {
341           return true;
342         }
343       }
344
345       return false;
346     }
347
348     if(!aShape->isEqual(aContextShape)) {
349       // Local selection on body does not allowed.
350       theError =
351         "Error: Selected shape is in the local selection. Only global selection is allowed.";
352       return false;
353     }
354
355     // Check that object is a shape with allowed type.
356     GeomValidators_ShapeType aShapeTypeValidator;
357     if(!aShapeTypeValidator.isValid(anAttr, theArguments, theError)) {
358       theError = "Error: Selected shape has unacceptable type. Acceptable types are: faces or "
359                  "wires on sketch, whole sketch(if it has at least one face), "
360                  "and whole objects with shape types: %1";
361       std::string anArgumentString;
362       for(auto anIt = theArguments.cbegin(); anIt != theArguments.cend(); ++anIt) {
363         if (!anArgumentString.empty())
364           anArgumentString += ", ";
365         anArgumentString += *anIt;
366       }
367       theError.arg(anArgumentString);
368       return false;
369     }
370
371   } else {
372     theError = "Error: Attribute \"%1\" does not supported by this validator.";
373     theError.arg(anAttributeType);
374     return false;
375   }
376
377   return true;
378 }
379
380 //==================================================================================================
381 bool FeaturesPlugin_ValidatorCompositeLauncher::isValid(const AttributePtr& theAttribute,
382                                                         const std::list<std::string>& theArguments,
383                                                         Events_InfoMessage& theError) const
384 {
385   if (theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) {
386     theError = "Error: The attribute with the %1 type is not processed";
387     theError.arg(theAttribute->attributeType());
388     return false;
389   }
390   if (theArguments.size() != 2) {
391     theError = "Error: Wrong parameters in XML definition for %1 type";
392     theError.arg(theAttribute->attributeType());
393     return false;
394   }
395   // first argument is for the base attribute, second - for skipping feature kind
396   std::list<std::string>::const_iterator anIt = theArguments.begin();
397   std::string aBaseAttributeId = *anIt;
398   FeaturePtr aFeature = ModelAPI_Feature::feature(theAttribute->owner());
399   AttributePtr aBaseAttribute = aFeature->attribute(aBaseAttributeId);
400   if (!aBaseAttribute.get()) {
401     theError = "Wrong parameters in XML definition for %1 type";
402     theError.arg(theAttribute->attributeType());
403     return false;
404   }
405   if (aBaseAttribute->isInitialized()) // when base list of composite feature is already filled,
406     // this validator is not necessary anymore
407     return true;
408
409   anIt++;
410   std::string aFeatureAttributeKind = *anIt;
411   GeomValidators_FeatureKind* aValidator = new GeomValidators_FeatureKind();
412   // check whether the selection is on the sketch
413   std::list<std::string> anArguments;
414   anArguments.push_back(aFeatureAttributeKind);
415
416   bool aFeatureKind = aValidator->isValid(theAttribute, theArguments, theError);
417   bool aPlanarFace = false;
418   // check if selection has Face selected
419   GeomValidators_ShapeType* aShapeType = new GeomValidators_ShapeType();
420   anArguments.clear();
421   anArguments.push_back("face");
422   aPlanarFace = aShapeType->isValid(theAttribute, anArguments, theError);
423
424   bool aValid = !aFeatureKind && aPlanarFace;
425   return aValid;
426 }
427
428 //==================================================================================================
429 bool FeaturesPlugin_ValidatorExtrusionDir::isValid(
430                                                const std::shared_ptr<ModelAPI_Feature>& theFeature,
431                                                const std::list<std::string>& theArguments,
432                                                Events_InfoMessage& theError) const
433 {
434   if(theArguments.size() != 2) {
435     theError = "Error: Validator should be used with 2 parameters for extrusion.";
436     return false;
437   }
438
439   std::list<std::string>::const_iterator
440     anArgsIt = theArguments.begin(), aLast = theArguments.end();
441
442   AttributePtr aCheckAttribute = theFeature->attribute(*anArgsIt);
443   ++anArgsIt;
444
445   GeomShapePtr aDirShape;
446   AttributeSelectionPtr aSelAttr = theFeature->selection(*anArgsIt);
447   if(aSelAttr.get()) {
448     aDirShape = aSelAttr->value();
449     if(!aDirShape.get()) {
450       ResultPtr aContext = aSelAttr->context();
451       if(aContext.get()) {
452         aDirShape = aContext->shape();
453       }
454     }
455   }
456
457   if(!aDirShape.get()) {
458     // Check that dir can be empty.
459     if(!isShapesCanBeEmpty(aCheckAttribute, theError)) {
460       theError = "Error: Base objects list contains vertex or edge, so attribute \"%1\" "
461                  "can not be used with default value. Select direction for extrusion.";
462       theError.arg(*anArgsIt);
463       return false;
464     } else {
465       return true;
466     }
467   }
468
469   std::shared_ptr<GeomAPI_Edge> aDirEdge(new GeomAPI_Edge(aDirShape));
470
471   // If faces selected check that direction not parallel with them.
472   AttributeSelectionListPtr aListAttr =
473     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(aCheckAttribute);
474   for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
475     AttributeSelectionPtr anAttr = aListAttr->value(anIndex);
476     GeomShapePtr aShapeInList = anAttr->value();
477     if(!aShapeInList.get()) {
478       aShapeInList = anAttr->context()->shape();
479     }
480     bool isParallel = true;
481     if(aShapeInList->shapeType() == GeomAPI_Shape::FACE ||
482        aShapeInList->shapeType() == GeomAPI_Shape::SHELL) {
483       for(GeomAPI_ShapeExplorer
484           anExp(aShapeInList, GeomAPI_Shape::FACE); anExp.more(); anExp.next()) {
485         std::shared_ptr<GeomAPI_Face> aFace(new GeomAPI_Face(anExp.current()));
486         isParallel = GeomAlgoAPI_ShapeTools::isParallel(aDirEdge, aFace);
487         if(isParallel) {
488           break;
489         }
490       }
491     } else if(aShapeInList->shapeType() == GeomAPI_Shape::COMPOUND) {
492       std::shared_ptr<GeomAPI_PlanarEdges> aPlanarEdges =
493         std::dynamic_pointer_cast<GeomAPI_PlanarEdges>(aShapeInList);
494       if(aPlanarEdges.get()) {
495         std::shared_ptr<GeomAPI_Dir> aSketchDir = aPlanarEdges->norm();
496         if(aDirEdge->isLine()) {
497           std::shared_ptr<GeomAPI_Dir> aDir = aDirEdge->line()->direction();
498           isParallel = fabs(aSketchDir->angle(aDir) - M_PI / 2.0) < 10e-7;
499         } else {
500           isParallel = false;
501         }
502       } else {
503         isParallel = false;
504       }
505     } else {
506       isParallel = false;
507     }
508     if(isParallel) {
509       theError =
510         "Error: Direction is parallel to one of the selected face or face on selected shell.";
511       return false;
512     }
513   }
514
515   return true;
516 }
517
518 //==================================================================================================
519 bool FeaturesPlugin_ValidatorExtrusionDir::isShapesCanBeEmpty(const AttributePtr& theAttribute,
520                                                               Events_InfoMessage& theError) const
521 {
522   if(!theAttribute.get()) {
523     return true;
524   }
525
526   std::string anAttributeType = theAttribute->attributeType();
527   if(anAttributeType == ModelAPI_AttributeSelectionList::typeId()) {
528     AttributeSelectionListPtr aListAttr =
529       std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
530     for(int anIndex = 0; anIndex < aListAttr->size(); ++anIndex) {
531       // If at least one attribute is invalid, the result is false.
532       if(!isShapesCanBeEmpty(aListAttr->value(anIndex), theError)) {
533         return false;
534       }
535     }
536   } else if(anAttributeType == ModelAPI_AttributeSelection::typeId()) {
537     // Getting context.
538     AttributeSelectionPtr anAttr =
539       std::dynamic_pointer_cast<ModelAPI_AttributeSelection>(theAttribute);
540     ResultPtr aContext = anAttr->context();
541     if(!aContext.get()) {
542       return false;
543     }
544
545     GeomShapePtr aShape = anAttr->value();
546     GeomShapePtr aContextShape = aContext->shape();
547     if(!aShape.get()) {
548       aShape = aContextShape;
549     }
550     if(!aShape.get()) {
551       return false;
552     }
553
554     if(aShape->shapeType() == GeomAPI_Shape::VERTEX ||
555        aShape->shapeType() == GeomAPI_Shape::EDGE ||
556        !aShape->isPlanar()) {
557       return false;
558     }
559   } else {
560     return false;
561   }
562
563   return true;
564 }
565
566 //==================================================================================================
567 bool FeaturesPlugin_ValidatorBooleanSelection::isValid(const AttributePtr& theAttribute,
568                                                        const std::list<std::string>& theArguments,
569                                                        Events_InfoMessage& theError) const
570 {
571   AttributeSelectionListPtr anAttrSelectionList =
572     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
573   if(!anAttrSelectionList.get()) {
574     theError =
575       "Error: This validator can only work with selection list attributes in \"Boolean\" feature.";
576     return false;
577   }
578   std::shared_ptr<FeaturesPlugin_Boolean> aFeature =
579     std::dynamic_pointer_cast<FeaturesPlugin_Boolean>(theAttribute->owner());
580   FeaturesPlugin_Boolean::OperationType anOperationType = aFeature->operationType();
581
582   for(int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
583     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
584     if(!anAttrSelection.get()) {
585       theError = "Error: Empty attribute selection.";
586       return false;
587     }
588     ResultPtr aContext = anAttrSelection->context();
589     if(!aContext.get()) {
590       FeaturePtr aContFeat = anAttrSelection->contextFeature();
591       if (!aContFeat.get() || !aContFeat->results().size()) {
592         theError = "Error: Empty selection context.";
593         return false;
594       }
595     }
596     ResultConstructionPtr aResultConstruction =
597       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
598     if(aResultConstruction.get()) {
599       if (anOperationType != FeaturesPlugin_Boolean::BOOL_FILL
600           || theAttribute->id() != FeaturesPlugin_Boolean::TOOL_LIST_ID()) {
601         theError = "Error: Result construction not allowed for selection.";
602         return false;
603       }
604     }
605     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
606     if(!aShape.get() && aContext.get()) {
607       GeomShapePtr aContextShape = aContext->shape();
608       aShape = aContextShape;
609     }
610     if(!aShape.get()) {
611       theError = "Error: Empty shape.";
612       return false;
613     }
614     if (aContext.get() && !aShape->isEqual(aContext->shape())) {
615       theError = "Error: Local selection not allowed.";
616       return false;
617     }
618
619     GeomAPI_Shape::ShapeType aShapeType = aShape->shapeType();
620     std::set<GeomAPI_Shape::ShapeType> anAllowedTypes;
621     if(anOperationType == FeaturesPlugin_Boolean::BOOL_FUSE) {
622       anAllowedTypes.insert(GeomAPI_Shape::EDGE);
623       anAllowedTypes.insert(GeomAPI_Shape::FACE);
624       anAllowedTypes.insert(GeomAPI_Shape::SOLID);
625       anAllowedTypes.insert(GeomAPI_Shape::COMPSOLID);
626       anAllowedTypes.insert(GeomAPI_Shape::COMPOUND);
627     } else if (anOperationType == FeaturesPlugin_Boolean::BOOL_FILL
628                || anOperationType == FeaturesPlugin_Boolean::BOOL_CUT)
629     {
630       anAllowedTypes.insert(GeomAPI_Shape::VERTEX);
631       anAllowedTypes.insert(GeomAPI_Shape::EDGE);
632       anAllowedTypes.insert(GeomAPI_Shape::WIRE);
633       anAllowedTypes.insert(GeomAPI_Shape::FACE);
634       anAllowedTypes.insert(GeomAPI_Shape::SHELL);
635       anAllowedTypes.insert(GeomAPI_Shape::SOLID);
636       anAllowedTypes.insert(GeomAPI_Shape::COMPSOLID);
637       anAllowedTypes.insert(GeomAPI_Shape::COMPOUND);
638     } else {
639       anAllowedTypes.insert(GeomAPI_Shape::SOLID);
640       anAllowedTypes.insert(GeomAPI_Shape::COMPSOLID);
641       anAllowedTypes.insert(GeomAPI_Shape::COMPOUND);
642     }
643
644     if(anAllowedTypes.find(aShapeType) == anAllowedTypes.end()
645       || (aResultConstruction.get() && aShapeType != GeomAPI_Shape::FACE)) {
646       theError = "Error: Selected shape has the wrong type.";
647       return false;
648     }
649
650   }
651
652   return true;
653 }
654
655 //==================================================================================================
656 bool FeaturesPlugin_ValidatorFilletSelection::isValid(const AttributePtr& theAttribute,
657                                                       const std::list<std::string>& theArguments,
658                                                       Events_InfoMessage& theError) const
659 {
660   AttributeSelectionListPtr anAttrSelectionList =
661     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
662   if(!anAttrSelectionList.get()) {
663     theError =
664       "Error: This validator can only work with selection list attributes in \"Fillet\" feature.";
665     return false;
666   }
667
668   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
669   // Check all selected entities are sub-shapes of single solid
670   GeomShapePtr aBaseSolid;
671   for(int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
672     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
673     if(!anAttrSelection.get()) {
674       theError = "Error: Empty attribute selection.";
675       return false;
676     }
677     ResultPtr aContext = anAttrSelection->context();
678     if(!aContext.get()) {
679       FeaturePtr aContFeat = anAttrSelection->contextFeature();
680       if (!aContFeat.get() || !aContFeat->results().size() ||
681           aContFeat->firstResult()->groupName() != ModelAPI_ResultBody::group()) {
682         theError = "Error: Empty selection context.";
683         return false;
684       }
685       if (aContFeat->results().size() == 1)
686         aContext = aContFeat->firstResult();
687       else {
688         theError = "Error: Too many shapes selected.";
689         return false;
690       }
691     }
692
693     ResultBodyPtr aContextOwner = ModelAPI_Tools::bodyOwner(aContext);
694     GeomShapePtr anOwner = aContextOwner.get() ? aContextOwner->shape() : aContext->shape();
695
696     if (anOwner->shapeType() != GeomAPI_Shape::SOLID &&
697         anOwner->shapeType() != GeomAPI_Shape::COMPSOLID) {
698       theError = "Error: Not all selected shapes are sub-shapes of solids.";
699       return false;
700     }
701
702     if (!aBaseSolid)
703       aBaseSolid = anOwner;
704     else if (!aBaseSolid->isEqual(anOwner)) {
705       theError = "Error: Sub-shapes of different solids have been selected.";
706       return false;
707     }
708   }
709
710   return true;
711 }
712
713 //==================================================================================================
714 bool FeaturesPlugin_ValidatorPartitionSelection::isValid(const AttributePtr& theAttribute,
715                                                        const std::list<std::string>& theArguments,
716                                                        Events_InfoMessage& theError) const
717 {
718   AttributeSelectionListPtr anAttrSelectionList =
719     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
720   if(!anAttrSelectionList.get()) {
721     theError = "Error: This validator can only work with selection list in \"Partition\" feature.";
722     return false;
723   }
724
725   for(int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
726     AttributeSelectionPtr aSelectAttr = anAttrSelectionList->value(anIndex);
727
728     //GeomValidators_BodyShapes aBodyValidator;
729     //if(aBodyValidator.isValid(aSelectAttr, theArguments, theError)) {
730     //  continue;
731     //}
732
733     GeomValidators_FeatureKind aFeatureKindValidator;
734     if(aFeatureKindValidator.isValid(aSelectAttr, theArguments, theError)) {
735       continue;
736     }
737
738     ResultPtr aContext = aSelectAttr->context();
739     ResultConstructionPtr aResultConstruction =
740       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
741     if(aResultConstruction.get()) {
742       theError = "Error: Only body shapes and construction planes are allowed for selection.";
743       return false;
744     }
745
746     ResultBodyPtr aResultBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(aContext);
747     if(aResultBody.get()) {
748       continue;
749     }
750     FeaturePtr aResultFeature = aSelectAttr->contextFeature();
751     if(aResultFeature.get()) {
752       bool aOkRes = false;
753       std::list<ResultPtr>::const_iterator aFRes = aResultFeature->results().cbegin();
754       for(; aFRes != aResultFeature->results().cend() && !aOkRes; aFRes++) {
755         ResultBodyPtr aBody = std::dynamic_pointer_cast<ModelAPI_ResultBody>(*aFRes);
756         if (aBody.get() && !aBody->isDisabled())
757           aOkRes = true;
758       }
759       if (aOkRes)
760         continue;
761     }
762
763     theError = "Error: Only body shapes and construction planes are allowed for selection.";
764     return false;
765   }
766
767   theError = "";
768   return true;
769 }
770
771 //==================================================================================================
772 bool FeaturesPlugin_ValidatorRemoveSubShapesSelection::isValid(const AttributePtr& theAttribute,
773                                                      const std::list<std::string>& theArguments,
774                                                      Events_InfoMessage& theError) const
775 {
776   AttributeSelectionListPtr aSubShapesAttrList =
777     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
778   if(!aSubShapesAttrList.get()) {
779     theError =
780       "Error: This validator can only work with selection list in \"Remove Sub-Shapes\" feature.";
781     return false;
782   }
783
784   static const std::string aBaseShapeID = "base_shape";
785   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
786   AttributeSelectionPtr aShapeAttrSelection = aFeature->selection(aBaseShapeID);
787
788   if(!aShapeAttrSelection.get()) {
789     theError = "Error: Could not get \"%1\" attribute.";
790     theError.arg(aBaseShapeID);
791     return false;
792   }
793
794   GeomShapePtr aBaseShape = aShapeAttrSelection->value();
795   ResultPtr aContext = aShapeAttrSelection->context();
796   if(!aContext.get()) {
797     theError = "Error: Empty context.";
798     return false;
799   }
800   if(!aBaseShape.get()) {
801     aBaseShape = aContext->shape();
802   }
803   if(!aBaseShape.get()) {
804     theError = "Error: Empty base shape.";
805     return false;
806   }
807
808   std::list<GeomShapePtr> aSubShapes = GeomAlgoAPI_ShapeTools::getLowLevelSubShapes(aBaseShape);
809   for(int anIndex = 0; anIndex < aSubShapesAttrList->size(); ++anIndex) {
810     bool isSameFound = false;
811     AttributeSelectionPtr anAttrSelectionInList = aSubShapesAttrList->value(anIndex);
812     GeomShapePtr aShapeToAdd = anAttrSelectionInList->value();
813     for (ListOfShape::const_iterator anIt = aSubShapes.cbegin(); anIt != aSubShapes.cend(); ++anIt) {
814       if ((*anIt)->isEqual(aShapeToAdd)) {
815         isSameFound = true;
816         break;
817       }
818     }
819     if (!isSameFound) {
820       theError = "Error: Only sub-shapes of selected shape is allowed for selection.";
821       return false;
822     }
823   }
824
825   return true;
826 }
827
828 //==================================================================================================
829 bool FeaturesPlugin_ValidatorRemoveSubShapesResult::isValid(
830   const std::shared_ptr<ModelAPI_Feature>& theFeature,
831   const std::list<std::string>& theArguments,
832   Events_InfoMessage& theError) const
833 {
834   static const std::string aBaseShapeID = "base_shape";
835   static const std::string aSubShapesID = "subshapes_to_keep";
836
837   if(theFeature->getKind() != "Remove_SubShapes") {
838     theError = "Error: Feature \"%1\" does not supported by this validator.";
839     theError.arg(theFeature->getKind());
840     return false;
841   }
842
843   AttributeSelectionPtr aShapeAttrSelection = theFeature->selection(aBaseShapeID);
844   if(!aShapeAttrSelection.get()) {
845     theError = "Error: Could not get \"%1\" attribute.";
846     theError.arg(aBaseShapeID);
847     return false;
848   }
849
850   AttributeSelectionListPtr aSubShapesAttrList = theFeature->selectionList(aSubShapesID);
851   if(!aSubShapesAttrList.get()) {
852     theError = "Error: Could not get \"%1\" attribute.";
853     theError.arg(aSubShapesID);
854     return false;
855   }
856
857   // Copy base shape.
858   GeomShapePtr aBaseShape = aShapeAttrSelection->value();
859   if(!aBaseShape.get()) {
860     theError = "Error: Base shape is empty.";
861     return false;
862   }
863   GeomShapePtr aResultShape = aBaseShape->emptyCopied();
864
865   if (aSubShapesAttrList->size() == 0) {
866     theError = "Error: Resulting shape is not valid.";
867     return false;
868   }
869
870   // Copy sub-shapes from list to new shape.
871   for(int anIndex = 0; anIndex < aSubShapesAttrList->size(); ++anIndex) {
872     AttributeSelectionPtr anAttrSelectionInList = aSubShapesAttrList->value(anIndex);
873     GeomShapePtr aShapeToAdd = anAttrSelectionInList->value();
874     GeomAlgoAPI_ShapeBuilder::add(aResultShape, aShapeToAdd);
875   }
876
877   // Check new shape.
878   if(!GeomAlgoAPI_ShapeTools::isShapeValid(aResultShape)) {
879     theError = "Error: Resulting shape is not valid.";
880     return false;
881   }
882
883   return true;
884 }
885
886 //==================================================================================================
887 bool FeaturesPlugin_ValidatorUnionSelection::isValid(const AttributePtr& theAttribute,
888                                                      const std::list<std::string>& theArguments,
889                                                      Events_InfoMessage& theError) const
890 {
891   AttributeSelectionListPtr aBaseObjectsAttrList =
892     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
893   if(!aBaseObjectsAttrList.get()) {
894     theError = "Error: This validator can only work with selection list in \"%1\" feature.";
895     theError.arg(FeaturesPlugin_Union::ID());
896     return false;
897   }
898
899   for(int anIndex = 0; anIndex < aBaseObjectsAttrList->size(); ++anIndex) {
900     bool isSameFound = false;
901     AttributeSelectionPtr anAttrSelectionInList = aBaseObjectsAttrList->value(anIndex);
902     ResultPtr aContext = anAttrSelectionInList->context();
903     if (!aContext.get()) {
904       theError = "Error: selection is invalid.";
905       return false;
906     }
907
908     ResultConstructionPtr aConstruction =
909       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
910     if(aConstruction.get()) {
911       theError = "Error: Result construction not allowed for selection.";
912       return false;
913     }
914
915     GeomShapePtr aShape = anAttrSelectionInList->value();
916     GeomShapePtr aContextShape = aContext->shape();
917     if (aShape.get() && aContextShape.get() && !aContextShape->isEqual(aShape)) {
918       theError = "Error: Local selection not allowed.";
919       return false;
920     }
921
922     ResultBodyPtr aResult =
923       std::dynamic_pointer_cast<ModelAPI_ResultBody>(aContext);
924     if(!aResult.get()) {
925       continue;
926     }
927
928     if(aResult->numberOfSubs() > 0) {
929       theError = "Error: Whole compsolids not allowed for selection.";
930       return false;
931     }
932   }
933
934   return true;
935 }
936
937 //==================================================================================================
938 bool FeaturesPlugin_ValidatorUnionArguments::isValid(
939   const std::shared_ptr<ModelAPI_Feature>& theFeature,
940   const std::list<std::string>& theArguments,
941   Events_InfoMessage& theError) const
942 {
943   // Check feature kind.
944   if(theFeature->getKind() != FeaturesPlugin_Union::ID()) {
945     theError = "Error: This validator supports only \"%1\" feature.";
946     theError.arg(FeaturesPlugin_Union::ID());
947     return false;
948   }
949
950   // Get base objects attribute list.
951   AttributeSelectionListPtr aBaseObejctsAttrList =
952     theFeature->selectionList(FeaturesPlugin_Union::BASE_OBJECTS_ID());
953   if(!aBaseObejctsAttrList.get()) {
954     theError = "Error: Could not get \"%1\" attribute.";
955     theError.arg(FeaturesPlugin_Union::BASE_OBJECTS_ID());
956     return false;
957   }
958
959   // Get all shapes.
960   GeomAPI_Shape::ShapeType aType = GeomAPI_Shape::COMPSOLID;
961   ListOfShape aBaseShapesList;
962   for(int anIndex = 0; anIndex < aBaseObejctsAttrList->size(); ++anIndex) {
963     AttributeSelectionPtr anAttrSelectionInList = aBaseObejctsAttrList->value(anIndex);
964     GeomShapePtr aShape = anAttrSelectionInList->value();
965     if (!aShape.get()) {
966       continue;
967     }
968     aBaseShapesList.push_back(aShape);
969     aType = aShape->shapeType() == GeomAPI_Shape::FACE ? GeomAPI_Shape::SHELL :
970                                                          GeomAPI_Shape::COMPSOLID;
971   }
972
973   // Make compound and find connected.
974   GeomShapePtr aCompound = GeomAlgoAPI_CompoundBuilder::compound(aBaseShapesList);
975   ListOfShape aCombined, aFree;
976   GeomAlgoAPI_ShapeTools::combineShapes(
977     aCompound,
978     aType,
979     aCombined,
980     aFree);
981
982   if(aFree.size() > 0 || aCombined.size() > 1) {
983     theError = "Error: Not all shapes have shared topology.";
984     return false;
985   }
986
987   return true;
988 }
989
990 bool FeaturesPlugin_ValidatorConcealedResult::isValid(const AttributePtr& theAttribute,
991                                             const std::list<std::string>& theArguments,
992                                             Events_InfoMessage& theError) const
993 {
994   if (theAttribute->attributeType() != ModelAPI_AttributeReference::typeId()) {
995     theError = "Error: The attribute with the %1 type is not processed";
996     theError.arg(theAttribute->attributeType());
997     return false;
998   }
999
1000   AttributeReferencePtr aRefAttribute = std::dynamic_pointer_cast<ModelAPI_AttributeReference>
1001                                                                                (theAttribute);
1002   ObjectPtr aRefObject = aRefAttribute->value();
1003   if (!aRefObject.get()) {
1004     theError = "Error: Empty feature.";
1005     return false;
1006   }
1007
1008   FeaturePtr aRefFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(aRefObject);
1009   if (!aRefFeature.get()) {
1010     theError = "Error: Empty feature.";
1011     return false;
1012   }
1013   std::list<std::shared_ptr<ModelAPI_Result> > aResults;
1014   ModelAPI_Tools::getConcealedResults(aRefFeature, aResults);
1015
1016   size_t aConcealedResults = aResults.size();
1017   if (!aConcealedResults && !theArguments.empty()) {
1018     // find if these results are touched by the feature in another attribute
1019     std::list<std::string>::const_iterator anIt = theArguments.begin();
1020     std::string aRecoveredList = *anIt;
1021     if (!aRecoveredList.empty()) {
1022       std::shared_ptr<ModelAPI_AttributeRefList> aParameterList =
1023                                  theAttribute->owner()->data()->reflist(aRecoveredList);
1024       if (aParameterList.get())
1025         aConcealedResults = aParameterList->size();
1026     }
1027   }
1028
1029   if (aConcealedResults == 0)
1030     theError = "Error: No concealed results.";
1031
1032   return theError.empty();
1033 }
1034
1035 bool FeaturesPlugin_ValidatorCircular::isValid(const AttributePtr& theAttribute,
1036                                                const std::list<std::string>& theArguments,
1037                                                Events_InfoMessage& theError) const
1038 {
1039   static std::list<std::string> aEdgeArg(1, "circle");
1040   static std::list<std::string> aFaceArg(1, "cylinder");
1041
1042   Events_InfoMessage aError;
1043   bool isValid = GeomValidators_ShapeType().isValid(theAttribute, aEdgeArg, aError);
1044   if (!isValid) {
1045     isValid = GeomValidators_Face().isValid(theAttribute, aFaceArg, aError);
1046     if (!isValid)
1047       theError = "The shape neither circle nor cylinder";
1048   }
1049   return isValid;
1050 }
1051
1052 //=================================================================================================
1053 bool FeaturesPlugin_ValidatorBooleanArguments::isValid(
1054   const std::shared_ptr<ModelAPI_Feature>& theFeature,
1055   const std::list<std::string>& theArguments,
1056   Events_InfoMessage& theError) const
1057 {
1058   if (theArguments.size() != 2)
1059   {
1060     theError = "Wrong number of arguments (expected 2).";
1061     return false;
1062   }
1063
1064   int anObjectsNb = 0, aToolsNb = 0;
1065   //int anOperationType = 0;
1066
1067   std::list<std::string>::const_iterator anIt = theArguments.begin(), aLast = theArguments.end();
1068
1069   bool isAllInSameCompSolid = true;
1070   ResultBodyPtr aCompSolid;
1071
1072   AttributeSelectionListPtr anAttrSelList = theFeature->selectionList(*anIt);
1073   if (anAttrSelList)
1074   {
1075     anObjectsNb = anAttrSelList->size();
1076     for (int anIndex = 0; anIndex < anObjectsNb; ++anIndex)
1077     {
1078       AttributeSelectionPtr anAttr = anAttrSelList->value(anIndex);
1079       ResultPtr aContext = anAttr->context();
1080       ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1081       if (aResCompSolidPtr.get())
1082       {
1083         if (aCompSolid.get())
1084         {
1085           isAllInSameCompSolid = aCompSolid == aResCompSolidPtr;
1086         }
1087         else
1088         {
1089           aCompSolid = aResCompSolidPtr;
1090         }
1091       }
1092       else
1093       {
1094         isAllInSameCompSolid = false;
1095         break;
1096       }
1097     }
1098   }
1099   anIt++;
1100
1101
1102   anAttrSelList = theFeature->selectionList(*anIt);
1103   if (anAttrSelList)
1104   {
1105     aToolsNb = anAttrSelList->size();
1106     if (isAllInSameCompSolid)
1107     {
1108       for (int anIndex = 0; anIndex < aToolsNb; ++anIndex)
1109       {
1110         AttributeSelectionPtr anAttr = anAttrSelList->value(anIndex);
1111         ResultPtr aContext = anAttr->context();
1112         ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1113         if (aResCompSolidPtr.get())
1114         {
1115           if (aCompSolid.get())
1116           {
1117             isAllInSameCompSolid = aCompSolid == aResCompSolidPtr;
1118           }
1119           else
1120           {
1121             aCompSolid = aResCompSolidPtr;
1122           }
1123         }
1124         else
1125         {
1126           isAllInSameCompSolid = false;
1127           break;
1128         }
1129       }
1130     }
1131   }
1132   anIt++;
1133
1134   std::shared_ptr<FeaturesPlugin_Boolean> aFeature =
1135     std::dynamic_pointer_cast<FeaturesPlugin_Boolean>(theFeature);
1136   FeaturesPlugin_Boolean::OperationType anOperationType = aFeature->operationType();
1137
1138   if (anOperationType == FeaturesPlugin_Boolean::BOOL_FUSE)
1139   {
1140     // Fuse operation
1141     if (anObjectsNb + aToolsNb < 2)
1142     {
1143       theError = "Not enough arguments for Fuse operation.";
1144       return false;
1145     }
1146     else if (isAllInSameCompSolid)
1147     {
1148       theError = "Operations only between sub-shapes of the same shape not allowed.";
1149       return false;
1150     }
1151   }
1152   else
1153   {
1154     if (anObjectsNb < 1)
1155     {
1156       theError = "Objects not selected.";
1157       return false;
1158     }
1159     if (aToolsNb < 1)
1160     {
1161       theError = "Tools not selected.";
1162       return false;
1163     }
1164     if (isAllInSameCompSolid)
1165     {
1166       theError = "Operations only between sub-shapes of the same shape not allowed.";
1167       return false;
1168     }
1169   }
1170
1171   return true;
1172 }
1173
1174 //=================================================================================================
1175 bool FeaturesPlugin_ValidatorBooleanArguments::isNotObligatory(std::string theFeature,
1176                                                                std::string theAttribute)
1177 {
1178   if (theAttribute == "main_objects" || theAttribute == "tool_objects")
1179   {
1180     return true;
1181   }
1182
1183   return false;
1184 }
1185
1186 //==================================================================================================
1187 bool FeaturesPlugin_ValidatorBooleanSmashSelection::isValid(
1188   const AttributePtr& theAttribute,
1189   const std::list<std::string>& theArguments,
1190   Events_InfoMessage& theError) const
1191 {
1192   std::shared_ptr<FeaturesPlugin_BooleanSmash> aFeature =
1193     std::dynamic_pointer_cast<FeaturesPlugin_BooleanSmash>(theAttribute->owner());
1194
1195   AttributeSelectionListPtr anAttrSelectionList =
1196     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
1197   if (!aFeature.get() || !anAttrSelectionList.get()) {
1198     theError =
1199       "Error: Validator used in wrong feature or attribute";
1200     return false;
1201   }
1202
1203   AttributeSelectionListPtr anOtherAttrSelectionList;
1204   if (theAttribute->id() == FeaturesPlugin_BooleanSmash::OBJECT_LIST_ID()) {
1205     anOtherAttrSelectionList =
1206       aFeature->selectionList(FeaturesPlugin_BooleanSmash::TOOL_LIST_ID());
1207   } else {
1208     anOtherAttrSelectionList =
1209       aFeature->selectionList(FeaturesPlugin_BooleanSmash::OBJECT_LIST_ID());
1210   }
1211
1212   GeomAPI_Shape::ShapeType aSelectedShapesType = GeomAPI_Shape::SHAPE;
1213   GeomAPI_DataMapOfShapeShape aSelectedCompSolidsInOtherList;
1214   GeomPlanePtr aFacesPln;
1215
1216   for (int anIndex = 0; anIndex < anOtherAttrSelectionList->size(); ++anIndex) {
1217     AttributeSelectionPtr anAttrSelection = anOtherAttrSelectionList->value(anIndex);
1218
1219     if (anAttrSelection->contextFeature().get()) {
1220       theError = "Error: Features not allowed for selection.";
1221       return false;
1222     }
1223
1224     ResultPtr aContext = anAttrSelection->context();
1225     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1226     GeomShapePtr aContextShape = aContext->shape();
1227     if (!aShape.get()) {
1228       aShape = aContextShape;
1229     }
1230
1231     if (aShape->isSolid() || aShape->isCompSolid()) {
1232       aSelectedShapesType = GeomAPI_Shape::SOLID;
1233       ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1234       if (aResCompSolidPtr.get()) {
1235         GeomShapePtr aCompSolidShape = aResCompSolidPtr->shape();
1236         aSelectedCompSolidsInOtherList.bind(aCompSolidShape, aCompSolidShape);
1237       }
1238     } else {
1239       aSelectedShapesType = GeomAPI_Shape::FACE;
1240       GeomAPI_Face aFace(aShape);
1241       aFacesPln = aFace.getPlane();
1242       break;
1243     }
1244   }
1245
1246   for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
1247     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
1248     if (!anAttrSelection.get()) {
1249       theError = "Error: Empty attribute selection.";
1250       return false;
1251     }
1252
1253     if (anAttrSelection->contextFeature().get()) {
1254       theError = "Error: Features not allowed for selection.";
1255       return false;
1256     }
1257
1258     ResultPtr aContext = anAttrSelection->context();
1259     if(!aContext.get()) {
1260       FeaturePtr aContFeat = anAttrSelection->contextFeature();
1261       if (!aContFeat.get() || !aContFeat->results().size() ||
1262           aContFeat->firstResult()->groupName() != ModelAPI_ResultBody::group()) {
1263         theError = "Error: Empty selection context.";
1264         return false;
1265       }
1266     }
1267     ResultConstructionPtr aResultConstruction =
1268       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
1269     if (aResultConstruction.get()) {
1270       theError = "Error: Result construction not allowed for selection.";
1271       return false;
1272     }
1273     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1274     GeomShapePtr aContextShape = aContext->shape();
1275     if (!aShape.get()) {
1276       aShape = aContextShape;
1277     }
1278     if (!aShape.get()) {
1279       theError = "Error: Empty shape.";
1280       return false;
1281     }
1282     if (!aShape->isEqual(aContextShape)) {
1283       theError = "Error: Local selection not allowed.";
1284       return false;
1285     }
1286
1287     if (aSelectedShapesType == GeomAPI_Shape::SHAPE) {
1288       // Other list is empty.
1289       if (aShape->isSolid() || aShape->isCompSolid()) {
1290         aSelectedShapesType = GeomAPI_Shape::SOLID;
1291       } else {
1292         aSelectedShapesType = GeomAPI_Shape::FACE;
1293         GeomAPI_Face aFace(aShape);
1294         aFacesPln = aFace.getPlane();
1295
1296         if (!aFacesPln.get()) {
1297           theError = "Error: Only planar faces allowed.";
1298           return false;
1299         }
1300       }
1301
1302       continue;
1303     } else if (aSelectedShapesType == GeomAPI_Shape::SOLID) {
1304       if (!aShape->isSolid() && !aShape->isCompSolid()) {
1305         theError = "Error: Selected shapes should have the same type.";
1306         return false;
1307       }
1308
1309       ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1310       if (aResCompSolidPtr.get()) {
1311         GeomShapePtr aCompSolidShape = aResCompSolidPtr->shape();
1312         if (aSelectedCompSolidsInOtherList.isBound(aCompSolidShape)) {
1313           theError = "Error: Solids from compsolid in other list not allowed.";
1314           return false;
1315         }
1316       }
1317     } else {
1318       GeomAPI_Face aFace(aShape);
1319       GeomPlanePtr aPln = aFace.getPlane();
1320
1321       if (!aPln.get()) {
1322         theError = "Error: Only planar faces allowed.";
1323         return false;
1324       }
1325
1326       if (!aFacesPln->isCoincident(aPln)) {
1327         theError = "Error: Only coincident faces allowed.";
1328         return false;
1329       }
1330     }
1331   }
1332
1333   return true;
1334 }
1335
1336 //==================================================================================================
1337 bool FeaturesPlugin_IntersectionSelection::isValid(const AttributePtr& theAttribute,
1338                                                    const std::list<std::string>& theArguments,
1339                                                    Events_InfoMessage& theError) const
1340 {
1341   if (!theAttribute.get()) {
1342     theError = "Error: empty selection.";
1343     return false;
1344   }
1345   FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttribute->owner());
1346   AttributeSelectionListPtr anAttrSelectionList =
1347     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
1348   for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
1349     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
1350     if (!anAttrSelection.get()) {
1351       theError = "Error: empty attribute selection.";
1352       return false;
1353     }
1354     ResultPtr aContext = anAttrSelection->context();
1355     if(!aContext.get()) {
1356       FeaturePtr aContFeat = anAttrSelection->contextFeature();
1357       if (!aContFeat.get() || !aContFeat->results().size() ||
1358           aContFeat->firstResult()->groupName() != ModelAPI_ResultBody::group()) {
1359         theError = "Error: Empty selection context.";
1360         return false;
1361       }
1362     }
1363     FeaturePtr aFeature = anAttrSelection->contextFeature().get() ?
1364       anAttrSelection->contextFeature() : ModelAPI_Feature::feature(aContext);
1365     if (!aFeature.get()) {
1366       theError = "Error: empty feature.";
1367       return false;
1368     }
1369     std::string aFeatureKind = aFeature->getKind();
1370     if (aFeatureKind == "Sketch" ||
1371         aFeatureKind == "Plane" ||
1372         aFeatureKind == "Axis") {
1373       theError = "Error: %1 shape is not allowed for selection.";
1374       theError.arg(aFeatureKind);
1375       return false;
1376     }
1377     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1378     if (!aShape.get()) {
1379       GeomShapePtr aContextShape = aContext->shape();
1380       aShape = aContextShape;
1381     }
1382     if (!aShape.get()) {
1383       theError = "Error: empty shape.";
1384       return false;
1385     }
1386     if (aContext.get() && !aShape->isEqual(aContext->shape())) {
1387       theError = "Error: Local selection not allowed.";
1388       return false;
1389     }
1390
1391     int aShapeType = aShape->shapeType();
1392     // Allow to select edges, faces and solids.
1393     if (aShapeType != GeomAPI_Shape::EDGE &&
1394         aShapeType != GeomAPI_Shape::FACE &&
1395         aShapeType != GeomAPI_Shape::SOLID &&
1396         aShapeType != GeomAPI_Shape::COMPSOLID &&
1397         aShapeType != GeomAPI_Shape::COMPOUND) {
1398       theError = "Error: selected shape has the wrong type.";
1399       return false;
1400     }
1401   }
1402
1403   return true;
1404 }
1405
1406 //==================================================================================================
1407 bool FeaturesPlugin_ValidatorBooleanFuseSelection::isValid(
1408   const AttributePtr& theAttribute,
1409   const std::list<std::string>& theArguments,
1410   Events_InfoMessage& theError) const
1411 {
1412   AttributeSelectionListPtr anAttrSelectionList =
1413     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
1414   if (!anAttrSelectionList.get()) {
1415     theError =
1416       "Error: This validator can only work with selection list attributes in \"Boolean\" feature.";
1417     return false;
1418   }
1419
1420   for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
1421     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
1422     if (!anAttrSelection.get()) {
1423       theError = "Error: Empty attribute selection.";
1424       return false;
1425     }
1426     ResultPtr aContext = anAttrSelection->context();
1427     if(!aContext.get()) {
1428       FeaturePtr aContFeat = anAttrSelection->contextFeature();
1429       if (!aContFeat.get() || !aContFeat->results().size() ||
1430           aContFeat->firstResult()->groupName() != ModelAPI_ResultBody::group()) {
1431         theError = "Error: Empty selection context.";
1432         return false;
1433       }
1434     }
1435     ResultConstructionPtr aResultConstruction =
1436       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
1437     if (aResultConstruction.get()) {
1438       theError = "Error: Result construction not allowed for selection.";
1439       return false;
1440     }
1441     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1442     if (!aShape.get()) {
1443       GeomShapePtr aContextShape = aContext->shape();
1444       aShape = aContextShape;
1445     }
1446     if (!aShape.get()) {
1447       theError = "Error: Empty shape.";
1448       return false;
1449     }
1450     if (aContext.get() && !aShape->isEqual(aContext->shape())) {
1451       theError = "Error: Local selection not allowed.";
1452       return false;
1453     }
1454   }
1455
1456   return true;
1457 }
1458
1459 //=================================================================================================
1460 bool FeaturesPlugin_ValidatorBooleanFuseArguments::isValid(
1461   const std::shared_ptr<ModelAPI_Feature>& theFeature,
1462   const std::list<std::string>& theArguments,
1463   Events_InfoMessage& theError) const
1464 {
1465   if (theArguments.size() != 2) {
1466     theError = "Wrong number of arguments (expected 2).";
1467     return false;
1468   }
1469
1470   std::shared_ptr<FeaturesPlugin_BooleanFuse> aFeature =
1471     std::dynamic_pointer_cast<FeaturesPlugin_BooleanFuse>(theFeature);
1472
1473   int anObjectsNb = 0, aToolsNb = 0;
1474
1475   std::list<std::string>::const_iterator anIt = theArguments.begin(), aLast = theArguments.end();
1476
1477   bool isAllInSameCompSolid = true;
1478   ResultBodyPtr aCompSolid;
1479
1480   AttributeSelectionListPtr anAttrSelList = theFeature->selectionList(*anIt);
1481   if (anAttrSelList) {
1482     anObjectsNb = anAttrSelList->size();
1483     for (int anIndex = 0; anIndex < anObjectsNb; ++anIndex) {
1484       AttributeSelectionPtr anAttr = anAttrSelList->value(anIndex);
1485       ResultPtr aContext = anAttr->context();
1486       ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1487       if (aResCompSolidPtr.get()) {
1488         if (aCompSolid.get()) {
1489           isAllInSameCompSolid = aCompSolid == aResCompSolidPtr;
1490         } else {
1491           aCompSolid = aResCompSolidPtr;
1492         }
1493       } else {
1494         isAllInSameCompSolid = false;
1495         break;
1496       }
1497     }
1498   }
1499   anIt++;
1500
1501   if (aFeature->string(FeaturesPlugin_BooleanFuse::CREATION_METHOD())->value()
1502       == FeaturesPlugin_BooleanFuse::CREATION_METHOD_ADVANCED()) {
1503     anAttrSelList = theFeature->selectionList(*anIt);
1504     if (anAttrSelList) {
1505       aToolsNb = anAttrSelList->size();
1506       if (isAllInSameCompSolid) {
1507         for (int anIndex = 0; anIndex < aToolsNb; ++anIndex) {
1508           AttributeSelectionPtr anAttr = anAttrSelList->value(anIndex);
1509           ResultPtr aContext = anAttr->context();
1510           ResultBodyPtr aResCompSolidPtr = ModelAPI_Tools::bodyOwner(aContext);
1511           if (aResCompSolidPtr.get()) {
1512             if (aCompSolid.get()) {
1513               isAllInSameCompSolid = aCompSolid == aResCompSolidPtr;
1514             } else {
1515               aCompSolid = aResCompSolidPtr;
1516             }
1517           } else {
1518             isAllInSameCompSolid = false;
1519             break;
1520           }
1521         }
1522       }
1523     }
1524   }
1525
1526   anIt++;
1527
1528   if (anObjectsNb + aToolsNb < 2) {
1529     theError = "Not enough arguments for Fuse operation.";
1530     return false;
1531   } else if (isAllInSameCompSolid) {
1532     theError = "Operations only between sub-shapes of the same shape not allowed.";
1533     return false;
1534   }
1535
1536   return true;
1537 }
1538
1539 //=================================================================================================
1540 bool FeaturesPlugin_ValidatorBooleanFuseArguments::isNotObligatory(
1541   std::string theFeature,
1542   std::string theAttribute)
1543 {
1544   if (theAttribute == "main_objects" || theAttribute == "tool_objects") {
1545     return true;
1546   }
1547
1548   return false;
1549 }
1550
1551 //==================================================================================================
1552 bool FeaturesPlugin_ValidatorBooleanCommonSelection::isValid(
1553   const AttributePtr& theAttribute,
1554   const std::list<std::string>& theArguments,
1555   Events_InfoMessage& theError) const
1556 {
1557   AttributeSelectionListPtr anAttrSelectionList =
1558     std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
1559   if (!anAttrSelectionList.get()) {
1560     theError =
1561       "Error: This validator can only work with selection list attributes in \"Boolean\" feature.";
1562     return false;
1563   }
1564
1565   for (int anIndex = 0; anIndex < anAttrSelectionList->size(); ++anIndex) {
1566     AttributeSelectionPtr anAttrSelection = anAttrSelectionList->value(anIndex);
1567     if (!anAttrSelection.get()) {
1568       theError = "Error: Empty attribute selection.";
1569       return false;
1570     }
1571     ResultPtr aContext = anAttrSelection->context();
1572     if (!aContext.get()) {
1573       theError = "Error: Empty selection context.";
1574       return false;
1575     }
1576     ResultConstructionPtr aResultConstruction =
1577       std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aContext);
1578     if (aResultConstruction.get()) {
1579       if (theAttribute->id() != FeaturesPlugin_BooleanCommon::TOOL_LIST_ID()) {
1580         theError = "Error: Result construction not allowed for selection.";
1581         return false;
1582       }
1583     }
1584     std::shared_ptr<GeomAPI_Shape> aShape = anAttrSelection->value();
1585     GeomShapePtr aContextShape = aContext->shape();
1586     if (!aShape.get()) {
1587       aShape = aContextShape;
1588     }
1589     if (!aShape.get()) {
1590       theError = "Error: Empty shape.";
1591       return false;
1592     }
1593     if (!aShape->isEqual(aContextShape)) {
1594       theError = "Error: Local selection not allowed.";
1595       return false;
1596     }
1597
1598     if (aResultConstruction.get() && aShape->shapeType() != GeomAPI_Shape::FACE) {
1599       theError = "Error: Result construction should be plane.";
1600       return false;
1601     }
1602   }
1603
1604   return true;
1605 }
1606
1607 //=================================================================================================
1608 bool FeaturesPlugin_ValidatorBooleanCommonArguments::isValid(
1609   const std::shared_ptr<ModelAPI_Feature>& theFeature,
1610   const std::list<std::string>& theArguments,
1611   Events_InfoMessage& theError) const
1612 {
1613   if (theArguments.size() != 2) {
1614     theError = "Wrong number of arguments (expected 2).";
1615     return false;
1616   }
1617
1618   std::shared_ptr<FeaturesPlugin_BooleanCommon> aFeature =
1619     std::dynamic_pointer_cast<FeaturesPlugin_BooleanCommon>(theFeature);
1620
1621   int anObjectsNb = 0, aToolsNb = 0;
1622
1623   std::list<std::string>::const_iterator anIt = theArguments.begin(), aLast = theArguments.end();
1624
1625   bool isAllInSameCompSolid = true;
1626   ResultBodyPtr aCompSolid;
1627
1628   AttributeSelectionListPtr anAttrSelList = theFeature->selectionList(*anIt);
1629   if (anAttrSelList) {
1630     anObjectsNb = anAttrSelList->size();
1631   }
1632
1633   bool isSimpleMode = aFeature->string(FeaturesPlugin_BooleanCommon::CREATION_METHOD())->value()
1634                       == FeaturesPlugin_BooleanCommon::CREATION_METHOD_SIMPLE();
1635
1636   if (!isSimpleMode) {
1637     anAttrSelList = theFeature->selectionList(*anIt);
1638     if (anAttrSelList) {
1639       aToolsNb = anAttrSelList->size();
1640     }
1641   }
1642
1643   if ((isSimpleMode && anObjectsNb < 2)
1644       || (!isSimpleMode && (anObjectsNb == 0 || aToolsNb == 0))) {
1645     theError = "Not enough arguments for Fuse operation.";
1646     return false;
1647   }
1648 }
1649
1650 //=================================================================================================
1651 bool FeaturesPlugin_ValidatorBooleanCommonArguments::isNotObligatory(
1652   std::string theFeature,
1653   std::string theAttribute)
1654 {
1655   return false;
1656 }