void Model_Data::removeBackReference(FeaturePtr theFeature, std::string theAttrID)
{
AttributePtr anAttribute = theFeature->data()->attribute(theAttrID);
- if (myRefsToMe.find(anAttribute) == myRefsToMe.end())
+ removeBackReference(anAttribute);
+}
+
+void Model_Data::removeBackReference(AttributePtr theAttr)
+{
+ if (myRefsToMe.find(theAttr) == myRefsToMe.end())
return;
- myRefsToMe.erase(anAttribute);
+ myRefsToMe.erase(theAttr);
// remove concealment immideately: on deselection it must be posible to reselect in GUI the same
- if (ModelAPI_Session::get()->validators()->isConcealed(theFeature->getKind(), theAttrID)) {
+ FeaturePtr aFeatureOwner = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttr->owner());
+ if (aFeatureOwner.get() &&
+ ModelAPI_Session::get()->validators()->isConcealed(aFeatureOwner->getKind(), theAttr->id())) {
updateConcealmentFlag();
}
}
void Model_Data::addBackReference(FeaturePtr theFeature, std::string theAttrID,
const bool theApplyConcealment)
{
- // do not add the same attribute twice
+ // it is possible to add the same attribute twice: may be last time the owner was not Stable...
AttributePtr anAttribute = theFeature->data()->attribute(theAttrID);
- if (myRefsToMe.find(anAttribute) != myRefsToMe.end())
- return;
+ if (myRefsToMe.find(anAttribute) == myRefsToMe.end())
+ myRefsToMe.insert(theFeature->data()->attribute(theAttrID));
- myRefsToMe.insert(theFeature->data()->attribute(theAttrID));
- if (theApplyConcealment &&
+ if (theApplyConcealment && theFeature->isStable() &&
ModelAPI_Session::get()->validators()->isConcealed(theFeature->getKind(), theAttrID)) {
std::shared_ptr<ModelAPI_Result> aRes =
std::dynamic_pointer_cast<ModelAPI_Result>(myObject);
for(; aRefsIter != myRefsToMe.end(); aRefsIter++) {
if (aRefsIter->get()) {
FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>((*aRefsIter)->owner());
- if (aFeature.get() && !aFeature->isDisabled()) {
+ if (aFeature.get() && !aFeature->isDisabled() && aFeature->isStable()) {
if (ModelAPI_Session::get()->validators()->isConcealed(
aFeature->getKind(), (*aRefsIter)->id())) {
- return; // it is still concealed, nothing to do
+ std::shared_ptr<ModelAPI_Result> aRes =
+ std::dynamic_pointer_cast<ModelAPI_Result>(myObject);
+ if (aRes.get()) {
+ aRes->setIsConcealed(true); // set concealed
+ }
+ return;
}
}
}
// thus, no concealment references anymore => make not-concealed
std::shared_ptr<ModelAPI_Result> aRes =
std::dynamic_pointer_cast<ModelAPI_Result>(myObject);
- if (aRes.get() && aRes->isConcealed()) {
+ if (aRes.get()) {
aRes->setIsConcealed(false);
- static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED);
- ModelAPI_EventCreator::get()->sendUpdated(aRes, anEvent);
- Events_Loop::loop()->flush(anEvent);
}
}
private:
/// Removes all information about back references
void eraseBackReferences();
- /// Adds a back reference (with identifier which attribute references to this object
- /// It does not change the consealment flag of the data object result
+ /// Removes a back reference (with identifier which attribute references to this object)
/// \param theFeature feature referenced to this
/// \param theAttrID identifier of the attribute that is references from theFeature to this
void removeBackReference(FeaturePtr theFeature, std::string theAttrID);
+ /// Removes a back reference (by the attribute)
+ /// \param theAttr the referenced attribute
+ void removeBackReference(AttributePtr theAttr);
/// Adds a back reference (with identifier which attribute references to this object
/// \param theFeature feature referenced to this
/// \param theAttrID identifier of the attribute that is references from theFeature to this
TDF_Label aLab = aRef->Get();
FeaturePtr aResult = myObjs->feature(aLab);
if (theVisible) { // get nearest visible (in history) going up
- while(aResult.get() && // sub-composites are never in history
- (!aResult->isInHistory() || ModelAPI_Tools::compositeOwner(aResult).get())) {
+ while(aResult.get() && !aResult->isInHistory()) {
aResult = myObjs->nextFeature(aResult, true);
}
}
TDF_Label aRefLab = generalLabel().FindChild(TAG_CURRENT_FEATURE);
CompositeFeaturePtr aMain; // main feature that may nest the new current
+ std::set<FeaturePtr> anOwners; // composites that contain theCurrent (with any level of nesting)
if (theCurrent.get()) {
aMain = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theCurrent);
- if (!aMain.get()) {
- // if feature nests into compisite feature, make the composite feature as current
- const std::set<AttributePtr>& aRefsToMe = theCurrent->data()->refsToMe();
- std::set<AttributePtr>::const_iterator aRefToMe = aRefsToMe.begin();
- for(; aRefToMe != aRefsToMe.end(); aRefToMe++) {
- CompositeFeaturePtr aComposite =
- std::dynamic_pointer_cast<ModelAPI_CompositeFeature>((*aRefToMe)->owner());
- if (aComposite.get() && aComposite->isSub(theCurrent)) {
- aMain = aComposite;
- break;
- }
+ CompositeFeaturePtr anOwner = ModelAPI_Tools::compositeOwner(theCurrent);
+ while(anOwner.get()) {
+ if (!aMain.get()) {
+ aMain = anOwner;
}
+ anOwners.insert(anOwner);
+ anOwner = ModelAPI_Tools::compositeOwner(anOwner);
}
}
if (anIter == theCurrent) aPassed = true;
bool aDisabledFlag = !aPassed;
- if (aMain.get() && aMain->isSub(anIter)) // sub-elements of not-disabled feature are not disabled
- aDisabledFlag = false;
+ if (aMain.get()) {
+ if (aMain->isSub(anIter)) // sub-elements of not-disabled feature are not disabled
+ aDisabledFlag = false;
+ else if (anOwners.find(anIter) != anOwners.end()) // disable the higher-level feature is the nested is the current
+ aDisabledFlag = true;
+ }
+
if (anIter->getKind() == "Parameter") {// parameters are always out of the history of features, but not parameters
if (theCurrent.get() && theCurrent->getKind() != "Parameter")
aDisabledFlag = false;
anOwner->executeFeatures() = true;
}
-void Model_Objects::synchronizeBackRefs()
+/// synchronises back references for the given object basing on the collected data
+void Model_Objects::synchronizeBackRefsForObject(const std::set<AttributePtr>& theNewRefs,
+ ObjectPtr theObject)
{
- // keeps the concealed flags of result to catch the change and create created/deleted events
- std::list<std::pair<ResultPtr, bool> > aConcealed;
- // first cycle: erase all data about back-references
- NCollection_DataMap<TDF_Label, FeaturePtr>::Iterator aFeatures(myFeatures);
- for(; aFeatures.More(); aFeatures.Next()) {
- FeaturePtr aFeature = aFeatures.Value();
- std::shared_ptr<Model_Data> aFData =
- std::dynamic_pointer_cast<Model_Data>(aFeature->data());
- if (aFData.get()) {
- aFData->eraseBackReferences();
+ if (!theObject.get() || !theObject->data()->isValid())
+ return; // invalid
+ std::shared_ptr<Model_Data> aData = std::dynamic_pointer_cast<Model_Data>(theObject->data());
+ // iterate new list to compare with curent
+ std::set<AttributePtr>::iterator aNewIter = theNewRefs.begin();
+ for(; aNewIter != theNewRefs.end(); aNewIter++) {
+ if (aData->refsToMe().find(*aNewIter) == aData->refsToMe().end()) {
+ FeaturePtr aRefFeat = std::dynamic_pointer_cast<ModelAPI_Feature>((*aNewIter)->owner());
+ aData->addBackReference(aRefFeat, (*aNewIter)->id());
}
- const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
- std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRIter = aResults.begin();
- for (; aRIter != aResults.cend(); aRIter++) {
- std::shared_ptr<Model_Data> aResData =
- std::dynamic_pointer_cast<Model_Data>((*aRIter)->data());
- if (aResData.get()) {
- aConcealed.push_back(std::pair<ResultPtr, bool>(*aRIter, (*aRIter)->isConcealed()));
- aResData->eraseBackReferences();
- }
- // iterate sub-bodies of compsolid
- ResultCompSolidPtr aComp = std::dynamic_pointer_cast<ModelAPI_ResultCompSolid>(*aRIter);
- if (aComp.get()) {
- int aNumSub = aComp->numberOfSubs();
- for(int a = 0; a < aNumSub; a++) {
- ResultPtr aSub = aComp->subResult(a);
- std::shared_ptr<Model_Data> aResData =
- std::dynamic_pointer_cast<Model_Data>(aSub->data());
- if (aResData.get()) {
- aConcealed.push_back(std::pair<ResultPtr, bool>(aSub, aSub->isConcealed()));
- aResData->eraseBackReferences();
- }
- }
- }
+ }
+ if (theNewRefs.size() != aData->refsToMe().size()) { // some back ref must be removed
+ std::set<AttributePtr>::iterator aCurrentIter = aData->refsToMe().begin();
+ while(aCurrentIter != aData->refsToMe().end()) {
+ if (theNewRefs.find(*aCurrentIter) == theNewRefs.end()) {
+ aData->removeBackReference(*aCurrentIter);
+ aCurrentIter = aData->refsToMe().begin(); // reinitialize iteration after delete
+ } else aCurrentIter++;
}
}
+ aData->updateConcealmentFlag();
+}
- // second cycle: set new back-references: only features may have reference, iterate only them
- ModelAPI_ValidatorsFactory* aValidators = ModelAPI_Session::get()->validators();
- for(aFeatures.Initialize(myFeatures); aFeatures.More(); aFeatures.Next()) {
+void Model_Objects::synchronizeBackRefs()
+{
+ // collect all back references in the separated container: to update everything at once,
+ // without additional Concealment switchin on and off: only the final modification
+
+ // referenced (slave) objects to referencing attirbutes
+ std::map<ObjectPtr, std::set<AttributePtr> > allRefs;
+ NCollection_DataMap<TDF_Label, FeaturePtr>::Iterator aFeatures(myFeatures);
+ for(; aFeatures.More(); aFeatures.Next()) {
FeaturePtr aFeature = aFeatures.Value();
- std::shared_ptr<Model_Data> aFData =
- std::dynamic_pointer_cast<Model_Data>(aFeature->data());
+ std::shared_ptr<Model_Data> aFData = std::dynamic_pointer_cast<Model_Data>(aFeature->data());
if (aFData.get()) {
std::list<std::pair<std::string, std::list<ObjectPtr> > > aRefs;
aFData->referencesToObjects(aRefs);
- std::list<std::pair<std::string, std::list<ObjectPtr> > >::iterator
- aRefsIter = aRefs.begin();
- for(; aRefsIter != aRefs.end(); aRefsIter++) {
- std::list<ObjectPtr>::iterator aRefTo = aRefsIter->second.begin();
- for(; aRefTo != aRefsIter->second.end(); aRefTo++) {
+ std::list<std::pair<std::string, std::list<ObjectPtr> > >::iterator aRefsIt = aRefs.begin();
+ for(; aRefsIt != aRefs.end(); aRefsIt++) {
+ std::list<ObjectPtr>::iterator aRefTo = aRefsIt->second.begin();
+ for(; aRefTo != aRefsIt->second.end(); aRefTo++) {
if (*aRefTo) {
- std::shared_ptr<Model_Data> aRefData =
- std::dynamic_pointer_cast<Model_Data>((*aRefTo)->data());
- aRefData->addBackReference(aFeature, aRefsIter->first); // here the Concealed flag is updated
- // update enable/disable status: the nested status must be equal to the composite
- CompositeFeaturePtr aComp =
- std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(aFeature);
- if (aComp.get()) {
- FeaturePtr aReferenced = std::dynamic_pointer_cast<ModelAPI_Feature>(*aRefTo);
- if (aReferenced.get()) {
- aReferenced->setDisabled(aComp->isDisabled());
- }
+ std::map<ObjectPtr, std::set<AttributePtr> >::iterator aFound = allRefs.find(*aRefTo);
+ if (aFound == allRefs.end()) {
+ allRefs[*aRefTo] = std::set<AttributePtr>();
+ aFound = allRefs.find(*aRefTo);
}
+ aFound->second.insert(aFeature->data()->attribute(aRefsIt->first));
}
}
}
}
}
- std::list<std::pair<ResultPtr, bool> >::iterator aCIter = aConcealed.begin();
- for(; aCIter != aConcealed.end(); aCIter++) {
- if (aCIter->first->isConcealed() != aCIter->second) { // something is changed => produce event
- if (aCIter->second) { // was concealed become not => creation event
- static Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_CREATED);
- ModelAPI_EventCreator::get()->sendUpdated(aCIter->first, anEvent);
- } else { // was not concealed become concealed => delete event
- ModelAPI_EventCreator::get()->sendDeleted(myDoc, aCIter->first->groupName());
- // redisplay for the viewer (it must be disappeared also)
- static Events_ID EVENT_DISP =
- Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
- ModelAPI_EventCreator::get()->sendUpdated(aCIter->first, EVENT_DISP);
+ // second iteration: just compare back-references with existing in features and results
+ for(aFeatures.Initialize(myFeatures); aFeatures.More(); aFeatures.Next()) {
+ FeaturePtr aFeature = aFeatures.Value();
+ static std::set<AttributePtr> anEmpty;
+ std::map<ObjectPtr, std::set<AttributePtr> >::iterator aFound = allRefs.find(aFeature);
+ if (aFound == allRefs.end()) { // not found => erase all back references
+ synchronizeBackRefsForObject(anEmpty, aFeature);
+ } else {
+ synchronizeBackRefsForObject(aFound->second, aFeature);
+ }
+ // also for results
+ const std::list<std::shared_ptr<ModelAPI_Result> >& aResults = aFeature->results();
+ std::list<std::shared_ptr<ModelAPI_Result> >::const_iterator aRes = aResults.cbegin();
+ for(; aRes != aResults.cend(); aRes++) {
+ aFound = allRefs.find(*aRes);
+ if (aFound == allRefs.end()) { // not found => erase all back references
+ synchronizeBackRefsForObject(anEmpty, *aRes);
+ } else {
+ synchronizeBackRefsForObject(aFound->second, *aRes);
}
}
}
/// be created before)
std::string featureResultGroup(FeaturePtr theFeature);
- ///! Returns all features of the document including the hidden features which are not in
- ///! history. Not very fast method, for calling once, not in big cycles.
+ //! Returns all features of the document including the hidden features which are not in
+ //! history. Not very fast method, for calling once, not in big cycles.
std::list<std::shared_ptr<ModelAPI_Feature> > allFeatures();
+ //! synchronises back references for the given object basing on the collected data
+ void synchronizeBackRefsForObject(
+ const std::set<std::shared_ptr<ModelAPI_Attribute>>& theNewRefs, ObjectPtr theObject);
private:
TDF_Label myMain; ///< main label of the data storage
static void makeCurrentLast(std::shared_ptr<ModelAPI_Document> theDoc) {
if (theDoc.get()) {
FeaturePtr aLast = std::dynamic_pointer_cast<Model_Document>(theDoc)->lastFeature();
+ // if last is nested into something else, make this something else as last:
+ // otherwise it will look like edition of sub-element, so, the main will be disabled
+ if (aLast.get()) {
+ CompositeFeaturePtr aMain = ModelAPI_Tools::compositeOwner(aLast);
+ while(aMain.get()) {
+ aLast = aMain;
+ aMain = ModelAPI_Tools::compositeOwner(aLast);
+ }
+ }
theDoc->setCurrentFeature(aLast, false);
}
}
aLoop->registerListener(this, kOpAbortEvent);
static const Events_ID kOpStartEvent = aLoop->eventByName("StartOperation");
aLoop->registerListener(this, kOpStartEvent);
+ static const Events_ID kStabilityEvent = aLoop->eventByName(EVENT_STABILITY_CHANGED);
+ aLoop->registerListener(this, kStabilityEvent);
/* not needed now with history line
Config_PropManager::registerProp("Model update", "automatic_rebuild", "Rebuild immediately",
static const Events_ID kOpFinishEvent = aLoop->eventByName("FinishOperation");
static const Events_ID kOpAbortEvent = aLoop->eventByName("AbortOperation");
static const Events_ID kOpStartEvent = aLoop->eventByName("StartOperation");
+ static const Events_ID kStabilityEvent = aLoop->eventByName(EVENT_STABILITY_CHANGED);
#ifdef DEB_UPDATE
std::cout<<"****** Event "<<theMessage->eventID().eventText()<<std::endl;
#endif
+ if (theMessage->eventID() == kStabilityEvent)
+ updateStability(theMessage->sender());
if (theMessage->eventID() == kChangedEvent) { // automatic and manual rebuild flag is changed
/*bool aPropVal =
Config_PropManager::findProp("Model update", "automatic_rebuild")->value() == "true";
// check all features this feature depended on (recursive call of updateFeature)
static ModelAPI_ValidatorsFactory* aFactory = ModelAPI_Session::get()->validators();
- if (theFeature->isDisabled())
+ if (theFeature->isDisabled()) {
+ // possibly sub-elements are not disabled?
+ CompositeFeaturePtr aCompos = std::dynamic_pointer_cast<ModelAPI_CompositeFeature>(theFeature);
+ if (aCompos)
+ iterateUpdate(aCompos);
return;
+ }
// do not execute the composite that contains the current
bool isPostponedMain = false;
redisplayWithResults(theFeature, aState);
}
+void Model_Update::updateStability(void* theSender)
+{
+ if (theSender) {
+ bool added = false; // object may be was crated
+ ModelAPI_Object* aSender = static_cast<ModelAPI_Object*>(theSender);
+ if (aSender && aSender->document()) {
+ FeaturePtr aFeatureSender =
+ std::dynamic_pointer_cast<ModelAPI_Feature>(aSender->data()->owner());
+ if (aFeatureSender.get()) {
+ Model_Objects* aDocObjects =
+ std::dynamic_pointer_cast<Model_Document>(aSender->document())->objects();
+ if (aDocObjects) {
+ //aDocObjects->synchronizeBackRefs();
+ // remove or add all concealment refs from this feature
+ std::list<std::pair<std::string, std::list<ObjectPtr> > > aRefs;
+ aSender->data()->referencesToObjects(aRefs);
+ std::list<std::pair<std::string, std::list<ObjectPtr> > >::iterator aRefIt = aRefs.begin();
+ for(; aRefIt != aRefs.end(); aRefIt++) {
+ std::list<ObjectPtr>& aRefFeaturesList = aRefIt->second;
+ std::list<ObjectPtr>::iterator aReferenced = aRefFeaturesList.begin();
+ for(; aReferenced != aRefFeaturesList.end(); aReferenced++) {
+ // stability is only on results: feature to feature reference mean nested
+ // features, that will remove nesting references
+ if (aReferenced->get() && (*aReferenced)->data()->isValid() &&
+ (*aReferenced)->groupName() != ModelAPI_Feature::group()) {
+ std::shared_ptr<Model_Data> aData =
+ std::dynamic_pointer_cast<Model_Data>((*aReferenced)->data());
+ if (aFeatureSender->isStable()) {
+ aData->addBackReference(aFeatureSender, aRefIt->first);
+ } else {
+ aData->removeBackReference(aFeatureSender, aRefIt->first);
+ added = true; // remove of concealment may be caused creation of some result
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ if (added) {
+ static Events_Loop* aLoop = Events_Loop::loop();
+ static Events_ID kEventCreated = aLoop->eventByName(EVENT_OBJECT_CREATED);
+ aLoop->flush(kEventCreated);
+ }
+ }
+}
+
///////////////// Updated items iterator ////////////////////////
Model_Update::IterationItem::IterationItem(std::shared_ptr<ModelAPI_CompositeFeature> theFeature)
{
/// Returns true if the feature is older that the argument and it must be updated
bool isOlder(std::shared_ptr<ModelAPI_Feature> theFeature,
std::shared_ptr<ModelAPI_Object> theArgument);
+ /// Updates the properties of object because of stability state changes
+ void updateStability(void* theSender);
};
#endif
/// Event ID that order of objects in group is changed, so, tree must be fully rectreated (movement of feature)
static const char * EVENT_ORDER_UPDATED = "OrderUpdated";
+/// Event ID that informs that some object has changed the stability
+static const char * EVENT_STABILITY_CHANGED = "StabilityChanged";
+
/// Message that feature was changed (used for Object Browser update): moved, updated and deleted
class MODELAPI_EXPORT ModelAPI_ObjectUpdatedMessage : public Events_MessageGroup
{
return myIsDisabled;
}
+bool ModelAPI_Feature::setStable(const bool theFlag)
+{
+ if (myIsStable != theFlag) {
+ myIsStable = theFlag;
+ // send an event about the stability change (editing is started/finished)
+ static Events_Loop* aLoop = Events_Loop::loop();
+ static Events_ID EVENT_STAB = aLoop->eventByName(EVENT_STABILITY_CHANGED);
+ std::shared_ptr<Events_Message> aMessage(new Events_Message(EVENT_STAB, this));
+ aLoop->send(aMessage, false);
+ return true;
+ }
+ return false;
+}
+
+bool ModelAPI_Feature::isStable()
+{
+ return myIsStable;
+}
+
bool ModelAPI_Feature::isPreviewNeeded() const
{
return true;
void ModelAPI_Feature::init()
{
myIsDisabled = false;
+ myIsStable = true;
}
std::list<std::shared_ptr<ModelAPI_Result> > myResults;
///< is feature disabled or not
bool myIsDisabled;
+ ///< is feature is stable (not editing)
+ bool myIsStable;
+
public:
/// Returns the unique kind of a feature (like "Point")
virtual const std::string& getKind() = 0;
/// Returns the feature by the object (result).
MODELAPI_EXPORT static std::shared_ptr<ModelAPI_Feature> feature(ObjectPtr theObject);
+ /// Set the stable feature flag. If feature is currently editing then it is not stable.
+ /// \returns true if state is really changed
+ MODELAPI_EXPORT virtual bool setStable(const bool theFlag);
+
+ /// Returns the feature is stable or not.
+ MODELAPI_EXPORT virtual bool isStable();
+
//
// Helper methods, aliases for data()->method()
// -----------------------------------------------------------------------------------------------
{
if (myIsConcealed != theValue) {
myIsConcealed = theValue;
- if (document().get()) // can be on creation of result
+ if (document().get()) { // can be on creation of result
document()->updateHistory(groupName()); // to update the history cash data in the document
+ if (myIsConcealed) {
+ ModelAPI_EventCreator::get()->sendDeleted(document(), groupName());
+ static Events_ID kDispEvent = Events_Loop::loop()->eventByName(EVENT_OBJECT_TO_REDISPLAY);
+ ModelAPI_EventCreator::get()->sendUpdated(data()->owner(), kDispEvent);
+ } else {
+ static Events_ID kEventCreated = Events_Loop::eventByName(EVENT_OBJECT_CREATED);
+ ModelAPI_EventCreator::get()->sendUpdated(data()->owner(), kEventCreated);
+ }
+ }
}
}
signals:
/// The operation is started
+ void beforeStarted();
void started();
/// The operation is aborted
+ void beforeAborted();
void aborted();
/// The operation is committed
+ void beforeCommitted();
void committed();
/// The operation is aborted or committed
#include <ModelAPI_Object.h>
#include <ModelAPI_Validator.h>
#include <ModelAPI_Session.h>
+#include <ModelAPI_Tools.h>
#include <GeomAPI_Pnt2d.h>
if (!aFeature.get() || !isEditOperation())
return;
+ if (aFeature.get() && isEditOperation())
+ aFeature->setStable(false);
+
myVisualizedObjects.clear();
// store hidden result features
std::list<ResultPtr> aResults = aFeature->results();
}
ModelAPI_Session::get()->startOperation(anId.toStdString());
+ emit beforeStarted();
startOperation();
if (!myIsEditing) {
return;
}
}
- /// Set current feature and remeber old current feature
- if (myIsEditing) {
- SessionPtr aMgr = ModelAPI_Session::get();
- DocumentPtr aDoc = aMgr->activeDocument();
- // the parameter of current feature should be false, we should use all feature, not only visible
- // in order to correctly save the previous feature of the nested operation, where the
- // features can be not visible in the tree. The problem case is Edit sketch entitity(line)
- // in the Sketch, created in ExtrusionCut operation. The entity disappears by commit.
- // When sketch entity operation started, the sketch should be cashed here as the current.
- // Otherwise(the flag is true), the ExtrusionCut is cashed, when commit happens, the sketch
- // is disabled, sketch entity is disabled as extrusion cut is created earliest then sketch.
- // As a result the sketch disappears from the viewer. However after commit it is displayed back.
- myPreviousCurrentFeature = aDoc->currentFeature(false);
- aDoc->setCurrentFeature(feature(), false);
- }
-
- startOperation();
+ //Already called startOperation();
emit started();
}
void ModuleBase_OperationFeature::abort()
{
+ emit beforeAborted();
+
// the viewer update should be blocked in order to avoid the features blinking before they are
// hidden
std::shared_ptr<Events_Message> aMsg = std::shared_ptr<Events_Message>(
if (aPropertyPanel)
aPropertyPanel->cleanContent();
- SessionPtr aMgr = ModelAPI_Session::get();
- if (myIsEditing) {
- DocumentPtr aDoc = aMgr->activeDocument();
- bool aIsOp = aMgr->isOperation();
- if (!aIsOp)
- aMgr->startOperation();
- aDoc->setCurrentFeature(myPreviousCurrentFeature, true);
- if (!aIsOp)
- aMgr->finishOperation();
- myPreviousCurrentFeature = FeaturePtr();
- }
- abortOperation();
+ myFeature->setStable(true);
+ abortOperation();
stopOperation();
+ SessionPtr aMgr = ModelAPI_Session::get();
aMgr->abortOperation();
emit stopped();
// the viewer update should be unblocked in order to avoid the features blinking before they are
ModuleBase_IPropertyPanel* aPropertyPanel = propertyPanel();
if (aPropertyPanel)
aPropertyPanel->cleanContent();
+
+ myFeature->setStable(true);
SessionPtr aMgr = ModelAPI_Session::get();
/// Set current feature and remeber old current feature
- if (myIsEditing) {
- DocumentPtr aDoc = aMgr->activeDocument();
- bool aIsOp = aMgr->isOperation();
- if (!aIsOp)
- aMgr->startOperation();
- aDoc->setCurrentFeature(myPreviousCurrentFeature, true);
- if (!aIsOp)
- aMgr->finishOperation();
- myPreviousCurrentFeature = FeaturePtr();
- }
+
+ emit beforeCommitted();
commitOperation();
aMgr->finishOperation();
return myParentFeature;
}
+void ModuleBase_OperationFeature::setPreviousCurrentFeature(const FeaturePtr& theFeature)
+{
+ myPreviousCurrentFeature = theFeature;
+}
+
+FeaturePtr ModuleBase_OperationFeature::previousCurrentFeature()
+{
+ return myPreviousCurrentFeature;
+}
+
void ModuleBase_OperationFeature::initSelection(ModuleBase_ISelection* theSelection,
ModuleBase_IViewer* theViewer)
{
/// \return Installed parent feature (can be NULL)
CompositeFeaturePtr parentFeature() const;
+ /// Stores the previous to the operation current feature
+ /// \set theFeature a feature
+ void setPreviousCurrentFeature(const FeaturePtr& theFeature);
+
+ /// Returns the previous to the operation current feature
+ /// \return theFeature a feature
+ FeaturePtr previousCurrentFeature();
+
signals:
/// The operation is filled with existing preselection
void activatedByPreselection();
currentOperation()->postpone();
myOperations.append(theOperation);
+ connect(theOperation, SIGNAL(beforeStarted()), SLOT(onBeforeOperationStarted()));
+ connect(theOperation, SIGNAL(beforeAborted()), SLOT(onBeforeOperationAborted()));
+ connect(theOperation, SIGNAL(beforeCommitted()), SLOT(onBeforeOperationCommitted()));
+
connect(theOperation, SIGNAL(started()), SLOT(onOperationStarted()));
connect(theOperation, SIGNAL(aborted()), SLOT(onOperationAborted()));
connect(theOperation, SIGNAL(committed()), SLOT(onOperationCommitted()));
+
connect(theOperation, SIGNAL(stopped()), SLOT(onOperationStopped()));
connect(theOperation, SIGNAL(resumed()), SLOT(onOperationResumed()));
ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>
return isGranted;
}
+void XGUI_OperationMgr::setCurrentFeature(const FeaturePtr& theFeature)
+{
+ SessionPtr aMgr = ModelAPI_Session::get();
+ DocumentPtr aDoc = aMgr->activeDocument();
+ bool aIsOp = aMgr->isOperation();
+ if (!aIsOp)
+ aMgr->startOperation();
+ aDoc->setCurrentFeature(theFeature, false);
+ if (!aIsOp)
+ aMgr->finishOperation();
+}
+
bool XGUI_OperationMgr::canStartOperation(const QString& theId, const bool isAdditionallyGranted)
{
bool aCanStart = true;
}
}
+void XGUI_OperationMgr::onBeforeOperationStarted()
+{
+ ModuleBase_Operation* aCurrentOperation = dynamic_cast<ModuleBase_Operation*>(sender());
+ if (!aCurrentOperation)
+ return;
+
+ /// Set current feature and remeber old current feature
+ ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(aCurrentOperation);
+ if (aFOperation) {
+ SessionPtr aMgr = ModelAPI_Session::get();
+ DocumentPtr aDoc = aMgr->activeDocument();
+ // the parameter of current feature should be false, we should use all feature, not only visible
+ // in order to correctly save the previous feature of the nested operation, where the
+ // features can be not visible in the tree. The problem case is Edit sketch entitity(line)
+ // in the Sketch, created in ExtrusionCut operation. The entity disappears by commit.
+ // When sketch entity operation started, the sketch should be cashed here as the current.
+ // Otherwise(the flag is true), the ExtrusionCut is cashed, when commit happens, the sketch
+ // is disabled, sketch entity is disabled as extrusion cut is created earliest then sketch.
+ // As a result the sketch disappears from the viewer. However after commit it is displayed back.
+ aFOperation->setPreviousCurrentFeature(aDoc->currentFeature(false));
+ if (aFOperation->isEditOperation()) // it should be performed by the feature edit only
+ // in create operation, the current feature is changed by addFeature()
+ aDoc->setCurrentFeature(aFOperation->feature(), false);
+ }
+}
+
void XGUI_OperationMgr::onOperationStarted()
{
ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
emit operationStarted(aSenderOperation);
}
+void XGUI_OperationMgr::onBeforeOperationAborted()
+{
+ onBeforeOperationCommitted();
+}
+
void XGUI_OperationMgr::onOperationAborted()
{
ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
emit operationAborted(aSenderOperation);
}
+void XGUI_OperationMgr::onBeforeOperationCommitted()
+{
+ ModuleBase_Operation* aCurrentOperation = dynamic_cast<ModuleBase_Operation*>(sender());
+ if (!aCurrentOperation)
+ return;
+
+ /// Restore the previous current feature
+ ModuleBase_OperationFeature* aFOperation = dynamic_cast<ModuleBase_OperationFeature*>(aCurrentOperation);
+ if (aFOperation) {
+ if (aFOperation->isEditOperation()) {
+ /// Restore the previous current feature
+ setCurrentFeature(aFOperation->previousCurrentFeature());
+ }
+ else { // create operation
+ // the Top created feature should stays the current. In nested operations, like Line in the Sketch or
+ // Sketch in ExtrusionCut, a previous feature should be restored on commit. It is performed here
+ // in order to perform it in the current transaction without opening a new one.
+ if (myOperations.front() != aFOperation)
+ setCurrentFeature(aFOperation->previousCurrentFeature());
+ }
+ }
+}
+
void XGUI_OperationMgr::onOperationCommitted()
{
// apply state for all features from the stack of operations should be updated
#include "XGUI.h"
#include <ModuleBase_Operation.h>
+#include "ModelAPI_Feature.h"
#include <QList>
#include <QObject>
/// \return boolean result
bool isGrantedOperation(const QString& theId);
+ /// Sets the feature as a current in the document
+ /// \param theFeature a feature
+ void setCurrentFeature(const FeaturePtr& theFeature);
+
public slots:
/// SLOT, that is called by the key in the property panel is clicked.
/// \param theEvent the mouse event
/// If there is a suspended operation, restart it.
void onOperationStopped();
- /// Slot called on operation start
+ /// Slot called before operation started. Stores the previous current feature, set the feature
+ /// of the operation as a current in the document. The previous current feature should be restored
+ /// by the operation abort/commit
+ void onBeforeOperationStarted();
+
+ /// Slot called after operation started
void onOperationStarted();
- /// Slot called on operation abort
+ /// Slot called before operation aborted. Restore the previous current operation
+ void onBeforeOperationAborted();
+
+ /// Slot called after operation aborted
void onOperationAborted();
- /// Slot called on operation commit
+ /// Slot called before operation committed. Restore the previous current operation
+ void onBeforeOperationCommitted();
+
+ /// Slot called after operation committed
void onOperationCommitted();
/// Slot called on operation resume
/// Current workshop
ModuleBase_IWorkshop* myWorkshop;
-
/// Lock/Unlock access to Ok button in property panel
bool myIsValidationLock;
/// Lock/Unlock access to Ok button in property panel