]> SALOME platform Git repositories - modules/shaper.git/commitdiff
Salome HOME
Merge branch 'master' of newgeom:newgeom
authorvsv <vitaly.smetannikov@opencascade.com>
Thu, 15 May 2014 13:49:30 +0000 (17:49 +0400)
committervsv <vitaly.smetannikov@opencascade.com>
Thu, 15 May 2014 13:49:30 +0000 (17:49 +0400)
24 files changed:
src/Model/Model_Application.cpp
src/Model/Model_Application.h
src/Model/Model_AttributeDocRef.cpp
src/Model/Model_AttributeRefAttr.cpp
src/Model/Model_Document.cpp
src/Model/Model_Document.h
src/PartSet/PartSet_Listener.cpp
src/PartSet/PartSet_Module.cpp
src/PartSet/PartSet_Module.h
src/PartSet/PartSet_OperationSketch.cpp
src/PartSet/PartSet_OperationSketch.h
src/PartSet/PartSet_OperationSketchBase.cpp
src/PartSet/PartSet_OperationSketchBase.h
src/PartSetPlugin/PartSetPlugin_Part.h
src/SketchPlugin/SketchPlugin_Constraint.h
src/SketchPlugin/SketchPlugin_Line.cpp
src/SketchSolver/CMakeLists.txt
src/SketchSolver/SketchSolver_ConstraintManager.cpp
src/SketchSolver/SketchSolver_ConstraintManager.h
src/XGUI/XGUI_Displayer.cpp
src/XGUI/XGUI_Displayer.h
src/XGUI/XGUI_OperationMgr.cpp
src/XGUI/XGUI_OperationMgr.h
src/XGUI/XGUI_Workshop.cpp

index 166b4e1a173f3812013eabdce23d4aec14c8f8f2..df32ef977d7c599acfbb7dbadc23c99492533fb7 100644 (file)
@@ -26,6 +26,12 @@ const boost::shared_ptr<Model_Document>& Model_Application::getDocument(string t
 
   boost::shared_ptr<Model_Document> aNew(new Model_Document(theDocID));
   myDocs[theDocID] = aNew;
+  // load it if it must be loaded by demand
+  if (myLoadedByDemand.find(theDocID) != myLoadedByDemand.end() && !myPath.empty()) {
+    aNew->load(myPath.c_str());
+    myLoadedByDemand.erase(theDocID); // done, don't do it anymore
+  }
+
   return myDocs[theDocID];
 }
 
@@ -40,6 +46,18 @@ bool Model_Application::hasDocument(std::string theDocID)
   return myDocs.find(theDocID) != myDocs.end();
 }
 
+//=======================================================================
+void Model_Application::setLoadPath(std::string thePath)
+{
+  myPath = thePath;
+}
+
+//=======================================================================
+void Model_Application::setLoadByDemand(std::string theID)
+{
+  myLoadedByDemand.insert(theID);
+}
+
 //=======================================================================
 Model_Application::Model_Application()
 {
index ddd3155bd0ed9e599b34ebca545df95da6eca10c..9281f9ce6e4773565072d1c697508f315e09e63c 100644 (file)
@@ -36,6 +36,11 @@ public:
   //! Deletes the document from the application
   MODEL_EXPORT void deleteDocument(std::string theDocID);
 
+  //! Set path for the loaded by demand documents
+  void setLoadPath(std::string thePath);
+  //! Defines that specified document must be loaded by demand
+  void setLoadByDemand(std::string theID);
+
 public:
   // Redefined OCAF methods
   //! Return name of resource (i.e. "Standard")
@@ -51,6 +56,10 @@ public:
 private:
   /// Map from string identifiers to created documents of an application
   std::map<std::string, boost::shared_ptr<Model_Document> > myDocs;
+  /// Path for the loaded by demand documents
+  std::string myPath;
+  /// Path for the loaded by demand documents
+  std::set<std::string> myLoadedByDemand;
 };
 
 #endif
index 93c8af71346ce82569f5cea6cf867f8b0d8ac55b..dfb307f4dbfe0981cc8915fc838cea6a798540a4 100644 (file)
@@ -36,5 +36,11 @@ Model_AttributeDocRef::Model_AttributeDocRef(TDF_Label& theLabel)
   if (!theLabel.FindAttribute(TDataStd_Comment::GetID(), myComment)) {
     // create attribute: not initialized by value yet, just empty string
     myComment = TDataStd_Comment::Set(theLabel, "");
+  } else { // document was already referenced: try to set it as loaded by demand
+    Handle(Model_Application) anApp = Model_Application::getApplication();
+    string anID(TCollection_AsciiString(myComment->Get()).ToCString());
+    if (!anApp->hasDocument(anID)) {
+      anApp->setLoadByDemand(anID);
+    }
   }
 }
index 2d7a1bd5e4fa9d1754c9183fb13595f232940cc2..daa53a1a6075b5aaa9a558e32087c88bf23df557 100644 (file)
@@ -28,7 +28,7 @@ void Model_AttributeRefAttr::setAttr(boost::shared_ptr<ModelAPI_Attribute> theAt
   myID->Set(aData->id(theAttr).c_str());
 
   static Events_ID anEvent = Events_Loop::eventByName(EVENT_FEATURE_UPDATED);
-  Model_FeatureUpdatedMessage aMsg(feature(), anEvent);
+  Model_FeatureUpdatedMessage aMsg(owner(), anEvent);
   Events_Loop::loop()->send(aMsg);
 }
 
index 8c305effa4f45ff18eee37728e9f1cf8a144e732..274fc6f1b02719f206957a6048cf024abb870d8a 100644 (file)
@@ -9,6 +9,7 @@
 #include <Model_PluginManager.h>
 #include <Model_Events.h>
 #include <Events_Loop.h>
+#include <Events_Error.h>
 
 #include <TDataStd_Integer.hxx>
 #include <TDataStd_Comment.hxx>
 
 #include <climits>
 
+#ifdef WIN32
+# define _separator_ '\\'
+#else
+# define _separator_ '/'
+#endif
+
 static const int UNDO_LIMIT = 10; // number of possible undo operations
 
 static const int TAG_GENERAL = 1; // general properties tag
@@ -26,83 +33,125 @@ static const int TAG_HISTORY = 3; // tag of the history sub-tree (python dump)
 
 using namespace std;
 
