Salome HOME
Merge branch 'Dev_0.6.1' of newgeom:newgeom into Dev_0.6.1
[modules/shaper.git] / src / Model / Model_Document.cpp
index 304df74cbe8771daa53aa1a79c7d29b642eb77c0..1f5eedfe9a7a11639486087bc77cb32616532026 100644 (file)
@@ -1,3 +1,5 @@
+// Copyright (C) 2014-20xx CEA/DEN, EDF R&D
+
 // File:        Model_Document.cxx
 // Created:     28 Feb 2014
 // Author:      Mikhail PONIKAROV
@@ -24,6 +26,8 @@
 #include <TDF_Reference.hxx>
 #include <TDF_ChildIDIterator.hxx>
 #include <TDF_LabelMapHasher.hxx>
+#include <OSD_File.hxx>
+#include <OSD_Path.hxx>
 
 #include <climits>
 #ifndef WIN32
@@ -36,7 +40,7 @@
 # define _separator_ '/'
 #endif
 
-static const int UNDO_LIMIT = 10;  // number of possible undo operations
+static const int UNDO_LIMIT = 1000;  // number of possible undo operations (big for sketcher)
 
 static const int TAG_GENERAL = 1;  // general properties tag
 static const int TAG_OBJECTS = 2;  // tag of the objects sub-tree (features, results)
@@ -46,6 +50,11 @@ static const int TAG_HISTORY = 3;  // tag of the history sub-tree (python dump)
 static const int TAG_FEATURE_ARGUMENTS = 1;  ///< where the arguments are located
 static const int TAG_FEATURE_RESULTS = 2;  ///< where the results are located
 
+///
+/// 0:1:2 - where features are located
+/// 0:1:2:N:1 - data of the feature N
+/// 0:1:2:N:2:K:1 - data of the K result of the feature N
+
 Model_Document::Model_Document(const std::string theID, const std::string theKind)
     : myID(theID), myKind(theKind),
       myDoc(new TDocStd_Document("BinOcaf"))  // binary OCAF format
