Salome HOME
Merge branch 'BR_internationalization'
[modules/shaper.git] / src / ModuleBase / ModuleBase_Tools.cpp
index a17f61e4b37136d48452ad56eefb2495f1719c6a..a4890633ae0cf4a2ad726d83b83a98fa2eeb6fc0 100755 (executable)
@@ -21,6 +21,7 @@
 #include <ModelAPI_AttributeRefList.h>
 #include <ModelAPI_AttributeRefAttrList.h>
 #include <ModelAPI_ResultPart.h>
+#include <ModelAPI_ResultConstruction.h>
 #include <Events_Loop.h>
 
 #include <ModelAPI_Data.h>
@@ -35,6 +36,7 @@
 
 #include <GeomDataAPI_Point2D.h>
 #include <Events_InfoMessage.h>
+#include <GeomAPI_ShapeExplorer.h>
 
 #include <Config_PropManager.h>
 
 #include <string>
 
 const double tolerance = 1e-7;
+const double DEFAULT_DEVIATION_COEFFICIENT = 1.e-4;
 
 //#define DEBUG_ACTIVATE_WINDOW
 //#define DEBUG_SET_FOCUS
+//#define DEBUG_SELECTION_INFO
+
+#ifdef DEBUG_SELECTION_INFO
+#include <ModuleBase_ISelection.h>
+#include <ModuleBase_ViewerPrs.h>
+
+#include <AIS_InteractiveContext.hxx>
+#include <AIS_ListOfInteractive.hxx>
+#include <AIS_ListIteratorOfListOfInteractive.hxx>
+#include <AIS_Shape.hxx>
+#include <TopoDS_Shape.hxx>
+#include <AIS_LocalContext.hxx>
+#include <NCollection_List.hxx>
+#include <StdSelect_BRepOwner.hxx>
+#include <TColStd_ListOfInteger.hxx>
+#include <TColStd_ListIteratorOfListOfInteger.hxx>
+#endif
 
 namespace ModuleBase_Tools {
 
@@ -123,7 +143,7 @@ void setShadowEffect(QWidget* theWidget, const bool isSetEffect)
   else {
     QGraphicsEffect* anEffect = theWidget->graphicsEffect();
     if(anEffect)
-    anEffect->deleteLater();
+      anEffect->deleteLater();
     theWidget->setGraphicsEffect(NULL);
   }
 }