+/// Returns the file name of this document by the nameof directory and identifuer of a document
+static TCollection_ExtendedString DocFileName(const char* theFileName, const string& theID)
+{
+  TCollection_ExtendedString aPath ((const Standard_CString)theFileName);
+  aPath += _separator_;
+  aPath += theID.c_str();
+  aPath += ".cbf"; // standard binary file extension
+  return aPath;
+}
+
 bool Model_Document::load(const char* theFileName)
 {
-  bool myIsError = Standard_False;
-  /*
-   TCollection_ExtendedString aPath ((const Standard_CString)theFileName);
-   PCDM_ReaderStatus aStatus = (PCDM_ReaderStatus) -1;
-   try
-   {
-   Handle(TDocStd_Document) aDoc = this;
-   aStatus = Model_Application::GetApplication()->Open(aPath, aDoc);
-   }
-   catch (Standard_Failure)
-   {}
-   myIsError = aStatus != PCDM_RS_OK;
-   if (myIsError)
-   {
-   switch (aStatus)
-   {
-   case PCDM_RS_UnknownDocument: cout<<"OCAFApp_Appl_RUnknownDocument"<<endl; break;
-   case PCDM_RS_AlreadyRetrieved: cout<<"OCAFApp_Appl_RAlreadyRetrieved"<<endl; break;
-   case PCDM_RS_AlreadyRetrievedAndModified: cout<<"OCAFApp_Appl_RAlreadyRetrievedAndModified"<<endl; break;
-   case PCDM_RS_NoDriver: cout<<"OCAFApp_Appl_RNoDriver"<<endl; break;
-   case PCDM_RS_UnknownFileDriver: cout<<"OCAFApp_Appl_RNoDriver"<<endl; break;
-   case PCDM_RS_OpenError: cout<<"OCAFApp_Appl_ROpenError"<<endl; break;
-   case PCDM_RS_NoVersion: cout<<"OCAFApp_Appl_RNoVersion"<<endl; break;
-   case PCDM_RS_NoModel: cout<<"OCAFApp_Appl_RNoModel"<<endl; break;
-   case PCDM_RS_NoDocument: cout<<"OCAFApp_Appl_RNoDocument"<<endl; break;
-   case PCDM_RS_FormatFailure: cout<<"OCAFApp_Appl_RFormatFailure"<<endl; break;
-   case PCDM_RS_TypeNotFoundInSchema: cout<<"OCAFApp_Appl_RTypeNotFound"<<endl; break;
-   case PCDM_RS_UnrecognizedFileFormat: cout<<"OCAFApp_Appl_RBadFileFormat"<<endl; break;
-   case PCDM_RS_MakeFailure: cout<<"OCAFApp_Appl_RMakeFailure"<<endl; break;
-   case PCDM_RS_PermissionDenied: cout<<"OCAFApp_Appl_RPermissionDenied"<<endl; break;
-   case PCDM_RS_DriverFailure: cout<<"OCAFApp_Appl_RDriverFailure"<<endl; break;
-   default: cout<<"OCAFApp_Appl_RUnknownFail"<<endl; break;
-   }
-   }
-   SetUndoLimit(UNDO_LIMIT);
-   */
-  return !myIsError;
+  Handle(Model_Application) anApp = Model_Application::getApplication();
+  if (this == Model_PluginManager::get()->rootDocument().get()) {
+    anApp->setLoadPath(theFileName);
+  }
+  TCollection_ExtendedString aPath (DocFileName(theFileName, myID));
+  PCDM_ReaderStatus aStatus = (PCDM_ReaderStatus) -1;
+  try
+  {
+    aStatus = anApp->Open(aPath, myDoc);
+  }
+  catch (Standard_Failure)
+  {
+    Handle(Standard_Failure) aFail = Standard_Failure::Caught();
+    Events_Error::send(string("Exception in opening of document: ") + aFail->GetMessageString());
+    return false;
+  }
+  bool isError = aStatus != PCDM_RS_OK;
+  if (isError)
+  {
+    switch (aStatus)
+    {
+    case PCDM_RS_UnknownDocument: 
+      Events_Error::send(string("Can not open document: PCDM_RS_UnknownDocument")); break;
+    case PCDM_RS_AlreadyRetrieved: 
+      Events_Error::send(string("Can not open document: PCDM_RS_AlreadyRetrieved")); break;
+    case PCDM_RS_AlreadyRetrievedAndModified:
+      Events_Error::send(string("Can not open document: PCDM_RS_AlreadyRetrievedAndModified")); break;
+    case PCDM_RS_NoDriver:
+      Events_Error::send(string("Can not open document: PCDM_RS_NoDriver")); break;
+    case PCDM_RS_UnknownFileDriver:
+      Events_Error::send(string("Can not open document: PCDM_RS_UnknownFileDriver")); break;
+    case PCDM_RS_OpenError:
+      Events_Error::send(string("Can not open document: PCDM_RS_OpenError")); break;
+    case PCDM_RS_NoVersion:
+      Events_Error::send(string("Can not open document: PCDM_RS_NoVersion")); break;
+    case PCDM_RS_NoModel:
+      Events_Error::send(string("Can not open document: PCDM_RS_NoModel")); break;
+    case PCDM_RS_NoDocument:
+      Events_Error::send(string("Can not open document: PCDM_RS_NoDocument")); break;
+    case PCDM_RS_FormatFailure:
+      Events_Error::send(string("Can not open document: PCDM_RS_FormatFailure")); break;
+    case PCDM_RS_TypeNotFoundInSchema:
+      Events_Error::send(string("Can not open document: PCDM_RS_TypeNotFoundInSchema")); break;
+    case PCDM_RS_UnrecognizedFileFormat:
+      Events_Error::send(string("Can not open document: PCDM_RS_UnrecognizedFileFormat")); break;
+    case PCDM_RS_MakeFailure:
+      Events_Error::send(string("Can not open document: PCDM_RS_MakeFailure")); break;
+    case PCDM_RS_PermissionDenied:
+      Events_Error::send(string("Can not open document: PCDM_RS_PermissionDenied")); break;
+    case PCDM_RS_DriverFailure:
+      Events_Error::send(string("Can not open document: PCDM_RS_DriverFailure")); break;
+    default:
+      Events_Error::send(string("Can not open document: unknown error")); break;
+    }
+  }
+  if (!isError) {
+    myDoc->SetUndoLimit(UNDO_LIMIT);
+    synchronizeFeatures();
+  }
+  return !isError;
 }
 
 bool Model_Document::save(const char* theFileName)
 {
-  bool myIsError = true;
-  /*
-   TCollection_ExtendedString aPath ((const Standard_CString)theFileName);
-   PCDM_StoreStatus aStatus;
-   try {
-   Handle(TDocStd_Document) aDoc = this;
-   aStatus = Model_Application::GetApplication()->SaveAs (aDoc, aPath);
-   }
-   catch (Standard_Failure) {
-   Handle(Standard_Failure) aFail = Standard_Failure::Caught();
-   cout<<"OCAFApp_Engine:save Error: "<<aFail->GetMessageString()<<endl;
-   return false;
-   }
-   myIsError = aStatus != PCDM_SS_OK;
-   if (myIsError)
-   {
-   switch (aStatus)
-   {
-   case PCDM_SS_DriverFailure:
-   cout<<"OCAFApp_Appl_SDriverFailure"<<endl;
-   break;
-   case PCDM_SS_WriteFailure:
-   cout<<"OCAFApp_Appl_SWriteFailure"<<endl;
-   break;
-   case PCDM_SS_Failure:
-   default:
-   cout<<"OCAFApp_Appl_SUnknownFailure"<<endl;
-   break;
-   }
-   }
-   myTransactionsAfterSave = 0;
-   Standard::Purge(); // Release free memory
-   */
-  return !myIsError;
+  // create a directory in the root document if it is not yet exist
+  if (this == Model_PluginManager::get()->rootDocument().get()) {
+#ifdef WIN32
+    CreateDirectory(theFileName, NULL);
+#else
+    mkdir(theFileName, 0x1ff); 
+#endif
+  }
+  // filename in the dir is id of document inside of the given directory
+  TCollection_ExtendedString aPath(DocFileName(theFileName, myID));
+  PCDM_StoreStatus aStatus;
+  try {
+    aStatus = Model_Application::getApplication()->SaveAs(myDoc, aPath);
+  }
+  catch (Standard_Failure) {
+    Handle(Standard_Failure) aFail = Standard_Failure::Caught();
+    Events_Error::send(string("Exception in saving of document: ") + aFail->GetMessageString());
+    return false;
+  }
+  bool isDone = aStatus == PCDM_SS_OK || aStatus == PCDM_SS_No_Obj;
+  if (!isDone)
+  {
+    switch (aStatus)
+    {
+    case PCDM_SS_DriverFailure:
+      Events_Error::send(string("Can not save document: PCDM_SS_DriverFailure"));
+      break;
+    case PCDM_SS_WriteFailure:
+      Events_Error::send(string("Can not save document: PCDM_SS_WriteFailure"));
+      break;
+    case PCDM_SS_Failure:
+    default:
+      Events_Error::send(string("Can not save document: PCDM_SS_Failure"));
+      break;
+    }
+  }
+  myTransactionsAfterSave = 0;
+  if (isDone) { // save also sub-documents if any
+    set<string>::iterator aSubIter = mySubs.begin();
+    for(; aSubIter != mySubs.end() && isDone; aSubIter++)
+      isDone = subDocument(*aSubIter)->save(theFileName);
+  }
+  return isDone;
 }
 
 void Model_Document::close()
@@ -119,6 +168,10 @@ void Model_Document::close()
 
 void Model_Document::startOperation()
 {
+  // check is it nested or not
+  if (myDoc->HasOpenCommand()) {
+    myIsNested = true;
+  }
   // new command for this
   myDoc->NewCommand();
   // new command for all subs
@@ -132,6 +185,7 @@ void Model_Document::finishOperation()
   // returns false if delta is empty and no transaction was made
   myIsEmptyTr[myTransactionsAfterSave] = !myDoc->CommitCommand();
   myTransactionsAfterSave++;
+  myIsNested = false;
   // finish for all subs
   set<string>::iterator aSubIter = mySubs.begin();
   for(; aSubIter != mySubs.end(); aSubIter++)
@@ -344,6 +398,10 @@ Model_Document::Model_Document(const std::string theID)
 {
   myDoc->SetUndoLimit(UNDO_LIMIT);
   myTransactionsAfterSave = 0;
+  myIsNested = false;
+  myDoc->SetNestedTransactionMode();
+  // to have something in the document and avoid empty doc open/save problem
+  TDataStd_Integer::Set(myDoc->Main().Father(), 0);
 }
 
 TDF_Label Model_Document::groupLabel(const string theGroup)
@@ -458,10 +516,6 @@ void Model_Document::synchronizeFeatures()
         aFeature->setDoc(aThis);
         aFeature->setData(aData);
         aFeature->initAttributes();
-        // event: model is updated
-        static Events_ID anEvent = Events_Loop::eventByName(EVENT_FEATURE_CREATED);
-        Model_FeatureUpdatedMessage aMsg(aFeature, anEvent);
-        Events_Loop::loop()->send(aMsg);
 
         if (aFIter == aFeatures.end()) {
           aFeatures.push_back(aFeature);
@@ -470,6 +524,11 @@ void Model_Document::synchronizeFeatures()
           aFIter++;
           aFeatures.insert(aFIter, aFeature);
         }
+        // event: model is updated
+        static Events_ID anEvent = Events_Loop::eventByName(EVENT_FEATURE_CREATED);
+        Model_FeatureUpdatedMessage aMsg(aFeature, anEvent);
+        Events_Loop::loop()->send(aMsg);
+
         // feature for this label is added, so go to the next label
         aFLabIter.Next();
       } else { // nothing is changed, both iterators are incremented
index 0bf22b98e5b450e9dcbf1ef7771a64d82a267ba9..b314d9dc896c1bd9ca4f5081dd3008a3c32fa58e 100644 (file)
@@ -120,6 +120,8 @@ private:
   std::set<std::string> mySubs; ///< set of identifiers of sub-documents of this document
   /// transaction indexes (related to myTransactionsAfterSave) which were empty in this doc
   std::map<int, bool> myIsEmptyTr;
+  /// true if the current operation is nested
+  bool myIsNested;
 };
 
 #endif
index 3e1c4886a78f352827be6aadb1a0727f45f02a33..9615dac4cf175d81bc72b4c88c2c6e8c570f0be5 100644 (file)
@@ -21,8 +21,9 @@ PartSet_Listener::PartSet_Listener(PartSet_Module* theModule)
 : myModule(theModule)
 {
   Events_Loop* aLoop = Events_Loop::loop();
-  Events_ID aFeatureUpdatedId = aLoop->eventByName(EVENT_FEATURE_UPDATED);
-  aLoop->registerListener(this, aFeatureUpdatedId);
+  aLoop->registerListener(this, aLoop->eventByName(EVENT_FEATURE_UPDATED));
+  aLoop->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_CREATED));
+  aLoop->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_DELETED));
 }
 
 PartSet_Listener::~PartSet_Listener()