@@ -95,7 +104,7 @@ bool Model_Document::load(const char* theFileName)
   if (isError) {
     switch (aStatus) {
       case PCDM_RS_UnknownDocument:
-        Events_Error::send(std::string("Can not open document: unknown format"));
+        Events_Error::send(std::string("Can not open document"));
         break;
       case PCDM_RS_AlreadyRetrieved:
         Events_Error::send(std::string("Can not open document: already opened"));
@@ -159,6 +168,7 @@ bool Model_Document::load(const char* theFileName)
 bool Model_Document::save(const char* theFileName, std::list<std::string>& theResults)
 {
   // create a directory in the root document if it is not yet exist
+  Handle(Model_Application) anApp = Model_Application::getApplication();
   if (this == Model_Session::get()->moduleDocument().get()) {
 #ifdef WIN32
     CreateDirectory(theFileName, NULL);
@@ -170,7 +180,7 @@ bool Model_Document::save(const char* theFileName, std::list<std::string>& theRe
   TCollection_ExtendedString aPath(DocFileName(theFileName, myID));
   PCDM_StoreStatus aStatus;
   try {
-    aStatus = Model_Application::getApplication()->SaveAs(myDoc, aPath);
+    aStatus = anApp->SaveAs(myDoc, aPath);
   } catch (Standard_Failure) {
     Handle(Standard_Failure) aFail = Standard_Failure::Caught();
     Events_Error::send(
@@ -195,9 +205,30 @@ bool Model_Document::save(const char* theFileName, std::list<std::string>& theRe
   myTransactionSave = myTransactionsCounter;
   if (isDone) {  // save also sub-documents if any
     theResults.push_back(TCollection_AsciiString(aPath).ToCString());
-    std::set<std::string>::iterator aSubIter = mySubs.begin();
-    for (; aSubIter != mySubs.end() && isDone; aSubIter++) {
-      isDone = subDoc(*aSubIter)->save(theFileName, theResults);
+    const std::set<std::string> aSubs = subDocuments(false);
+    std::set<std::string>::iterator aSubIter = aSubs.begin();
+    for (; aSubIter != aSubs.end() && isDone; aSubIter++) {
+      if (anApp->isLoadByDemand(*aSubIter)) { 
+        // copy not-activated document that is not in the memory
+        std::string aDocName = *aSubIter;
+        if (!aDocName.empty()) {
+          // just copy file
+          TCollection_AsciiString aSubPath(DocFileName(anApp->loadPath().c_str(), aDocName));
+          OSD_Path aPath(aSubPath);
+          OSD_File aFile(aPath);
+          if (aFile.Exists()) {
+            TCollection_AsciiString aDestinationDir(DocFileName(theFileName, aDocName));
+            OSD_Path aDestination(aDestinationDir);
+            aFile.Copy(aDestination);
+            theResults.push_back(aDestinationDir.ToCString());
+          } else {
+            Events_Error::send(
+              std::string("Can not open file ") + aSubPath.ToCString() + " for saving");
+          }
+        }
+      } else { // simply save opened document
+        isDone = subDoc(*aSubIter)->save(theFileName, theResults);
+      }
     }
   }
   return isDone;
@@ -210,10 +241,10 @@ void Model_Document::close(const bool theForever)
     aPM->setActiveDocument(aPM->moduleDocument());
   }
   // close all subs
-  std::set<std::string>::iterator aSubIter = mySubs.begin();
-  for (; aSubIter != mySubs.end(); aSubIter++)
+  const std::set<std::string> aSubs = subDocuments(true);
+  std::set<std::string>::iterator aSubIter = aSubs.begin();
+  for (; aSubIter != aSubs.end(); aSubIter++)
     subDoc(*aSubIter)->close(theForever);
-  mySubs.clear();
 
   // close for thid document needs no transaction in this document
   std::static_pointer_cast<Model_Session>(Model_Session::get())->setCheckTransactions(false);
@@ -258,8 +289,9 @@ void Model_Document::startOperation()
     myDoc->NewCommand();
   }
   // new command for all subs
-  std::set<std::string>::iterator aSubIter = mySubs.begin();
-  for (; aSubIter != mySubs.end(); aSubIter++)
+  const std::set<std::string> aSubs = subDocuments(true);
+  std::set<std::string>::iterator aSubIter = aSubs.begin();
+  for (; aSubIter != aSubs.end(); aSubIter++)
     subDoc(*aSubIter)->startOperation();
 }
 
@@ -317,8 +349,9 @@ void Model_Document::finishOperation()
         ->setCheckTransactions(true);  // for nested transaction commit
 
   // finish for all subs first: to avoid nested finishing and "isOperation" calls problems inside
-  std::set<std::string>::iterator aSubIter = mySubs.begin();
-  for (; aSubIter != mySubs.end(); aSubIter++)
+  const std::set<std::string> aSubs = subDocuments(true);
+  std::set<std::string>::iterator aSubIter = aSubs.begin();
+  for (; aSubIter != aSubs.end(); aSubIter++)
     subDoc(*aSubIter)->finishOperation();
 
   if (myNestedNum != -1)  // this nested transaction is owervritten
@@ -352,8 +385,9 @@ void Model_Document::abortOperation()
   }
   synchronizeFeatures(true, false); // references were not changed since transaction start
   // abort for all subs
-  std::set<std::string>::iterator aSubIter = mySubs.begin();
-  for (; aSubIter != mySubs.end(); aSubIter++)
+  const std::set<std::string> aSubs = subDocuments(true);
+  std::set<std::string>::iterator aSubIter = aSubs.begin();
+  for (; aSubIter != aSubs.end(); aSubIter++)
     subDoc(*aSubIter)->abortOperation();
 }
 
@@ -375,8 +409,9 @@ bool Model_Document::canUndo()
       && myTransactionsCounter != 0 /* for omitting the first useless transaction */)
     return true;
   // check other subs contains operation that can be undoed
-  std::set<std::string>::iterator aSubIter = mySubs.begin();
-  for (; aSubIter != mySubs.end(); aSubIter++)
+  const std::set<std::string> aSubs = subDocuments(true);
+  std::set<std::string>::iterator aSubIter = aSubs.begin();
+  for (; aSubIter != aSubs.end(); aSubIter++)
     if (subDoc(*aSubIter)->canUndo())
       return true;
   return false;
@@ -391,8 +426,9 @@ void Model_Document::undo()
     myDoc->Undo();
   synchronizeFeatures(true, true);
   // undo for all subs
-  std::set<std::string>::iterator aSubIter = mySubs.begin();
-  for (; aSubIter != mySubs.end(); aSubIter++)
+  const std::set<std::string> aSubs = subDocuments(true);
+  std::set<std::string>::iterator aSubIter = aSubs.begin();
+  for (; aSubIter != aSubs.end(); aSubIter++)
     subDoc(*aSubIter)->undo();
 }
 
@@ -401,8 +437,9 @@ bool Model_Document::canRedo()
   if (myDoc->GetAvailableRedos() > 0)
     return true;
   // check other subs contains operation that can be redoed
-  std::set<std::string>::iterator aSubIter = mySubs.begin();
-  for (; aSubIter != mySubs.end(); aSubIter++)
+  const std::set<std::string> aSubs = subDocuments(true);
+  std::set<std::string>::iterator aSubIter = aSubs.begin();
+  for (; aSubIter != aSubs.end(); aSubIter++)
     if (subDoc(*aSubIter)->canRedo())
       return true;
   return false;
@@ -417,8 +454,9 @@ void Model_Document::redo()
   myTransactionsCounter++;
   synchronizeFeatures(true, true);
   // redo for all subs
-  std::set<std::string>::iterator aSubIter = mySubs.begin();
-  for (; aSubIter != mySubs.end(); aSubIter++)
+  const std::set<std::string> aSubs = subDocuments(true);
+  std::set<std::string>::iterator aSubIter = aSubs.begin();
+  for (; aSubIter != aSubs.end(); aSubIter++)
     subDoc(*aSubIter)->redo();
 }
 
@@ -543,7 +581,7 @@ void Model_Document::removeFeature(FeaturePtr theFeature, const bool theCheck)
   ModelAPI_EventCreator::get()->sendDeleted(theFeature->document(), ModelAPI_Feature::group());
 }
 
