Salome HOME
Merge branch 'master' into pra/blocFissure
[modules/smesh.git] / src / Tools / YamsPlug / monYamsPlugDialog.py
1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2007-2014  EDF R&D
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, or (at your option) any later version.
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
21 # Modules Python
22 # Modules Eficas
23
24 import os, subprocess
25 from YamsPlugDialog_ui import Ui_YamsPlugDialog
26 from monViewText import MonViewText
27 from PyQt4.QtGui import *
28 from PyQt4.QtCore import *
29
30
31 class MonYamsPlugDialog(Ui_YamsPlugDialog,QWidget):
32   """
33   """
34   def __init__(self):
35     QWidget.__init__(self)
36     self.setupUi(self)
37     self.connecterSignaux()
38     self.fichierIn=""
39     self.fichierOut=""
40     self.MeshIn=""
41     self.commande=""
42     self.num=1
43     self.__selectedMesh=None
44
45     # complex whith QResources: not used
46     # The icon are supposed to be located in the $SMESH_ROOT_DIR/share/salome/resources/smesh folder,
47     # other solution could be in the same folder than this python module file:
48     # iconfolder=os.path.dirname(os.path.abspath(__file__))
49
50     self.iconfolder=os.environ["SMESH_ROOT_DIR"]+"/share/salome/resources/smesh"
51     #print "monYamsPlugDialog iconfolder",iconfolder
52     icon = QIcon()
53     icon.addFile(os.path.join(self.iconfolder,"select1.png"))
54     self.PB_LoadHyp.setIcon(icon)
55     self.PB_LoadHyp.setToolTip("hypothesis from Salome Object Browser")
56     self.PB_SaveHyp.setIcon(icon)
57     self.PB_SaveHyp.setToolTip("hypothesis to Salome Object Browser")
58     self.PB_MeshSmesh.setIcon(icon)
59     self.PB_MeshSmesh.setToolTip("source mesh from Salome Object Browser")
60     icon = QIcon()
61     icon.addFile(os.path.join(self.iconfolder,"open.png"))
62     self.PB_ParamsFileExplorer.setIcon(icon)
63     self.PB_Load.setIcon(icon)
64     self.PB_Load.setToolTip("hypothesis from file")
65     self.PB_Save.setIcon(icon)
66     self.PB_Save.setToolTip("hypothesis to file")
67     self.PB_MeshFile.setIcon(icon)
68     self.PB_MeshFile.setToolTip("source mesh from a file in disk")
69
70     #Ces parametres ne sont pas remis à rien par le clean
71     self.paramsFile= os.path.abspath(os.path.join(os.environ["HOME"],".yams.dat"))
72     self.LE_ParamsFile.setText(self.paramsFile)
73     self.LE_MeshFile.setText("")
74     self.LE_MeshSmesh.setText("")
75     
76     v1=QDoubleValidator(self)
77     v1.setBottom(0.)
78     #v1.setTop(1000.) #per thousand... only if relative
79     v1.setDecimals(3)
80     self.SP_Tolerance.setValidator(v1)
81     self.SP_Tolerance.titleForWarning="Chordal Tolerance"
82     
83     self.resize(800, 600)
84     self.clean()
85
86   def connecterSignaux(self) :
87     self.connect(self.PB_Cancel,SIGNAL("clicked()"),self.PBCancelPressed)
88     self.connect(self.PB_Default,SIGNAL("clicked()"),self.clean)
89     self.connect(self.PB_Help,SIGNAL("clicked()"),self.PBHelpPressed)
90     self.connect(self.PB_OK,SIGNAL("clicked()"),self.PBOKPressed)
91     
92     self.connect(self.PB_Load,SIGNAL("clicked()"),self.PBLoadPressed)
93     self.connect(self.PB_Save,SIGNAL("clicked()"),self.PBSavePressed)
94     self.connect(self.PB_LoadHyp,SIGNAL("clicked()"),self.PBLoadHypPressed)
95     self.connect(self.PB_SaveHyp,SIGNAL("clicked()"),self.PBSaveHypPressed)
96     
97     self.connect(self.PB_MeshFile,SIGNAL("clicked()"),self.PBMeshFilePressed)
98     self.connect(self.PB_MeshSmesh,SIGNAL("clicked()"),self.PBMeshSmeshPressed)
99     self.connect(self.LE_MeshSmesh,SIGNAL("returnPressed()"),self.meshSmeshNameChanged)
100     self.connect(self.PB_ParamsFileExplorer,SIGNAL("clicked()"),self.setParamsFileName)
101     self.connect(self.LE_MeshFile,SIGNAL("returnPressed()"),self.meshFileNameChanged)
102     self.connect(self.LE_ParamsFile,SIGNAL("returnPressed()"),self.paramsFileNameChanged)
103
104   def PBHelpPressed(self):
105     import SalomePyQt
106     sgPyQt = SalomePyQt.SalomePyQt()
107     try :
108       mydir=os.environ["SMESH_ROOT_DIR"]
109     except Exception:
110       QMessageBox.warning(self, "Help", "Help unavailable $SMESH_ROOT_DIR not found")
111       return
112
113     maDoc=mydir+"/share/doc/salome/gui/SMESH/yams/index.html"
114     sgPyQt.helpContext(maDoc,"")
115     
116     #maDoc=mydir+"/share/doc/salome/gui/SMESH/yams/_downloads/mg-surfopt_user_manual.pdf"
117     #command="xdg-open "+maDoc+";"
118     #subprocess.call(command, shell=True)
119
120   def PBOKPressed(self):
121     if not(self.PrepareLigneCommande()):
122       #warning done yet
123       #QMessageBox.warning(self, "Compute", "Command not found")
124       return
125     maFenetre=MonViewText(self,self.commande)
126
127   def enregistreResultat(self):
128     import salome
129     import SMESH
130     from salome.kernel import studyedit
131     from salome.smesh import smeshBuilder
132     smesh = smeshBuilder.New(salome.myStudy)
133     
134     if not os.path.isfile(self.fichierOut):
135       QMessageBox.warning(self, "Compute", "Result file "+self.fichierOut+" not found")
136
137     maStudy=studyedit.getActiveStudy()
138     smesh.SetCurrentStudy(maStudy)
139     (outputMesh, status) = smesh.CreateMeshesFromGMF(self.fichierOut)
140     name=str(self.LE_MeshSmesh.text())
141     initialMeshFile=None
142     initialMeshObject=None
143     if name=="":
144       a=str(self.fichierIn)
145       name=os.path.basename(os.path.splitext(a)[0])
146       initialMeshFile=a
147     else:
148       initialMeshObject=maStudy.FindObjectByName(name ,"SMESH")[0]
149
150     meshname = name+"_YAMS_"+str(self.num)
151     smesh.SetName(outputMesh.GetMesh(), meshname)
152     outputMesh.Compute() #no algorithms message for "Mesh_x" has been computed with warnings: -  global 1D algorithm is missing
153
154     self.editor = studyedit.getStudyEditor()
155     moduleEntry=self.editor.findOrCreateComponent("SMESH","SMESH")
156     HypReMeshEntry = self.editor.findOrCreateItem(
157         moduleEntry, name = "Plugins Hypotheses", icon="mesh_tree_hypo.png") #, comment = "HypoForRemeshing" )
158     
159     monStudyBuilder=maStudy.NewBuilder()
160     monStudyBuilder.NewCommand()
161     newStudyIter=monStudyBuilder.NewObject(HypReMeshEntry)
162     self.editor.setAttributeValue(newStudyIter, "AttributeName", "YAMS Parameters_"+str(self.num))
163     self.editor.setAttributeValue(newStudyIter, "AttributeComment", self.getResumeData(separator=" ; "))
164     
165     SOMesh=maStudy.FindObjectByName(meshname ,"SMESH")[0]
166     
167     if initialMeshFile!=None:
168       newStudyFileName=monStudyBuilder.NewObject(SOMesh)
169       self.editor.setAttributeValue(newStudyFileName, "AttributeName", "meshFile")
170       self.editor.setAttributeValue(newStudyFileName, "AttributeExternalFileDef", initialMeshFile)
171       self.editor.setAttributeValue(newStudyFileName, "AttributeComment", initialMeshFile)
172
173     if initialMeshObject!=None:
174       newLink=monStudyBuilder.NewObject(SOMesh)
175       monStudyBuilder.Addreference(newLink, initialMeshObject)
176
177     newLink=monStudyBuilder.NewObject(SOMesh)
178     monStudyBuilder.Addreference(newLink, newStudyIter)
179
180     if salome.sg.hasDesktop(): salome.sg.updateObjBrowser(0)
181     self.num+=1
182     return True
183
184   def PBSavePressed(self):
185     from datetime import datetime
186     if not(self.PrepareLigneCommande()): return
187     text = "# YAMS hypothesis parameters\n" 
188     text += "# Params for mesh : " +  self.LE_MeshSmesh.text() +"\n"
189     text += datetime.now().strftime("# Date : %d/%m/%y %H:%M:%S\n")
190     text += "# Command : "+self.commande+"\n"
191     text += self.getResumeData(separator="\n")
192     text += "\n\n"
193
194     try:
195       f=open(self.paramsFile,"a")
196     except:
197       QMessageBox.warning(self, "File", "Unable to open "+self.paramsFile)
198       return
199     try:
200       f.write(text)
201     except:
202       QMessageBox.warning(self, "File", "Unable to write "+self.paramsFile)
203       return
204     f.close()
205
206   def PBSaveHypPressed(self):
207     """save hypothesis in Object Browser"""
208     import salome
209     import SMESH
210     from salome.kernel import studyedit
211     from salome.smesh import smeshBuilder
212     smesh = smeshBuilder.New(salome.myStudy)
213
214     maStudy=studyedit.getActiveStudy()
215     smesh.SetCurrentStudy(maStudy)
216     
217     self.editor = studyedit.getStudyEditor()
218     moduleEntry=self.editor.findOrCreateComponent("SMESH","SMESH")
219     HypReMeshEntry = self.editor.findOrCreateItem(
220         moduleEntry, name = "Plugins Hypotheses", icon="mesh_tree_hypo.png") #, comment = "HypoForRemeshing" )
221     
222     monStudyBuilder=maStudy.NewBuilder()
223     monStudyBuilder.NewCommand()
224     newStudyIter=monStudyBuilder.NewObject(HypReMeshEntry)
225     self.editor.setAttributeValue(newStudyIter, "AttributeName", "YAMS Parameters_"+str(self.num))
226     self.editor.setAttributeValue(newStudyIter, "AttributeComment", self.getResumeData(separator=" ; "))
227     
228     if salome.sg.hasDesktop(): salome.sg.updateObjBrowser(0)
229     self.num+=1
230     return True
231
232   def SP_toStr(self, widget):
233     """only for a QLineEdit widget"""
234     #cr, pos=widget.validator().validate(res, 0) #n.b. "1,3" is acceptable !locale!
235     try:
236       val=float(widget.text())
237     except:
238       QMessageBox.warning(self, widget.titleForWarning, "float value is incorrect: '"+widget.text()+"'")
239       res=str(widget.validator().bottom())
240       widget.setProperty("text", res)
241       return res
242     valtest=widget.validator().bottom()
243     if valtest!=None:
244       if val<valtest:
245         QMessageBox.warning(self, widget.titleForWarning, "float value is under minimum: "+str(val)+" < "+str(valtest))
246         res=str(valtest)
247         widget.setProperty("text", res)
248         return res
249     valtest=widget.validator().top()
250     if valtest!=None:
251       if val>valtest:
252         QMessageBox.warning(self, widget.titleForWarning, "float value is over maximum: "+str(val)+" > "+str(valtest))
253         res=str(valtest)
254         widget.setProperty("text", res)
255         return res    
256     return str(val)
257
258   def getResumeData(self, separator="\n"):
259     text=""
260     for RB in self.GBOptim.findChildren(QRadioButton,):
261       if RB.isChecked()==True:
262         text+="Optimisation="+RB.text()+separator
263         break
264     if self.RB_Absolute.isChecked():
265       text+="Units=absolute"+separator
266     else:
267       text+="Units=relative"+separator
268     v=self.SP_toStr(self.SP_Tolerance)
269     text+="ChordalToleranceDeviation="+v+separator
270     text+="RidgeDetection="+str(self.CB_Ridge.isChecked())+separator
271     text+="SplitEdge="+str(self.CB_SplitEdge.isChecked())+separator
272     text+="PointSmoothing="+str(self.CB_Point.isChecked())+separator
273     text+="GeometricalApproximation="+str(self.SP_Geomapp.value())+separator
274     text+="RidgeAngle="+str(self.SP_Ridge.value())+separator
275     text+="MaximumSize="+str(self.SP_MaxSize.value())+separator
276     text+="MinimumSize="+str(self.SP_MinSize.value())+separator
277     text+="MeshGradation="+str(self.SP_Gradation.value())+separator
278     text+="Verbosity="+str(self.SP_Verbosity.value())+separator
279     text+="Memory="+str(self.SP_Memory.value())+separator
280     return str(text)
281
282   def loadResumeData(self, hypothesis, separator="\n"):
283     text=str(hypothesis)
284     self.clean()
285     for slig in reversed(text.split(separator)):
286       lig=slig.strip()
287       #print "load ResumeData",lig
288       if lig=="": continue #skip blanck lines
289       if lig[0]=="#": break
290       try:
291         tit,value=lig.split("=")
292         if tit=="Optimisation":
293           #no need: exlusives QRadioButton
294           #for RB in self.GBOptim.findChildren(QRadioButton,):
295           #  RB.setChecked(False)
296           for RB in self.GBOptim.findChildren(QRadioButton,):
297             if RB.text()==value :
298               RB.setChecked(True)
299               break
300         if tit=="Units":
301           if value=="absolute":
302             self.RB_Absolute.setChecked(True)
303             self.RB_Relative.setChecked(False)
304           else:
305             self.RB_Absolute.setChecked(False)
306             self.RB_Relative.setChecked(True)
307         if tit=="ChordalToleranceDeviation": self.SP_Tolerance.setProperty("text", float(value))
308         if tit=="RidgeDetection": self.CB_Ridge.setChecked(value=="True")
309         if tit=="SplitEdge": self.CB_SplitEdge.setChecked(value=="True")
310         if tit=="PointSmoothing": self.CB_Point.setChecked(value=="True")
311         if tit=="GeometricalApproximation": self.SP_Geomapp.setProperty("value", float(value))
312         if tit=="RidgeAngle": self.SP_Ridge.setProperty("value", float(value))
313         if tit=="MaximumSize": self.SP_MaxSize.setProperty("value", float(value))
314         if tit=="MinimumSize": self.SP_MinSize.setProperty("value", float(value))
315         if tit=="MeshGradation": self.SP_Gradation.setProperty("value", float(value))
316         if tit=="Verbosity": self.SP_Verbosity.setProperty("value", int(float(value)))
317         if tit=="Memory": self.SP_Memory.setProperty("value", float(value))
318       except:
319         QMessageBox.warning(self, "load YAMS Hypothesis", "Problem on '"+lig+"'")
320
321   def PBLoadPressed(self):
322     """load last hypothesis saved in tail of file"""
323     try:
324       f=open(self.paramsFile,"r")
325     except:
326       QMessageBox.warning(self, "File", "Unable to open "+self.paramsFile)
327       return
328     try:
329       text=f.read()
330     except:
331       QMessageBox.warning(self, "File", "Unable to read "+self.paramsFile)
332       return
333     f.close()
334     self.loadResumeData(text, separator="\n")
335
336   def PBLoadHypPressed(self):
337     """load hypothesis saved in Object Browser"""
338     #QMessageBox.warning(self, "load Object Browser YAMS hypothesis", "TODO")
339     import salome
340     from salome.kernel import studyedit
341     from salome.smesh.smeshstudytools import SMeshStudyTools
342     from salome.gui import helper as guihelper
343     from omniORB import CORBA
344
345     mySObject, myEntry = guihelper.getSObjectSelected()
346     if CORBA.is_nil(mySObject) or mySObject==None:
347       QMessageBox.critical(self, "Hypothese", "select an Object Browser YAMS hypothesis")
348       return
349     
350     text=mySObject.GetComment()
351     
352     #a verification
353     if "Optimisation=" not in text:
354       QMessageBox.critical(self, "Load Hypothese", "Object Browser selection not a YAMS Hypothesis")
355       return
356     self.loadResumeData(text, separator=" ; ")
357     return
358     
359   def PBCancelPressed(self):
360     self.close()
361
362   def PBMeshFilePressed(self):
363     fd = QFileDialog(self, "select an existing Mesh file", self.LE_MeshFile.text(), "Mesh-Files (*.mesh);;All Files (*)")
364     if fd.exec_():
365       infile = fd.selectedFiles()[0]
366       self.LE_MeshFile.setText(infile)
367       self.fichierIn=infile.toLatin1()
368       self.MeshIn=""
369       self.LE_MeshSmesh.setText("")
370
371   def setParamsFileName(self):
372     fd = QFileDialog(self, "select a file", self.LE_ParamsFile.text(), "dat Files (*.dat);;All Files (*)")
373     if fd.exec_():
374       infile = fd.selectedFiles()[0]
375       self.LE_ParamsFile.setText(infile)
376       self.paramsFile=infile.toLatin1()
377
378   def meshFileNameChanged(self):
379     self.fichierIn=str(self.LE_MeshFile.text())
380     #print "meshFileNameChanged", self.fichierIn
381     if os.path.exists(self.fichierIn): 
382       self.__selectedMesh=None
383       self.MeshIn=""
384       self.LE_MeshSmesh.setText("")
385       return
386     QMessageBox.warning(self, "Mesh file", "File doesn't exist")
387
388   def meshSmeshNameChanged(self):
389     """only change by GUI mouse selection, otherwise clear"""
390     self.__selectedMesh = None
391     self.MeshIn=""
392     self.LE_MeshSmesh.setText("")
393     self.fichierIn=""
394     return
395
396   def paramsFileNameChanged(self):
397     self.paramsFile=self.LE_ParamsFile.text()
398
399   def PBMeshSmeshPressed(self):
400     from omniORB import CORBA
401     import salome
402     from salome.kernel import studyedit
403     from salome.smesh.smeshstudytools import SMeshStudyTools
404     from salome.gui import helper as guihelper
405     from salome.smesh import smeshBuilder
406     smesh = smeshBuilder.New(salome.myStudy)
407
408     mySObject, myEntry = guihelper.getSObjectSelected()
409     if CORBA.is_nil(mySObject) or mySObject==None:
410       #QMessageBox.critical(self, "Mesh", "select an input mesh")
411       self.LE_MeshSmesh.setText("")
412       self.MeshIn=""
413       self.LE_MeshFile.setText("")
414       self.fichierIn=""
415       return
416     self.smeshStudyTool = SMeshStudyTools()
417     try:
418       self.__selectedMesh = self.smeshStudyTool.getMeshObjectFromSObject(mySObject)
419     except:
420       QMessageBox.critical(self, "Mesh", "select an input mesh")
421       return
422     if CORBA.is_nil(self.__selectedMesh):
423       QMessageBox.critical(self, "Mesh", "select an input mesh")
424       return
425     myName = mySObject.GetName()
426     #print "MeshSmeshNameChanged", myName
427     self.MeshIn=myName
428     self.LE_MeshSmesh.setText(myName)
429     self.LE_MeshFile.setText("")
430     self.fichierIn=""
431
432   def prepareFichier(self):
433     self.fichierIn="/tmp/ForSurfOpt_"+str(self.num)+".meshb"
434     self.__selectedMesh.ExportGMF(self.__selectedMesh, self.fichierIn, True)
435
436   def PrepareLigneCommande(self):
437     if self.fichierIn=="" and self.MeshIn=="":
438       QMessageBox.critical(self, "Mesh", "select an input mesh")
439       return False
440     if self.__selectedMesh!=None: self.prepareFichier()
441     if not (os.path.isfile(self.fichierIn)):
442       QMessageBox.critical(self, "File", "unable to read GMF Mesh in "+str(self.fichierIn))
443       return False
444     
445     self.commande="mg-surfopt.exe"
446     
447     for obj in self.GBOptim.findChildren(QRadioButton,):
448       try:
449         if obj.isChecked():
450           self.style=obj.objectName().remove(0,3)
451           self.style.replace("_","-")
452           break
453       except:
454         pass
455       
456     style = self.style.toLatin1()
457     # Translation of old Yams options to new MG-SurfOpt options
458     if   style == "0" :
459       self.commande+= " --optimisation only"
460     elif style == "2" :
461       self.commande+= " --Hausdorff_like yes"
462     elif style == "-1":
463       self.commande+= " --enrich no"
464     elif style == "-2":
465       self.commande+= " --Hausdorff_like yes --enrich no"
466     elif style == "U" :
467       self.commande+= " --uniform_flat_subdivision yes"
468     elif style == "S" :
469       self.commande+= " --sand_paper yes"
470     elif style == "G" :
471       self.commande+= " -O G"  # This option has not been updated to the new option style yet
472
473     deb=os.path.splitext(self.fichierIn)
474     self.fichierOut=deb[0] + "_output.meshb"
475     
476     tolerance=self.SP_toStr(self.SP_Tolerance)
477     if not self.RB_Absolute.isChecked():
478       tolerance+="r"  
479     self.commande+=" --chordal_error %s"%tolerance
480     
481     if self.CB_Ridge.isChecked()    == False : self.commande+=" --compute_ridges no"
482     if self.CB_Point.isChecked()    == False : self.commande+=" --optimisation no"
483     if self.CB_SplitEdge.isChecked()== True  : self.commande+=" --element_order quadratic"
484     if self.SP_Geomapp.value()      != 15.0  : self.commande+=" --geometric_approximation_angle %f"%self.SP_Geomapp.value()
485     if self.SP_Ridge.value()        != 45.0  : self.commande+=" --ridge_angle %f"%self.SP_Ridge.value()
486     if self.SP_MaxSize.value()      != 100   : self.commande+=" --max_size %f"   %self.SP_MaxSize.value()
487     if self.SP_MinSize.value()      != 5     : self.commande+=" --min_size %f"   %self.SP_MinSize.value()
488     if self.SP_Gradation.value()    != 1.3   : self.commande+=" --gradation %f"  %self.SP_Gradation.value()
489     if self.SP_Memory.value()       != 0     : self.commande+=" --max_memory %d" %self.SP_Memory.value()
490     if self.SP_Verbosity.value()    != 3     : self.commande+=" --verbose %d" %self.SP_Verbosity.value()
491
492     self.commande+=" --in "  + self.fichierIn
493     self.commande+=" --out " + self.fichierOut
494     
495     print self.commande
496     return True
497
498   def clean(self):
499     self.RB_0.setChecked(True)
500     #no need: exlusives QRadioButton
501     #self.RB_G.setChecked(False)
502     #self.RB_U.setChecked(False)
503     #self.RB_S.setChecked(False)
504     #self.RB_2.setChecked(False)
505     #self.RB_1.setChecked(False)
506     self.RB_Relative.setChecked(True)
507     #no need: exlusives QRadioButton
508     #self.RB_Absolute.setChecked(False)
509     self.SP_Tolerance.setProperty("text", "0.001")
510     self.SP_Geomapp.setProperty("value", 15.0)
511     self.SP_Ridge.setProperty("value", 45.0)
512     self.SP_Gradation.setProperty("value", 1.3)
513     self.CB_Ridge.setChecked(True)
514     self.CB_Point.setChecked(True)
515     self.CB_SplitEdge.setChecked(False)
516     self.SP_MaxSize.setProperty("value", 100)
517     self.SP_MinSize.setProperty("value", 5)
518     self.SP_Verbosity.setProperty("value", 3)
519     self.SP_Memory.setProperty("value", 0)
520     self.PBMeshSmeshPressed()
521     self.TWOptions.setCurrentIndex(0) # Reset current active tab to the first tab
522
523 __dialog=None
524 def getDialog():
525   """
526   This function returns a singleton instance of the plugin dialog.
527   It is mandatory in order to call show without a parent ...
528   """
529   global __dialog
530   if __dialog is None:
531     __dialog = MonYamsPlugDialog()
532   else :
533     __dialog.clean()
534   return __dialog
535
536 #
537 # ==============================================================================
538 # Basic use cases and unit test functions
539 # ==============================================================================
540 #
541 def TEST_MonYamsPlugDialog():
542   import sys
543   from PyQt4.QtGui import QApplication
544   from PyQt4.QtCore import QObject, SIGNAL, SLOT
545   app = QApplication(sys.argv)
546   QObject.connect(app, SIGNAL("lastWindowClosed()"), app, SLOT("quit()"))
547
548   dlg=MonYamsPlugDialog()
549   dlg.show()
550   sys.exit(app.exec_())
551
552 if __name__ == "__main__":
553   TEST_MonYamsPlugDialog()
554   pass