@@ -32,11 +33,24 @@ PartSet_Listener::~PartSet_Listener()
 //******************************************************
 void PartSet_Listener::processEvent(const Events_Message* theMessage)
 {
-  if (QString(theMessage->eventID().eventText()) == EVENT_FEATURE_UPDATED)
+  QString aType = QString(theMessage->eventID().eventText());
+  if (aType == EVENT_FEATURE_UPDATED ||
+      aType == EVENT_FEATURE_CREATED)
   {
     const Model_FeatureUpdatedMessage* aUpdMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
     boost::shared_ptr<ModelAPI_Feature> aFeature = aUpdMsg->feature();
-    if (myModule->workshop()->displayer()->IsVisible(aFeature))
+    if (myModule->workshop()->displayer()->IsVisible(aFeature) ||
+        aType == EVENT_FEATURE_CREATED)
       myModule->visualizePreview(aFeature, true);
   }
+  if (aType == EVENT_FEATURE_DELETED)
+  {
+    const Model_FeatureDeletedMessage* aDelMsg = dynamic_cast<const Model_FeatureDeletedMessage*>(theMessage);
+    boost::shared_ptr<ModelAPI_Document> aDoc = aDelMsg->document();
+
+    std::string aGroup = aDelMsg->group();
+    if (aDelMsg->group().compare("Sketch") == 0) { // Update only Sketch group
+      myModule->updateCurrentPreview(aGroup);
+    }
+  }
 }
index d7a92caf5118640d66b07f755918bc2985742a8a..9e47626c8a02a42220e26e1315d41ccebdf1e15f 100644 (file)
@@ -308,3 +308,36 @@ void PartSet_Module::visualizePreview(boost::shared_ptr<ModelAPI_Feature> theFea
     aDisplayer->Erase(anOperation->feature());
   }
 }
+
+void PartSet_Module::updateCurrentPreview(const std::string& theCmdId)
+{
+  ModuleBase_Operation* anOperation = myWorkshop->operationMgr()->currentOperation();
+  if (!anOperation)
+    return;
+
+  PartSet_OperationSketchBase* aPreviewOp = dynamic_cast<PartSet_OperationSketchBase*>(anOperation);
+  if (!aPreviewOp)
+    return;
+
+  boost::shared_ptr<ModelAPI_Feature> aFeature = aPreviewOp->feature();
+  if (!aFeature || aFeature->getKind() != theCmdId)
+    return;
+
+  std::map<boost::shared_ptr<ModelAPI_Feature>, boost::shared_ptr<GeomAPI_Shape> >
+                                                                     aList = aPreviewOp->preview();
+  XGUI_Displayer* aDisplayer = myWorkshop->displayer();
+  std::list<int> aModes = aPreviewOp->getSelectionModes(aPreviewOp->feature());
+
+  std::map<boost::shared_ptr<ModelAPI_Feature>, boost::shared_ptr<GeomAPI_Shape> >::const_iterator
+                                                         anIt = aList.begin(), aLast = aList.end();
+  aDisplayer->EraseAll(false);
+  for (; anIt != aLast; anIt++) {
+    boost::shared_ptr<ModelAPI_Feature> aFeature = (*anIt).first;
+    boost::shared_ptr<GeomAPI_Shape> aPreview = (*anIt).second;
+    aDisplayer->RedisplayInLocalContext(aFeature,
+                                        aPreview ? aPreview->impl<TopoDS_Shape>() : TopoDS_Shape(),
+                                        aModes, false);
+  }
+  aDisplayer->UpdateViewer();
+}
+
index 6138a43dc6ed539da34e0daba492b97e3c84930d..14a418d01435fbb58e037a7af0e375118edf6265 100644 (file)
@@ -44,6 +44,10 @@ public:
   /// \param isDisplay the state whether the presentation should be displayed or erased
   void visualizePreview(boost::shared_ptr<ModelAPI_Feature> theFeature, bool isDisplay);
 
+  /// Updates current operation preview, if it has it.
+  /// \param theCmdId the operation name
+  void updateCurrentPreview(const std::string& theCmdId);
+
 public slots:
   void onFeatureTriggered();
   /// SLOT, that is called after the operation is stopped. Switched off the modfications performed
index e5290aa77eb9bc3cbd86ec285cb4b6afdf623019..bcbbf15719214015b0d593b40ac521c71b0f665e 100644 (file)
@@ -11,6 +11,8 @@
 
 #include <ModelAPI_Data.h>
 #include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeRefList.h>
+
 #include <GeomAlgoAPI_FaceBuilder.h>
 #include <GeomDataAPI_Point.h>
 #include <GeomDataAPI_Dir.h>
@@ -79,6 +81,29 @@ void PartSet_OperationSketch::mouseMoved(QMouseEvent* theEvent, Handle(V3d_View)
     emit launchOperation(PartSet_OperationEditLine::Type(), aFeature);
 }
 
+std::map<boost::shared_ptr<ModelAPI_Feature>, boost::shared_ptr<GeomAPI_Shape> >
+                                                        PartSet_OperationSketch::preview() const
+{
+  std::map<boost::shared_ptr<ModelAPI_Feature>, boost::shared_ptr<GeomAPI_Shape> > aPreviewMap;
+
+  boost::shared_ptr<SketchPlugin_Feature> aFeature;
+
+  boost::shared_ptr<ModelAPI_Data> aData = feature()->data();
+  boost::shared_ptr<ModelAPI_AttributeRefList> aRefList =
+        boost::dynamic_pointer_cast<ModelAPI_AttributeRefList>(aData->attribute(SKETCH_ATTR_FEATURES));
+
+  std::list<boost::shared_ptr<ModelAPI_Feature> > aFeatures = aRefList->list();
+  std::list<boost::shared_ptr<ModelAPI_Feature> >::const_iterator anIt = aFeatures.begin(),
+                                                                  aLast = aFeatures.end();
+  for (; anIt != aLast; anIt++) {
+    aFeature = boost::dynamic_pointer_cast<SketchPlugin_Feature>(*anIt);
+    boost::shared_ptr<GeomAPI_Shape> aPreview = aFeature->preview();
+    if (aPreview)
+      aPreviewMap[aFeature] = aPreview;
+  }
+  return aPreviewMap;
+}
+
 void PartSet_OperationSketch::setSketchPlane(const TopoDS_Shape& theShape)
 {
   if (theShape.IsNull())
index 227722dc7c91b9849a8227e11e76d575a40d09d8..3f8215ac953f30f081ebfbdb80720a2ac6e014b2 100644 (file)
@@ -47,6 +47,10 @@ public:
   virtual void mouseMoved(QMouseEvent* theEvent, Handle_V3d_View theView,
                           const std::list<XGUI_ViewerPrs>& theSelected);
 
+  /// Returns the map of the operation previews including the nested feature previews
+  /// \return the map of feature to the feature preview
+  virtual std::map<boost::shared_ptr<ModelAPI_Feature>, boost::shared_ptr<GeomAPI_Shape> >
+                                                                           preview() const;
 signals:
   /// signal about the sketch plane is selected
   /// \param theX the value in the X direction of the plane
index 4113c3cba83fbab23eed59174fbd7e08d98cb4a3..daa0211b1d8b0656ccaf4f0162af8357a5057598 100644 (file)
@@ -32,6 +32,12 @@ boost::shared_ptr<GeomAPI_Shape> PartSet_OperationSketchBase::preview(
   return aFeature->preview();
 }
 
+std::map<boost::shared_ptr<ModelAPI_Feature>, boost::shared_ptr<GeomAPI_Shape> >
+                                                     PartSet_OperationSketchBase::preview() const
+{
+  return std::map<boost::shared_ptr<ModelAPI_Feature>, boost::shared_ptr<GeomAPI_Shape> >();
+}
+
 boost::shared_ptr<ModelAPI_Feature> PartSet_OperationSketchBase::createFeature()
 {
   boost::shared_ptr<ModelAPI_Feature> aFeature = ModuleBase_Operation::createFeature();
index b30f29935ba303eae52adcf9576b3e45ba1de2b0..cce1c55113f1b99362c47e0bce2efdc500d42f18 100644 (file)
@@ -15,6 +15,8 @@
 #include <ModuleBase_Operation.h>
 #include <QObject>
 
+#include <map>
+
 class Handle_V3d_View;
 class QMouseEvent;
 class GeomAPI_Shape;
@@ -43,6 +45,10 @@ public:
   /// \param theFeature the feature object to obtain the preview
   boost::shared_ptr<GeomAPI_Shape> preview(boost::shared_ptr<ModelAPI_Feature> theFeature) const;
 
+  /// Returns the map of the operation previews including the nested feature previews
+  /// \return the map of feature to the feature preview
+  virtual std::map<boost::shared_ptr<ModelAPI_Feature>, boost::shared_ptr<GeomAPI_Shape> > preview() const;
+
   /// Returns the operation local selection mode
   /// \param theFeature the feature object to get the selection mode
   /// \return the selection mode
index 25dc0e0ce7b3ac015483a4106a09ce2a557c3fc0..dc6a80a49bc76163f7cf230849336b874568d534 100644 (file)
@@ -34,6 +34,9 @@ public:
 
   PARTSETPLUGIN_EXPORT virtual boost::shared_ptr<ModelAPI_Document> documentToAdd();
 
+  /// Returns true if this feature must be displayed in the history (top level of Part tree)
+  PARTSETPLUGIN_EXPORT virtual bool isInHistory() {return false;}
+
   /// Use plugin manager for features creation
   PartSetPlugin_Part();
 
index e69a316cc46a6b0fa4867fe09ccceda9a0553901..61cd2bf0554bc18567dbc87e17c4d48e078be365 100644 (file)
@@ -34,7 +34,8 @@ const std::string CONSTRAINT_ATTR_ENTITY_C("ConstraintEntityC");
 /// Fourth entity for the constraint
 const std::string CONSTRAINT_ATTR_ENTITY_D("ConstraintEntityD");
 /// List of constraint attributes
-const std::string CONSTRAINT_ATTRIBUTES[4] = 
+const unsigned int CONSTRAINT_ATTR_SIZE = 4;
+const std::string CONSTRAINT_ATTRIBUTES[CONSTRAINT_ATTR_SIZE] = 
                       {CONSTRAINT_ATTR_ENTITY_A, CONSTRAINT_ATTR_ENTITY_B, 
                        CONSTRAINT_ATTR_ENTITY_C, CONSTRAINT_ATTR_ENTITY_D};
 
index 8462d99bdea0ca55518a41d6c8fe4efce13b118a..5c71d37791f3c65fae984a133dc9e6c91f2fff00 100644 (file)
@@ -16,6 +16,7 @@ const double PLANE_SIZE = 200;
 
 SketchPlugin_Line::SketchPlugin_Line()
 {
+  setSketch(0);
 }
 
 void SketchPlugin_Line::initAttributes()
@@ -31,17 +32,18 @@ void SketchPlugin_Line::execute()
 const boost::shared_ptr<GeomAPI_Shape>& SketchPlugin_Line::preview()
 {
   SketchPlugin_Sketch* aSketch = sketch();
-  // compute a start point in 3D view
-  boost::shared_ptr<GeomDataAPI_Point2D> aStartAttr = 
-    boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(LINE_ATTR_START));
-  boost::shared_ptr<GeomAPI_Pnt> aStart(aSketch->to3D(aStartAttr->x(), aStartAttr->y()));
-  // compute an end point in 3D view
-  boost::shared_ptr<GeomDataAPI_Point2D> anEndAttr = 
-    boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(LINE_ATTR_END));
-  boost::shared_ptr<GeomAPI_Pnt> anEnd(aSketch->to3D(anEndAttr->x(), anEndAttr->y()));
-  // make linear edge
-  boost::shared_ptr<GeomAPI_Shape> anEdge = GeomAlgoAPI_EdgeBuilder::line(aStart, anEnd);
-  setPreview(anEdge);
-
+  if (aSketch) {
+    // compute a start point in 3D view
+    boost::shared_ptr<GeomDataAPI_Point2D> aStartAttr = 
+      boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(LINE_ATTR_START));
+    boost::shared_ptr<GeomAPI_Pnt> aStart(aSketch->to3D(aStartAttr->x(), aStartAttr->y()));
+    // compute an end point in 3D view
+    boost::shared_ptr<GeomDataAPI_Point2D> anEndAttr = 
+      boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(data()->attribute(LINE_ATTR_END));
+    boost::shared_ptr<GeomAPI_Pnt> anEnd(aSketch->to3D(anEndAttr->x(), anEndAttr->y()));
+    // make linear edge
+    boost::shared_ptr<GeomAPI_Shape> anEdge = GeomAlgoAPI_EdgeBuilder::line(aStart, anEnd);
+    setPreview(anEdge);
+  }
   return getPreview();
 }