-FeaturePtr Model_Document::feature(TDF_Label& theLabel)
+FeaturePtr Model_Document::feature(TDF_Label& theLabel) const
 {
   if (myObjs.IsBound(theLabel))
     return myObjs.Find(theLabel);
@@ -573,17 +611,37 @@ ObjectPtr Model_Document::object(TDF_Label theLabel)
 
 std::shared_ptr<ModelAPI_Document> Model_Document::subDocument(std::string theDocID)
 {
-  // just store sub-document identifier here to manage it later
-  if (mySubs.find(theDocID) == mySubs.end())
-    mySubs.insert(theDocID);
   return Model_Application::getApplication()->getDocument(theDocID);
 }
 
+const std::set<std::string> Model_Document::subDocuments(const bool theActivatedOnly) const
+{
+  std::set<std::string> aResult;
+  // comment must be in any feature: it is kind
+  int anIndex = 0;
+  TDF_ChildIDIterator aLabIter(featuresLabel(), TDataStd_Comment::GetID());
+  for (; aLabIter.More(); aLabIter.Next()) {
+    TDF_Label aFLabel = aLabIter.Value()->Label();
+    FeaturePtr aFeature = feature(aFLabel);
+    if (aFeature.get()) { // if document is closed the feature may be not in myObjs map
+      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++) {
+        if ((*aRIter)->groupName() != ModelAPI_ResultPart::group()) continue;
+        if ((*aRIter)->isInHistory()) {
+          ResultPartPtr aPart = std::dynamic_pointer_cast<ModelAPI_ResultPart>(*aRIter);
+          if (aPart && (!theActivatedOnly || aPart->isActivated()))
+            aResult.insert(aPart->data()->name());
+        }
+      }
+    }
+  }
+  return aResult;
+}
+
 std::shared_ptr<Model_Document> Model_Document::subDoc(std::string theDocID)
 {
   // just store sub-document identifier here to manage it later
-  if (mySubs.find(theDocID) == mySubs.end())
-    mySubs.insert(theDocID);
   return std::dynamic_pointer_cast<Model_Document>(
     Model_Application::getApplication()->getDocument(theDocID));
 }
@@ -674,7 +732,7 @@ int Model_Document::size(const std::string& theGroupID, const bool theHidden)
   return aResult;
 }
 
-TDF_Label Model_Document::featuresLabel()
+TDF_Label Model_Document::featuresLabel() const
 {
   return myDoc->Main().FindChild(TAG_OBJECTS);
 }
@@ -1059,3 +1117,16 @@ Standard_Boolean IsEqual(const TDF_Label& theLab1, const TDF_Label& theLab2)
 {
   return TDF_LabelMapHasher::IsEqual(theLab1, theLab2);
 }
+
+void Model_Document::addNamingName(const TDF_Label theLabel, std::string theName)
+{
+  myNamingNames[theName] = theLabel;
+}
+
+TDF_Label Model_Document::findNamingName(std::string theName)
+{
+  std::map<std::string, TDF_Label>::iterator aFind = myNamingNames.find(theName);
+  if (aFind == myNamingNames.end())
+    return TDF_Label(); // not found
+  return aFind->second;
+}