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>
32 #include <SketchPlugin_SketchEntity.h>
33 #include <FeaturesPlugin_CompositeBoolean.h>
35 #include <ModuleBase_Tools.h>
36 #include <ModuleBase_Operation.h>
37 #include <ModuleBase_IPropertyPanel.h>
38 #include <ModuleBase_OperationFeature.h>
39 #include <Config_WidgetAPI.h>
41 #include <Events_Loop.h>
45 //#include <QFormLayout>
46 #include <QVBoxLayout>
47 #include <QMessageBox>
48 #include <QMainWindow>
50 PartSet_WidgetSketchCreator::PartSet_WidgetSketchCreator(QWidget* theParent,
51 PartSet_Module* theModule,
52 const Config_WidgetAPI* theData)
53 : ModuleBase_WidgetSelector(theParent, theModule->workshop(), theData),
54 myModule(theModule), myIsCustomAttribute(false)
56 myAttributeListID = theData->getProperty("attribute_list_id");
58 //QFormLayout* aLayout = new QFormLayout(this);
59 QVBoxLayout* aLayout = new QVBoxLayout(this);
60 ModuleBase_Tools::zeroMargins(aLayout);
62 ModuleBase_Tools::adjustMargins(aLayout);
64 QString aLabelText = QString::fromStdString(theData->widgetLabel());
65 QString aLabelIcon = QString::fromStdString(theData->widgetIcon());
67 myLabel = new QLabel(aLabelText, this);
68 myLabel->setWordWrap(true);
69 aLayout->addWidget(myLabel);
70 /*if (!aLabelIcon.isEmpty())
71 myLabel->setPixmap(QPixmap(aLabelIcon));
74 QString aToolTip = QString::fromStdString(theData->widgetTooltip());
75 myTextLine = new QLineEdit(this);
76 myTextLine->setReadOnly(true);
77 myTextLine->setToolTip(aToolTip);
78 myTextLine->installEventFilter(this);
80 myLabel->setToolTip(aToolTip);
82 aLayout->addRow(myLabel, myTextLine);*/
84 std::string aTypes = theData->getProperty("shape_types");
85 myShapeTypes = QString(aTypes.c_str()).split(' ', QString::SkipEmptyParts);
87 myPreviewPlanes = new PartSet_PreviewPlanes();
90 PartSet_WidgetSketchCreator::~PartSet_WidgetSketchCreator()
94 QList<QWidget*> PartSet_WidgetSketchCreator::getControls() const
96 QList<QWidget*> aControls;
97 aControls.append(myLabel);
101 bool PartSet_WidgetSketchCreator::restoreValueCustom()
103 /*CompositeFeaturePtr aCompFeature =
104 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(myFeature);
105 if (aCompFeature->numberOfSubs() > 0) {
106 FeaturePtr aSubFeature = aCompFeature->subFeature(0);
107 myTextLine->setText(QString::fromStdString(aSubFeature->data()->name()));
112 bool PartSet_WidgetSketchCreator::storeValueCustom() const
117 AttributePtr PartSet_WidgetSketchCreator::attribute() const
119 AttributePtr anAttribute;
120 if (myIsCustomAttribute)
121 anAttribute = myFeature->attribute(myAttributeListID);
123 anAttribute = ModuleBase_WidgetSelector::attribute();
128 //********************************************************************
129 bool PartSet_WidgetSketchCreator::isValidSelection(const ModuleBase_ViewerPrs& theValue)
132 if (myIsCustomAttribute) {
133 // check only suiting of the value to custom attribute (myAttributeListID)
134 // do not cash of validation to avoid using states, stored for XML attribute
135 // there is an alternative is to call clearValidatedCash() in setSelection()
136 aValid = isValidSelectionForAttribute(theValue, attribute());
138 else { /// if the validated attribute is already custom
139 if (getValidState(theValue, aValid)) {
142 aValid = isValidSelectionCustom(theValue);
144 // check selection to create new sketh (XML current attribute)
145 aValid = isValidSelectionForAttribute(theValue, attribute());
147 // check selection to fill list attribute (myAttributeListID)
148 bool isCustomAttribute = myIsCustomAttribute;
149 myIsCustomAttribute = true;
150 aValid = isValidSelectionForAttribute(theValue, attribute());
151 myIsCustomAttribute = isCustomAttribute;
154 storeValidState(theValue, aValid);
158 //********************************************************************
159 bool PartSet_WidgetSketchCreator::isValidSelectionCustom(const ModuleBase_ViewerPrs& theValue)
161 return PartSet_WidgetSketchLabel::canFillSketch(theValue);
164 void PartSet_WidgetSketchCreator::activateSelectionControl()
166 setVisibleSelectionControl(true);
168 // we need to call activate here as the widget has no focus accepted controls
169 // if these controls are added here, activate will happens automatically after focusIn()
170 XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myModule->workshop());
171 XGUI_PropertyPanel* aPanel = aWorkshop->propertyPanel();
172 aPanel->activateWidget(this, false);
175 void PartSet_WidgetSketchCreator::setVisibleSelectionControl(const bool theSelectionControl)
177 // hide current widget, activate the next widget
178 XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myModule->workshop());
179 XGUI_PropertyPanel* aPanel = aWorkshop->propertyPanel();
180 const QList<ModuleBase_ModelWidget*>& aWidgets = aPanel->modelWidgets();
181 foreach(ModuleBase_ModelWidget* aWidget, aWidgets) {
182 if (theSelectionControl) { // hide other controls
184 aWidget->setVisible(false);
186 else { // hide current control
188 aWidget->setVisible(false);
190 aWidget->setVisible(true);
194 if (theSelectionControl) {
195 bool aBodyIsVisualized = myPreviewPlanes->hasVisualizedBodies(myWorkshop);
196 if (!aBodyIsVisualized) {
197 // We have to select a plane before any operation
198 myPreviewPlanes->showPreviewPlanes(myWorkshop);
201 bool aHidePreview = myPreviewPlanes->isPreviewDisplayed();
202 myPreviewPlanes->erasePreviewPlanes(myWorkshop);
204 aWorkshop->viewer()->update();
208 QIntList PartSet_WidgetSketchCreator::getShapeTypes() const
210 QIntList aShapeTypes;
211 foreach(QString aType, myShapeTypes) {
212 aShapeTypes.append(ModuleBase_Tools::shapeType(aType));
217 void PartSet_WidgetSketchCreator::setEditingMode(bool isEditing)
219 ModuleBase_ModelWidget::setEditingMode(isEditing);
221 setVisibleSelectionControl(false);
224 bool PartSet_WidgetSketchCreator::canCommitCurrentSketch(ModuleBase_IWorkshop* theWorkshop)
226 bool aCanCommit = true;
227 ModuleBase_Operation* anOperation = theWorkshop->currentOperation();
228 XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(theWorkshop);
229 XGUI_OperationMgr* anOpMgr = aWorkshop->operationMgr();
230 // check if the operation is nested
231 if (anOperation && anOpMgr->operationsCount() > 1) {
232 ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(anOperation);
233 FeaturePtr aCurrentFeature = aFOperation ? aFOperation->feature() : FeaturePtr();
235 ModuleBase_Operation* aPOperation = anOpMgr->previousOperation(anOperation);
236 ModuleBase_OperationFeature* aFPOperation = dynamic_cast<ModuleBase_OperationFeature*>(aPOperation);
237 FeaturePtr aParentFeature = aFPOperation ? aFPOperation->feature() : FeaturePtr();
239 CompositeFeaturePtr aCompositeFeature =
240 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aCurrentFeature);
241 CompositeFeaturePtr aPCompositeFeature =
242 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aParentFeature);
243 // check if both features are composite: extrusion and sketch
244 if (aCompositeFeature.get() && aPCompositeFeature.get()) {
245 // selection attribute list is currently filled in execute(), so we need to call it
246 // if there is no opened transaction, it should be started and finished
247 SessionPtr aMgr = ModelAPI_Session::get();
248 bool aIsOp = aMgr->isOperation();
250 aMgr->startOperation();
251 aPCompositeFeature->execute(); // to fill attribute selection list
253 std::list<AttributePtr> aSelListAttributes = aParentFeature->data()->attributes(
254 ModelAPI_AttributeSelectionList::typeId());
255 if (aSelListAttributes.size() == 1) {
256 AttributePtr aFirstAttribute = aSelListAttributes.front();
258 SessionPtr aMgr = ModelAPI_Session::get();
259 ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
260 std::string aValidatorID, anError;
261 bool isValidPComposite = aFactory->validate(aFirstAttribute, aValidatorID, anError);
262 if (!isValidPComposite) {
263 int anAnswer = QMessageBox::question(
264 aWorkshop->desktop(), tr("Apply current feature"),
265 tr("The current feature can not be used as an argument of the parent feature.\n\
266 After apply it will be deleted. Would you like to continue?"),
267 QMessageBox::Ok | QMessageBox::Cancel, QMessageBox::Cancel);
268 if (anAnswer == QMessageBox::Ok)
276 aMgr->finishOperation();
278 aMgr->abortOperation();
285 bool PartSet_WidgetSketchCreator::isSelectionMode() const
287 AttributeSelectionListPtr anAttrList = myFeature->data()->selectionList(myAttributeListID);
288 bool aHasValueInList = anAttrList.get() && anAttrList->size() > 0;
290 return !aHasValueInList;
293 bool PartSet_WidgetSketchCreator::setSelection(QList<ModuleBase_ViewerPrs>& theValues,
294 const bool theToValidate)
297 if (!startSketchOperation(theValues)) {
298 myIsCustomAttribute = true;
299 QList<ModuleBase_ViewerPrs>::const_iterator anIt = theValues.begin(), aLast = theValues.end();
300 bool aProcessed = false;
301 for (; anIt != aLast; anIt++) {
302 ModuleBase_ViewerPrs aValue = *anIt;
303 if (!theToValidate || isValidInFilters(aValue))
304 aProcessed = setSelectionCustom(aValue) || aProcessed;
306 myIsCustomAttribute = false;
309 emit valuesChanged();
310 updateObject(myFeature);
311 setVisibleSelectionControl(false);
312 // manually deactivation because the widget was not activated as has no focus acceptin controls
314 emit focusOutWidget(this);
320 //********************************************************************
321 void PartSet_WidgetSketchCreator::onSelectionChanged()
323 QList<ModuleBase_ViewerPrs> aSelected = getFilteredSelected();
324 bool isDone = setSelection(aSelected, true/*false*/);
327 //********************************************************************
328 void PartSet_WidgetSketchCreator::updateOnSelectionChanged(const bool theDone)
332 bool PartSet_WidgetSketchCreator::startSketchOperation(const QList<ModuleBase_ViewerPrs>& theValues)
334 bool aSketchStarted = false;
336 if (theValues.size() != 1)
337 return aSketchStarted;
339 ModuleBase_ViewerPrs aValue = theValues.front();
340 if (!PartSet_WidgetSketchLabel::canFillSketch(aValue))
341 return aSketchStarted;
343 aSketchStarted = true;
345 // manually deactivation because the widget was not activated as has no focus acceptin controls
347 bool aHidePreview = myPreviewPlanes->isPreviewDisplayed();
348 myPreviewPlanes->erasePreviewPlanes(myWorkshop);
350 // Launch Sketch operation
351 CompositeFeaturePtr aCompFeature =
352 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(myFeature);
354 /// add sketch feature without current feature change.
355 /// it is important to do not change the current feature in order to
356 /// after sketch edition, the extrusion cut feature becomes current
357 SessionPtr aMgr = ModelAPI_Session::get();
358 DocumentPtr aDoc = aMgr->activeDocument();
359 FeaturePtr aPreviousCurrentFeature = aDoc->currentFeature(false);
360 FeaturePtr aSketch = aCompFeature->addFeature("Sketch");
362 PartSet_WidgetSketchLabel::fillSketchPlaneBySelection(aSketch, aValue);
364 aDoc->setCurrentFeature(aPreviousCurrentFeature, false);
366 // start edit operation for the sketch
367 ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
368 (myModule->createOperation("Sketch"));
370 aFOperation->setFeature(aSketch);
371 myModule->sendOperation(aFOperation);
373 return aSketchStarted;
376 bool PartSet_WidgetSketchCreator::focusTo()
378 if (isSelectionMode()) {
379 activateSelectionControl();
381 SessionPtr aMgr = ModelAPI_Session::get();
382 bool aIsOp = aMgr->isOperation();
384 aMgr->startOperation(myFeature->getKind());
388 //setVisibleSelectionControl(false);
390 connect(myModule, SIGNAL(resumed(ModuleBase_Operation*)), SLOT(onResumed(ModuleBase_Operation*)));
391 SessionPtr aMgr = ModelAPI_Session::get();
392 // Open transaction that is general for the previous nested one: it will be closed on nested commit
393 bool aIsOp = aMgr->isOperation();
395 const static std::string aNestedOpID("Parameters modification");
396 aMgr->startOperation(aNestedOpID, true);
403 void PartSet_WidgetSketchCreator::deactivate()
405 ModuleBase_WidgetSelector::deactivate();
407 bool aHidePreview = myPreviewPlanes->isPreviewDisplayed();
408 myPreviewPlanes->erasePreviewPlanes(myWorkshop);
410 XGUI_Tools::workshop(myWorkshop)->viewer()->update();
414 void PartSet_WidgetSketchCreator::onResumed(ModuleBase_Operation* theOp)
416 XGUI_Workshop* aWorkshop = XGUI_Tools::workshop(myModule->workshop());
418 CompositeFeaturePtr aCompFeature =
419 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(myFeature);
420 //CompositeFeaturePtr aSketchFeature =
421 // std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aCompFeature->subFeature(0));
422 if (aCompFeature->numberOfSubs() == 0) {
423 // do nothing, selection control should be hidden
424 setVisibleSelectionControl(false);
426 // check if the created sketch is invalid. Validate attribute selection list
427 // Shetch should be deleted if the attribute is invalid.
428 AttributeSelectionListPtr anAttrList = myFeature->data()->selectionList(myAttributeListID);
430 SessionPtr aMgr = ModelAPI_Session::get();
431 ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
432 std::string aValidatorID, anError;
433 bool isValidPComposite = aFactory->validate(anAttrList, aValidatorID, anError);
434 /// if the sketch is not appropriate fro extrusion, it should be deleted and
435 /// the selection control should be activated again
436 if (!isValidPComposite) {
437 CompositeFeaturePtr aSketchFeature =
438 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aCompFeature->subFeature(0));
440 QObjectPtrList anObjects;
441 anObjects.append(aSketchFeature);
442 std::set<FeaturePtr> anIgnoredFeatures;
443 aWorkshop->deleteFeatures(anObjects, anIgnoredFeatures);
445 // do nothing, selection control should be shown
446 activateSelectionControl();
449 setVisibleSelectionControl(false);
450 // Update value in attribute selection list
451 XGUI_PropertyPanel* aPanel = aWorkshop->propertyPanel();
452 const QList<ModuleBase_ModelWidget*>& aWidgets = aPanel->modelWidgets();
453 foreach(ModuleBase_ModelWidget* aWidget, aWidgets) {
454 if (aWidget->attributeID() == myAttributeListID)
455 aWidget->restoreValue();
458 // Hide sketcher result
459 CompositeFeaturePtr aSketchFeature =
460 std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aCompFeature->subFeature(0));
461 std::list<ResultPtr> aResults = aSketchFeature->results();
462 std::list<ResultPtr>::const_iterator aIt;
463 for (aIt = aResults.begin(); aIt != aResults.end(); ++aIt) {
464 (*aIt)->setDisplayed(false);
466 aSketchFeature->setDisplayed(false);
467 static Events_Loop* aLoop = Events_Loop::loop();
468 aLoop->flush(aLoop->eventByName(EVENT_OBJECT_TO_REDISPLAY));
470 // Add Selected body were created the sketcher to list of selected objects
471 std::string anObjectsAttribute = FeaturesPlugin_CompositeBoolean::OBJECTS_ID();
472 AttributeSelectionListPtr aSelList = aCompFeature->data()->selectionList(anObjectsAttribute);
473 if (aSelList.get()) {
474 DataPtr aData = aSketchFeature->data();
475 AttributeSelectionPtr aSelAttr = std::dynamic_pointer_cast<ModelAPI_AttributeSelection>
476 (aData->attribute(SketchPlugin_SketchEntity::EXTERNAL_ID()));
477 ResultPtr aRes = aSelAttr.get() ? aSelAttr->context() : ResultPtr();
479 SessionPtr aMgr = ModelAPI_Session::get();
480 ModelAPI_ValidatorsFactory* aFactory = aMgr->validators();
481 AttributePtr anAttribute = myFeature->attribute(anObjectsAttribute);
482 std::string aValidatorID, anError;
483 aSelList->append(aRes, GeomShapePtr());
484 if (aFactory->validate(anAttribute, aValidatorID, anError))
485 updateObject(aCompFeature);