index 5d04a4a95d0d3161dc114cd23f86e9ba09218835..70b9fecbbc4b97fcc43737dfc9d4febd20c76781 100644 (file)
@@ -15,12 +15,16 @@ SET(PROJECT_SOURCES
 SET(PROJECT_LIBRARIES
     ${SLVS_LIBRARIES}
     SketchPlugin
+    Events
 )
 
 INCLUDE_DIRECTORIES(
-    ../SketchPlugin
-    ../ModelAPI
-    ../GeomAPI
+    ${PROJECT_SOURCE_DIR}/src/SketchPlugin
+    ${PROJECT_SOURCE_DIR}/src/ModelAPI
+    ${PROJECT_SOURCE_DIR}/src/Model
+    ${PROJECT_SOURCE_DIR}/src/GeomAPI
+    ${PROJECT_SOURCE_DIR}/src/GeomDataAPI
+    ${PROJECT_SOURCE_DIR}/src/Events
 )
 
 ADD_DEFINITIONS(-DSKETCHSOLVER_EXPORTS ${BOOST_DEFINITIONS})
index 7984b031cf8d44cc6c06117439860cf8c72b11ea..bc33e9e5cee91d58ce223d1c04ece095a345abb2 100644 (file)
@@ -4,22 +4,65 @@
 
 #include "SketchSolver_ConstraintManager.h"
 
+#include <Events_Loop.h>
+#include <GeomDataAPI_Dir.h>
+#include <GeomDataAPI_Point.h>
+#include <GeomDataAPI_Point2D.h>
 #include <ModelAPI_AttributeDouble.h>
+#include <ModelAPI_AttributeRefList.h>
 #include <ModelAPI_Data.h>
+#include <Model_Events.h>
 #include <SketchPlugin_Constraint.h>
 #include <SketchPlugin_ConstraintCoincidence.h>
 #include <SketchPlugin_Line.h>
+#include <SketchPlugin_Sketch.h>
 
+SketchSolver_ConstraintManager* SketchSolver_ConstraintManager::_self = 0;
+
+/// Global constaint manager object
+SketchSolver_ConstraintManager* myManager = SketchSolver_ConstraintManager::Instance();
 
 /// This value is used to give unique index to the groups
 static Slvs_hGroup myGroupIndexer = 0;
 
+/** \brief Makes transformation from ModelAPI_Attribute to the list of parameters' values
+ *  \remark Convertion of normal in 3D needs two attributes (coordinate axis of transversal plane)
+ *  \param[in,out] theParams        list of converted values which appended to incoming list
+ *  \param[in]     theAttr          attribute to be converted
+ *  \param[in]     theNormExtraAttr additional attribute for conversion of a normal
+ */
+static void ConvertAttributeToParamList(
+        std::vector<double>&                  theParams, 
+        boost::shared_ptr<ModelAPI_Attribute> theAttr, 
+        boost::shared_ptr<ModelAPI_Attribute> theNormExtraAttr = boost::shared_ptr<ModelAPI_Attribute>());
+
+/** \brief Search the entity/parameter with specified ID in the list of elements
+ *  \param[in] theEntityID unique ID of the element
+ *  \param[in] theEntities list of elements
+ *  \return position of the found element or -1 if the element is not found
+ */
+template <typename T>
+static int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities);
+
+
 // ========================================================
 // ========= SketchSolver_ConstraintManager ===============
 // ========================================================
+SketchSolver_ConstraintManager* SketchSolver_ConstraintManager::Instance()
+{
+  if (!_self)
+    _self = new SketchSolver_ConstraintManager();
+  return _self;
+}
+
 SketchSolver_ConstraintManager::SketchSolver_ConstraintManager()
 {
   myGroups.clear();
+
+  // Register in event loop
+  Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_CREATED));
+  Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_UPDATED));
+  Events_Loop::loop()->registerListener(this, Events_Loop::eventByName(EVENT_FEATURE_DELETED));
 }
 
 SketchSolver_ConstraintManager::~SketchSolver_ConstraintManager()
@@ -27,6 +70,131 @@ SketchSolver_ConstraintManager::~SketchSolver_ConstraintManager()
   myGroups.clear();
 }
 
+void SketchSolver_ConstraintManager::processEvent(const Events_Message* theMessage)
+{
+  if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_CREATED))
+  {
+    const Model_FeatureUpdatedMessage* aCreateMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
+
+    // Only sketches and constraints can be added by Create event
+    boost::shared_ptr<SketchPlugin_Sketch> aSketch = 
+      boost::dynamic_pointer_cast<SketchPlugin_Sketch>(aCreateMsg->feature());
+    if (aSketch)
+    {
+      addWorkplane(aSketch);
+      return ;
+    }
+    boost::shared_ptr<SketchPlugin_Constraint> aConstraint = 
+      boost::dynamic_pointer_cast<SketchPlugin_Constraint>(aCreateMsg->feature());
+    if (aConstraint)
+    {
+      addConstraint(aConstraint);
+      return ;
+    }
+  }
+  else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_DELETED))
+  {
+    const Model_FeatureDeletedMessage* aDeleteMsg = dynamic_cast<const Model_FeatureDeletedMessage*>(theMessage);
+    /// \todo Implement deleting objects on event
+  }
+  else if (theMessage->eventID() == Events_Loop::loop()->eventByName(EVENT_FEATURE_UPDATED))
+  {
+    const Model_FeatureUpdatedMessage* aUpdateMsg = dynamic_cast<const Model_FeatureUpdatedMessage*>(theMessage);
+
+    boost::shared_ptr<SketchPlugin_Sketch> aSketch = 
+      boost::dynamic_pointer_cast<SketchPlugin_Sketch>(aUpdateMsg->feature());
+    if (aSketch)
+    {
+      updateWorkplane(aSketch);
+      return ;
+    }
+
+    boost::shared_ptr<SketchPlugin_Constraint> aConstraint = 
+      boost::dynamic_pointer_cast<SketchPlugin_Constraint>(aUpdateMsg->feature());
+    if (aConstraint)
+    {
+//      updateConstraint(aConstraint);
+      return ;
+    }
+
+    boost::shared_ptr<SketchPlugin_Feature> aFeature = 
+      boost::dynamic_pointer_cast<SketchPlugin_Feature>(aUpdateMsg->feature());
+//    if (aFeature)
+//      updateEntity(aFeature);
+  }
+}
+
+
+bool SketchSolver_ConstraintManager::addWorkplane(boost::shared_ptr<SketchPlugin_Sketch> theSketch)
+{
+  // Check the specified workplane is already used
+  std::vector<SketchSolver_ConstraintGroup>::const_iterator aGroupIter;
+  for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
+    if (aGroupIter->isBaseWorkplane(theSketch))
+      return true;
+  // Create new group for workplane
+  SketchSolver_ConstraintGroup aNewGroup(theSketch);
+  // Verify that the group is created successfully
+  if (!aNewGroup.isBaseWorkplane(theSketch))
+    return false;
+  myGroups.push_back(aNewGroup);
+  return true;
+}
+
+bool SketchSolver_ConstraintManager::updateWorkplane(boost::shared_ptr<SketchPlugin_Sketch> theSketch)
+{
+  bool aResult = true; // changed when a workplane wrongly updated
+  bool isUpdated = false;
+  // Try to update specified workplane in all groups
+  std::vector<SketchSolver_ConstraintGroup>::iterator aGroupIter;
+  for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
+    if (aGroupIter->isBaseWorkplane(theSketch))
+    {
+      isUpdated = true;
+      if (!aGroupIter->updateWorkplane(theSketch))
+        aResult = false;
+    }
+  // If the workplane is not updates, so this is a new workplane
+  if (!isUpdated)
+    return addWorkplane(theSketch);
+  return aResult;
+}
+
+bool SketchSolver_ConstraintManager::addConstraint(
+              boost::shared_ptr<SketchPlugin_Constraint> theConstraint)
+{
+  // Search the groups which this constraint touchs
+  std::vector<Slvs_hGroup> aGroups;
+  findGroups(theConstraint, aGroups);
+
+  // Process the groups list
+  if (aGroups.size() == 0)
+  { // There are no groups applicable for this constraint => create new one
+    boost::shared_ptr<SketchPlugin_Sketch> aWP = findWorkplaneForConstraint(theConstraint);
+    if (!aWP) return false;
+    SketchSolver_ConstraintGroup aGroup(aWP);
+    aGroup.addConstraint(theConstraint);
+    myGroups.push_back(aGroup);
+    return true;
+  }
+  else if (aGroups.size() == 1)
+  { // Only one group => add constraint into it
+    Slvs_hGroup aGroupId = *(aGroups.begin());
+    std::vector<SketchSolver_ConstraintGroup>::iterator aGroupIter;
+    for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
+      if (aGroupIter->getId() == aGroupId)
+        return aGroupIter->addConstraint(theConstraint);
+  }
+  else if (aGroups.size() > 1)
+  { // Several groups applicable for this constraint => need to merge them
+    /// \todo Implement merging of groups
+  }
+
+  // Something goes wrong
+  return false;
+}
+
+
 void SketchSolver_ConstraintManager::findGroups(
               boost::shared_ptr<SketchPlugin_Constraint> theConstraint, 
               std::vector<Slvs_hGroup>&                  theGroupIDs) const
