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