Salome HOME
Task #3237: Allow usage of accented characters in ObjectBrowser
[modules/shaper.git] / src / Model / Model_Data.cpp
index 74f19ec71f3b4bb90ba4b8ceaccb51e57392fb78..0a3fa52d6e70a9e579336f964121dc3dd0a87107 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2017  CEA/DEN, EDF R&D
+// Copyright (C) 2014-2019  CEA/DEN, EDF R&D
 //
 // This library is free software; you can redistribute it and/or
 // modify it under the terms of the GNU Lesser General Public
 //
 // You should have received a copy of the GNU Lesser General Public
 // License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 //
-// See http://www.salome-platform.org/ or
-// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
 
 #include <Model_Data.h>
 #include <Model_AttributeTables.h>
 #include <Model_Events.h>
 #include <Model_Expression.h>
+#include <Model_Tools.h>
+#include <Model_Validator.h>
+
 #include <ModelAPI_Feature.h>
 #include <ModelAPI_Result.h>
 #include <ModelAPI_ResultParameter.h>
+#include <ModelAPI_ResultConstruction.h>
 #include <ModelAPI_Validator.h>
 #include <ModelAPI_Session.h>
 #include <ModelAPI_ResultPart.h>
 #include <ModelAPI_Tools.h>
-#include <Model_Validator.h>
 
 #include <GeomDataAPI_Point.h>
 #include <GeomDataAPI_Point2D.h>
+#include <GeomDataAPI_Point2DArray.h>
 
 #include <GeomData_Point.h>
 #include <GeomData_Point2D.h>
+#include <GeomData_Point2DArray.h>
 #include <GeomData_Dir.h>
 #include <Events_Loop.h>
 #include <Events_InfoMessage.h>
 
+#include <Locale_Convert.h>
+
 #include <TDataStd_Name.hxx>
 #include <TDataStd_AsciiString.hxx>
-#include <TDataStd_IntegerArray.hxx>
 #include <TDataStd_UAttribute.hxx>
-#include <TDF_AttributeIterator.hxx>
-#include <TDF_ChildIterator.hxx>
-#include <TDF_RelocationTable.hxx>
-#include <TColStd_HArray1OfByte.hxx>
+#include <TDF_ChildIDIterator.hxx>
 
 #include <string>
 
@@ -77,11 +79,18 @@ static const int kFlagDisplayed = 1;
 static const int kFlagDeleted = 2;
 // TDataStd_Integer - 0 if the name of the object is generated automatically,
 //                    otherwise the name is defined by user
-Standard_GUID kUSER_DEFINED_NAME("9c694d18-a83c-4a56-bc9b-8020628a8244");
+static const Standard_GUID kUSER_DEFINED_NAME("9c694d18-a83c-4a56-bc9b-8020628a8244");
 
 // invalid data
 const static std::shared_ptr<ModelAPI_Data> kInvalid(new Model_Data());
 
+static const Standard_GUID kGroupAttributeGroupID("df64ea4c-fc42-4bf8-ad7e-08f7a54bf1b8");
+static const Standard_GUID kGroupAttributeID("ebdcb22a-e045-455b-9a7f-cfd38d68e185");
+
+// id of attribute to store the version of the feature
+static const Standard_GUID kVERSION_ID("61cdb78a-1ba7-4942-976f-63bea7f4a2b1");
+
+
 Model_Data::Model_Data() : mySendAttributeUpdated(true), myWasChangedButBlocked(false)
 {
 }
@@ -96,37 +105,28 @@ void Model_Data::setLabel(TDF_Label theLab)
     myFlags->SetValue(kFlagInHistory, Standard_True); // is in history by default is true
     myFlags->SetValue(kFlagDisplayed, Standard_True); // is displayed by default is true
     myFlags->SetValue(kFlagDeleted, Standard_False); // is deleted by default is false