@@ -37,12 +205,33 @@ void SketchSolver_ConstraintManager::findGroups(
       theGroupIDs.push_back(aGroupIter->getId());
 }
 
+boost::shared_ptr<SketchPlugin_Sketch> SketchSolver_ConstraintManager::findWorkplaneForConstraint(
+              boost::shared_ptr<SketchPlugin_Constraint> theConstraint) const
+{
+  std::vector<SketchSolver_ConstraintGroup>::const_iterator aGroupIter;
+  for (aGroupIter = myGroups.begin(); aGroupIter != myGroups.end(); aGroupIter++)
+  {
+    boost::shared_ptr<SketchPlugin_Sketch> aWP = aGroupIter->getWorkplane();
+    boost::shared_ptr<ModelAPI_AttributeRefList> aWPFeatures = 
+      boost::dynamic_pointer_cast<ModelAPI_AttributeRefList>(aWP->data()->attribute(SKETCH_ATTR_FEATURES));
+    std::list< boost::shared_ptr<ModelAPI_Feature> > aFeaturesList = aWPFeatures->list();
+    std::list< boost::shared_ptr<ModelAPI_Feature> >::const_iterator anIter;
+    for (anIter = aFeaturesList.begin(); anIter != aFeaturesList.end(); anIter++)
+      if (*anIter == theConstraint)
+        return aWP; // workplane is found
+  }
+
+  return boost::shared_ptr<SketchPlugin_Sketch>();
+}
+
+
 
 // ========================================================
 // =========  SketchSolver_ConstraintGroup  ===============
 // ========================================================
 
-SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::SketchSolver_ConstraintGroup()
+SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::
+  SketchSolver_ConstraintGroup(boost::shared_ptr<SketchPlugin_Sketch> theWorkplane)
   : myID(++myGroupIndexer),
     myParamMaxID(0),
     myEntityMaxID(0),
@@ -53,14 +242,15 @@ SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::SketchSolver_Const
   myEntities.clear();
   myConstraints.clear();
 
-  // The workplane will be initialized on first constraint, so its handle is NULL meanwhile
-  myWorkplane.h = 0;
-
   // Nullify all elements of the set of equations
   myConstrSet.param = 0;
   myConstrSet.entity = 0;
   myConstrSet.constraint = 0;
   myConstrSet.failed = 0;
+
+  // Initialize workplane
+  myWorkplane.h = 0;
+  addWorkplane(theWorkplane);
 }
 
 SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::~SketchSolver_ConstraintGroup()
@@ -80,6 +270,12 @@ SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::~SketchSolver_Cons
     delete [] myConstrSet.failed;
 }
 
+bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::isBaseWorkplane(
+                boost::shared_ptr<SketchPlugin_Sketch> theWorkplane) const
+{
+  return theWorkplane == mySketch;
+}
+
 bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::isInteract(
                 boost::shared_ptr<SketchPlugin_Constraint> theConstraint) const
 {
@@ -90,45 +286,36 @@ bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::isInteract(
 bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addConstraint(
                 boost::shared_ptr<SketchPlugin_Constraint> theConstraint)
 {
+  // There is no workplane yet, something wrong
   if (myWorkplane.h == 0)
-  {
-//    // Create workplane when first constraint is added
-//    std::list< boost::shared_ptr<ModelAPI_Attribute> > aWPAttr;
-//    theConstraint->getSketchParameters(aWPAttr);
-//    if (!addWorkplane(aWPAttr))
-//      return false;
-  }
+    return false;
+
+  // Get constraint type and verify the constraint parameters are correct
+  int aConstrType = getConstraintType(theConstraint);
+  if (aConstrType == SLVS_C_UNKNOWN)
+    return false;
 
   // Create constraint parameters
   double aDistance = 0.0; // scalar value of the constraint
   boost::shared_ptr<ModelAPI_AttributeDouble> aDistAttr =
     boost::dynamic_pointer_cast<ModelAPI_AttributeDouble>(theConstraint->data()->attribute(CONSTRAINT_ATTR_VALUE));
-  if (aDistAttr.get())
+  if (aDistAttr)
     aDistance = aDistAttr->value();
 
-  /// \todo Specify the entities
-  Slvs_hEntity aPtA, aPtB, aEntityA, aEntityB; // parameters of the constraint
-  boost::shared_ptr<ModelAPI_Attribute> aEntAttr = theConstraint->data()->attribute(CONSTRAINT_ATTR_ENTITY_A);
-  aPtA = addEntity(aEntAttr);
-  if (aPtA == 0) return false;
-  aEntAttr = theConstraint->data()->attribute(CONSTRAINT_ATTR_ENTITY_B);
-  aPtB = addEntity(aEntAttr);
-  if (aPtB == 0) return false;
-  aEntAttr = theConstraint->data()->attribute(CONSTRAINT_ATTR_ENTITY_C);
-  aEntityA = addEntity(aEntAttr);
-  if (aEntityA == 0) return false;
-  aEntAttr = theConstraint->data()->attribute(CONSTRAINT_ATTR_ENTITY_D);
-  aEntityB = addEntity(aEntAttr);
-  if (aEntityB == 0) return false;
-
-  // Constraint type
-  int aConstrType = getConstraintType(theConstraint);
-  if (aConstrType == 0) return false;
+  Slvs_hEntity aConstrEnt[CONSTRAINT_ATTR_SIZE]; // parameters of the constraint
+  for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++)
+  {
+    boost::shared_ptr<ModelAPI_AttributeRefAttr> aConstrAttr = 
+      boost::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+        theConstraint->data()->attribute(CONSTRAINT_ATTRIBUTES[indAttr])
+      );
+    aConstrEnt[indAttr] = addEntity(aConstrAttr->attr());
+  }
 
   // Create SolveSpace constraint structure
   Slvs_Constraint aConstraint = 
     Slvs_MakeConstraint(++myConstrMaxID, myID, aConstrType, myWorkplane.h, 
-                        aDistance, aPtA, aPtB, aEntityA, aEntityB);
+                        aDistance, aConstrEnt[0], aConstrEnt[1], aConstrEnt[2], aConstrEnt[3]);
   myConstraints.push_back(aConstraint);
   myConstraintMap[theConstraint] = *(myConstraints.rbegin());
 
@@ -138,57 +325,250 @@ bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addConstraint
 Slvs_hEntity SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addEntity(
                 boost::shared_ptr<ModelAPI_Attribute> theEntity)
 {
-  /// \todo Should be implemented
+  // Look over supported types of entities
+
+  // Point in 3D
+  boost::shared_ptr<GeomDataAPI_Point> aPoint = 
+    boost::dynamic_pointer_cast<GeomDataAPI_Point>(theEntity);
+  if (aPoint)
+  {
+    Slvs_hParam aX = addParameter(aPoint->x());
+    Slvs_hParam aY = addParameter(aPoint->y());
+    Slvs_hParam aZ = addParameter(aPoint->z());
+    Slvs_Entity aPtEntity = Slvs_MakePoint3d(++myEntityMaxID, myID, aX, aY, aZ);
+    myEntities.push_back(aPtEntity);
+    return aPtEntity.h;
+  }
+
+  // Point in 2D
+  boost::shared_ptr<GeomDataAPI_Point2D> aPoint2D = 
+    boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(theEntity);
+  if (aPoint2D)
+  {
+    // The 2D points are created on workplane. So, if there is no workplane yet, then error
+    if (myWorkplane.h == 0)
+      return 0;
+    Slvs_hParam aU = addParameter(aPoint2D->x());
+    Slvs_hParam aV = addParameter(aPoint2D->y());
+    Slvs_Entity aPt2DEntity = Slvs_MakePoint2d(++myEntityMaxID, myID, myWorkplane.h, aU, aV);
+    myEntities.push_back(aPt2DEntity);
+    return aPt2DEntity.h;
+  }
+
+  /// \todo Other types of entities
+  
+  // Unsupported or wrong entity type
   return 0;
 }
 
