Salome HOME
IMP 23373: [CEA 1170] Optimization of a 3D mesh using MG-Tetra
[modules/smesh.git] / src / SMESHGUI / SMESHGUI_HypothesesUtils.cxx
1 // Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License, or (at your option) any later version.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 // SMESH SMESHGUI : GUI for SMESH component
24 // File   : SMESHGUI_HypothesesUtils.cxx
25 // Author : Julia DOROVSKIKH, Open CASCADE S.A.S.
26 // SMESH includes
27 //
28 #include "SMESHGUI_HypothesesUtils.h"
29
30 #include "SMESHGUI.h"
31 #include "SMESHGUI_Hypotheses.h"
32 #include "SMESHGUI_XmlHandler.h"
33 #include "SMESHGUI_Utils.h"
34 #include "SMESHGUI_GEOMGenUtils.h"
35
36 // SALOME GUI includes
37 #include <SUIT_Desktop.h>
38 #include <SUIT_MessageBox.h>
39 #include <SUIT_OverrideCursor.h>
40 #include <SUIT_ResourceMgr.h>
41
42 #include <SalomeApp_Study.h>
43 #include <SalomeApp_Tools.h>
44
45 // SALOME KERNEL includes
46 #include <utilities.h>
47
48 // STL includes
49 #include <string>
50
51 // Qt includes
52 #include <QDir>
53
54
55 // Other includes
56 #ifdef WIN32
57 #include <windows.h>
58 #else
59 #include <dlfcn.h>
60 #endif
61
62 #ifdef WIN32
63 #define LibHandle HMODULE
64 #define LoadLib( name ) LoadLibrary( name )
65 #define GetProc GetProcAddress
66 #define UnLoadLib( handle ) FreeLibrary( handle );
67 #else
68 #define LibHandle void*
69 #define LoadLib( name ) dlopen( name, RTLD_LAZY )
70 #define GetProc dlsym
71 #define UnLoadLib( handle ) dlclose( handle );
72 #endif
73
74 #ifdef _DEBUG_
75 static int MYDEBUG = 0;
76 #else
77 static int MYDEBUG = 0;
78 #endif
79
80 namespace SMESH
81 {
82   typedef IMap<QString,HypothesisData*> THypothesisDataMap;
83   THypothesisDataMap myHypothesesMap;
84   THypothesisDataMap myAlgorithmsMap;
85
86   // BUG 0020378
87   //typedef QMap<QString,SMESHGUI_GenericHypothesisCreator*> THypCreatorMap;
88   //THypCreatorMap myHypCreatorMap;
89
90   QList<HypothesesSet*> myListOfHypothesesSets;
91
92   void processHypothesisStatus(const int                   theHypStatus,
93                                SMESH::SMESH_Hypothesis_ptr theHyp,
94                                const bool                  theIsAddition,
95                                const char*                 theError = 0)
96   {
97     if (theHypStatus > SMESH::HYP_OK) {
98       // get Hyp name
99       QString aHypName ("NULL Hypothesis");
100       if (!CORBA::is_nil(theHyp)) {
101         _PTR(SObject) Shyp = SMESH::FindSObject(theHyp);
102         if (Shyp) {
103           // name in study
104           aHypName = Shyp->GetName().c_str();
105         }
106         else {
107           // label in xml file
108           CORBA::String_var hypType = theHyp->GetName();
109           aHypName = GetHypothesisData( hypType.in() )->Label;
110         }
111       }
112
113       // message
114       bool isFatal = (theHypStatus >= SMESH::HYP_UNKNOWN_FATAL);
115       QString aMsg;
116       if (theIsAddition)
117         aMsg = (isFatal ? "SMESH_CANT_ADD_HYP" : "SMESH_ADD_HYP_WRN");
118       else
119         aMsg = (isFatal ? "SMESH_CANT_RM_HYP"  : "SMESH_RM_HYP_WRN");
120
121       aMsg = QObject::tr(aMsg.toLatin1().data()).arg(aHypName);
122
123       if ( theError && theError[0] )
124       {
125         aMsg += theError;
126       }
127       else
128       {
129         aMsg += QObject::tr(QString("SMESH_HYP_%1").arg(theHypStatus).toLatin1().data());
130
131         if ( theHypStatus == SMESH::HYP_HIDDEN_ALGO ) { // PAL18501
132           CORBA::String_var hypType = theHyp->GetName();
133           if ( HypothesisData* hd = GetHypothesisData( hypType.in() ))
134             aMsg = aMsg.arg( hd->Dim[0] );
135         }
136       }
137       SUIT_MessageBox::warning(SMESHGUI::desktop(),
138                                QObject::tr("SMESH_WRN_WARNING"),
139                                aMsg);
140     }
141   }
142
143   //================================================================================
144   /*!
145    * \brief Prepends dimension and appends '[custom]' to the name of hypothesis set
146    */
147   //================================================================================
148
149   static QString mangledHypoSetName(HypothesesSet* hypSet)
150   {
151     QString name = hypSet->name();
152
153     // prepend 'xD: '
154     int dim = hypSet->maxDim();
155     if ( dim > -1 )
156       name = QString("%1D: %2").arg(dim).arg(name);
157
158     // custom
159     if ( hypSet->getIsCustom() )
160       name = QString("%1 [custom]").arg(name);
161
162     return name;
163   }
164
165   //================================================================================
166   /*!
167    * \brief Removes dimension and '[custom]' from the name of hypothesis set
168    */
169   //================================================================================
170
171   static QString demangledHypoSetName(QString name)
172   {
173     name.remove(QRegExp("[0-3]D: "));
174     name.remove(" [custom]");
175     return name;
176   }
177
178   void InitAvailableHypotheses()
179   {
180     SUIT_OverrideCursor wc;
181     if ( myHypothesesMap.empty() && myAlgorithmsMap.empty() )
182     {
183       // Resource manager
184       SUIT_ResourceMgr* resMgr = SMESHGUI::resourceMgr();
185       if (!resMgr) return;
186
187       // Find name of a resource XML file ("SMESH_Meshers.xml");
188       QString HypsXml;
189       char* cenv = getenv("SMESH_MeshersList");
190       if (cenv)
191         HypsXml.sprintf("%s", cenv);
192
193       QStringList HypsXmlList = HypsXml.split(":", QString::SkipEmptyParts);
194       if (HypsXmlList.count() == 0) {
195         SUIT_MessageBox::critical(SMESHGUI::desktop(),
196                                   QObject::tr("SMESH_WRN_WARNING"),
197                                   QObject::tr("MESHERS_FILE_NO_VARIABLE"));
198         return;
199       }
200       // get full names of xml files from HypsXmlList
201       QStringList xmlFiles;
202       xmlFiles.append( QDir::home().filePath("CustomMeshers.xml")); // may be inexistent
203       for (int i = 0; i < HypsXmlList.count(); i++) {
204         QString HypsXml = HypsXmlList[ i ];
205
206         // Find full path to the resource XML file
207         QString xmlFile = resMgr->path("resources", "SMESH", HypsXml + ".xml");
208         if ( xmlFile.isEmpty() ) // try PLUGIN resources
209           xmlFile = resMgr->path("resources", HypsXml, HypsXml + ".xml");
210         if ( !xmlFile.isEmpty() )
211           xmlFiles.append( xmlFile );
212       }
213
214       // loop on xmlFiles
215       QString aNoAccessFiles;
216       for (int i = 0; i < xmlFiles.count(); i++)
217       {
218         QString xmlFile = xmlFiles[ i ];
219         QFile file (xmlFile);
220         if (file.exists() && file.open(QIODevice::ReadOnly))
221         {
222           file.close();
223
224           SMESHGUI_XmlHandler* aXmlHandler = new SMESHGUI_XmlHandler();
225           ASSERT(aXmlHandler);
226
227           QXmlInputSource source (&file);
228           QXmlSimpleReader reader;
229           reader.setContentHandler(aXmlHandler);
230           reader.setErrorHandler(aXmlHandler);
231           bool ok = reader.parse(source);
232           file.close();
233           if (ok) {
234
235             THypothesisDataMap::ConstIterator it1 = aXmlHandler->myHypothesesMap.begin();
236
237             for( ;it1 != aXmlHandler->myHypothesesMap.end(); it1++)
238               myHypothesesMap.insert( it1.key(), it1.value() );
239
240             it1 = aXmlHandler->myAlgorithmsMap.begin();
241             for( ;it1 != aXmlHandler->myAlgorithmsMap.end(); it1++)
242               myAlgorithmsMap.insert( it1.key(), it1.value() );
243
244             QList<HypothesesSet*>::iterator it;
245             for ( it = aXmlHandler->myListOfHypothesesSets.begin();
246                   it != aXmlHandler->myListOfHypothesesSets.end();
247                   ++it )
248             {
249               (*it)->setIsCustom( i == 0 );
250               myListOfHypothesesSets.append( *it );
251             }
252           }
253           else {
254             SUIT_MessageBox::critical(SMESHGUI::desktop(),
255                                       QObject::tr("INF_PARSE_ERROR"),
256                                       QObject::tr(aXmlHandler->errorProtocol().toLatin1().data()));
257           }
258           delete aXmlHandler;
259         }
260         else if ( i > 0 ) { // 1st is ~/CustomMeshers.xml
261           if (aNoAccessFiles.isEmpty())
262             aNoAccessFiles = xmlFile;
263           else
264             aNoAccessFiles += ", " + xmlFile;
265         }
266       } // end loop on xmlFiles
267
268
269       if (!aNoAccessFiles.isEmpty()) {
270         QString aMess = QObject::tr("MESHERS_FILE_CANT_OPEN") + " " + aNoAccessFiles + "\n";
271         aMess += QObject::tr("MESHERS_FILE_CHECK_VARIABLE");
272         wc.suspend();
273         SUIT_MessageBox::warning(SMESHGUI::desktop(),
274                                  QObject::tr("SMESH_WRN_WARNING"),
275                                  aMess);
276         wc.resume();
277       }
278     }
279   }
280
281
282   QStringList GetAvailableHypotheses( const bool isAlgo,
283                                       const int  theDim,
284                                       const bool isAux,
285                                       const bool hasGeometry,
286                                       const bool isSubMesh)
287   {
288     QStringList aHypList;
289
290     // Init list of available hypotheses, if needed
291     InitAvailableHypotheses();
292     bool checkGeometry = ( isAlgo );
293     const char* context = isSubMesh ? "LOCAL" : "GLOBAL";
294     // fill list of hypotheses/algorithms
295     THypothesisDataMap& pMap = isAlgo ? myAlgorithmsMap : myHypothesesMap;
296     THypothesisDataMap::ConstIterator anIter;
297     for ( anIter = pMap.begin(); anIter != pMap.end(); anIter++ )
298     {
299       HypothesisData* aData = anIter.value();
300       if (( aData && !aData->Label.isEmpty() ) &&
301           ( theDim < 0              || aData->Dim.contains( theDim )) &&
302           ( isAlgo                  || aData->IsAuxOrNeedHyp == isAux ) &&
303           ( aData->Context == "ANY" || aData->Context == context ) &&
304           ( !checkGeometry          || (!aData->IsNeedGeometry  ||
305                                         ( aData->IsNeedGeometry > 0 ) == hasGeometry)))
306       {
307         aHypList.append(anIter.key());
308       }
309     }
310     return aHypList;
311   }
312
313
314   QStringList GetHypothesesSets(int maxDim)
315   {
316     QStringList aSetNameList;
317
318     // Init list of available hypotheses, if needed
319     InitAvailableHypotheses();
320     QList<HypothesesSet*>::iterator hypoSet;
321     for ( hypoSet  = myListOfHypothesesSets.begin();
322         hypoSet != myListOfHypothesesSets.end();
323         ++hypoSet ) {
324       HypothesesSet* aSet = *hypoSet;
325       if ( aSet && ( aSet->count( true ) || aSet->count( false )) &&
326           aSet->maxDim() <= maxDim)
327       {
328         aSetNameList.append( mangledHypoSetName( aSet ));
329       }
330     }
331     aSetNameList.removeDuplicates();
332     aSetNameList.sort();
333
334     //  reverse order of aSetNameList
335     QStringList reversedNames;
336     for ( int i = 0; i < aSetNameList.count(); ++i )
337       reversedNames.prepend( aSetNameList[i] );
338
339     return reversedNames;
340   }
341
342   HypothesesSet* GetHypothesesSet(const QString& theSetName)
343   {
344     QString name = demangledHypoSetName( theSetName );
345     QList<HypothesesSet*>::iterator hypoSet;
346     for ( hypoSet  = myListOfHypothesesSets.begin();
347           hypoSet != myListOfHypothesesSets.end();
348           ++hypoSet ) {
349       HypothesesSet* aSet = *hypoSet;
350       if ( aSet && aSet->name() == name )
351         return aSet;
352     }
353     return 0;
354   }
355
356   HypothesisData* GetHypothesisData (const QString& aHypType)
357   {
358     HypothesisData* aHypData = 0;
359
360     // Init list of available hypotheses, if needed
361     InitAvailableHypotheses();
362
363     if (myHypothesesMap.contains(aHypType)) {
364       aHypData = myHypothesesMap[aHypType];
365     }
366     else if (myAlgorithmsMap.contains(aHypType)) {
367       aHypData = myAlgorithmsMap[aHypType];
368     }
369     return aHypData;
370   }
371
372   //================================================================================
373   /*!
374    * \brief Return the HypothesisData holding a name of a group of hypotheses
375    *        a given hypothesis belongs to
376    */
377   //================================================================================
378
379   HypothesisData* GetGroupTitle( const HypothesisData* hyp, const bool isAlgo )
380   {
381     static std::vector< std::vector< HypothesisData > > theGroups;
382     if ( theGroups.empty() )
383     {
384       theGroups.resize(14); // 14: isAlgo * 10 + dim
385
386       QString dummyS("GROUP");
387       QList<int> dummyIL; dummyIL << 1;
388       QStringList dummySL;
389       HypothesisData group( dummyS,dummyS,dummyS,dummyS,dummyS,dummyS,dummyS,-1,-1,
390                             dummyIL, 0, dummySL,dummySL,dummySL,dummySL,0,0 );
391       // no group
392       int key = 0;
393       theGroups[ key ].push_back( group );
394
395       // 1D algo
396       key = 11;
397       //        0: Basic
398       group.Label = "GROUP:" + QObject::tr( "SMESH_1D_ALGO_GROUP_BASIC" );
399       theGroups[ key ].push_back( group );
400       //        1: Advanced
401       group.Label = "GROUP:" + QObject::tr( "SMESH_1D_ALGO_GROUP_ADVANCED" );
402       theGroups[ key ].push_back( group );
403
404       // 1D hypotheses
405       key = 01;
406       //        0: Basic
407       group.Label = "GROUP:" + QObject::tr( "SMESH_1D_HYP_GROUP_BASIC" );
408       theGroups[ key ].push_back( group );
409       //        1: Progression
410       group.Label = "GROUP:" + QObject::tr( "SMESH_1D_HYP_GROUP_PROGRESSION" );
411       theGroups[ key ].push_back( group );
412       //        2: Advanced
413       group.Label = "GROUP:" + QObject::tr( "SMESH_1D_HYP_GROUP_ADVANCED" );
414       theGroups[ key ].push_back( group );
415
416       // 2D algo
417       key = 12;
418       //        0: Regular
419       group.Label = "GROUP:" + QObject::tr( "SMESH_2D_ALGO_GROUP_REGULAR" );
420       theGroups[ key ].push_back( group );
421       //        1: Free
422       group.Label = "GROUP:" + QObject::tr( "SMESH_2D_ALGO_GROUP_FREE" );
423       theGroups[ key ].push_back( group );
424       //        2: Advanced
425       group.Label = "GROUP:" + QObject::tr( "SMESH_2D_ALGO_GROUP_ADVANCED" );
426       theGroups[ key ].push_back( group );
427
428       // 3D algo
429       key = 13;
430       //        0: Regular
431       group.Label = "GROUP:" + QObject::tr( "SMESH_3D_ALGO_GROUP_REGULAR" );
432       theGroups[ key ].push_back( group );
433       //        1: Free
434       group.Label = "GROUP:" + QObject::tr( "SMESH_3D_ALGO_GROUP_FREE" );
435       theGroups[ key ].push_back( group );
436       //        2: Advanced
437       group.Label = "GROUP:" + QObject::tr( "SMESH_3D_ALGO_GROUP_ADVANCED" );
438       theGroups[ key ].push_back( group );
439     }
440
441     size_t key = 0, groupID = 0;
442     if ( hyp && !hyp->Dim.isEmpty() )
443     {
444       key     = hyp->Dim[0] + isAlgo * 10;
445       groupID = hyp->GroupID;
446     }
447
448     if ( key < theGroups.size() && !theGroups[ key ].empty() )
449     {
450       std::vector< HypothesisData > & group = theGroups[ key ];
451       return & ( groupID < group.size() ? group[ groupID ] : group.back() );
452     }
453     return & theGroups[ 0 ][ 0 ];
454   }
455
456   bool IsAvailableHypothesis(const HypothesisData* algoData,
457                              const QString&        hypType,
458                              bool&                 isAuxiliary)
459   {
460     isAuxiliary = false;
461     if ( !algoData )
462       return false;
463     if ( algoData->BasicHypos.contains( hypType ))
464       return true;
465     if ( algoData->OptionalHypos.contains( hypType )) {
466       isAuxiliary = true;
467       return true;
468     }
469     return false;
470   }
471
472   bool IsCompatibleAlgorithm(const HypothesisData* algo1Data,
473                              const HypothesisData* algo2Data)
474   {
475     if ( !algo1Data || !algo2Data )
476       return false;
477     const HypothesisData* algoIn = algo1Data, *algoMain = algo2Data;
478     if ( algoIn->Dim.first() > algoMain->Dim.first() ) {
479       algoIn = algo2Data; algoMain = algo1Data;
480     }
481     // look for any output type of algoIn between input types of algoMain
482     QStringList::const_iterator inElemType = algoIn->OutputTypes.begin();
483     for ( ; inElemType != algoIn->OutputTypes.end(); ++inElemType )
484       if ( algoMain->InputTypes.contains( *inElemType ))
485         return true;
486     return false;
487   }
488
489   SMESHGUI_GenericHypothesisCreator* GetHypothesisCreator(const QString& aHypType)
490   {
491     if(MYDEBUG) MESSAGE("Get HypothesisCreator for " << aHypType.toLatin1().data());
492
493     SMESHGUI_GenericHypothesisCreator* aCreator = 0;
494
495     // check, if creator for this hypothesis type already exists
496     // BUG 0020378
497     //if (myHypCreatorMap.find(aHypType) != myHypCreatorMap.end()) {
498     //  aCreator = myHypCreatorMap[aHypType];
499     //}
500     //else
501     {
502       // 1. Init list of available hypotheses, if needed
503       InitAvailableHypotheses();
504
505       // 2. Get names of plugin libraries
506       HypothesisData* aHypData = GetHypothesisData(aHypType);
507       if (!aHypData)
508         return aCreator;
509
510       QString aClientLibName = aHypData->ClientLibName;
511       QString aServerLibName = aHypData->ServerLibName;
512
513       // 3. Load Client Plugin Library
514       try {
515         // load plugin library
516         if(MYDEBUG) MESSAGE("Loading client meshers plugin library ...");
517         LibHandle libHandle = LoadLib( aClientLibName.toLatin1().data() );
518         if (!libHandle) {
519           // report any error, if occured
520           {
521 #ifdef WIN32
522             const char* anError = "Can't load client meshers plugin library";
523 #else
524             const char* anError = dlerror();
525 #endif
526             INFOS(anError); // always display this kind of error !
527           }
528         }
529         else {
530           // get method, returning hypothesis creator
531           if(MYDEBUG) MESSAGE("Find GetHypothesisCreator() method ...");
532           typedef SMESHGUI_GenericHypothesisCreator* (*GetHypothesisCreator) \
533             ( const QString& );
534           GetHypothesisCreator procHandle =
535             (GetHypothesisCreator)GetProc(libHandle, "GetHypothesisCreator");
536           if (!procHandle) {
537             if(MYDEBUG) MESSAGE("bad hypothesis client plugin library");
538             UnLoadLib(libHandle);
539           }
540           else {
541             // get hypothesis creator
542             if(MYDEBUG) MESSAGE("Get Hypothesis Creator for " << aHypType.toLatin1().data());
543             aCreator = procHandle( aHypType );
544             if (!aCreator) {
545               if(MYDEBUG) MESSAGE("no such a hypothesis in this plugin");
546             }
547             else {
548               // map hypothesis creator to a hypothesis name
549               // BUG 0020378
550               //myHypCreatorMap[aHypType] = aCreator;
551
552               //rnv : This dynamic property of the QObject stores the name of the plugin.
553               //      It is used to obtain plugin root dir environment variable
554               //      in the SMESHGUI_HypothesisDlg class. Plugin root dir environment
555               //      variable is used to display documentation.
556               aCreator->setProperty(SMESH::Plugin_Name(),aHypData->PluginName);
557             }
558           }
559         }
560       }
561       catch (const SALOME::SALOME_Exception& S_ex) {
562         SalomeApp_Tools::QtCatchCorbaException(S_ex);
563       }
564     }
565
566     return aCreator;
567   }
568
569
570   SMESH::SMESH_Hypothesis_ptr CreateHypothesis(const QString& aHypType,
571                                                const QString& aHypName,
572                                                const bool isAlgo)
573   {
574     if(MYDEBUG) MESSAGE("Create " << aHypType.toLatin1().data() <<
575                         " with name " << aHypName.toLatin1().data());
576     HypothesisData* aHypData = GetHypothesisData(aHypType);
577     QString aServLib = aHypData->ServerLibName;
578     try {
579       SMESH::SMESH_Hypothesis_var aHypothesis;
580       aHypothesis = SMESHGUI::GetSMESHGen()->CreateHypothesis(aHypType.toLatin1().data(),
581                                                               aServLib.toLatin1().data());
582       if (!aHypothesis->_is_nil()) {
583         _PTR(SObject) aHypSObject = SMESH::FindSObject(aHypothesis.in());
584         if (aHypSObject) {
585           if (!aHypName.isEmpty())
586             SMESH::SetName(aHypSObject, aHypName);
587           SMESHGUI::Modified();
588           SMESHGUI::GetSMESHGUI()->updateObjBrowser();
589           return aHypothesis._retn();
590         }
591       }
592     } catch (const SALOME::SALOME_Exception & S_ex) {
593       SalomeApp_Tools::QtCatchCorbaException(S_ex);
594     }
595
596     return SMESH::SMESH_Hypothesis::_nil();
597   }
598
599   bool IsApplicable(const QString&        aHypType,
600                     GEOM::GEOM_Object_ptr theGeomObject,
601                     const bool            toCheckAll)
602   {
603     if ( getenv("NO_LIMIT_ALGO_BY_SHAPE")) // allow a workaround for a case if
604       return true;                         // IsApplicable() returns false due to a bug
605
606     HypothesisData* aHypData = GetHypothesisData(aHypType);
607     QString aServLib = aHypData->ServerLibName;
608     return SMESHGUI::GetSMESHGen()->IsApplicable( aHypType.toLatin1().data(),
609                                                   aServLib.toLatin1().data(),
610                                                   theGeomObject,
611                                                   toCheckAll);
612   }
613
614
615   bool AddHypothesisOnMesh (SMESH::SMESH_Mesh_ptr aMesh, SMESH::SMESH_Hypothesis_ptr aHyp)
616   {
617     if(MYDEBUG) MESSAGE ("SMESHGUI::AddHypothesisOnMesh");
618     int res = SMESH::HYP_UNKNOWN_FATAL;
619     SUIT_OverrideCursor wc;
620
621     if (!aMesh->_is_nil()) {
622       _PTR(SObject) SM = SMESH::FindSObject(aMesh);
623       GEOM::GEOM_Object_var aShapeObject = SMESH::GetShapeOnMeshOrSubMesh(SM);
624       try {
625         CORBA::String_var error;
626         res = aMesh->AddHypothesis(aShapeObject, aHyp, error.out());
627         if (res < SMESH::HYP_UNKNOWN_FATAL) {
628           _PTR(SObject) aSH = SMESH::FindSObject(aHyp);
629           if (SM && aSH) {
630             SMESH::ModifiedMesh(SM, false, aMesh->NbNodes()==0);
631           }
632         }
633         if (res > SMESH::HYP_OK) {
634           wc.suspend();
635           processHypothesisStatus(res, aHyp, true, error.in() );
636           wc.resume();
637         }
638       }
639       catch(const SALOME::SALOME_Exception& S_ex) {
640         wc.suspend();
641         SalomeApp_Tools::QtCatchCorbaException(S_ex);
642         res = SMESH::HYP_UNKNOWN_FATAL;
643       }
644     }
645     return res < SMESH::HYP_UNKNOWN_FATAL;
646   }
647
648
649   bool AddHypothesisOnSubMesh (SMESH::SMESH_subMesh_ptr aSubMesh, SMESH::SMESH_Hypothesis_ptr aHyp)
650   {
651     if(MYDEBUG) MESSAGE("SMESHGUI::AddHypothesisOnSubMesh() ");
652     int res = SMESH::HYP_UNKNOWN_FATAL;
653     SUIT_OverrideCursor wc;
654
655     if (!aSubMesh->_is_nil() && ! aHyp->_is_nil()) {
656       try {
657         SMESH::SMESH_Mesh_var aMesh = aSubMesh->GetFather();
658         _PTR(SObject) SsubM = SMESH::FindSObject(aSubMesh);
659         GEOM::GEOM_Object_var aShapeObject = SMESH::GetShapeOnMeshOrSubMesh(SsubM);
660         if (!aMesh->_is_nil() && SsubM && !aShapeObject->_is_nil())
661         {
662           CORBA::String_var error;
663           res = aMesh->AddHypothesis( aShapeObject, aHyp, error.out() );
664           if (res < SMESH::HYP_UNKNOWN_FATAL)  {
665             _PTR(SObject) meshSO = SMESH::FindSObject(aMesh);
666             if (meshSO)
667               SMESH::ModifiedMesh(meshSO, false, aMesh->NbNodes()==0);
668           }
669           if (res > SMESH::HYP_OK) {
670             wc.suspend();
671             processHypothesisStatus( res, aHyp, true, error.in() );
672             wc.resume();
673           }
674         }
675         else {
676           SCRUTE(aHyp->_is_nil());
677           SCRUTE(aMesh->_is_nil());
678           SCRUTE(!SsubM);
679           SCRUTE(aShapeObject->_is_nil());
680         }
681       }
682       catch(const SALOME::SALOME_Exception& S_ex) {
683         wc.suspend();
684         SalomeApp_Tools::QtCatchCorbaException(S_ex);
685         res = SMESH::HYP_UNKNOWN_FATAL;
686       }
687     }
688     else {
689       SCRUTE(aSubMesh->_is_nil());
690       SCRUTE(aHyp->_is_nil());
691     }
692     return res < SMESH::HYP_UNKNOWN_FATAL;
693   }
694
695   bool RemoveHypothesisOrAlgorithmOnMesh (const Handle(SALOME_InteractiveObject)& IObject)
696   {
697     int res = SMESH::HYP_UNKNOWN_FATAL;
698     SUIT_OverrideCursor wc;
699
700     try {
701       _PTR(Study) aStudy = GetActiveStudyDocument();
702       _PTR(SObject) aHypObj = aStudy->FindObjectID( IObject->getEntry() );
703       if( aHypObj )
704         {
705           _PTR(SObject) MorSM = SMESH::GetMeshOrSubmesh( aHypObj );
706           _PTR(SObject) aRealHypo;
707           if( aHypObj->ReferencedObject( aRealHypo ) )
708             {
709               SMESH_Hypothesis_var hypo = SMESH_Hypothesis::_narrow( SObjectToObject( aRealHypo ) );
710               RemoveHypothesisOrAlgorithmOnMesh( MorSM, hypo );
711             }
712           else
713             {
714               SMESH_Hypothesis_var hypo = SMESH_Hypothesis::_narrow( SObjectToObject( aHypObj ) );
715               SObjectList meshList = GetMeshesUsingAlgoOrHypothesis( hypo );
716               for( size_t i = 0; i < meshList.size(); i++ )
717                 RemoveHypothesisOrAlgorithmOnMesh( meshList[ i ], hypo );
718             }
719         }
720     }
721     catch(const SALOME::SALOME_Exception& S_ex)
722       {
723         wc.suspend();
724         SalomeApp_Tools::QtCatchCorbaException(S_ex);
725         res = SMESH::HYP_UNKNOWN_FATAL;
726       }
727     return res < SMESH::HYP_UNKNOWN_FATAL;
728   }
729
730   bool RemoveHypothesisOrAlgorithmOnMesh (_PTR(SObject)               MorSM,
731                                           SMESH::SMESH_Hypothesis_ptr anHyp)
732   {
733     int res = SMESH::HYP_UNKNOWN_FATAL;
734     SUIT_OverrideCursor wc;
735
736     if (MorSM) {
737       try {
738         GEOM::GEOM_Object_var aShapeObject = SMESH::GetShapeOnMeshOrSubMesh(MorSM);
739         SMESH::SMESH_Mesh_var aMesh        = SMESH::SObjectToInterface<SMESH::SMESH_Mesh>(MorSM);
740         SMESH::SMESH_subMesh_var aSubMesh  = SMESH::SObjectToInterface<SMESH::SMESH_subMesh>(MorSM);
741
742         if (!aSubMesh->_is_nil())
743           aMesh = aSubMesh->GetFather();
744
745         if (!aMesh->_is_nil()) {
746           if (aMesh->HasShapeToMesh() && !aShapeObject->_is_nil()) {
747             res = aMesh->RemoveHypothesis(aShapeObject, anHyp);
748             if (res < SMESH::HYP_UNKNOWN_FATAL) {
749               _PTR(SObject) meshSO = SMESH::FindSObject(aMesh);
750               if (meshSO)
751                 SMESH::ModifiedMesh(meshSO, false, aMesh->NbNodes()==0);
752             }
753
754           }
755           else if(!aMesh->HasShapeToMesh()){
756             res = aMesh->RemoveHypothesis(aShapeObject, anHyp);
757             if (res < SMESH::HYP_UNKNOWN_FATAL) {
758               _PTR(SObject) meshSO = SMESH::FindSObject(aMesh);
759               if (meshSO)
760                 SMESH::ModifiedMesh(meshSO, false, aMesh->NbNodes()==0);
761             }
762           }
763           if (res > SMESH::HYP_OK) {
764             wc.suspend();
765             processHypothesisStatus(res, anHyp, false);
766             wc.resume();
767           }
768         }
769       } catch(const SALOME::SALOME_Exception& S_ex) {
770         wc.suspend();
771         SalomeApp_Tools::QtCatchCorbaException(S_ex);
772         res = SMESH::HYP_UNKNOWN_FATAL;
773       }
774     }
775     return res < SMESH::HYP_UNKNOWN_FATAL;
776   }
777
778   SObjectList GetMeshesUsingAlgoOrHypothesis(SMESH::SMESH_Hypothesis_ptr AlgoOrHyp)
779   {
780     SObjectList listSOmesh;
781     listSOmesh.resize(0);
782
783     unsigned int index = 0;
784     if (!AlgoOrHyp->_is_nil()) {
785       _PTR(SObject) SO_Hypothesis = SMESH::FindSObject(AlgoOrHyp);
786       if (SO_Hypothesis) {
787         SObjectList listSO =
788           SMESHGUI::activeStudy()->studyDS()->FindDependances(SO_Hypothesis);
789
790         if(MYDEBUG) MESSAGE("SMESHGUI::GetMeshesUsingAlgoOrHypothesis(): dependency number ="<<listSO.size());
791         for (unsigned int i = 0; i < listSO.size(); i++) {
792           _PTR(SObject) SO = listSO[i];
793           if (SO) {
794             _PTR(SObject) aFather = SO->GetFather();
795             if (aFather) {
796               _PTR(SObject) SOfatherFather = aFather->GetFather();
797               if (SOfatherFather) {
798                 if(MYDEBUG) MESSAGE("SMESHGUI::GetMeshesUsingAlgoOrHypothesis(): dependency added to list");
799                 index++;
800                 listSOmesh.resize(index);
801                 listSOmesh[index - 1] = SOfatherFather;
802               }
803             }
804           }
805         }
806       }
807     }
808     if (MYDEBUG) MESSAGE("SMESHGUI::GetMeshesUsingAlgoOrHypothesis(): completed");
809     return listSOmesh;
810   }
811
812 #define CASE2MESSAGE(enum) case SMESH::enum: msg = QObject::tr( "STATE_" #enum ); break;
813   QString GetMessageOnAlgoStateErrors(const algo_error_array& errors)
814   {
815     QString resMsg; // PAL14861 = QObject::tr("SMESH_WRN_MISSING_PARAMETERS") + ":\n";
816     for ( size_t i = 0; i < errors.length(); ++i ) {
817       const SMESH::AlgoStateError & error = errors[ i ];
818       const bool hasAlgo = ( strlen( error.algoName ) != 0 );
819       QString msg;
820       if ( !hasAlgo )
821         msg = QObject::tr( "STATE_ALGO_MISSING" );
822       else
823         switch( error.state ) {
824           CASE2MESSAGE( HYP_MISSING );
825           CASE2MESSAGE( HYP_NOTCONFORM );
826           CASE2MESSAGE( HYP_BAD_PARAMETER );
827           CASE2MESSAGE( HYP_BAD_GEOMETRY );
828         default: continue;
829         }
830       // apply args to message:
831       // %1 - algo name
832       if ( hasAlgo )
833         msg = msg.arg( error.algoName.in() );
834       // %2 - dimension
835       msg = msg.arg( error.algoDim );
836       // %3 - global/local
837       msg = msg.arg( QObject::tr( error.isGlobalAlgo ? "GLOBAL_ALGO" : "LOCAL_ALGO" ));
838       // %4 - hypothesis dim == algoDim
839       msg = msg.arg( error.algoDim );
840
841       if ( i ) resMsg += ";\n";
842       resMsg += msg;
843     }
844     return resMsg;
845   }
846 } // end of namespace SMESH