Salome HOME
PAL18501 Bug in Netgen 1D2D3D assignement
[modules/smesh.git] / src / SMESHGUI / SMESHGUI_HypothesesUtils.cxx
1 //  Copyright (C) 2003  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
2 //  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
3 //
4 //  This library is free software; you can redistribute it and/or
5 //  modify it under the terms of the GNU Lesser General Public
6 //  License as published by the Free Software Foundation; either
7 //  version 2.1 of the License.
8 //
9 //  This library is distributed in the hope that it will be useful,
10 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 //  Lesser General Public License for more details.
13 //
14 //  You should have received a copy of the GNU Lesser General Public
15 //  License along with this library; if not, write to the Free Software
16 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
17 //
18 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
19
20 #include "SMESHGUI_HypothesesUtils.h"
21
22 #include "SMESHGUI.h"
23 #include "SMESHGUI_Hypotheses.h"
24 #include "SMESHGUI_XmlHandler.h"
25 #include "SMESHGUI_Utils.h"
26 #include "SMESHGUI_GEOMGenUtils.h"
27
28 #include "SUIT_Tools.h"
29 #include "SUIT_Desktop.h"
30 #include "SUIT_MessageBox.h"
31 #include "SUIT_OverrideCursor.h"
32 #include "SUIT_ResourceMgr.h"
33 #include "SUIT_Session.h"
34
35 #include "OB_Browser.h"
36
37 #include "SalomeApp_Study.h"
38 #include "SalomeApp_Tools.h"
39 #include "SalomeApp_Application.h"
40
41 #include <SALOMEDSClient_Study.hxx>
42 #include <SALOMEDSClient_SObject.hxx>
43
44 #include "SALOMEconfig.h"
45 #include CORBA_CLIENT_HEADER(SALOMEDS_Attributes)
46
47 #include <map>
48 #include <string>
49
50 #include <dlfcn.h>
51
52 #ifdef _DEBUG_
53 static int MYDEBUG = 0;
54 #else
55 static int MYDEBUG = 0;
56 #endif
57
58 namespace SMESH{
59
60   using namespace std;
61
62   typedef map<string,HypothesisData*> THypothesisDataMap;
63   THypothesisDataMap myHypothesesMap;
64   THypothesisDataMap myAlgorithmsMap;
65
66   typedef map<string,SMESHGUI_GenericHypothesisCreator*> THypCreatorMap;
67   THypCreatorMap myHypCreatorMap;
68
69   list<HypothesesSet*> myListOfHypothesesSets;
70
71   void processHypothesisStatus(const int theHypStatus,
72                                SMESH::SMESH_Hypothesis_ptr theHyp,
73                                const bool theIsAddition)
74   {
75     if (theHypStatus > SMESH::HYP_OK) {
76
77       // get Hyp name
78       QString aHypName ("NULL Hypothesis");
79       if (!CORBA::is_nil(theHyp)) {
80         _PTR(SObject) Shyp = SMESH::FindSObject(theHyp);
81         if (Shyp)
82           // name in study
83           aHypName = Shyp->GetName().c_str();
84         else
85           // label in xml file
86           aHypName = GetHypothesisData(theHyp->GetName())->Label;
87       }
88
89       // message
90       bool isFatal = (theHypStatus >= SMESH::HYP_UNKNOWN_FATAL);
91       QString aMsg;
92       if (theIsAddition)
93         aMsg = (isFatal ? "SMESH_CANT_ADD_HYP" : "SMESH_ADD_HYP_WRN");
94       else
95         aMsg = (isFatal ? "SMESH_CANT_RM_HYP"  : "SMESH_RM_HYP_WRN");
96
97       aMsg = QObject::tr(aMsg).arg(aHypName) +
98         QObject::tr(QString("SMESH_HYP_%1").arg(theHypStatus));
99
100       if ( theHypStatus == SMESH::HYP_HIDDEN_ALGO ) // PAL18501
101         aMsg = aMsg.arg( GetHypothesisData(theHyp->GetName())->Dim[0] );
102
103       SUIT_MessageBox::warn1(SMESHGUI::desktop(),
104                             QObject::tr("SMESH_WRN_WARNING"),
105                             aMsg,
106                             QObject::tr("SMESH_BUT_OK"));
107     }
108   }
109
110
111   void InitAvailableHypotheses()
112   {
113     SUIT_OverrideCursor wc;
114     if (myHypothesesMap.empty() && myAlgorithmsMap.empty()) {
115       // Resource manager
116       SUIT_ResourceMgr* resMgr = SMESHGUI::resourceMgr();
117       if (!resMgr) return;
118
119       // Find name of a resource XML file ("SMESH_Meshers.xml");
120       QString HypsXml;
121       char* cenv = getenv("SMESH_MeshersList");
122       if (cenv)
123         HypsXml.sprintf("%s", cenv);
124
125       QStringList HypsXmlList = QStringList::split(":", HypsXml, false);
126       if (HypsXmlList.count() == 0)
127         {
128           SUIT_MessageBox::error1(SMESHGUI::desktop(),
129                                  QObject::tr("SMESH_WRN_WARNING"),
130                                  QObject::tr("MESHERS_FILE_NO_VARIABLE"),
131                                  QObject::tr("SMESH_BUT_OK"));
132           return;
133         }
134
135       // loop on files in HypsXml
136       QString aNoAccessFiles;
137       for (int i = 0; i < HypsXmlList.count(); i++) {
138         QString HypsXml = HypsXmlList[ i ];
139
140         // Find full path to the resource XML file
141         QString xmlFile = resMgr->path("resources", "SMESH", HypsXml + ".xml");
142         if ( xmlFile.isEmpty() ) // try PLUGIN resources
143           xmlFile = resMgr->path("resources", HypsXml, HypsXml + ".xml");
144         
145         QFile file (xmlFile);
146         if (file.exists() && file.open(IO_ReadOnly)) {
147           file.close();
148
149           SMESHGUI_XmlHandler* aXmlHandler = new SMESHGUI_XmlHandler();
150           ASSERT(aXmlHandler);
151
152           QXmlInputSource source (file);
153           QXmlSimpleReader reader;
154           reader.setContentHandler(aXmlHandler);
155           reader.setErrorHandler(aXmlHandler);
156           bool ok = reader.parse(source);
157           file.close();
158           if (ok) {
159             myHypothesesMap.insert( aXmlHandler->myHypothesesMap.begin(),
160                                     aXmlHandler->myHypothesesMap.end() );
161             myAlgorithmsMap.insert( aXmlHandler->myAlgorithmsMap.begin(),
162                                     aXmlHandler->myAlgorithmsMap.end() );
163             myListOfHypothesesSets.splice( myListOfHypothesesSets.begin(),
164                                            aXmlHandler->myListOfHypothesesSets );
165           }
166           else {
167             SUIT_MessageBox::error1(SMESHGUI::desktop(),
168                                    QObject::tr("INF_PARSE_ERROR"),
169                                    QObject::tr(aXmlHandler->errorProtocol()),
170                                    QObject::tr("SMESH_BUT_OK"));
171           }
172         }
173         else {
174           if (aNoAccessFiles.isEmpty())
175             aNoAccessFiles = xmlFile;
176           else
177             aNoAccessFiles += ", " + xmlFile;
178         }
179       } // end loop
180
181
182       if (!aNoAccessFiles.isEmpty()) {
183         QString aMess = QObject::tr("MESHERS_FILE_CANT_OPEN") + " " + aNoAccessFiles + "\n";
184         aMess += QObject::tr("MESHERS_FILE_CHECK_VARIABLE");
185         wc.suspend();
186         SUIT_MessageBox::warn1(SMESHGUI::desktop(),
187                               QObject::tr("SMESH_WRN_WARNING"),
188                               aMess,
189                               QObject::tr("SMESH_BUT_OK"));
190         wc.resume();
191       }
192     }
193   }
194
195
196   QStringList GetAvailableHypotheses( const bool isAlgo, 
197                                       const int theDim,                          
198                                       const bool isAux )
199   {
200     QStringList aHypList;
201
202     // Init list of available hypotheses, if needed
203     InitAvailableHypotheses();
204
205     // fill list of hypotheses/algorithms
206     THypothesisDataMap* pMap = isAlgo ? &myAlgorithmsMap : &myHypothesesMap;
207     THypothesisDataMap::iterator anIter;
208     for ( anIter = pMap->begin(); anIter != pMap->end(); anIter++ )
209     {
210       HypothesisData* aData = (*anIter).second;
211       if ( ( theDim < 0 || aData->Dim.contains( theDim ) ) && aData->IsAux == isAux )
212         aHypList.append(((*anIter).first).c_str());
213     }
214     return aHypList;
215   }
216
217
218   QStringList GetHypothesesSets()
219   {
220     QStringList aSetNameList;
221
222     // Init list of available hypotheses, if needed
223     InitAvailableHypotheses();
224
225     list<HypothesesSet*>::iterator hypoSet = myListOfHypothesesSets.begin();
226     for ( ; hypoSet != myListOfHypothesesSets.end(); ++hypoSet )
227     {
228       HypothesesSet* aSet = *hypoSet;
229       if ( aSet && aSet->AlgoList.count() ) {
230         aSetNameList.append( aSet->HypoSetName );
231       }
232     }
233
234     return aSetNameList;
235   }
236
237   HypothesesSet* GetHypothesesSet(const QString theSetName)
238   {
239     list<HypothesesSet*>::iterator hypoSet = myListOfHypothesesSets.begin();
240     for ( ; hypoSet != myListOfHypothesesSets.end(); ++hypoSet )
241     {
242       HypothesesSet* aSet = *hypoSet;
243       if ( aSet && aSet->HypoSetName == theSetName )
244         return aSet;
245     }
246     return 0;
247   }
248
249   HypothesisData* GetHypothesisData (const char* aHypType)
250   {
251     HypothesisData* aHypData = 0;
252
253     // Init list of available hypotheses, if needed
254     InitAvailableHypotheses();
255
256     THypothesisDataMap::iterator type_data = myHypothesesMap.find(aHypType);
257     if (type_data != myHypothesesMap.end()) {
258       aHypData = type_data->second;
259     }
260     else {
261       type_data = myAlgorithmsMap.find(aHypType);
262       if (type_data != myAlgorithmsMap.end())
263         aHypData = type_data->second;
264     }
265     return aHypData;
266   }
267
268   bool IsAvailableHypothesis(const HypothesisData* algoData,
269                              const QString&        hypType,
270                              bool&                 isAuxiliary)
271   {
272     isAuxiliary = false;
273     if ( !algoData )
274       return false;
275     if ( algoData->NeededHypos.contains( hypType ))
276       return true;
277     if ( algoData->OptionalHypos.contains( hypType)) {
278       isAuxiliary = true;
279       return true;
280     }
281     return false;
282   }
283
284   bool IsCompatibleAlgorithm(const HypothesisData* algo1Data,
285                              const HypothesisData* algo2Data)
286   {
287     if ( !algo1Data || !algo2Data )
288       return false;
289     const HypothesisData* algoIn = algo1Data, *algoMain = algo2Data;
290     if ( algoIn->Dim.first() > algoMain->Dim.first() ) {
291       algoIn = algo2Data; algoMain = algo1Data;
292     }
293     // look for any output type of algoIn between input types of algoMain
294     QStringList::const_iterator inElemType = algoIn->OutputTypes.begin();
295     for ( ; inElemType != algoIn->OutputTypes.end(); ++inElemType )
296       if ( algoMain->InputTypes.contains( *inElemType ))
297         return true;
298     return false;
299   }
300
301   SMESHGUI_GenericHypothesisCreator* GetHypothesisCreator(const char* aHypType)
302   {
303     if(MYDEBUG) MESSAGE("Get HypothesisCreator for " << aHypType);
304
305     SMESHGUI_GenericHypothesisCreator* aCreator = 0;
306
307     // check, if creator for this hypothesis type already exists
308     if (myHypCreatorMap.find(aHypType) != myHypCreatorMap.end()) {
309       aCreator = myHypCreatorMap[aHypType];
310     }
311     else {
312       // 1. Init list of available hypotheses, if needed
313       InitAvailableHypotheses();
314
315       // 2. Get names of plugin libraries
316       HypothesisData* aHypData = GetHypothesisData(aHypType);
317       if (!aHypData) 
318         return aCreator;
319       QString aClientLibName = aHypData->ClientLibName;
320       QString aServerLibName = aHypData->ServerLibName;
321
322       // 3. Load Client Plugin Library
323       try {
324         // load plugin library
325         if(MYDEBUG) MESSAGE("Loading client meshers plugin library ...");
326         void* libHandle = dlopen (aClientLibName, RTLD_LAZY);
327         if (!libHandle) {
328           // report any error, if occured
329           const char* anError = dlerror();
330           MESSAGE(anError);
331         }
332         else {
333           // get method, returning hypothesis creator
334           if(MYDEBUG) MESSAGE("Find GetHypothesisCreator() method ...");
335           typedef SMESHGUI_GenericHypothesisCreator* (*GetHypothesisCreator) \
336             ( const QString& );
337           GetHypothesisCreator procHandle =
338             (GetHypothesisCreator)dlsym(libHandle, "GetHypothesisCreator");
339           if (!procHandle) {
340             if(MYDEBUG) MESSAGE("bad hypothesis client plugin library");
341             dlclose(libHandle);
342           }
343           else {
344             // get hypothesis creator
345             if(MYDEBUG) MESSAGE("Get Hypothesis Creator for " << aHypType);
346             aCreator = procHandle( aHypType );
347             if (!aCreator) {
348               if(MYDEBUG) MESSAGE("no such a hypothesis in this plugin");
349             }
350             else {
351               // map hypothesis creator to a hypothesis name
352               myHypCreatorMap[aHypType] = aCreator;
353             }
354           }
355         }
356       }
357       catch (const SALOME::SALOME_Exception& S_ex) {
358         SalomeApp_Tools::QtCatchCorbaException(S_ex);
359       }
360     }
361
362     return aCreator;
363   }
364
365
366   SMESH::SMESH_Hypothesis_ptr CreateHypothesis(const char* aHypType,
367                                                const char* aHypName,
368                                                const bool isAlgo)
369   {
370     if(MYDEBUG) MESSAGE("Create " << aHypType << " with name " << aHypName);
371     HypothesisData* aHypData = GetHypothesisData(aHypType);
372     QString aServLib = aHypData->ServerLibName;
373     try {
374       SMESH::SMESH_Hypothesis_var aHypothesis;
375       aHypothesis = SMESHGUI::GetSMESHGen()->CreateHypothesis(aHypType, aServLib);
376       if (!aHypothesis->_is_nil()) {
377         _PTR(SObject) aHypSObject = SMESH::FindSObject(aHypothesis.in());
378         if (aHypSObject) {
379           if (strlen(aHypName) > 0)
380             SMESH::SetName(aHypSObject, aHypName);
381           SMESHGUI::GetSMESHGUI()->updateObjBrowser();
382           return aHypothesis._retn();
383         }
384       }
385     } catch (const SALOME::SALOME_Exception & S_ex) {
386       SalomeApp_Tools::QtCatchCorbaException(S_ex);
387     }
388
389     return SMESH::SMESH_Hypothesis::_nil();
390   }
391
392
393   bool AddHypothesisOnMesh (SMESH::SMESH_Mesh_ptr aMesh, SMESH::SMESH_Hypothesis_ptr aHyp)
394   {
395     if(MYDEBUG) MESSAGE ("SMESHGUI::AddHypothesisOnMesh");
396     int res = SMESH::HYP_UNKNOWN_FATAL;
397     SUIT_OverrideCursor wc;
398
399     if (!aMesh->_is_nil()) {
400       _PTR(SObject) SM = SMESH::FindSObject(aMesh);
401       GEOM::GEOM_Object_var aShapeObject = SMESH::GetShapeOnMeshOrSubMesh(SM);
402       try {
403         res = aMesh->AddHypothesis(aShapeObject, aHyp);
404         if (res < SMESH::HYP_UNKNOWN_FATAL) {
405           _PTR(SObject) aSH = SMESH::FindSObject(aHyp);
406           if (SM && aSH) {
407             SMESH::ModifiedMesh(SM, false, aMesh->NbNodes()==0);
408           }
409         }
410         if (res > SMESH::HYP_OK) {
411           wc.suspend();
412           processHypothesisStatus(res, aHyp, true);
413           wc.resume();
414         }
415       }
416       catch(const SALOME::SALOME_Exception& S_ex) {
417         wc.suspend();
418         SalomeApp_Tools::QtCatchCorbaException(S_ex);
419         res = SMESH::HYP_UNKNOWN_FATAL;
420       }
421     }
422     return res < SMESH::HYP_UNKNOWN_FATAL;
423   }
424
425
426   bool AddHypothesisOnSubMesh (SMESH::SMESH_subMesh_ptr aSubMesh, SMESH::SMESH_Hypothesis_ptr aHyp)
427   {
428     if(MYDEBUG) MESSAGE("SMESHGUI::AddHypothesisOnSubMesh() ");
429     int res = SMESH::HYP_UNKNOWN_FATAL;
430     SUIT_OverrideCursor wc;
431
432     if (!aSubMesh->_is_nil() && ! aHyp->_is_nil()) {
433       try {
434         SMESH::SMESH_Mesh_var aMesh = aSubMesh->GetFather();
435         _PTR(SObject) SsubM = SMESH::FindSObject(aSubMesh);
436         GEOM::GEOM_Object_var aShapeObject = SMESH::GetShapeOnMeshOrSubMesh(SsubM);
437         if (!aMesh->_is_nil() && SsubM && !aShapeObject->_is_nil()) {
438           res = aMesh->AddHypothesis(aShapeObject, aHyp);
439           if (res < SMESH::HYP_UNKNOWN_FATAL)  {
440             _PTR(SObject) meshSO = SMESH::FindSObject(aMesh);
441             if (meshSO)
442               SMESH::ModifiedMesh(meshSO, false, aMesh->NbNodes()==0);
443           }
444           if (res > SMESH::HYP_OK) {
445             wc.suspend();
446             processHypothesisStatus(res, aHyp, true);
447             wc.resume();
448           }
449         }
450         else {
451           SCRUTE(aHyp->_is_nil());
452           SCRUTE(aMesh->_is_nil());
453           SCRUTE(!SsubM);
454           SCRUTE(aShapeObject->_is_nil());
455         }
456       }
457       catch(const SALOME::SALOME_Exception& S_ex) {
458         wc.suspend();
459         SalomeApp_Tools::QtCatchCorbaException(S_ex);
460         res = SMESH::HYP_UNKNOWN_FATAL;
461       }
462     }
463     else {
464       SCRUTE(aSubMesh->_is_nil());
465       SCRUTE(aHyp->_is_nil());
466     }
467     return res < SMESH::HYP_UNKNOWN_FATAL;
468   }
469
470   bool RemoveHypothesisOrAlgorithmOnMesh (const Handle(SALOME_InteractiveObject)& IObject)
471   {
472     int res = SMESH::HYP_UNKNOWN_FATAL;
473     SUIT_OverrideCursor wc;
474
475     try {
476       _PTR(Study) aStudy = GetActiveStudyDocument();
477       _PTR(SObject) aHypObj = aStudy->FindObjectID( IObject->getEntry() );
478       if( aHypObj )
479       {
480         _PTR(SObject) MorSM = SMESH::GetMeshOrSubmesh( aHypObj );
481         _PTR(SObject) aRealHypo;
482         if( aHypObj->ReferencedObject( aRealHypo ) )
483         {
484           SMESH_Hypothesis_var hypo = SMESH_Hypothesis::_narrow( SObjectToObject( aRealHypo ) );
485           RemoveHypothesisOrAlgorithmOnMesh( MorSM, hypo );
486         }
487         else
488         {
489           SMESH_Hypothesis_var hypo = SMESH_Hypothesis::_narrow( SObjectToObject( aHypObj ) );
490           SObjectList meshList = GetMeshesUsingAlgoOrHypothesis( hypo );
491           for( int i = 0; i < meshList.size(); i++ )
492             RemoveHypothesisOrAlgorithmOnMesh( meshList[ i ], hypo );
493         }
494       }
495     }
496     catch(const SALOME::SALOME_Exception& S_ex)
497     {
498       wc.suspend();
499       SalomeApp_Tools::QtCatchCorbaException(S_ex);
500       res = SMESH::HYP_UNKNOWN_FATAL;
501     }
502     return res < SMESH::HYP_UNKNOWN_FATAL;
503   }
504
505   bool RemoveHypothesisOrAlgorithmOnMesh (_PTR(SObject) MorSM,
506                                           SMESH::SMESH_Hypothesis_ptr anHyp)
507   {
508     SALOMEDS::GenericAttribute_var anAttr;
509     SALOMEDS::AttributeIOR_var anIOR;
510     int res = SMESH::HYP_UNKNOWN_FATAL;
511     SUIT_OverrideCursor wc;
512
513     if (MorSM) {
514       try {
515         GEOM::GEOM_Object_var aShapeObject = SMESH::GetShapeOnMeshOrSubMesh(MorSM);
516         if (!aShapeObject->_is_nil()) {
517           SMESH::SMESH_Mesh_var aMesh = SMESH::SObjectToInterface<SMESH::SMESH_Mesh>(MorSM);
518           SMESH::SMESH_subMesh_var aSubMesh = SMESH::SObjectToInterface<SMESH::SMESH_subMesh>(MorSM);
519
520           if (!aSubMesh->_is_nil())
521             aMesh = aSubMesh->GetFather();
522
523           if (!aMesh->_is_nil()) {
524             res = aMesh->RemoveHypothesis(aShapeObject, anHyp);
525             if (res < SMESH::HYP_UNKNOWN_FATAL) {
526               _PTR(SObject) meshSO = SMESH::FindSObject(aMesh);
527               if (meshSO)
528                 SMESH::ModifiedMesh(meshSO, false, aMesh->NbNodes()==0);
529             }
530             if (res > SMESH::HYP_OK) {
531               wc.suspend();
532               processHypothesisStatus(res, anHyp, false);
533               wc.resume();
534             }
535           }
536         }
537       } catch(const SALOME::SALOME_Exception& S_ex) {
538         wc.suspend();
539         SalomeApp_Tools::QtCatchCorbaException(S_ex);
540         res = SMESH::HYP_UNKNOWN_FATAL;
541       }
542     }
543     return res < SMESH::HYP_UNKNOWN_FATAL;
544   }
545
546   SObjectList GetMeshesUsingAlgoOrHypothesis(SMESH::SMESH_Hypothesis_ptr AlgoOrHyp)
547   {
548     SObjectList listSOmesh;
549     listSOmesh.resize(0);
550
551     unsigned int index = 0;
552     if (!AlgoOrHyp->_is_nil()) {
553       _PTR(SObject) SO_Hypothesis = SMESH::FindSObject(AlgoOrHyp);
554       if (SO_Hypothesis) {
555         SObjectList listSO =
556           SMESHGUI::activeStudy()->studyDS()->FindDependances(SO_Hypothesis);
557
558         if(MYDEBUG) MESSAGE("SMESHGUI::GetMeshesUsingAlgoOrHypothesis(): dependency number ="<<listSO.size());
559         for (unsigned int i = 0; i < listSO.size(); i++) {
560           _PTR(SObject) SO = listSO[i];
561           if (SO) {
562             _PTR(SObject) aFather = SO->GetFather();
563             if (aFather) {
564               _PTR(SObject) SOfatherFather = aFather->GetFather();
565               if (SOfatherFather) {
566                 if(MYDEBUG) MESSAGE("SMESHGUI::GetMeshesUsingAlgoOrHypothesis(): dependency added to list");
567                 index++;
568                 listSOmesh.resize(index);
569                 listSOmesh[index - 1] = SOfatherFather;
570               }
571             }
572           }
573         }
574       }
575     }
576     if (MYDEBUG) MESSAGE("SMESHGUI::GetMeshesUsingAlgoOrHypothesis(): completed");
577     return listSOmesh;
578   }
579
580 #define CASE2MESSAGE(enum) case SMESH::enum: msg = QObject::tr( "STATE_" #enum ); break;
581   QString GetMessageOnAlgoStateErrors(const algo_error_array& errors)
582   {
583     QString resMsg; // PAL14861 = QObject::tr("SMESH_WRN_MISSING_PARAMETERS") + ":\n";
584     for ( int i = 0; i < errors.length(); ++i ) {
585       const SMESH::AlgoStateError & error = errors[ i ];
586       const bool hasAlgo = ( strlen( error.algoName ) != 0 );
587       QString msg;
588       if ( !hasAlgo )
589         msg = QObject::tr( "STATE_ALGO_MISSING" );
590       else 
591         switch( error.state ) {
592           CASE2MESSAGE( HYP_MISSING );
593           CASE2MESSAGE( HYP_NOTCONFORM );
594           CASE2MESSAGE( HYP_BAD_PARAMETER );
595           CASE2MESSAGE( HYP_BAD_GEOMETRY );
596         default: continue;
597         }
598       // apply args to message:
599       // %1 - algo name
600       if ( hasAlgo )
601         msg = msg.arg( error.algoName.in() );
602       // %2 - dimension
603       msg = msg.arg( error.algoDim );
604       // %3 - global/local
605       msg = msg.arg( QObject::tr( error.isGlobalAlgo ? "GLOBAL_ALGO" : "LOCAL_ALGO" ));
606       // %4 - hypothesis dim == algoDim
607       msg = msg.arg( error.algoDim );
608
609       if ( i ) resMsg += ";\n";
610       resMsg += msg;
611     }
612     return resMsg;
613   }
614
615 }