+Slvs_hEntity SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addNormal(
+                boost::shared_ptr<ModelAPI_Attribute> theDirX, 
+                boost::shared_ptr<ModelAPI_Attribute> theDirY)
+{
+  // Convert axes to the coordinates of normal
+  std::vector<double> aNormCoord;
+  ConvertAttributeToParamList(aNormCoord, theDirX, theDirY);
+  
+  // Create a normal
+  Slvs_hParam aNormParams[4];
+  for (int i = 0; i < 4; i++)
+    aNormParams[i] = addParameter(aNormCoord[i]);
+  Slvs_Entity aNormal = Slvs_MakeNormal3d(++myEntityMaxID, myID, 
+                aNormParams[0], aNormParams[1], aNormParams[2], aNormParams[3]);
+  myEntities.push_back(aNormal);
+  return aNormal.h;
+}
+
+
 bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addWorkplane(
-                std::list< boost::shared_ptr<ModelAPI_Attribute> >& theParams)
+                boost::shared_ptr<SketchPlugin_Sketch> theSketch)
 {
-  /// \todo Should be implemented
-  return false;
+  if (myWorkplane.h)
+    return false; // the workplane already exists
+
+  // Get parameters of workplane
+  boost::shared_ptr<ModelAPI_Attribute> aDirX    = theSketch->data()->attribute(SKETCH_ATTR_DIRX);
+  boost::shared_ptr<ModelAPI_Attribute> aDirY    = theSketch->data()->attribute(SKETCH_ATTR_DIRY);
+  boost::shared_ptr<ModelAPI_Attribute> anOrigin = theSketch->data()->attribute(SKETCH_ATTR_ORIGIN);
+  // Transform them into SolveSpace format
+  Slvs_hEntity aNormalWP = addNormal(aDirX, aDirY);
+  if (!aNormalWP) return false;
+  Slvs_hEntity anOriginWP = addEntity(anOrigin);
+  if (!anOriginWP) return false;
+  // Create workplane
+  myWorkplane = Slvs_MakeWorkplane(++myEntityMaxID, myID, anOriginWP, aNormalWP);
+  mySketch = theSketch;
+  // Workplane should be added to the list of entities
+  myEntities.push_back(myWorkplane);
+  return true;
+}
+
+bool SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::updateWorkplane(
+                boost::shared_ptr<SketchPlugin_Sketch> theSketch)
+{
+  // Renew Sketch pointer
+  mySketch = theSketch;
+
+  // Get parameters of workplane
+  boost::shared_ptr<ModelAPI_Attribute> aDirX  = theSketch->data()->attribute(SKETCH_ATTR_DIRX);
+  boost::shared_ptr<ModelAPI_Attribute> aDirY  = theSketch->data()->attribute(SKETCH_ATTR_DIRY);
+  boost::shared_ptr<ModelAPI_Attribute> anOrig = theSketch->data()->attribute(SKETCH_ATTR_ORIGIN);
+  // Transform them to lists of coordinates
+  std::vector<double> aNormal;
+  ConvertAttributeToParamList(aNormal, aDirX, aDirY);
+  std::vector<double> anOrigin;
+  ConvertAttributeToParamList(anOrigin, anOrig);
+
+  // Search the normal and the origin in the parameters list and update their values.
+  // Remark: entities are sorted in the vector, so the most probable position 
+  //         of the entity is equal to identifier the entity
+  
+  // search normal
+  int aEntPos = Search(myWorkplane.normal, myEntities);
+  if (aEntPos < 0) return false;
+  // search first parameter of normal
+  int aParamPos = Search(myEntities[aEntPos].param[0], myParams);
+  if (aParamPos < 0) return false;
+  std::vector<Slvs_Param>::iterator aParamIter = myParams.begin() + aParamPos;
+  // change normal parameters
+  std::vector<double>::iterator anIter;
+  for (anIter = aNormal.begin(); anIter != aNormal.end(); anIter++, aParamIter++)
+    aParamIter->val = *anIter;
+
+  // search origin
+  aEntPos = Search(myWorkplane.point[0], myEntities);
+  if (aEntPos < 0) return false;
+  // search first parameter of origin
+  aParamPos = Search(myEntities[aEntPos].param[0], myParams);
+  if (aParamPos < 0) return false;
+  aParamIter = myParams.begin() + aParamPos;
+  // change origin's parameters
+  for (anIter = anOrigin.begin(); anIter != anOrigin.end(); anIter++, aParamIter++)
+    aParamIter->val = *anIter;
+
+  return true;
+}
+
+
+Slvs_hParam SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::addParameter(double theParam)
+{
+  Slvs_Param aParam = Slvs_MakeParam(++myParamMaxID, myID, theParam);
+  myParams.push_back(aParam);
+  return aParam.h;
 }
 
 int SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup::getConstraintType(
                 const boost::shared_ptr<SketchPlugin_Constraint>& theConstraint) const
 {
-//  if (theConstraint->getKind() == SketchPlugin_ConstraintDistance().getKind())
-//  {
-//    boost::shared_ptr<ModelAPI_Attribute> aPtA  = theConstraint->data()->attribute(CONSTRAINT_ATTR_POINT_A);
-//    boost::shared_ptr<ModelAPI_Attribute> aPtB  = theConstraint->data()->attribute(CONSTRAINT_ATTR_POINT_B);
-//    boost::shared_ptr<ModelAPI_Attribute> aEntA = theConstraint->data()->attribute(CONSTRAINT_ATTR_ENTITY_A);
-//    boost::shared_ptr<ModelAPI_Attribute> aEntB = theConstraint->data()->attribute(CONSTRAINT_ATTR_ENTITY_B);
-//    boost::shared_ptr<ModelAPI_AttributeDouble> aDistance = 
-//      boost::shared_dynamic_cast<ModelAPI_AttributeDouble>(theConstraint->data()->attribute(CONSTRAINT_ATTR_VALUE));
-//    if (aPtA.get()) // ptA is an attribute of the constraint
-//    {
-////      if (aEntA.get()) // entityA is an attribute of the constraint
-////      {
-////        if (aEntA->feature()->getKind() == SketchPlugin_Line().getKind()) // entityA is a line
-////        {
-////          if (aEntB.get() && aEntB->feature()->getKind() == SketchPlugin_Line().getKind()) // entityB is a line too
-////            return SLVS_C_ANGLE;
-////          else if (aPtB.get()) // ptB is also an attribute of the constraint
-////            return SLVS_C_PROJ_PT_DISTANCE;
-////          else
-////            return SLVS_C_PT_LINE_DISTANCE;
-////        }
-////        /// \todo Implement other point-entity distances
-////      }
-////      else 
-//      if (aPtB.get()) // ptB is an attribute of the constrtaint => point-point distance
-//      {
-//        if (aDistance->value() == 0.0)
-//          return SLVS_C_POINTS_COINCIDENT;
-//        else 
-//          return SLVS_C_PT_PT_DISTANCE;
-//      }
-//    }
-//    else if (aEntA.get() && !aEntB.get() && !aPtB.get())
-//      return SLVS_C_DIAMETER;
-//    return SLVS_C_UNKNOWN;
-//  }
+  // Constraint for coincidence of two points
+  boost::shared_ptr<SketchPlugin_ConstraintCoincidence> aPtEquiv = 
+    boost::dynamic_pointer_cast<SketchPlugin_ConstraintCoincidence>(theConstraint);
+  if (aPtEquiv)
+  {
+    // Verify the constraint has only two attributes and they are points
+    int aPt2d = 0; // bit-mapped field, each bit indicates whether the attribute is 2D point 
+    int aPt3d = 0; // bit-mapped field, the same information for 3D points
+    for (unsigned int indAttr = 0; indAttr < CONSTRAINT_ATTR_SIZE; indAttr++)
+    {
+      boost::shared_ptr<ModelAPI_AttributeRefAttr> anAttr = 
+        boost::dynamic_pointer_cast<ModelAPI_AttributeRefAttr>(
+          theConstraint->data()->attribute(CONSTRAINT_ATTRIBUTES[indAttr])
+        );
+      // Verify the attribute is a 2D point
+      boost::shared_ptr<GeomDataAPI_Point2D> aPoint2D = 
+        boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(anAttr->attr());
+      if (aPoint2D)
+      {
+        aPt2d |= (1 << indAttr);
+        continue;
+      }
+      // Verify the attribute is a 3D point
+      boost::shared_ptr<GeomDataAPI_Point> aPoint3D = 
+        boost::dynamic_pointer_cast<GeomDataAPI_Point>(anAttr->attr());
+      if (aPoint3D)
+      {
+        aPt3d |= (1 << indAttr);
+        continue;
+      }
+      // Attribute neither 2D nor 3D point is not supported by this type of constraint
+      return SLVS_C_UNKNOWN;
+    }
+    // The constrained points should be in first and second positions,
+    // so the expected value of aPt2d or aPt3d is 3
+    if ((aPt2d == 3 && aPt3d == 0) || (aPt2d == 0 && aPt3d == 3))
+      return SLVS_C_POINTS_COINCIDENT;
+    // Constraint parameters are wrong
+    return SLVS_C_UNKNOWN;
+  }
+
   /// \todo Implement other kind of constrtaints
 
   return SLVS_C_UNKNOWN;
 }