@@ -271,7 +291,7 @@ QString objectInfo(const ObjectPtr& theObj, const bool isUseAttributesInfo)
   if (aFeature.get()) {
     aFeatureStr.append(QString(": %1").arg(aFeature->getKind().c_str()).toStdString().c_str());
     if (aFeature->data()->isValid()) {
-      aFeatureStr.append(QString(", name=%1").arg(aFeature->data()->name().c_str()).toStdString()
+      aFeatureStr.append(QString(", name=%1").arg(theObj->data()->name().c_str()).toStdString()
                                                                                        .c_str());
     }
     if (isUseAttributesInfo) {
@@ -301,28 +321,218 @@ QString objectInfo(const ObjectPtr& theObj, const bool isUseAttributesInfo)
   return aFeatureStr;
 }
 
+#ifdef DEBUG_SELECTION_INFO
+QString getShapeTypeInfo(const int theType)
+{
+  QString anInfo = "Undefined";
+  switch(theType) {
+    case TopAbs_COMPOUND:  anInfo = "compound"; break;
+    case TopAbs_COMPSOLID: anInfo = "compsolid"; break;
+    case TopAbs_SOLID:     anInfo = "solid"; break;
+    case TopAbs_SHELL:     anInfo = "shell"; break;
+    case TopAbs_FACE:      anInfo = "face"; break;
+    case TopAbs_WIRE:      anInfo = "wire"; break;
+    case TopAbs_EDGE:      anInfo = "edge"; break;
+    case TopAbs_VERTEX:    anInfo = "vertex"; break;
+    case TopAbs_SHAPE:     anInfo = "shape"; break;
+    default: break;
+  }
+  return anInfo;
+}
+
+QString getModeInfo(const int theMode)
+{
+  QString anInfo = "Undefined";
+  switch(theMode) {
+    case 0: anInfo = "SHAPE(0)"; break;
+    case 1: anInfo = "VERTEX(1)"; break;
+    case 2: anInfo = "EDGE(2)"; break;
+    case 3: anInfo = "WIRE(3)"; break;
+    case 4: anInfo = "FACE(4)"; break;
+    case 5: anInfo = "SHELL(5)"; break;
+    case 6: anInfo = "SOLID(6)"; break;
+    case 7: anInfo = "COMPSOLID(7)"; break;
+    case 8: anInfo = "COMPOUND(8)"; break;
+    case 100: anInfo = "Sel_Mode_First(100)"; break; //SketcherPrs_Tools
+    case 101: anInfo = "Sel_Constraint(101)"; break;
+    case 102: anInfo = "Sel_Dimension_All(102)"; break;
+    case 103: anInfo = "Sel_Dimension_Line(103)"; break;
+    case 104: anInfo = "Sel_Dimension_Text(104)"; break;
+    default: break;
+  }
+  return anInfo;
+}
+
+QString displayedInteractiveObjects(Handle(AIS_InteractiveContext)& theContext,
+                                    const bool theShapeInfoOnly = true)
+{
+  if (theContext.IsNull())
+    return "";
+  AIS_ListOfInteractive aListOfIO;
+  theContext->DisplayedObjects(aListOfIO, false);
+  QStringList anObjects;
+  AIS_ListIteratorOfListOfInteractive aIt;
+  for (aIt.Initialize(aListOfIO); aIt.More(); aIt.Next()) {
+    Handle(AIS_InteractiveObject) anAISIO = aIt.Value();
+    Handle(AIS_Shape) aShapePrs = Handle(AIS_Shape)::DownCast(anAISIO);
+    if (theShapeInfoOnly && aShapePrs.IsNull())
+      continue;
+
+    QString anInfo = "IO";
+    std::ostringstream aPtrStr;
+    aPtrStr << "[" << anAISIO.Access() << "]";
+    anInfo += aPtrStr.str().c_str();
+
+    if (!aShapePrs.IsNull()) {
+      const TopoDS_Shape& aShape = aShapePrs->Shape();
+      if (aShape.IsNull())
+        Events_Error::throwException("An empty AIS presentation");
+      else
+        anInfo += QString(", shape type: %1").arg(getShapeTypeInfo(aShape.ShapeType()));
+    }
+    TColStd_ListOfInteger aTColModes;
+    theContext->ActivatedModes(anAISIO, aTColModes);
+    TColStd_ListIteratorOfListOfInteger itr( aTColModes );
+    QIntList aModesActivatedForIO;
+    bool isDeactivated = false;
+    QStringList aModes;
+    for (; itr.More(); itr.Next() ) {
+      Standard_Integer aMode = itr.Value();
+      aModes.append(getModeInfo(aMode));
+      //int aShapeMode = (aMode > 8)? aMode : AIS_Shape::SelectionType(aMode);
+    }
+    if (aModes.size() > 0)
+      anInfo += QString(", activated modes: %1").arg(aModes.join(", "));
+
+    anObjects += anInfo;
+  }
+  QString aValue = QString("displayedIO[%1]").arg(anObjects.size());
+  if (anObjects.size() > 0)
+    aValue += QString(":\n  %1").arg(anObjects.join("\n  "));
+  return aValue;
+}
+
+QString activeOwners(Handle(AIS_InteractiveContext)& theContext, const bool theShapeInfoOnly = true)
+{
+  if (theContext.IsNull())
+    return "";
+  Handle(AIS_LocalContext) aLContext = theContext->LocalContext();
+  TCollection_AsciiString aSelectionName = aLContext->SelectionName();
+  aLContext->UnhilightPicked(Standard_False);
+
+  NCollection_List<Handle(SelectBasics_EntityOwner)> anActiveOwners;
+  aLContext->MainSelector()->ActiveOwners(anActiveOwners);
+  NCollection_List<Handle(SelectBasics_EntityOwner)>::Iterator anOwnersIt (anActiveOwners);
+  Handle(SelectMgr_EntityOwner) anOwner;
+  QStringList anObjects;
+  for (; anOwnersIt.More(); anOwnersIt.Next()) {
+    anOwner = Handle(SelectMgr_EntityOwner)::DownCast (anOwnersIt.Value());
+    Handle(StdSelect_BRepOwner) BROwnr = Handle(StdSelect_BRepOwner)::DownCast(anOwner);
+    if (theShapeInfoOnly && BROwnr.IsNull())
+      continue;
+
+    QString anInfo = "Owner";
+    std::ostringstream aPtrStr;
+    aPtrStr << "[" << anOwner.Access() << "]";
+    anInfo += aPtrStr.str().c_str();
+
+    Handle(AIS_InteractiveObject) aAISObj = 
+          Handle(AIS_InteractiveObject)::DownCast(anOwner->Selectable());
+    if (!aAISObj.IsNull()) {
+      std::ostringstream aPtrStr;
+      aPtrStr << "[" << aAISObj.Access() << "]";
+      anInfo += QString(", selectable(IO): %1").arg(aPtrStr.str().c_str());
+    }
+
+    if (!BROwnr.IsNull() && BROwnr->HasShape()) {
+      const TopoDS_Shape& aShape = BROwnr->Shape();
+      if (aShape.IsNull())
+        Events_Error::throwException("An empty AIS presentation");
+      else
+        anInfo += QString(", shape type: %1").arg(getShapeTypeInfo(aShape.ShapeType()));
+    }
+    anObjects += anInfo;
+  }
+  QString aValue = QString("activeOwners[%1]").arg(anObjects.size());
+  if (anObjects.size() > 0)
+    aValue += QString(":\n  %1").arg(anObjects.join("\n  "));
+  return aValue;
+}
+
+QString selectedOwners(Handle(AIS_InteractiveContext)& theContext, const bool theShapeInfoOnly = true)
+{
+  QStringList anObjects;
+  if (theContext.IsNull())
+    return "";
+
+  QList<long> aSelectedIds; // Remember of selected address in order to avoid duplicates
+  for (theContext->InitSelected(); theContext->MoreSelected(); theContext->NextSelected()) {
+    Handle(SelectMgr_EntityOwner) anOwner = theContext->SelectedOwner();
+    Handle(StdSelect_BRepOwner) BROwnr = Handle(StdSelect_BRepOwner)::DownCast(anOwner);
+    if (theShapeInfoOnly && BROwnr.IsNull())
+      continue;
+
+    if (aSelectedIds.contains((long)anOwner.Access()))
+      continue;
+    aSelectedIds.append((long)anOwner.Access());
+
+    QString anInfo = "Owner";
+    std::ostringstream aPtrStr;
+    aPtrStr << "[" << anOwner.Access() << "]";
+    anInfo += aPtrStr.str().c_str();
+
+    if (!BROwnr.IsNull() && BROwnr->HasShape()) {
+      const TopoDS_Shape& aShape = BROwnr->Shape();
+      anInfo += QString(", shape type = %1").arg(getShapeTypeInfo(aShape.ShapeType()));
+    }
+    anObjects += anInfo;
+  }
+  QString aValue = QString("selectedOwners[%1]").arg(anObjects.size());
+  if (anObjects.size() > 0)
+    aValue += QString(":\n  %1").arg(anObjects.join("\n  "));
+  return aValue;
+}
+#endif
+
+void selectionInfo(Handle(AIS_InteractiveContext)& theContext, const std::string& thePrefix)
+{
+#ifdef DEBUG_SELECTION_INFO
+  QString aValue = QString("\n\n\nDEBUG_SELECTION_INFO for '%1'\n%2\n%3\n%4")
+                                              .arg(thePrefix.c_str())
+                                              .arg(displayedInteractiveObjects(theContext))
+                                              .arg(activeOwners(theContext))
+                                              .arg(selectedOwners(theContext));
+  qDebug(aValue.toStdString().c_str());
+#endif
+}
+
 typedef QMap<QString, TopAbs_ShapeEnum> ShapeTypes;
-static ShapeTypes MyShapeTypes;
+static ShapeTypes myShapeTypes;
 
 TopAbs_ShapeEnum shapeType(const QString& theType)
 {
-  if (MyShapeTypes.count() == 0) {
-    MyShapeTypes["face"] = TopAbs_FACE;
-    MyShapeTypes["faces"] = TopAbs_FACE;
-    MyShapeTypes["vertex"] = TopAbs_VERTEX;
-    MyShapeTypes["vertices"] = TopAbs_VERTEX;
-    MyShapeTypes["wire"] = TopAbs_WIRE;
-    MyShapeTypes["wires"] = TopAbs_WIRE;
-    MyShapeTypes["edge"] = TopAbs_EDGE;
-    MyShapeTypes["edges"] = TopAbs_EDGE;
-    MyShapeTypes["shell"] = TopAbs_SHELL;
-    MyShapeTypes["solid"] = TopAbs_SOLID;
-    MyShapeTypes["solids"] = TopAbs_SOLID;
-    MyShapeTypes["objects"] = TopAbs_SHAPE;
+  if (myShapeTypes.count() == 0) {
+    myShapeTypes["compound"]   = TopAbs_COMPOUND;
+    myShapeTypes["compounds"]  = TopAbs_COMPOUND;
+    myShapeTypes["compsolid"]  = TopAbs_COMPSOLID;
+    myShapeTypes["compsolids"] = TopAbs_COMPSOLID;
+    myShapeTypes["solid"]      = TopAbs_SOLID;
+    myShapeTypes["solids"]     = TopAbs_SOLID;
+    myShapeTypes["shell"]      = TopAbs_SHELL;
+    myShapeTypes["shells"]     = TopAbs_SHELL;
+    myShapeTypes["face"]       = TopAbs_FACE;
+    myShapeTypes["faces"]      = TopAbs_FACE;
+    myShapeTypes["wire"]       = TopAbs_WIRE;
+    myShapeTypes["wires"]      = TopAbs_WIRE;
+    myShapeTypes["edge"]       = TopAbs_EDGE;
+    myShapeTypes["edges"]      = TopAbs_EDGE;
+    myShapeTypes["vertex"]     = TopAbs_VERTEX;
+    myShapeTypes["vertices"]   = TopAbs_VERTEX;
+    myShapeTypes["objects"]    = TopAbs_SHAPE;
   }
   QString aType = theType.toLower();
-  if (MyShapeTypes.contains(aType))
-    return MyShapeTypes[aType];
+  if(myShapeTypes.contains(aType))
+    return myShapeTypes[aType];
   Events_InfoMessage("ModuleBase_Tools", "Shape type defined in XML is not implemented!").send();
   return TopAbs_SHAPE;
 }
@@ -349,14 +559,46 @@ void checkObjects(const QObjectPtrList& theObjects, bool& hasResult, bool& hasFe
   }
 }
 
+bool setDefaultDeviationCoefficient(std::shared_ptr<GeomAPI_Shape> theGeomShape)
+{
+  if (!theGeomShape.get())
+    return false;
+  // if the shape could not be exploded on faces, it contains only wires, edges, and vertices
+  // correction of deviation for them should not influence to the application performance
+  GeomAPI_ShapeExplorer anExp(theGeomShape, GeomAPI_Shape::FACE);
+  bool anEmpty = anExp.empty();
+  return !anExp.more();
+}
+
+void setDefaultDeviationCoefficient(const std::shared_ptr<ModelAPI_Result>& theResult,
+                                    const Handle(Prs3d_Drawer)& theDrawer)
+{
+  if (!theResult.get())
+    return;
+  bool aUseDeviation = false;
+
+  std::string aResultGroup = theResult->groupName();
+  if (aResultGroup == ModelAPI_ResultConstruction::group())
+    aUseDeviation = true;
+  else if (aResultGroup == ModelAPI_ResultBody::group()) {
+    GeomShapePtr aGeomShape = theResult->shape();
+    if (aGeomShape.get())
+      aUseDeviation = setDefaultDeviationCoefficient(aGeomShape);
+  }
+  if (aUseDeviation)
+    theDrawer->SetDeviationCoefficient(DEFAULT_DEVIATION_COEFFICIENT);
+}
+
 void setDefaultDeviationCoefficient(const TopoDS_Shape& theShape,
                                     const Handle(Prs3d_Drawer)& theDrawer)
 {
   if (theShape.IsNull())
     return;
-  TopAbs_ShapeEnum aType = theShape.ShapeType();
-  if ((aType == TopAbs_EDGE) || (aType == TopAbs_WIRE)) 
-    theDrawer->SetDeviationCoefficient(1.e-4);
+
+  std::shared_ptr<GeomAPI_Shape> aGeomShape(new GeomAPI_Shape());
+  aGeomShape->setImpl(new TopoDS_Shape(theShape));
+  if (setDefaultDeviationCoefficient(aGeomShape))
+    theDrawer->SetDeviationCoefficient(DEFAULT_DEVIATION_COEFFICIENT);
 }
 
 Quantity_Color color(const std::string& theSection,
@@ -719,6 +961,18 @@ bool isSubOfComposite(const ObjectPtr& theObject, const FeaturePtr& theFeature)
   return isSub;
 }
 
+//**************************************************************
+ResultPtr firstResult(const ObjectPtr& theObject)
+{
+  ResultPtr aResult = std::dynamic_pointer_cast<ModelAPI_Result>(theObject);
+  if (!aResult.get()) {
+    FeaturePtr aFeature = std::dynamic_pointer_cast<ModelAPI_Feature>(theObject);
+    if (aFeature.get())
+      aResult = aFeature->firstResult();
+  }
+  return aResult;
+}
+
 //**************************************************************
 bool isFeatureOfResult(const FeaturePtr& theFeature, const std::string& theGroupOfResult)
 {
@@ -734,15 +988,42 @@ bool isFeatureOfResult(const FeaturePtr& theFeature, const std::string& theGroup
   return aFirstResult->groupName() == theGroupOfResult;
 }
 
+//**************************************************************
+bool hasModuleDocumentFeature(const std::set<FeaturePtr>& theFeatures)
+{
+  bool aFoundModuleDocumentObject = false;
+  DocumentPtr aModuleDoc = ModelAPI_Session::get()->moduleDocument();
+
+  std::set<FeaturePtr>::const_iterator anIt = theFeatures.begin(), aLast = theFeatures.end();
+  for (; anIt != aLast && !aFoundModuleDocumentObject; anIt++) {
+    FeaturePtr aFeature = *anIt;
+    ResultPtr aResult = ModuleBase_Tools::firstResult(aFeature);
+    if (aResult.get() && aResult->groupName() == ModelAPI_ResultPart::group())
+      continue;
+    aFoundModuleDocumentObject = aFeature->document() == aModuleDoc;
+  }
+
+  return aFoundModuleDocumentObject;
+}
+
 //**************************************************************
 bool askToDelete(const std::set<FeaturePtr> theFeatures,
                  const std::map<FeaturePtr, std::set<FeaturePtr> >& theReferences,
                  QWidget* theParent,
                  std::set<FeaturePtr>& theReferencesToDelete)
 {
+  QString aNotActivatedDocWrn;
+  std::string aNotActivatedNames;
+  if (!ModelAPI_Tools::allDocumentsActivated(aNotActivatedNames)) {
+    if (ModuleBase_Tools::hasModuleDocumentFeature(theFeatures))
+      aNotActivatedDocWrn = QObject::tr("Selected objects can be used in Part documents which are not loaded:%1.\n")
+                            .arg(aNotActivatedNames.c_str());
+  }
+  
   std::set<FeaturePtr> aFeaturesRefsTo;
   std::set<FeaturePtr> aFeaturesRefsToParameter;
   std::set<FeaturePtr> aParameterFeatures;
+  QStringList aPartFeatureNames;
   std::set<FeaturePtr>::const_iterator anIt = theFeatures.begin(),
                                        aLast = theFeatures.end();
   // separate features to references to parameter features and references to others
@@ -751,6 +1032,9 @@ bool askToDelete(const std::set<FeaturePtr> theFeatures,
     if (theReferences.find(aFeature) == theReferences.end())
       continue;
 
+    if (isFeatureOfResult(aFeature, ModelAPI_ResultPart::group()))
+      aPartFeatureNames.append(aFeature->name().c_str());
+
     std::set<FeaturePtr> aRefFeatures;
     std::set<FeaturePtr> aRefList = theReferences.at(aFeature);
     std::set<FeaturePtr>::const_iterator aRefIt = aRefList.begin(), aRefLast = aRefList.end();
@@ -783,7 +1067,7 @@ bool askToDelete(const std::set<FeaturePtr> theFeatures,
     }
   }
   aParamFeatureNames.sort();
-  QStringList aPartFeatureNames, anOtherFeatureNames;
+  QStringList anOtherFeatureNames;
   anIt = theReferencesToDelete.begin();
   aLast = theReferencesToDelete.end();
   for (; anIt != aLast; anIt++) {
@@ -808,6 +1092,8 @@ bool askToDelete(const std::set<FeaturePtr> theFeatures,
   QString aSep = ", ";
   if (!aPartFeatureNames.empty())
     aText += QString(QObject::tr("The following parts will be deleted: %1.\n")).arg(aPartFeatureNames.join(aSep));
+  if (!aNotActivatedDocWrn.isEmpty())
+    aText += aNotActivatedDocWrn;
   if (!anOtherFeatureNames.empty())
     aText += QString(QObject::tr("Selected features are used in the following features: %1.\nThese features will be deleted.\n"))
                      .arg(anOtherFeatureNames.join(aSep));