1 # -*- coding: utf-8 -*-
2 # Copyright (C) 2013-2015 EDF R&D
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.
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.
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
18 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
25 from MGCleanerPlugDialog_ui import Ui_MGCleanerPlugDialog
26 from MGCleanerMonViewText import MGCleanerMonViewText
27 from qtsalome import *
30 class MGCleanerMonPlugDialog(Ui_MGCleanerPlugDialog,QWidget):
34 QWidget.__init__(self)
36 self.connecterSignaux()
42 self.__selectedMesh=None
44 # complex whith QResources: not used
45 # The icon are supposed to be located in the $SMESH_ROOT_DIR/share/salome/resources/smesh folder,
46 # other solution could be in the same folder than this python module file:
47 # iconfolder=os.path.dirname(os.path.abspath(__file__))
49 self.iconfolder=os.environ["SMESH_ROOT_DIR"]+"/share/salome/resources/smesh"
50 #print "MGCleanerMonPlugDialog iconfolder",iconfolder
52 icon.addFile(os.path.join(self.iconfolder,"select1.png"))
53 self.PB_LoadHyp.setIcon(icon)
54 self.PB_LoadHyp.setToolTip("hypothesis from Salome Object Browser")
55 self.PB_SaveHyp.setIcon(icon)
56 self.PB_SaveHyp.setToolTip("hypothesis to Salome Object Browser")
57 self.PB_MeshSmesh.setIcon(icon)
58 self.PB_MeshSmesh.setToolTip("source mesh from Salome Object Browser")
60 icon.addFile(os.path.join(self.iconfolder,"open.png"))
61 self.PB_ParamsFileExplorer.setIcon(icon)
62 self.PB_Load.setIcon(icon)
63 self.PB_Load.setToolTip("hypothesis from file")
64 self.PB_Save.setIcon(icon)
65 self.PB_Save.setToolTip("hypothesis to file")
66 self.PB_MeshFile.setIcon(icon)
67 self.PB_MeshFile.setToolTip("source mesh from a file in disk")
69 #Ces parametres ne sont pas remis ?? rien par le clean
70 self.paramsFile= os.path.abspath(os.path.join(os.environ["HOME"],".MGCleaner.dat"))
71 self.LE_ParamsFile.setText(self.paramsFile)
72 self.LE_MeshFile.setText("")
73 self.LE_MeshSmesh.setText("")
75 v1=QDoubleValidator(self)
79 self.SP_MinHoleSize.setValidator(v1)
80 self.SP_MinHoleSize.titleForWarning="MinHoleSize"
82 v2=QDoubleValidator(self)
86 self.SP_ToleranceDisplacement.setValidator(v2)
87 self.SP_ToleranceDisplacement.titleForWarning="ToleranceDisplacement"
89 v3=QDoubleValidator(self)
93 self.SP_ResolutionLength.setValidator(v3)
94 self.SP_ResolutionLength.titleForWarning="ResolutionLength"
96 v4=QDoubleValidator(self)
100 self.SP_OverlapDistance.setValidator(v4)
101 self.SP_OverlapDistance.titleForWarning="OverlapDistance"
103 self.resize(800, 500)
106 def connecterSignaux(self) :
107 self.PB_Cancel.clicked.connect(self.PBCancelPressed)
108 self.PB_Default.clicked.connect(self.clean)
109 self.PB_Help.clicked.connect(self.PBHelpPressed)
110 self.PB_OK.clicked.connect(self.PBOKPressed)
112 self.PB_Load.clicked.connect(self.PBLoadPressed)
113 self.PB_Save.clicked.connect(self.PBSavePressed)
114 self.PB_LoadHyp.clicked.connect(self.PBLoadHypPressed)
115 self.PB_SaveHyp.clicked.connect(self.PBSaveHypPressed)
117 self.PB_MeshFile.clicked.connect(self.PBMeshFilePressed)
118 self.PB_MeshSmesh.clicked.connect(self.PBMeshSmeshPressed)
119 self.LE_MeshSmesh.returnPressed.connect(self.meshSmeshNameChanged)
120 self.PB_ParamsFileExplorer.clicked.connect(self.setParamsFileName)
121 self.LE_MeshFile.returnPressed.connect(self.meshFileNameChanged)
122 self.LE_ParamsFile.returnPressed.connect(self.paramsFileNameChanged)
124 #QtCore.QObject.connect(self.checkBox, QtCore.SIGNAL("stateChanged(int)"), self.change)
125 self.CB_FillHoles.stateChanged[int].connect(self.SP_MinHoleSize.setEnabled)
126 self.CB_ComputedToleranceDisplacement.stateChanged[int].connect(self.SP_ToleranceDisplacement.setDisabled)
127 self.CB_ComputedResolutionLength.stateChanged[int].connect(self.SP_ResolutionLength.setDisabled)
128 self.CB_ComputedOverlapDistance.stateChanged[int].connect(self.SP_OverlapDistance.setDisabled)
130 def PBHelpPressed(self):
132 sgPyQt = SalomePyQt.SalomePyQt()
134 mydir=os.environ["SMESH_ROOT_DIR"]
136 QMessageBox.warning( self, "Help", "Help unavailable $SMESH_ROOT_DIR not found")
139 maDoc=mydir+"/share/doc/salome/gui/SMESH/MGCleaner/index.html"
140 sgPyQt.helpContext(maDoc,"")
142 #maDoc=mydir+"/share/doc/salome/gui/SMESH/MGCleaner/_downloads/mg-cleaner_user_manual.pdf"
143 #command="xdg-open "+maDoc+";"
144 #subprocess.call(command, shell=True)
146 def PBOKPressed(self):
147 if not(self.PrepareLigneCommande()):
149 #QMessageBox.warning(self, "Compute", "Command not found")
151 maFenetre=MGCleanerMonViewText(self, self.commande)
153 def enregistreResultat(self):
156 from salome.kernel import studyedit
157 from salome.smesh import smeshBuilder
158 smesh = smeshBuilder.New(salome.myStudy)
160 if not os.path.isfile(self.fichierOut):
161 QMessageBox.warning(self, "Compute", "Result file "+self.fichierOut+" not found")
163 maStudy=studyedit.getActiveStudy()
164 smesh.SetCurrentStudy(maStudy)
165 (outputMesh, status) = smesh.CreateMeshesFromGMF(self.fichierOut)
166 name=str(self.LE_MeshSmesh.text())
168 initialMeshObject=None
170 a=str(self.fichierIn)
171 name=os.path.basename(os.path.splitext(a)[0])
174 initialMeshObject=maStudy.FindObjectByName(name ,"SMESH")[0]
176 meshname = name+"_MGC_"+str(self.num)
177 smesh.SetName(outputMesh.GetMesh(), meshname)
178 outputMesh.Compute() #no algorithms message for "Mesh_x" has been computed with warnings: - global 1D algorithm is missing
180 self.editor = studyedit.getStudyEditor()
181 moduleEntry=self.editor.findOrCreateComponent("SMESH","SMESH")
182 HypReMeshEntry = self.editor.findOrCreateItem(
183 moduleEntry, name = "Plugins Hypotheses", icon="mesh_tree_hypo.png") #, comment = "HypoForRemeshing" )
185 monStudyBuilder=maStudy.NewBuilder()
186 monStudyBuilder.NewCommand()
187 newStudyIter=monStudyBuilder.NewObject(HypReMeshEntry)
188 self.editor.setAttributeValue(newStudyIter, "AttributeName", "MGCleaner Parameters_"+str(self.num))
189 self.editor.setAttributeValue(newStudyIter, "AttributeComment", self.getResumeData(separator=" ; "))
191 SOMesh=maStudy.FindObjectByName(meshname ,"SMESH")[0]
193 if initialMeshFile!=None:
194 newStudyFileName=monStudyBuilder.NewObject(SOMesh)
195 self.editor.setAttributeValue(newStudyFileName, "AttributeName", "meshFile")
196 self.editor.setAttributeValue(newStudyFileName, "AttributeExternalFileDef", initialMeshFile)
197 self.editor.setAttributeValue(newStudyFileName, "AttributeComment", initialMeshFile)
199 if initialMeshObject!=None:
200 newLink=monStudyBuilder.NewObject(SOMesh)
201 monStudyBuilder.Addreference(newLink, initialMeshObject)
203 newLink=monStudyBuilder.NewObject(SOMesh)
204 monStudyBuilder.Addreference(newLink, newStudyIter)
206 if salome.sg.hasDesktop(): salome.sg.updateObjBrowser(0)
210 def PBSavePressed(self):
211 from datetime import datetime
212 if not(self.PrepareLigneCommande()): return
213 text = "# MGCleaner hypothesis parameters\n"
214 text += "# Params for mesh : " + self.LE_MeshSmesh.text() +"\n"
215 text += datetime.now().strftime("# Date : %d/%m/%y %H:%M:%S\n")
216 text += "# Command : "+self.commande+"\n"
217 text += self.getResumeData(separator="\n")
221 f=open(self.paramsFile,"a")
223 QMessageBox.warning(self, "File", "Unable to open "+self.paramsFile)
228 QMessageBox.warning(self, "File", "Unable to write "+self.paramsFile)
232 def PBSaveHypPressed(self):
233 """save hypothesis in Object Browser"""
236 from salome.kernel import studyedit
237 from salome.smesh import smeshBuilder
238 smesh = smeshBuilder.New(salome.myStudy)
240 maStudy=studyedit.getActiveStudy()
241 smesh.SetCurrentStudy(maStudy)
243 self.editor = studyedit.getStudyEditor()
244 moduleEntry=self.editor.findOrCreateComponent("SMESH","SMESH")
245 HypReMeshEntry = self.editor.findOrCreateItem(
246 moduleEntry, name = "Plugins Hypotheses", icon="mesh_tree_hypo.png") #, comment = "HypoForRemeshing" )
248 monStudyBuilder=maStudy.NewBuilder()
249 monStudyBuilder.NewCommand()
250 newStudyIter=monStudyBuilder.NewObject(HypReMeshEntry)
251 self.editor.setAttributeValue(newStudyIter, "AttributeName", "MGCleaner Parameters_"+str(self.num))
252 self.editor.setAttributeValue(newStudyIter, "AttributeComment", self.getResumeData(separator=" ; "))
254 if salome.sg.hasDesktop(): salome.sg.updateObjBrowser(0)
259 import salome_pluginsmanager
260 print "salome_pluginsmanager.plugins",salome_pluginsmanager.plugins
261 print "salome_pluginsmanager.current_plugins_manager",salome_pluginsmanager.current_plugins_manager
264 def SP_toStr(self, widget):
265 """only for a QLineEdit widget"""
266 #cr, pos=widget.validator().validate(res, 0) #n.b. "1,3" is acceptable !locale!
268 val=float(widget.text())
270 QMessageBox.warning(self, widget.titleForWarning, "float value is incorrect: '"+widget.text()+"'")
271 res=str(widget.validator().bottom())
272 widget.setProperty("text", res)
274 valtest=widget.validator().bottom()
277 QMessageBox.warning(self, widget.titleForWarning, "float value is under minimum: "+str(val)+" < "+str(valtest))
279 widget.setProperty("text", res)
281 valtest=widget.validator().top()
284 QMessageBox.warning(self, widget.titleForWarning, "float value is over maximum: "+str(val)+" > "+str(valtest))
286 widget.setProperty("text", res)
290 def getResumeData(self, separator="\n"):
292 if self.RB_Fix1.isChecked():
293 CheckOrFix="fix1pass"
295 if self.RB_Fix2.isChecked():
296 CheckOrFix="fix2pass"
299 text+="CheckOrFix="+CheckOrFix+separator
300 text+="PreserveTopology="+str(self.CB_PreserveTopology.isChecked())+separator
301 text+="FillHoles="+str(self.CB_FillHoles.isChecked())+separator
302 v=self.SP_toStr(self.SP_MinHoleSize)
303 text+="MinHoleSize="+v+separator
304 text+="ComputedToleranceDisplacement="+str(self.CB_ComputedToleranceDisplacement.isChecked())+separator
305 v=self.SP_toStr(self.SP_ToleranceDisplacement)
306 text+="ToleranceDisplacement="+v+separator
307 text+="ComputedResolutionLength="+str(self.CB_ComputedResolutionLength.isChecked())+separator
308 v=self.SP_toStr(self.SP_ResolutionLength)
309 text+="ResolutionLength="+v+separator
310 text+="FoldingAngle="+str(self.SP_FoldingAngle.value())+separator
311 text+="RemeshPlanes="+str(self.CB_RemeshPlanes.isChecked())+separator
312 text+="ComputedOverlapDistance="+str(self.CB_ComputedOverlapDistance.isChecked())+separator
313 v=self.SP_toStr(self.SP_OverlapDistance)
314 text+="OverlapDistance="+v+separator
315 text+="OverlapAngle="+str(self.SP_OverlapAngle.value())+separator
316 text+="Verbosity="+str(self.SP_Verbosity.value())+separator
319 def loadResumeData(self, hypothesis, separator="\n"):
322 for slig in reversed(text.split(separator)):
324 #print "load ResumeData",lig
325 if lig=="": continue #skip blanck lines
326 if lig[0]=="#": break
328 tit,value=lig.split("=")
329 if tit=="CheckOrFix":
330 self.RB_Fix1.setChecked(False)
331 self.RB_Fix2.setChecked(False)
332 self.RB_Check.setChecked(False)
333 if value=="fix1pass": self.RB_Fix1.setChecked(True)
334 if value=="fix2pass": self.RB_Fix2.setChecked(True)
335 if value=="check": self.RB_Check.setChecked(True)
336 if tit=="PreserveTopology": self.CB_PreserveTopology.setChecked(value=="True")
337 if tit=="FillHoles": self.CB_FillHoles.setChecked(value=="True")
338 if tit=="MinHoleSize": self.SP_MinHoleSize.setProperty("text", value)
339 if tit=="ComputedToleranceDisplacement": self.CB_ComputedToleranceDisplacement.setChecked(value=="True")
340 if tit=="ToleranceDisplacement": self.SP_ToleranceDisplacement.setProperty("text", value)
341 if tit=="ComputedResolutionLength": self.CB_ComputedResolutionLength.setChecked(value=="True")
342 if tit=="ResolutionLength": self.SP_ResolutionLength.setProperty("text", value)
343 if tit=="FoldingAngle": self.SP_FoldingAngle.setProperty("value", float(value))
344 if tit=="RemeshPlanes": self.CB_RemeshPlanes.setChecked(value=="True")
345 if tit=="ComputedOverlapDistance": self.CB_ComputedOverlapDistance.setChecked(value=="True")
346 if tit=="OverlapDistance": self.SP_OverlapDistance.setProperty("text", value)
347 if tit=="OverlapAngle": self.SP_OverlapAngle.setProperty("value", float(value))
348 if tit=="Verbosity": self.SP_Verbosity.setProperty("value", int(float(value)))
350 QMessageBox.warning(self, "load MGCleaner Hypothesis", "Problem on '"+lig+"'")
352 def PBLoadPressed(self):
353 """load last hypothesis saved in tail of file"""
355 f=open(self.paramsFile,"r")
357 QMessageBox.warning(self, "File", "Unable to open "+self.paramsFile)
362 QMessageBox.warning(self, "File", "Unable to read "+self.paramsFile)
365 self.loadResumeData(text, separator="\n")
367 def PBLoadHypPressed(self):
368 """load hypothesis saved in Object Browser"""
369 #QMessageBox.warning(self, "load Object Browser MGCleaner hypothesis", "TODO")
371 from salome.kernel import studyedit
372 from salome.smesh.smeshstudytools import SMeshStudyTools
373 from salome.gui import helper as guihelper
374 from omniORB import CORBA
376 mySObject, myEntry = guihelper.getSObjectSelected()
377 if CORBA.is_nil(mySObject) or mySObject==None:
378 QMessageBox.critical(self, "Hypothese", "select an Object Browser MGCleaner hypothesis")
381 #for i in dir(mySObject): print "dir mySObject",i
382 #print "GetAllAttributes",mySObject.GetAllAttributes()
383 #print "GetComment",mySObject.GetComment()
384 #print "GetName",mySObject.GetName()
387 #if mySObject.GetFather().GetName()!="MGCleaner Hypotheses":
388 # QMessageBox.critical(self, "Hypothese", "not a child of MGCleaner Hypotheses")
391 text=mySObject.GetComment()
394 if "CheckOrFix=" not in text:
395 QMessageBox.critical(self, "Load Hypothese", "Object Browser selection not a MGCleaner Hypothesis")
397 self.loadResumeData(text, separator=" ; ")
400 def PBCancelPressed(self):
403 def PBMeshFilePressed(self):
404 fd = QFileDialog(self, "select an existing Mesh file", self.LE_MeshFile.text(), "Mesh-Files (*.mesh);;All Files (*)")
406 infile = fd.selectedFiles()[0]
407 self.LE_MeshFile.setText(infile)
408 self.fichierIn=unicode(infile).encode("latin-1")
410 self.LE_MeshSmesh.setText("")
412 def setParamsFileName(self):
413 fd = QFileDialog(self, "select a file", self.LE_ParamsFile.text(), "dat Files (*.dat);;All Files (*)")
415 infile = fd.selectedFiles()[0]
416 self.LE_ParamsFile.setText(infile)
417 self.paramsFile=unicode(infile).encode("latin-1")
419 def meshFileNameChanged(self):
420 self.fichierIn=str(self.LE_MeshFile.text())
421 #print "meshFileNameChanged", self.fichierIn
422 if os.path.exists(self.fichierIn):
423 self.__selectedMesh=None
425 self.LE_MeshSmesh.setText("")
427 QMessageBox.warning(self, "Mesh file", "File doesn't exist")
429 def meshSmeshNameChanged(self):
430 """only change by GUI mouse selection, otherwise clear"""
431 #self.MeshIn=str(self.LE_MeshSmesh.text())
432 #print "meshSmeshNameChanged", self.MeshIn
433 self.__selectedMesh = None
435 self.LE_MeshSmesh.setText("")
439 def paramsFileNameChanged(self):
440 self.paramsFile=self.LE_ParamsFile.text()
442 def PBMeshSmeshPressed(self):
443 from omniORB import CORBA
445 from salome.kernel import studyedit
446 from salome.smesh.smeshstudytools import SMeshStudyTools
447 from salome.gui import helper as guihelper
448 from salome.smesh import smeshBuilder
449 smesh = smeshBuilder.New(salome.myStudy)
451 mySObject, myEntry = guihelper.getSObjectSelected()
452 if CORBA.is_nil(mySObject) or mySObject==None:
453 QMessageBox.critical(self, "Mesh", "select an input mesh")
455 self.smeshStudyTool = SMeshStudyTools()
457 self.__selectedMesh = self.smeshStudyTool.getMeshObjectFromSObject(mySObject)
459 QMessageBox.critical(self, "Mesh", "select an input mesh")
461 if CORBA.is_nil(self.__selectedMesh):
462 QMessageBox.critical(self, "Mesh", "select an input mesh")
464 myName = mySObject.GetName()
465 #print "MeshSmeshNameChanged", myName
467 self.LE_MeshSmesh.setText(myName)
468 self.LE_MeshFile.setText("")
471 def prepareFichier(self):
472 self.fichierIn="/tmp/ForMGCleaner_"+str(self.num)+".mesh"
473 self.__selectedMesh.ExportGMF(self.__selectedMesh, self.fichierIn, True)
475 def PrepareLigneCommande(self):
477 #use doc examples of mg-cleaner:
478 ls -al /data/tmplgls/salome/prerequis/install/COMMON_64/MeshGems-1.0/bin
479 source /data/tmplgls/salome/prerequis/install/LICENSE/dlim8.var.sh
480 export PATH=/data/tmplgls/salome/prerequis/install/COMMON_64/MeshGems-1.0/bin/Linux_64:$PATH
481 cp -r /data/tmplgls/salome/prerequis/install/COMMON_64/MeshGems-1.0/examples .
483 mg-cleaner.exe --help
484 mg-cleaner.exe --in case7.mesh --out case7-test.mesh --check
485 mg-cleaner.exe case7.mesh case7-fix.mesh --fix
486 mg-cleaner.exe --in Porsche.mesh --out Porsche-test.mesh --check
487 mg-cleaner.exe --in Porsche.mesh --out Porschefix.mesh --fix
488 mg-cleaner.exe --in Porsche.mesh --out PorscheNewfix.mesh --fix --resolution_length 0.03
491 #self.commande="mg-cleaner.exe --in " + self.fichierIn + " --out " + self.fichierOut + " --fix2pass"
493 #print "PrepareLigneCommande '"+self.fichierIn+"' '"+self.MeshIn+"'",self.__selectedMesh
494 if self.fichierIn=="" and self.MeshIn=="":
495 QMessageBox.critical(self, "Mesh", "select an input mesh")
497 if self.__selectedMesh!=None: self.prepareFichier()
498 if not (os.path.isfile(self.fichierIn)):
499 QMessageBox.critical(self, "File", "unable to read GMF Mesh in "+str(self.fichierIn))
502 self.commande="mg-cleaner.exe"
503 verbosity=str(self.SP_Verbosity.value())
504 self.commande+=" --verbose " + verbosity
505 self.commande+=" --in " + self.fichierIn
506 #print "self.fichierIn",self.fichierIn,type(self.fichierIn)
507 deb=os.path.splitext(str(self.fichierIn))
508 self.fichierOut=deb[0] + "_fix.mesh"
509 self.commande+=" --out "+self.fichierOut
510 if self.RB_Fix1.isChecked():
511 self.commande+=" --fix1pass"
513 if self.RB_Fix2.isChecked():
514 self.commande+=" --fix2pass"
516 self.commande+=" --check"
517 if self.CB_PreserveTopology.isChecked():
518 self.commande+=" --topology respect"
520 self.commande+=" --topology ignore"
521 if self.CB_FillHoles.isChecked(): #no fill holes default
522 self.commande+=" --min_hole_size " + self.SP_toStr(self.SP_MinHoleSize)
523 if not self.CB_ComputedToleranceDisplacement.isChecked(): #computed default
524 self.commande+=" --tolerance_displacement " + self.SP_toStr(self.SP_ToleranceDisplacement)
525 if not self.CB_ComputedResolutionLength.isChecked(): #computed default
526 self.commande+=" --resolution_length " + self.SP_toStr(self.SP_ResolutionLength)
527 self.commande+=" --folding_angle " + str(self.SP_FoldingAngle.value())
528 if self.CB_RemeshPlanes.isChecked(): #no remesh default
529 self.commande+=" --remesh_planes"
530 if not self.CB_ComputedOverlapDistance.isChecked(): #computed default
531 self.commande+=" --overlap_distance " + self.SP_toStr(self.SP_OverlapDistance)
532 self.commande+=" --overlap_angle " + str(self.SP_OverlapAngle.value())
536 self.RB_Check.setChecked(False)
537 self.RB_Fix1.setChecked(False)
538 self.RB_Fix2.setChecked(True)
539 self.CB_PreserveTopology.setChecked(False)
540 self.CB_FillHoles.setChecked(False)
541 self.CB_RemeshPlanes.setChecked(False)
543 self.SP_MinHoleSize.setProperty("text", 0)
544 self.SP_ToleranceDisplacement.setProperty("text", 0)
545 self.SP_ResolutionLength.setProperty("text", 0)
546 self.SP_FoldingAngle.setProperty("value", 15)
547 self.SP_OverlapDistance.setProperty("text", 0)
548 self.SP_OverlapAngle.setProperty("value", 15)
549 self.SP_Verbosity.setProperty("value", 3)
551 self.CB_ComputedToleranceDisplacement.setChecked(True)
552 self.CB_ComputedResolutionLength.setChecked(True)
553 self.CB_ComputedOverlapDistance.setChecked(True)
558 This function returns a singleton instance of the plugin dialog.
559 c est obligatoire pour faire un show sans parent...
563 __dialog = MGCleanerMonPlugDialog()
570 # ==============================================================================
572 # ==============================================================================
574 def TEST_standalone():
576 works only if a salome is launched yet with a study loaded
577 to launch standalone python do:
581 python ./INSTALL/SMESH/share/salome/plugins/smesh/MGCleanerMonPlugDialog.py
585 from salome.kernel import studyedit
587 maStudy=studyedit.getActiveStudy()
591 # ==============================================================================
592 # Basic use cases and unit test functions
593 # ==============================================================================
595 def TEST_MGCleanerMonPlugDialog():
597 from qtsalome import QApplication
598 app = QApplication(sys.argv)
599 app.lastWindowClosed.connect(app.quit)
601 dlg=MGCleanerMonPlugDialog()
603 sys.exit(app.exec_())
605 if __name__ == "__main__":
606 TEST_MGCleanerMonPlugDialog()