+
+
+
+// ========================================================
+// =========      Auxiliary functions       ===============
+// ========================================================
+
+void ConvertAttributeToParamList(
+                std::vector<double>&                  theParams, 
+                boost::shared_ptr<ModelAPI_Attribute> theAttr, 
+                boost::shared_ptr<ModelAPI_Attribute> theNormExtraAttr)
+{
+  // Point in 3D
+  boost::shared_ptr<GeomDataAPI_Point> aPoint = 
+    boost::dynamic_pointer_cast<GeomDataAPI_Point>(theAttr);
+  if (aPoint)
+  {
+    theParams.push_back(aPoint->x());
+    theParams.push_back(aPoint->y());
+    theParams.push_back(aPoint->z());
+    return ;
+  }
+
+  // Point in 2D
+  boost::shared_ptr<GeomDataAPI_Point2D> aPoint2D = 
+    boost::dynamic_pointer_cast<GeomDataAPI_Point2D>(theAttr);
+  if (aPoint2D)
+  {
+    theParams.push_back(aPoint2D->x());
+    theParams.push_back(aPoint2D->y());
+    return ;
+  }
+
+  // Normal in 3D
+  boost::shared_ptr<GeomDataAPI_Dir> aDirX = 
+    boost::dynamic_pointer_cast<GeomDataAPI_Dir>(theAttr);
+  boost::shared_ptr<GeomDataAPI_Dir> aDirY = 
+    boost::dynamic_pointer_cast<GeomDataAPI_Dir>(theNormExtraAttr);
+  if (aDirX && aDirY)
+  {
+    // quaternion parameters of normal vector
+    double qw, qx, qy, qz;
+    Slvs_MakeQuaternion(aDirX->x(), aDirX->y(), aDirX->z(), 
+                        aDirY->x(), aDirY->y(), aDirY->z(), 
+                        &qw, &qx, &qy, &qz);
+    theParams.push_back(qw);
+    theParams.push_back(qx);
+    theParams.push_back(qy);
+    theParams.push_back(qz);
+  }
+
+  /// \todo Other types of entities
+}
+
+template <typename T>
+int Search(const uint32_t& theEntityID, const std::vector<T>& theEntities)
+{
+  std::vector<T>::const_iterator aEntIter = theEntities.begin() + theEntityID - 1;
+  while (aEntIter != theEntities.end() && aEntIter->h > theEntityID)
+    aEntIter--;
+  while (aEntIter != theEntities.end() && aEntIter->h < theEntityID)
+    aEntIter++;
+  if (aEntIter == theEntities.end())
+    return -1;
+  return aEntIter - theEntities.begin();
+}
+
index 7bd108df6f62ad480d2a563bbc976de6e99a5959..e44cb6444b040a1b3b6e1b789c903e3043b1bea2 100644 (file)
@@ -7,6 +7,7 @@
 
 #include "SketchSolver.h"
 
+#include <Events_Listener.h>
 #include <SketchPlugin_Constraint.h>
 
 // Need to be defined before including SolveSpace to avoid additional dependances on Windows platform
@@ -25,15 +26,29 @@ typedef unsigned int UINT32;
 
 /** \class   SketchSolver_ConstraintManager
  *  \ingroup DataModel
- *  \brief   Transforms the Constraint feature into the format understandable by SolveSpace library.
+ *  \brief   Listens the changes of SketchPlugin features and transforms the Constraint 
+ *           feature into the format understandable by SolveSpace library.
  *
- *  Constraints created for SolveSpace library will be divided into the groups.
+ *  Constraints created for SolveSpace library are divided into the groups.
  *  The division order based on connectedness of the features by the constraints.
  *  The groups may be fused or separated according to the new constraints.
+ *
+ *  \remark This is a singleton.
  */
-class SketchSolver_ConstraintManager
+class SketchSolver_ConstraintManager : public Events_Listener
 {
 public:
+  /** \brief Main method to create constraint manager
+   *  \return pointer to the singleton
+   */
+  static SketchSolver_ConstraintManager* Instance();
+
+  /** \brief Implementation of Event Listener method
+   *  \param[in] theMessage the data of the event
+   */
+  virtual void processEvent(const Events_Message* theMessage);
+
+protected:
   SketchSolver_ConstraintManager();
   ~SketchSolver_ConstraintManager();
 
@@ -41,13 +56,44 @@ public:
    *  \param[in] theConstraint constraint to be added
    *  \return \c true if the constraint added successfully
    */
-  SKETCHSOLVER_EXPORT bool addConstraint(boost::shared_ptr<SketchPlugin_Constraint> theConstraint);
+  bool addConstraint(boost::shared_ptr<SketchPlugin_Constraint> theConstraint);
 
   /** \brief Removes a constraint from the manager
    *  \param[in] theConstraint constraint to be removed
    *  \return \c true if the constraint removed successfully
    */
-  SKETCHSOLVER_EXPORT bool removeConstraint(boost::shared_ptr<SketchPlugin_Constraint> theConstraint);
+  bool removeConstraint(boost::shared_ptr<SketchPlugin_Constraint> theConstraint);
+
+  /** \brief Updates a constraint
+   *  \param[in] theConstraint constraint to be updated
+   *  \return \c true if the constraint was updated
+   */
+  bool updateConstraint(boost::shared_ptr<SketchPlugin_Constraint> theConstraint);
+
+  /** \brief Adds a workplane into the manager
+   *  \param[in] theSketch the feature to create workplane
+   *  \return \c true if the workplane added successfully
+   */
+  bool addWorkplane(boost::shared_ptr<SketchPlugin_Sketch> theSketch);
+
+  /** \brief Removes a workplane from the manager. 
+   *         All groups based on such workplane will be removed too.
+   *  \param[in] theSketch the feature to be removed
+   *  \return \c true if the workplane removed successfully
+   */
+  bool removeWorkplane(boost::shared_ptr<SketchPlugin_Sketch> theSketch);
+
+  /** \brief Updates a workplane
+   *  \param[in] theSketch workplane to be updated
+   *  \return \c true if the workplane was updated
+   */
+  bool updateWorkplane(boost::shared_ptr<SketchPlugin_Sketch> theSketch);
+
+  /** \brief Updates entity which is neither workplane nor constraint
+   *  \param[in] theFeature entity to be updated
+   *  \return \c true if the entity updated successfully
+   */
+  bool updateEntity(boost::shared_ptr<SketchPlugin_Feature> theFeature);
 
 private:
   class SketchSolver_ConstraintGroup;
@@ -59,8 +105,16 @@ private:
   void findGroups(boost::shared_ptr<SketchPlugin_Constraint> theConstraint, 
                   std::vector<Slvs_hGroup>&                  theGroupIDs) const;
 
+  /** \brief Searches in the list of groups the workplane which constains specified constraint
+   *  \param[in] theConstraint constraint to be found
+   *  \return workplane contains the constraint
+   */
+  boost::shared_ptr<SketchPlugin_Sketch> findWorkplaneForConstraint(
+                  boost::shared_ptr<SketchPlugin_Constraint> theConstraint) const;
+
 private:
-  std::vector<SketchSolver_ConstraintGroup> myGroups; ///< groups of constraints
+  static SketchSolver_ConstraintManager*    _self;    ///< Self pointer to implement singleton functionality
+  std::vector<SketchSolver_ConstraintGroup> myGroups; ///< Groups of constraints
 };
 
 
