1 // Copyright (C) 2014-20xx CEA/DEN, EDF R&D
3 // File: PartSet_WidgetSketchCreator.cpp
4 // Created: 08 June 2015
5 // Author: Vitaly SMETANNIKOV
7 #include "PartSet_WidgetSketchCreator.h"
8 #include "PartSet_Module.h"
9 #include "PartSet_WidgetSketchLabel.h"
10 #include "PartSet_PreviewPlanes.h"
12 #include <Config_Keywords.h>
14 #include <XGUI_ModuleConnector.h>
15 #include <XGUI_Workshop.h>
16 #include <XGUI_Displayer.h>
17 #include <XGUI_SelectionMgr.h>
18 #include <XGUI_OperationMgr.h>
19 #include <XGUI_PropertyPanel.h>
20 #include <XGUI_Tools.h>
21 #include <XGUI_ViewerProxy.h>
23 #include <GeomAPI_Face.h>
25 #include <ModelAPI_Session.h>
26 #include <ModelAPI_ResultBody.h>
27 #include <ModelAPI_AttributeSelection.h>
28 #include <ModelAPI_AttributeSelectionList.h>
29 #include <ModelAPI_Validator.h>
30 #include <ModelAPI_Events.h>
31 #include <ModelAPI_ResultConstruction.h>
33 #include <SketchPlugin_SketchEntity.h>
34 #include <FeaturesPlugin_CompositeBoolean.h>
36 #include <ModuleBase_Tools.h>
37 #include <ModuleBase_Operation.h>
38 #include <ModuleBase_IPropertyPanel.h>
39 #include <ModuleBase_OperationFeature.h>
40 #include <Config_WidgetAPI.h>
42 #include <Events_Loop.h>
46 //#include <QFormLayout>
47 #include <QVBoxLayout>
48 #include <QMessageBox>
49 #include <QMainWindow>
51 //#define DEBUG_UNDO_INVALID_SKETCH
53 PartSet_WidgetSketchCreator::PartSet_WidgetSketchCreator(QWidget* theParent,
54 PartSet_Module* theModule,
55 const Config_WidgetAPI* theData)
56 : ModuleBase_WidgetSelector(theParent, theModule->workshop(), theData),
57 myModule(theModule), myIsCustomAttribute(false)
59 myAttributeListID = theData->getProperty("attribute_list_id");
61 //QFormLayout* aLayout = new QFormLayout(this);
62 QVBoxLayout* aLayout = new QVBoxLayout(this);
63 ModuleBase_Tools::zeroMargins(aLayout);
65 ModuleBase_Tools::adjustMargins(aLayout);
67 QString aLabelText = QString::fromStdString(theData->widgetLabel());
68 QString aLabelIcon = QString::fromStdString(theData->widgetIcon());
70 myLabel = new QLabel(aLabelText, this);
71 myLabel->setWordWrap(true);
72 aLayout->addWidget(myLabel);
73 aLayout->addStretch(1);
74 /*if (!aLabelIcon.isEmpty())
75 myLabel->setPixmap(QPixmap(aLabelIcon));
78 QString aToolTip = QString::fromStdString(theData->widgetTooltip());
79 myTextLine = new QLineEdit(this);
80 myTextLine->setReadOnly(true);
81 myTextLine->setToolTip(aToolTip);
82 myTextLine->installEventFilter(this);
84 myLabel->setToolTip(aToolTip);
86 aLayout->addRow(myLabel, myTextLine);*/
88 std::string aTypes = theData->getProperty("shape_types");
89 myShapeTypes = QString(aTypes.c_str()).split(' ', QString::SkipEmptyParts);
91 myPreviewPlanes = new PartSet_PreviewPlanes();
94 PartSet_WidgetSketchCreator::~PartSet_WidgetSketchCreator()
98 QList<QWidget*> PartSet_WidgetSketchCreator::getControls() const
100 QList<QWidget*> aControls;
101 aControls.append(myLabel);
105 bool PartSet_WidgetSketchCreator::restoreValueCustom()
107 /*CompositeFeaturePtr aCompFeature =
108 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(myFeature);
109 if (aCompFeature->numberOfSubs() > 0) {
110 FeaturePtr aSubFeature = aCompFeature->subFeature(0);
111 myTextLine->setText(QString::fromStdString(aSubFeature->data()->name()));
116 bool PartSet_WidgetSketchCreator::storeValueCustom() const
121 AttributePtr PartSet_WidgetSketchCreator::attribute() const
123 AttributePtr anAttribute;
124 if (myIsCustomAttribute)
125 anAttribute = myFeature->attribute(myAttributeListID);
127 anAttribute = ModuleBase_WidgetSelector::attribute();
132 //********************************************************************
133 void PartSet_WidgetSketchCreator::openExtrusionTransaction()
135 SessionPtr aMgr = ModelAPI_Session::get();
136 bool aIsOp = aMgr->isOperation();
138 const static std::string aNestedOpID("Parameters modification");
139 aMgr->startOperation(aNestedOpID, true);
143 //********************************************************************
144 bool PartSet_WidgetSketchCreator::isValidSelection(const ModuleBase_ViewerPrs& theValue)
147 if (myIsCustomAttribute) {
148 // check only suiting of the value to custom attribute (myAttributeListID)
149 // do not cash of validation to avoid using states, stored for XML attribute
150 // there is an alternative is to call clearValidatedCash() in setSelection()
151 aValid = isValidSelectionForAttribute(theValue, attribute());
153 else { /// if the validated attribute is already custom
154 if (getValidState(theValue, aValid)) {
157 aValid = isValidSelectionCustom(theValue);
159 // check selection to create new sketh (XML current attribute)
160 aValid = isValidSelectionForAttribute(theValue, attribute());
162 // check selection to fill list attribute (myAttributeListID)
163 bool isCustomAttribute = myIsCustomAttribute;
164 myIsCustomAttribute = true;
165 aValid = isValidSelectionForAttribute(theValue, attribute());
166 myIsCustomAttribute = isCustomAttribute;
169 storeValidState(theValue, aValid);
173 //********************************************************************
174 bool PartSet_WidgetSketchCreator::isValidSelectionCustom(const ModuleBase_ViewerPrs& theValue)
176 return PartSet_WidgetSketchLabel::canFillSketch(theValue);
179 void PartSet_WidgetSketchCreator::activateSelectionControl()
181 setVisibleSelectionControl(true);
183 // we need to call activate here as the widget has no focus accepted controls
184 // if these controls are added here, activate will happens automatically after focusIn()
185 XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myModule->workshop());
186 XGUI_PropertyPanel* aPanel = aWorkshop->propertyPanel();
187 aPanel->activateWidget(this, false);
190 void PartSet_WidgetSketchCreator::setVisibleSelectionControl(const bool theSelectionControl)
192 // hide current widget, activate the next widget
193 XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myModule->workshop());
194 XGUI_PropertyPanel* aPanel = aWorkshop->propertyPanel();
195 const QList<ModuleBase_ModelWidget*>& aWidgets = aPanel->modelWidgets();
196 foreach(ModuleBase_ModelWidget* aWidget, aWidgets) {
197 if (theSelectionControl) { // hide other controls
199 aWidget->setVisible(false);
201 else { // hide current control
203 aWidget->setVisible(false);
205 aWidget->setVisible(true);
209 if (theSelectionControl) {
210 bool aBodyIsVisualized = myPreviewPlanes->hasVisualizedBodies(myWorkshop);
211 if (!aBodyIsVisualized) {
212 // We have to select a plane before any operation
213 myPreviewPlanes->showPreviewPlanes(myWorkshop);
216 bool aHidePreview = myPreviewPlanes->isPreviewDisplayed();
217 myPreviewPlanes->erasePreviewPlanes(myWorkshop);
219 aWorkshop->viewer()->update();
223 QIntList PartSet_WidgetSketchCreator::getShapeTypes() const
225 QIntList aShapeTypes;
226 foreach(QString aType, myShapeTypes) {
227 aShapeTypes.append(ModuleBase_Tools::shapeType(aType));
232 void PartSet_WidgetSketchCreator::setEditingMode(bool isEditing)
234 ModuleBase_ModelWidget::setEditingMode(isEditing);
236 setVisibleSelectionControl(false);
239 bool PartSet_WidgetSketchCreator::isSelectionMode() const
241 AttributeSelectionListPtr anAttrList = myFeature->data()->selectionList(myAttributeListID);
242 bool aHasValueInList = anAttrList.get() && anAttrList->size() > 0;
244 return !aHasValueInList;
247 bool PartSet_WidgetSketchCreator::setSelection(QList<ModuleBase_ViewerPrs>& theValues,
248 const bool theToValidate)
251 if (!startSketchOperation(theValues)) {
252 myIsCustomAttribute = true;
253 QList<ModuleBase_ViewerPrs>::const_iterator anIt = theValues.begin(), aLast = theValues.end();
254 bool aProcessed = false;
255 for (; anIt != aLast; anIt++) {
256 ModuleBase_ViewerPrs aValue = *anIt;
257 if (!theToValidate || isValidInFilters(aValue))
258 aProcessed = setSelectionCustom(aValue) || aProcessed;
260 myIsCustomAttribute = false;
263 emit valuesChanged();
264 updateObject(myFeature);
265 setVisibleSelectionControl(false);
266 // manually deactivation because the widget was not activated as has no focus acceptin controls
268 emit focusOutWidget(this);
274 //********************************************************************
275 void PartSet_WidgetSketchCreator::onSelectionChanged()
277 QList<ModuleBase_ViewerPrs> aSelected = getFilteredSelected();
278 bool isDone = setSelection(aSelected, true/*false*/);
281 //********************************************************************
282 void PartSet_WidgetSketchCreator::updateOnSelectionChanged(const bool theDone)
286 bool PartSet_WidgetSketchCreator::startSketchOperation(const QList<ModuleBase_ViewerPrs>& theValues)
288 bool aSketchStarted = false;
290 if (theValues.size() != 1)
291 return aSketchStarted;
293 ModuleBase_ViewerPrs aValue = theValues.front();
294 if (!PartSet_WidgetSketchLabel::canFillSketch(aValue))
295 return aSketchStarted;
297 aSketchStarted = true;
299 // manually deactivation because the widget was not activated as has no focus acceptin controls
301 bool aHidePreview = myPreviewPlanes->isPreviewDisplayed();
302 myPreviewPlanes->erasePreviewPlanes(myWorkshop);
304 // Launch Sketch operation
305 CompositeFeaturePtr aCompFeature =
306 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(myFeature);
308 /// add sketch feature without current feature change.
309 /// it is important to do not change the current feature in order to
310 /// after sketch edition, the extrusion cut feature becomes current
311 SessionPtr aMgr = ModelAPI_Session::get();
312 DocumentPtr aDoc = aMgr->activeDocument();
313 FeaturePtr aPreviousCurrentFeature = aDoc->currentFeature(false);
314 FeaturePtr aSketch = aCompFeature->addFeature("Sketch");
316 PartSet_WidgetSketchLabel::fillSketchPlaneBySelection(aSketch, aValue);
318 aDoc->setCurrentFeature(aPreviousCurrentFeature, false);
320 // start edit operation for the sketch
321 ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
322 (myModule->createOperation("Sketch"));
324 aFOperation->setFeature(aSketch);
325 myModule->sendOperation(aFOperation);
327 return aSketchStarted;
330 bool PartSet_WidgetSketchCreator::focusTo()
332 // this method is called only in creation mode. In Edition mode this widget is hidden
333 CompositeFeaturePtr aCompFeature =
334 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(myFeature);
335 if (isSelectionMode() && aCompFeature->numberOfSubs() == 0) {
336 activateSelectionControl();
337 openExtrusionTransaction();
341 connect(myModule, SIGNAL(resumed(ModuleBase_Operation*)), SLOT(onResumed(ModuleBase_Operation*)));
345 void PartSet_WidgetSketchCreator::deactivate()
347 ModuleBase_WidgetSelector::deactivate();
349 bool aHidePreview = myPreviewPlanes->isPreviewDisplayed();
350 myPreviewPlanes->erasePreviewPlanes(myWorkshop);
352 XGUI_Tools::workshop(myWorkshop)->viewer()->update();
356 void PartSet_WidgetSketchCreator::onResumed(ModuleBase_Operation* theOp)
358 SessionPtr aMgr = ModelAPI_Session::get();
359 bool aIsOp = aMgr->isOperation();
361 // in current implementation, all transactions are closed when resume happens
362 // so, this is a wrong case, which is not checked.
363 // To provide it, make correction in later rows about abort/undo transactions
366 // Set visible only selection control
367 setVisibleSelectionControl(true);
369 // Validate the created sketch. If it is valid, it is set into the composite feature selection
370 // list, otherwise it is removed
371 CompositeFeaturePtr aCompFeature =
372 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(myFeature);
373 AttributeSelectionListPtr anAttrList = myFeature->data()->selectionList(myAttributeListID);
374 if (aCompFeature->numberOfSubs() > 0) {
375 // set the sub feature to attribute selection list and check whether sketch is valid
376 SessionPtr aMgr = ModelAPI_Session::get();
377 const static std::string aNestedOpID("Set Sketch result into Selection list");
378 aMgr->startOperation(aNestedOpID, false); // false to not attach to Extrusion operation
379 setSketchObjectToList(aCompFeature, anAttrList);
380 aMgr->finishOperation();
382 if (!validateSelectionList()) {
383 #ifdef DEBUG_UNDO_INVALID_SKETCH
384 aMgr->undo(); // Extrusion modification parameters: setSketchObjectToList()
385 aMgr->undo(); /// Sketch creation
387 aMgr->startOperation("Delete invalid Sketch feature", false);
389 // delete invalid sketch
390 CompositeFeaturePtr aSketchFeature =
391 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aCompFeature->subFeature(0));
392 QObjectPtrList anObjects;
393 anObjects.append(aSketchFeature);
395 XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myModule->workshop());
396 aWorkshop->deleteFeatures(anObjects, std::set<FeaturePtr>());
398 aMgr->finishOperation();
402 openExtrusionTransaction();
404 if (aCompFeature->numberOfSubs() > 0) {
405 // check if the created sketch is valid. If it is invalid, it will be deleted with warning else
406 /// the attribute selection list will be filled by result of this sketch.
407 setVisibleSelectionControl(false);
409 // Update value in attribute selection list
410 XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myModule->workshop());
411 XGUI_PropertyPanel* aPanel = aWorkshop->propertyPanel();
412 const QList<ModuleBase_ModelWidget*>& aWidgets = aPanel->modelWidgets();
413 foreach(ModuleBase_ModelWidget* aWidget, aWidgets) {
414 if (aWidget->attributeID() == myAttributeListID)
415 aWidget->restoreValue();
418 // Hide sketcher result
419 CompositeFeaturePtr aSketchFeature =
420 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aCompFeature->subFeature(0));
421 std::list<ResultPtr> aResults = aSketchFeature->results();
422 std::list<ResultPtr>::const_iterator aIt;
423 for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
424 (*aIt)->setDisplayed(false);
426 aSketchFeature->setDisplayed(false);
427 static Events_Loop* aLoop = Events_Loop::loop();
428 aLoop->flush(aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY));
430 // Add Selected body were created the sketcher to list of selected objects
431 std::string anObjectsAttribute = FeaturesPlugin_CompositeBoolean::OBJECTS_ID();
432 AttributeSelectionListPtr aSelList = aCompFeature->data()->selectionList(anObjectsAttribute);
433 if (aSelList.get()) {
434 DataPtr aData = aSketchFeature->data();
435 AttributeSelectionPtr aSelAttr = std::dynamic_pointer_cast<ModelAPI_AttributeSelection>
436 (aData->attribute(SketchPlugin_SketchEntity::EXTERNAL_ID()));
437 ResultPtr aRes = aSelAttr.get() ? aSelAttr->context() : ResultPtr();
439 SessionPtr aMgr = ModelAPI_Session::get();
440 ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
441 AttributePtr anAttribute = myFeature->attribute(anObjectsAttribute);
442 std::string aValidatorID, anError;
443 aSelList->append(aRes, GeomShapePtr());
444 if (aFactory->validate(anAttribute, aValidatorID, anError))
445 updateObject(aCompFeature);
454 bool PartSet_WidgetSketchCreator::validateSelectionList() const
456 AttributeSelectionListPtr anAttrList = myFeature->data()->selectionList(myAttributeListID);
458 SessionPtr aMgr = ModelAPI_Session::get();
459 ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
460 std::string aValidatorID, anError;
461 bool isValidPComposite = aFactory->validate(anAttrList, aValidatorID, anError);
462 if (!isValidPComposite) {
463 XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myModule->workshop());
464 QMessageBox::question(aWorkshop->desktop(), tr("Apply current feature"),
465 tr("Sketch is invalid and will be deleted.\nError: %1").arg(anError.c_str()),
468 return isValidPComposite;
471 void PartSet_WidgetSketchCreator::setSketchObjectToList(const CompositeFeaturePtr& theCompositeFeature,
472 const AttributePtr& theAttribute)
474 if (!theCompositeFeature.get() || theCompositeFeature->numberOfSubs() != 1)
477 AttributeSelectionListPtr aBaseObjectsSelectionList =
478 std::dynamic_pointer_cast<ModelAPI_AttributeSelectionList>(theAttribute);
479 if(!aBaseObjectsSelectionList.get() || aBaseObjectsSelectionList->isInitialized()) {
483 FeaturePtr aSketchFeature = theCompositeFeature->subFeature(0);
484 if(!aSketchFeature.get() || aSketchFeature->results().empty()) {
488 ResultPtr aSketchRes = aSketchFeature->results().front();
489 ResultConstructionPtr aConstruction = std::dynamic_pointer_cast<ModelAPI_ResultConstruction>(aSketchRes);
490 if(!aConstruction.get()) {
494 if(aBaseObjectsSelectionList->size() == 0) {
495 aBaseObjectsSelectionList->append(aSketchRes, GeomShapePtr());