-  } else if (myFlags->Length() != 3) { // for old formats support
-    Standard_Boolean aFlag0 = myFlags->Upper() >= 0 ? myFlags->Value(0) : Standard_True;
-    Standard_Boolean aFlag1 = myFlags->Upper() >= 1 ? myFlags->Value(1) : Standard_True;
-    Standard_Boolean aFlag2 = myFlags->Upper() >= 2 ? myFlags->Value(2) : Standard_True;
-    Handle(TColStd_HArray1OfByte) aNewArray = new TColStd_HArray1OfByte(0, 2);
-    myFlags->SetInternalArray(aNewArray);
-    myFlags->SetValue(0, aFlag0);
-    myFlags->SetValue(1, aFlag1);
-    myFlags->SetValue(2, aFlag2);
   }
 }
 
-std::string Model_Data::name()
+std::wstring Model_Data::name()
 {
   Handle(TDataStd_Name) aName;
-  if (myLab.FindAttribute(TDataStd_Name::GetID(), aName)) {
+  if (shapeLab().FindAttribute(TDataStd_Name::GetID(), aName)) {
 #ifdef DEBUG_NAMES
-    myObject->myName = TCollection_AsciiString(aName->Get()).ToCString();
+    myObject->myName = Locale::Convert::toWString(aName->Get().ToExtString());
 #endif
-    return std::string(TCollection_AsciiString(aName->Get()).ToCString());
+    return Locale::Convert::toWString(aName->Get().ToExtString());
   }
-  return "";  // not defined
+  return L"";  // not defined
 }
 
-void Model_Data::setName(const std::string& theName)
+void Model_Data::setName(const std::wstring& theName)
 {
   bool isModified = false;
-  std::string anOldName = name();
+  std::wstring anOldName = name();
   Handle(TDataStd_Name) aName;
-  if (!myLab.FindAttribute(TDataStd_Name::GetID(), aName)) {
-    TDataStd_Name::Set(myLab, theName.c_str());
+  if (!shapeLab().FindAttribute(TDataStd_Name::GetID(), aName)) {
+    TDataStd_Name::Set(shapeLab(), theName.c_str());
     isModified = true;
   } else {
     isModified = !aName->Get().IsEqual(theName.c_str());
@@ -138,12 +138,12 @@ void Model_Data::setName(const std::string& theName)
       bool isUserDefined = true;
       ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(myObject);
       if (aResult) {
-        std::string aDefaultName = ModelAPI_Tools::getDefaultName(aResult, false).first;
+        std::wstring aDefaultName = ModelAPI_Tools::getDefaultName(aResult, false).first;
         isUserDefined = aDefaultName != theName;
       }
       if (isUserDefined) {
         // name is user-defined, thus special attribute is set
-        TDataStd_UAttribute::Set(myLab, kUSER_DEFINED_NAME);
+        TDataStd_UAttribute::Set(shapeLab(), kUSER_DEFINED_NAME);
       }
     }
   }
@@ -151,7 +151,7 @@ void Model_Data::setName(const std::string& theName)
     ModelAPI_ObjectRenamedMessage::send(myObject, anOldName, theName, this);
   if (isModified && myObject && myObject->document()) {
     std::dynamic_pointer_cast<Model_Document>(myObject->document())->
-      changeNamingName(anOldName, theName, myLab);
+      changeNamingName(anOldName, theName, shapeLab());
   }
 #ifdef DEBUG_NAMES
   myObject->myName = theName;
@@ -160,13 +160,32 @@ void Model_Data::setName(const std::string& theName)
 
 bool Model_Data::hasUserDefinedName() const
 {
-  return myLab.IsAttribute(kUSER_DEFINED_NAME);
+  return shapeLab().IsAttribute(kUSER_DEFINED_NAME);
 }
 
-AttributePtr Model_Data::addAttribute(const std::string& theID, const std::string theAttrType)
+std::string Model_Data::version()
+{
+  Handle(TDataStd_Name) aVersionAttr;
+  std::string aVersion;
+  if (shapeLab().FindAttribute(kVERSION_ID, aVersionAttr))
+    aVersion = TCollection_AsciiString(aVersionAttr->Get()).ToCString();
+  return aVersion;
+}
+
+void Model_Data::setVersion(const std::string& theVersion)
+{
+  Handle(TDataStd_Name) aVersionAttr;
+  std::string aVersion;
+  if (!shapeLab().FindAttribute(kVERSION_ID, aVersionAttr))
+    aVersionAttr = TDataStd_Name::Set(shapeLab(), kVERSION_ID, TCollection_ExtendedString());
+  aVersionAttr->Set(theVersion.c_str());
+}
+
+AttributePtr Model_Data::addAttribute(
+  const std::string& theID, const std::string theAttrType, const int theIndex)
 {
   AttributePtr aResult;
-  int anAttrIndex = int(myAttrs.size()) + 1;
+  int anAttrIndex = theIndex == -1 ? int(myAttrs.size()) + 1 : theIndex;
   TDF_Label anAttrLab = myLab.FindChild(anAttrIndex);
   ModelAPI_Attribute* anAttr = 0;
   if (theAttrType == ModelAPI_AttributeDocRef::typeId()) {
@@ -223,7 +242,10 @@ AttributePtr Model_Data::addAttribute(const std::string& theID, const std::strin
     }
     anAttribute->myIsInitialized = anAllInitialized;
     anAttr = anAttribute;
+  } else if (theAttrType == GeomData_Point2DArray::typeId()) {
+    anAttr = new GeomData_Point2DArray(anAttrLab);
   }
+
   if (anAttr) {
     aResult = std::shared_ptr<ModelAPI_Attribute>(anAttr);
     myAttrs[theID] = std::pair<AttributePtr, int>(aResult, anAttrIndex);
@@ -236,6 +258,97 @@ AttributePtr Model_Data::addAttribute(const std::string& theID, const std::strin
   return aResult;
 }
 
+AttributePtr Model_Data::addFloatingAttribute(
+  const std::string& theID, const std::string theAttrType, const std::string& theGroup)
+{
+  // compute the index of the attribute placement
+  int anIndex;
+  TDF_Label aLab;
+  if (myLab.IsAttribute(TDF_TagSource::GetID())) {
+    // check this is re-init of attributes, so, check attribute with this name already there
+    TDF_ChildIDIterator anIter(myLab, kGroupAttributeID, false);
+    for(; anIter.More(); anIter.Next()) {
+      TCollection_AsciiString aThisName(Handle(TDataStd_Name)::DownCast(anIter.Value())->Get());
+      if (theID == aThisName.ToCString()) {
+        TDF_Label aLab = anIter.Value()->Label();
+        Handle(TDataStd_Name) aGName;
+        if (aLab.FindAttribute(kGroupAttributeGroupID, aGName)) {
+          TCollection_AsciiString aGroupName(aGName->Get());
+          if (theGroup == aGroupName.ToCString()) {
+            return addAttribute(theGroup + "__" + theID, theAttrType, aLab.Tag());
+          }
+        }
+      }
+    }
+    aLab = myLab.NewChild(); // already exists a floating attribute, create the next
+    anIndex = aLab.Tag();
+  } else { // put the first floating attribute, quite far from other standard attributes
+    anIndex = int(myAttrs.size()) + 1000;
+    TDF_TagSource::Set(myLab)->Set(anIndex);
+    aLab = myLab.FindChild(anIndex, true);
+  }
+  // store the group ID and the attribute ID (to restore correctly)
+  TDataStd_Name::Set(aLab, kGroupAttributeGroupID, theGroup.c_str());
+  TDataStd_Name::Set(aLab, kGroupAttributeID, theID.c_str());
+
+  return addAttribute(theGroup + "__" + theID, theAttrType, anIndex);
+}
+
+void Model_Data::allGroups(std::list<std::string>& theGroups)
+{
+  std::set<std::string> alreadyThere;
+  for(TDF_ChildIDIterator aGroup(myLab, kGroupAttributeGroupID); aGroup.More(); aGroup.Next()) {
+    Handle(TDataStd_Name) aGroupAttr = Handle(TDataStd_Name)::DownCast(aGroup.Value());
+    std::string aGroupID = TCollection_AsciiString(aGroupAttr->Get()).ToCString();
+    if (alreadyThere.find(aGroupID) == alreadyThere.end()) {
+      theGroups.push_back(aGroupID);
+      alreadyThere.insert(aGroupID);
+    }
+  }
+}
+
+void Model_Data::attributesOfGroup(const std::string& theGroup,
+  std::list<std::shared_ptr<ModelAPI_Attribute> >& theAttrs)
+{
+  for(TDF_ChildIDIterator aGroup(myLab, kGroupAttributeGroupID); aGroup.More(); aGroup.Next()) {
+    Handle(TDataStd_Name) aGroupID = Handle(TDataStd_Name)::DownCast(aGroup.Value());
+    if (aGroupID->Get().IsEqual(theGroup.c_str())) {
+      Handle(TDataStd_Name) anID;
+      if (aGroup.Value()->Label().FindAttribute(kGroupAttributeID, anID)) {
+        TCollection_AsciiString anAsciiID(aGroupID->Get() + "__" + anID->Get());
+        theAttrs.push_back(attribute(anAsciiID.ToCString()));
+      }
+    }
+  }
+}
+
+void Model_Data::removeAttributes(const std::string& theGroup)
+{
+  TDF_LabelList aLabsToRemove; // collect labels that must be erased after the cycle
+  for(TDF_ChildIDIterator aGroup(myLab, kGroupAttributeGroupID); aGroup.More(); aGroup.Next()) {
+    Handle(TDataStd_Name) aGroupID = Handle(TDataStd_Name)::DownCast(aGroup.Value());
+    if (aGroupID->Get().IsEqual(theGroup.c_str())) {
+      Handle(TDataStd_Name) anID;
+      if (!aGroup.Value()->Label().IsNull() &&
+          aGroup.Value()->Label().FindAttribute(kGroupAttributeID, anID)) {
+        aLabsToRemove.Append(aGroup.Value()->Label());
+      }
+      TCollection_AsciiString anAsciiID(aGroupID->Get() + "__" + anID->Get());
+      myAttrs.erase(anAsciiID.ToCString());
+    }
+  }
+  for(TDF_LabelList::Iterator aLab(aLabsToRemove); aLab.More(); aLab.Next()) {
+    aLab.ChangeValue().ForgetAllAttributes(true);
+  }
+}
+
+void Model_Data::clearAttributes()
+{
+  myAttrs.clear();
+}
+
+
+
 // macro for the generic returning of the attribute by the ID
 #define GET_ATTRIBUTE_BY_ID(ATTR_TYPE, METHOD_NAME) \
   std::shared_ptr<ATTR_TYPE> Model_Data::METHOD_NAME(const std::string& theID) { \
@@ -345,8 +458,10 @@ void Model_Data::sendAttributeUpdated(ModelAPI_Attribute* theAttr)
         myWasChangedButBlocked.push_back(theAttr);
     }
   } else {
-    // trim: need to redisplay
-    if (myObject) {
+    // trim: need to redisplay or set color in the python script
+    if (myObject && (theAttr->attributeType() == "Point2D" || theAttr->id() == "Color" ||
+      theAttr->id() == "Transparency" || theAttr->id() == "Deflection" ||
+      theAttr->id() == "Iso_lines" || theAttr->id() == "Show_Iso_lines")) {
       static const Events_ID anEvent = Events_Loop::eventByName(EVENT_OBJECT_TO_REDISPLAY);
       ModelAPI_EventCreator::get()->sendUpdated(myObject, anEvent);
     }
@@ -417,7 +532,7 @@ enum StatesIndexes {
   STATE_INDEX_TRANSACTION = 2, // transaction ID
 };
 
-/// Returns the label array, initialises it by default values if not exists
+/// Returns the label array, initializes it by default values if not exists
 static Handle(TDataStd_IntegerArray) stateArray(TDF_Label& theLab)
 {
   Handle(TDataStd_IntegerArray) aStateArray;
@@ -481,15 +596,6 @@ int Model_Data::featureId() const
   return myLab.Father().Tag(); // tag of the feature label
 }
 
-void Model_Data::eraseBackReferences()
-{
-  myRefsToMe.clear();
-  std::shared_ptr<ModelAPI_Result> aRes = std::dynamic_pointer_cast<ModelAPI_Result>(myObject);
-  if (aRes) {
-    aRes->setIsConcealed(false);
-  }
-}
-
 void Model_Data::removeBackReference(ObjectPtr theObject, std::string theAttrID)
 {
   AttributePtr anAttribute = theObject->data()->attribute(theAttrID);
@@ -503,7 +609,7 @@ void Model_Data::removeBackReference(AttributePtr theAttr)
 
   myRefsToMe.erase(theAttr);
 
-  // remove concealment immideately: on deselection it must be posible to reselect in GUI the same
+  // remove concealment immediately: on deselection it must be possible to reselect in GUI the same
   FeaturePtr aFeatureOwner = std::dynamic_pointer_cast<ModelAPI_Feature>(theAttr->owner());
   if (aFeatureOwner.get() &&
     ModelAPI_Session::get()->validators()->isConcealed(aFeatureOwner->getKind(), theAttr->id())) {
@@ -523,7 +629,7 @@ void Model_Data::addBackReference(FeaturePtr theFeature, std::string theAttrID,
     // be displayed and previewed; also for avoiding of quick show/hide on history
     // moving deep down
     if (aRes && !theFeature->isDisabled()) {
-      aRes->setIsConcealed(true);
+      aRes->setIsConcealed(true, theFeature->getKind() == "RemoveResults");
     }
   }
 }
@@ -545,10 +651,16 @@ void Model_Data::updateConcealmentFlag()
       if (aFeature.get() && !aFeature->isDisabled() && aFeature->isStable()) {
         if (ModelAPI_Session::get()->validators()->isConcealed(
               aFeature->getKind(), (*aRefsIter)->id())) {
-          std::shared_ptr<ModelAPI_Result> aRes = std::dynamic_pointer_cast<ModelAPI_Result>(myObject);
+          std::shared_ptr<ModelAPI_Result> aRes =
+            std::dynamic_pointer_cast<ModelAPI_Result>(myObject);
           if (aRes.get()) {
-            aRes->setIsConcealed(true); // set concealed
-            return;
+            if (aRes->groupName() != ModelAPI_ResultConstruction::group()) {
+              aRes->setIsConcealed(true); // set concealed
+              return;
+            } else if (aFeature->getKind() == "RemoveResults") {
+              aRes->setIsConcealed(true, true);
+              return;
+            }
           }
         }
       }
@@ -712,35 +824,14 @@ void Model_Data::referencesToObjects(
   }
 }
 
-/// makes copy of all attributes on the given label and all sub-labels
-static void copyAttrs(TDF_Label theSource, TDF_Label theDestination) {
-  TDF_AttributeIterator anAttrIter(theSource);
-  for(; anAttrIter.More(); anAttrIter.Next()) {
-    Handle(TDF_Attribute) aTargetAttr;
-    if (!theDestination.FindAttribute(anAttrIter.Value()->ID(), aTargetAttr)) {
-      // create a new attribute if not yet exists in the destination
-           aTargetAttr = anAttrIter.Value()->NewEmpty();
-      theDestination.AddAttribute(aTargetAttr);
-    }
-    // no special relocation, empty map, but self-relocation is on: copy references w/o changes
-    Handle(TDF_RelocationTable) aRelocTable = new TDF_RelocationTable(Standard_True);
-    anAttrIter.Value()->Paste(aTargetAttr, aRelocTable);
-  }
-  // copy the sub-labels content
-  TDF_ChildIterator aSubLabsIter(theSource);
-  for(; aSubLabsIter.More(); aSubLabsIter.Next()) {
-    copyAttrs(aSubLabsIter.Value(), theDestination.FindChild(aSubLabsIter.Value().Tag()));
-  }
-}
-
 void Model_Data::copyTo(std::shared_ptr<ModelAPI_Data> theTarget)
 {
   TDF_Label aTargetRoot = std::dynamic_pointer_cast<Model_Data>(theTarget)->label();
-  copyAttrs(myLab, aTargetRoot);
+  Model_Tools::copyAttrs(myLab, aTargetRoot);
   // reinitialize Model_Attributes by TDF_Attributes set
   std::shared_ptr<Model_Data> aTData = std::dynamic_pointer_cast<Model_Data>(theTarget);
   aTData->myAttrs.clear();
-  theTarget->owner()->initAttributes(); // reinit feature attributes
+  theTarget->owner()->initAttributes(); // reinitialize feature attributes
 }
 
 bool Model_Data::isInHistory()