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