@@ -71,7 +125,10 @@ private:
 class SketchSolver_ConstraintManager::SketchSolver_ConstraintGroup
 {
 public:
-  SketchSolver_ConstraintGroup();
+  /** \brief New group based on specified workplane
+   */
+  SketchSolver_ConstraintGroup(boost::shared_ptr<SketchPlugin_Sketch> theWorkplane);
+
   ~SketchSolver_ConstraintGroup();
 
   /// \brief Returns group's unique identifier
@@ -96,19 +153,47 @@ public:
    */
   bool isInteract(boost::shared_ptr<SketchPlugin_Constraint> theConstraint) const;
 
-protected:
-  /** \brief Creates a workplane from the sketch parameters
-   *  \param[in] theParams list of the basic parameters of the workplane
-   *  \return \c true if success
+  /** \brief Verifies the specified workplane is the same as a base workplane for this group
+   *  \param[in] theWorkplane workplane to be compared
+   *  \return \c true if workplanes are the same
+   */
+  bool isBaseWorkplane(boost::shared_ptr<SketchPlugin_Sketch> theWorkplane) const;
+
+  boost::shared_ptr<SketchPlugin_Sketch> getWorkplane() const
+  { return mySketch; }
+
+  /** \brief Update parameters of workplane. Should be called when Update event is coming
+   *  \param[in] theWorkplane workplane to be updated
+   *  \return \c true if workplane updated successfully
    */
-  bool addWorkplane(std::list< boost::shared_ptr<ModelAPI_Attribute> >& theParams);
+  bool updateWorkplane(boost::shared_ptr<SketchPlugin_Sketch> theWorkplane);
 
+protected:
   /** \brief Adds an entity into the group
+   *
+   *  The parameters of entity will be parsed and added to the list of SolveSpace parameters.
+   *  Parameters of certain entity will be placed sequentially in the list.
+   *
    *  \param[in] theEntity the object of constraint
    *  \return identifier of created entity or 0 if entity was not added
    */
   Slvs_hEntity addEntity(boost::shared_ptr<ModelAPI_Attribute> theEntity);
 
+  /** \brief Adds a normal into the group
+   *
+   *  Normal is a special entity in SolveSpace, which defines a direction in 3D and 
+   *  a rotation about this direction. So, SolveSpace represents normals as unit quaternions.
+   *
+   *  To define a normal there should be specified two coordinate axis 
+   *  on the plane transversed to created normal.
+   *
+   *  \param[in] theDirX first coordinate axis of the plane
+   *  \param[in] theDirY second coordinate axis of the plane
+   *  \return identifier of created normal
+   */
+  Slvs_hEntity addNormal(boost::shared_ptr<ModelAPI_Attribute> theDirX, 
+                         boost::shared_ptr<ModelAPI_Attribute> theDirY);
+
   /** \brief Adds a parameter into the group
    *  \param[in] theParam parameter to be added
    *  \return identifier of created parameter or 0 if it was not added
@@ -116,21 +201,33 @@ protected:
   Slvs_hParam addParameter(double theParam);
 
   /** \brief Compute constraint type according to SolveSpace identifiers
+   *         and verify that constraint parameters are correct
    *  \param[in] theConstraint constraint which type should be determined
-   *  \return identifier of constraint type
+   *  \return identifier of constraint type or SLVS_C_UNKNOWN if the type is wrong
    */
   int getConstraintType(const boost::shared_ptr<SketchPlugin_Constraint>& theConstraint) const;
 
 private:
+  /** \brief Creates a workplane from the sketch parameters
+   *  \param[in] theSketch parameters of workplane are the attributes of this sketch
+   *  \return \c true if success
+   */
+  bool addWorkplane(boost::shared_ptr<SketchPlugin_Sketch> theSketch);
+
+private:
+  // SolveSpace entities
   Slvs_hGroup                  myID;            ///< the index of the group
   Slvs_Entity                  myWorkplane;     ///< Workplane for the current group
   std::vector<Slvs_Param>      myParams;        ///< List of parameters of the constraints
-  Slvs_hParam                  myParamMaxID;    ///< Actual maximal ID of parameters
+  Slvs_hParam                  myParamMaxID;    ///< Actual maximal ID of parameters (not equal to myParams size)
   std::vector<Slvs_Entity>     myEntities;      ///< List of entities of the constaints
-  Slvs_hEntity                 myEntityMaxID;   ///< Actual maximal ID of entities
+  Slvs_hEntity                 myEntityMaxID;   ///< Actual maximal ID of entities (not equal to myEntities size)
   std::vector<Slvs_Constraint> myConstraints;   ///< List of constraints in SolveSpace format
-  Slvs_hConstraint             myConstrMaxID;   ///< Actual maximal ID of constraints
+  Slvs_hConstraint             myConstrMaxID;   ///< Actual maximal ID of constraints (not equal to myConstraints size)
   Slvs_System                  myConstrSet;     ///< SolveSpace's set of equations obtained by constraints
+
+  // SketchPlugin entities
+  boost::shared_ptr<SketchPlugin_Sketch> mySketch; ///< Equivalent to workplane
   std::map<boost::shared_ptr<SketchPlugin_Constraint>, Slvs_Constraint> 
                                myConstraintMap; ///< The map between SketchPlugin and SolveSpace constraints
 };
index 20a6f721e9f38e7285b3440405e7e18a2edf67e5..2613adae6bbc9ab20b77f31e8b3f5e49b7bb6e75 100644 (file)
@@ -141,6 +141,26 @@ void XGUI_Displayer::RedisplayInLocalContext(boost::shared_ptr<ModelAPI_Feature>
     aContext->UpdateCurrentViewer();
 }
 
+void XGUI_Displayer::EraseAll(const bool isUpdateViewer)
+{
+  Handle(AIS_InteractiveContext) ic = AISContext();
+
+  AIS_ListOfInteractive aList;
+  ic->DisplayedObjects(aList);
+  AIS_ListIteratorOfListOfInteractive anIter(aList);
+  for (; anIter.More(); anIter.Next()) {
+    if ((anIter.Value()->DynamicType() == STANDARD_TYPE(AIS_Trihedron)))
+      continue;
+
+    // erase an object
+    Handle(AIS_InteractiveObject) anIO = anIter.Value();
+    ic->Erase(anIO, false);
+  }
+  myFeature2AISObjectMap.clear();
+  if (isUpdateViewer)
+    ic->UpdateCurrentViewer();
+}
+
 void XGUI_Displayer::CloseLocalContexts(const bool isUpdateViewer)
 {
   closeAllContexts(true);
@@ -156,6 +176,13 @@ void XGUI_Displayer::closeAllContexts(const bool isUpdateViewer)
   }
 }
 
+void XGUI_Displayer::UpdateViewer()
+{
+  Handle(AIS_InteractiveContext) ic = AISContext();
+  if (!ic.IsNull())
+    ic->UpdateCurrentViewer();
+}
+
 Handle(AIS_InteractiveContext) XGUI_Displayer::AISContext() const 
 { 
   return myWorkshop->viewer()->AISContext(); 
index cda9331e648489f658a302927900d3a2af8e1d3d..a8bfbe2f35d0d2364befa48b2b01163bf6deb4ea 100644 (file)
@@ -81,10 +81,17 @@ public:
   /// \param isUpdateViewer the parameter whether the viewer should be update immediatelly
   void Erase(boost::shared_ptr<ModelAPI_Feature> theFeature, const bool isUpdateViewer = true);
 
+  /// Erase all presentations
+  /// \param isUpdateViewer the parameter whether the viewer should be update immediatelly
+  void EraseAll(const bool isUpdateViewer = true);
+
   /// Deactivates selection of sub-shapes
   /// \param isUpdateViewer the parameter whether the viewer should be update immediatelly
   void CloseLocalContexts(const bool isUpdateViewer = true);
 
+  /// Updates the viewer
+  void UpdateViewer();
+
 protected:
   /// Deactivate local selection
   /// \param isUpdateViewer the state wether the viewer should be updated immediatelly
index 7119a8fa19cbf726c364190dd736e9d70cef6f74..00419c69238d19063e84d0aa1c41cb39cce61bf2 100644 (file)
@@ -46,6 +46,16 @@ bool XGUI_OperationMgr::startOperation(ModuleBase_Operation* theOperation)
   return true;
 }
 
+bool XGUI_OperationMgr::abortOperation()
+{
+  ModuleBase_Operation* aCurrentOp = currentOperation();
+  if (!aCurrentOp || !canStopOperation())
+    return false; 
+
+  aCurrentOp->abort();
+  return true;
+}
+
 void XGUI_OperationMgr::resumeOperation(ModuleBase_Operation* theOperation)
 {
   connect(theOperation, SIGNAL(stopped()), this, SLOT(onOperationStopped()));
@@ -60,10 +70,7 @@ bool XGUI_OperationMgr::canStartOperation(ModuleBase_Operation* theOperation)
   ModuleBase_Operation* aCurrentOp = currentOperation();
   if (aCurrentOp && !theOperation->isGranted())
   {
-    int anAnswer = QMessageBox::question(0, tr("Operation launch"),
-                                tr("Previous operation is not finished and will be aborted"),
-                                QMessageBox::Ok, QMessageBox::Cancel);
-    if (anAnswer == QMessageBox::Ok) {
+    if (canStopOperation()) {
       aCurrentOp->abort();
     } else {
       aCanStart = false;
@@ -72,6 +79,14 @@ bool XGUI_OperationMgr::canStartOperation(ModuleBase_Operation* theOperation)
   return aCanStart;
 }
 
+bool XGUI_OperationMgr::canStopOperation()
+{
+  int anAnswer = QMessageBox::question(0, tr("Operation launch"),
+                              tr("Previous operation is not finished and will be aborted"),
+                              QMessageBox::Ok, QMessageBox::Cancel);
+  return anAnswer == QMessageBox::Ok;
+}
+
 void XGUI_OperationMgr::onOperationStopped()
 {
   ModuleBase_Operation* aSenderOperation = dynamic_cast<ModuleBase_Operation*>(sender());
index fc6214d56748e7772dd6e86cf64935ee3243cab8..41323570ec46fc3e6fcf12566182c9c84e0e48a6 100644 (file)
@@ -43,6 +43,10 @@ public:
   /// \return the state whether the current operation is started
   bool startOperation(ModuleBase_Operation* theOperation);
 
+  /// Abort the operation and append it to the stack of operations
+  /// \return the state whether the current operation is aborted
+  bool abortOperation();
+
 signals:
   /// Signal about an operation is started. It is emitted after the start() of operation is done.
   void operationStarted();
@@ -62,6 +66,9 @@ protected:
   /// \param theOperation an operation to check
   bool canStartOperation(ModuleBase_Operation* theOperation);
 
+  /// Returns whether the operation can be stopped.
+  bool canStopOperation();
+
 protected slots:
   /// Slot that is called by an operation stop. Removes the stopped operation form the stack.
   /// If there is a suspended operation, restart it.
index 5b3c5616b5108684154eb253f0542ca9d77115f9..f3ac95d98e222d23cba387e0a7cfba64caca25e7 100644 (file)
@@ -424,7 +424,7 @@ void XGUI_Workshop::onOpen()
   }
 
   //show file dialog, check if readable and open
-  myCurrentFile = QFileDialog::getOpenFileName(mainWindow());
+  myCurrentFile = QFileDialog::getExistingDirectory(mainWindow());
   if(myCurrentFile.isEmpty())
     return;
   QFileInfo aFileInfo(myCurrentFile);
@@ -473,6 +473,8 @@ void XGUI_Workshop::onUndo()
   objectBrowser()->setCurrentIndex(QModelIndex());
   boost::shared_ptr<ModelAPI_PluginManager> aMgr = ModelAPI_PluginManager::get();
   boost::shared_ptr<ModelAPI_Document> aDoc = aMgr->rootDocument();
+  if (!operationMgr()->abortOperation())
+    return;
   aDoc->undo();
   updateCommandStatus();
 }