Salome HOME
b293d775cd3df9f326710a9ff43d5bcbaa44fbba
[modules/yacs.git] / src / pyqt / gui / Appli.py
1 # Copyright (C) 2006-2023  CEA, EDF
2 #
3 # This library is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU Lesser General Public
5 # License as published by the Free Software Foundation; either
6 # version 2.1 of the License, or (at your option) any later version.
7 #
8 # This library is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 # Lesser General Public License for more details.
12 #
13 # You should have received a copy of the GNU Lesser General Public
14 # License along with this library; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 #
17 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 #
19
20 """
21 """
22 import sys,os
23 from qt import *
24 from . import Tree
25 from . import PanelManager
26 from . import BoxManager
27 from . import Icons
28 from . import Items
29 from . import adapt
30 from . import Item
31 from . import logview
32 import pilot
33 import threading
34 import time
35 from . import CONNECTOR
36 from . import catalog
37 import traceback
38 import glob
39
40 class ErrorEvent(QCustomEvent):
41   def __init__(self,caption,msg):
42     QCustomEvent.__init__(self,8888)
43     self.caption=caption
44     self.msg=msg
45   def process(self,parent):
46     QMessageBox.warning(parent,self.caption,self.msg)
47
48 class Runner(threading.Thread):
49   def __init__(self,parent,executor,proc):
50     threading.Thread.__init__(self)
51     self.parent=parent
52     self.executor=executor
53     self.proc=proc
54
55   def run(self):
56     try:
57       self.executor.RunW(self.proc,0)
58     except ValueError as ex:
59       #traceback.print_exc()
60       QApplication.postEvent(self.parent, ErrorEvent('YACS execution error',str(ex)))
61
62 class Browser(QVBox):
63   def __init__(self,parent,proc):
64     QVBox.__init__(self,parent)
65     pp=Item.adapt(proc)
66     self.proc=proc
67     self.pproc=pp
68     self.hSplitter = QSplitter(self,"hSplitter")
69     self.objectBrowser=Tree.Tree(self.hSplitter,self.onSelect,self.onDblSelect)
70     self.objectBrowser.additem(pp)
71     self.panelManager=PanelManager.PanelManager(self.hSplitter)
72     self.panelManager.setRootItem(pp)
73     self.boxManager=BoxManager.BoxManager(self.hSplitter)
74     self.boxManager.setRootItem(pp)
75     self.selected=None
76     self.executor=None
77     self.resume=0
78     self.thr=None
79     self.log=logview.LogView()
80
81   def view_log(self):
82     self.log.text.setText(self.proc.getLogger("parser").getStr())
83     self.log.show()
84
85   def onDblSelect(self,item):
86     #item is instance of Item.Item
87     pass
88
89   def onSelect(self,item):
90     #item is instance of Item.Item
91     self.selected=item
92
93   def customEvent(self,ev):
94     if ev.type() == 8888:
95       ev.process(self)
96
97   def run(self):
98     if not self.executor:
99       self.executor = pilot.ExecutorSwig()
100     if self.thr and self.thr.isAlive():
101       return
102     #continue execution mode
103     self.executor.setExecMode(0)
104     #execute it in a thread
105     self.thr = Runner(self, self.executor, self.proc)
106     #as a daemon (no need to join)
107     self.thr.setDaemon(1)
108     #start the thread
109     self.thr.start()
110     time.sleep(0.1)
111     self.resume=0
112
113   def susp(self):
114     """Suspend or resume an executing schema"""
115     if not self.executor:
116       return
117     if not self.thr.isAlive():
118       return
119
120     if self.resume:
121       #continue execution mode
122       self.executor.setExecMode(0)
123       #resume it
124       self.executor.resumeCurrentBreakPoint()
125       self.resume=0
126     else:
127       #step by step execution mode
128       self.executor.setExecMode(1)
129       self.resume=1
130
131   def step(self):
132     """Step on a paused schema"""
133     if not self.executor:
134       self.executor = pilot.ExecutorSwig()
135     if not self.thr or not self.thr.isAlive():
136       #start in step by step mode
137       self.executor.setExecMode(1)
138       self.thr = Runner(self, self.executor, self.proc)
139       self.thr.setDaemon(1)
140       self.thr.start()
141       self.resume=1
142       return
143
144     #step by step execution mode
145     self.resume=1
146     self.executor.setExecMode(1)
147     #resume it
148     self.executor.resumeCurrentBreakPoint()
149
150   def stop(self):
151     """Stop the schema"""
152     if not self.executor:
153       return
154     if not self.thr.isAlive():
155       return
156     self.executor.setExecMode(1)
157     self.executor.waitPause()
158     self.executor.resumeCurrentBreakPoint()
159     #self.executor.stopExecution()
160
161 class Appli(QMainWindow):
162   """
163       Appli()
164       Cree la fenetre principale de l'interface utilisateur
165   """
166   def __init__(self):
167     QMainWindow.__init__(self)
168     self.createWidgets()
169     self.initActions()
170     self.initMenus()
171     self.initToolbar()
172     self.initStatusbar()
173     self.initYACS()
174
175   def createWidgets(self):
176     self.tabWidget = QTabWidget(self)
177     self.currentPanel=None
178     self.connect(self.tabWidget, SIGNAL('currentChanged(QWidget *)'),self.handlePanelChanged)
179     self.setCentralWidget(self.tabWidget)
180     self.resize(800,600)
181
182   def handlePanelChanged(self,panel):
183     self.currentPanel=panel
184
185   def initActions(self):
186     self.actions = []
187
188     self.newAct=QAction('New', QIconSet(Icons.get_image("new")), '&New',
189                           QKeySequence("CTRL+N"),self)
190     self.newAct.setStatusTip('Open an empty editor window')
191     self.newAct.setWhatsThis( """<b>New</b>"""
192             """<p>An empty editor window will be created.</p>""")
193     self.newAct.connect(self.newAct,SIGNAL('activated()'), self.newProc)
194     self.actions.append(self.newAct)
195
196     self.prefAct=QAction('Preferences',QIconSet(Icons.get_image("configure.png")),'&Preferences...',
197                            0, self)
198     self.prefAct.setStatusTip('Set the prefered configuration')
199     self.prefAct.setWhatsThis("""<b>Preferences</b>"""
200                               """<p>Set the configuration items of the application"""
201                               """ with your prefered values.</p>""")
202     self.prefAct.connect(self.prefAct,SIGNAL('activated()'), self.handlePreferences)
203     self.actions.append(self.prefAct)
204
205     self.runAct=QAction('Run',QIconSet(Icons.get_image("run.png")),'&Run',0,self)
206     self.runAct.connect(self.runAct,SIGNAL('activated()'), self.run)
207     self.runAct.setStatusTip('Run the selected schema')
208     self.actions.append(self.runAct)
209
210     self.suspAct=QAction('Suspend/resume',QIconSet(Icons.get_image("suspend-resume.gif")),'&Suspend/resume',0,self)
211     self.suspAct.connect(self.suspAct,SIGNAL('activated()'), self.susp)
212     self.suspAct.setStatusTip('Suspend/resume the selected schema')
213     self.actions.append(self.suspAct)
214
215     self.stepAct=QAction('Step',QIconSet(Icons.get_image("steps.png")),'&Step',0,self)
216     self.stepAct.connect(self.stepAct,SIGNAL('activated()'), self.step)
217     self.stepAct.setStatusTip('Step the selected schema')
218     self.actions.append(self.stepAct)
219
220     self.stopAct=QAction('Stop',QIconSet(Icons.get_image("kill.png")),'&Stop',0,self)
221     self.stopAct.connect(self.stopAct,SIGNAL('activated()'), self.stop)
222     self.stopAct.setStatusTip('Stop the selected schema')
223     self.actions.append(self.stopAct)
224
225     self.cataToolAct=QAction('Catalog Tool',0,self,"catatool")
226     self.cataToolAct.connect(self.cataToolAct,SIGNAL('activated()'), self.cata_tool)
227     self.actions.append(self.cataToolAct)
228
229   def initMenus(self):
230     menubar = self.menuBar()
231
232     #menu file
233     self.fileMenu=QPopupMenu(self)
234     self.newAct.addTo(self.fileMenu)
235     self.fileMenu.insertItem("&Open", self.openFile)
236     self.fileMenu.insertItem("&Open Salome", self.openSalomeFile)
237     self.loadersMenu = QPopupMenu(self)
238     self.fileMenu.insertItem("Loaders", self.loadersMenu)
239     self.loaders=[]
240     for file in glob.glob("/local/chris/SALOME2/SUPERV/YACS/BR_CC/YACS_SRC/src/pyqt/*loader.py"):
241       d,f=os.path.split(file)
242       name=f[:-9]
243       def call_loader(event,obj=self,file=file):
244         obj.openFileWithLoader(file)
245       self.loaders.append(call_loader)
246       self.loadersMenu.insertItem(name, call_loader)
247     menubar.insertItem('&File',self.fileMenu)
248
249     #menu settings
250     self.settingsMenu = QPopupMenu(self)
251     menubar.insertItem('&Settings', self.settingsMenu)
252     self.settingsMenu.insertTearOffHandle()
253     self.prefAct.addTo(self.settingsMenu)
254
255     #menu Edit
256     self.editMenu = QPopupMenu(self)
257     self.editMenu.insertItem("&Add node", self.addNode)
258     menubar.insertItem('&Edit', self.editMenu)
259
260     #menu Canvas
261     #sous menu layout
262     self.layoutMenu = QPopupMenu(self)
263     self.layoutMenu.insertItem("&Left Right", self.LR)
264     self.layoutMenu.insertItem("Right Left", self.RL)
265     self.layoutMenu.insertItem("Top Bottom", self.TB)
266     self.layoutMenu.insertItem("Bottom Top", self.BT)
267     self.canvasMenu = QPopupMenu(self)
268     self.canvasMenu.insertItem("&Zoom in", self.zoomIn)
269     self.canvasMenu.insertItem("Zoom &out", self.zoomOut)
270     self.canvasMenu.insertItem("Layout", self.layoutMenu)
271     self.canvasMenu.insertItem("Ortholinks", self.orthoLinks)
272     self.canvasMenu.insertItem("Clearlinks", self.clearLinks)
273     self.canvasMenu.insertItem("&Update", self.updateCanvas)
274     menubar.insertItem('&Canvas', self.canvasMenu)
275
276     #menu window
277     self.windowMenu = QPopupMenu(self)
278     self.cataToolAct.addTo(self.windowMenu)
279     self.windowMenu.insertItem("&Log", self.view_log)
280     menubar.insertItem('&Window', self.windowMenu)
281     self.connect(self.windowMenu, SIGNAL('aboutToShow()'), self.handleWindowMenu)
282
283     #menu help
284     self.help=QPopupMenu(self)
285     menubar.insertItem('&Help',self.help)
286     self.help.insertItem('&About',self.about,Qt.Key_F1)
287     self.help.insertItem('About &Qt',self.aboutQt)
288
289   def initYACS(self):
290     import pilot
291     import loader
292     import salomeloader
293     self.runtime= pilot.getRuntime()
294     self.loader = loader.YACSLoader()
295     self.executor = pilot.ExecutorSwig()
296     self.salomeloader=salomeloader.SalomeLoader()
297     self.loader.registerProcCataLoader()
298
299   def openSalomeFile(self):
300     fn = QFileDialog.getOpenFileName(QString.null,QString.null,self)
301     if fn.isEmpty():
302       self.statusBar().message('Loading aborted',2000)
303       return
304     fileName = str(fn)
305     proc=self.salomeloader.load(fileName)
306     logger=proc.getLogger("parser")
307     if logger.hasErrors():
308       self.logFile=logview.LogView()
309       self.logFile.text.setText(logger.getStr())
310       self.logFile.show()
311
312     panel=Browser(self.tabWidget,proc)
313     self.currentPanel=panel
314     self.tabWidget.addTab( panel,os.path.basename(fileName))
315     self.tabWidget.showPage(panel)
316
317   def openFile(self):
318     fn = QFileDialog.getOpenFileName(QString.null,QString.null,self)
319     if fn.isEmpty():
320       self.statusBar().message('Loading aborted',2000)
321       return
322     fileName = str(fn)
323     proc=self.loader.load(fileName)
324     logger=proc.getLogger("parser")
325     if logger.hasErrors():
326       self.logFile=logview.LogView()
327       self.logFile.text.setText(logger.getStr())
328       self.logFile.show()
329
330     panel=Browser(self.tabWidget,proc)
331     self.currentPanel=panel
332     self.tabWidget.addTab( panel,os.path.basename(fileName))
333     self.tabWidget.showPage(panel)
334
335   def newProc(self):
336     r=pilot.getRuntime()
337     proc=r.createProc("pr")
338     panel=Browser(self.tabWidget,proc)
339     self.currentPanel=panel
340     self.tabWidget.addTab( panel,proc.getName())
341     self.tabWidget.showPage(panel)
342
343   def openFileWithLoader(self,file):
344     d,f=os.path.split(file)
345     sys.path.insert(0,d)
346     module=__import__(os.path.splitext(f)[0])
347     del sys.path[0]
348     loader=module.Loader()
349
350     fn = QFileDialog.getOpenFileName(QString.null,QString.null,self)
351     if fn.isEmpty():
352       self.statusBar().message('Loading aborted',2000)
353       return
354     fileName = str(fn)
355     proc=loader.load(fileName)
356     logger=proc.getLogger("parser")
357     if logger.hasErrors():
358       self.logFile=logview.LogView()
359       self.logFile.text.setText(logger.getStr())
360       self.logFile.show()
361
362     panel=Browser(self.tabWidget,proc)
363     self.currentPanel=panel
364     self.tabWidget.addTab( panel,os.path.basename(fileName))
365     self.tabWidget.showPage(panel)
366
367   def cata_tool(self):
368     self.catalogTool=catalog.CatalogTool(self)
369     self.catalogTool.show()
370     return
371
372   def view_log(self):
373     if self.currentPanel:
374       self.currentPanel.view_log()
375
376   def LR(self,*args ):self.rankdir("LR")
377   def RL(self,*args ):self.rankdir("RL")
378   def TB(self,*args ):self.rankdir("TB")
379   def BT(self,*args ):self.rankdir("BT")
380
381   def rankdir(self,orient):
382     if self.currentPanel and self.currentPanel.panelManager.visible:
383       self.currentPanel.panelManager.visible.layout(orient)
384
385   def updateCanvas(self):
386     if self.currentPanel.selected:#item selected
387       if isinstance(self.currentPanel.selected,Items.ItemComposedNode):
388         #can update
389         self.currentPanel.selected.graph.editor.updateCanvas()
390
391   def addNode(self,node):
392     if self.currentPanel and self.currentPanel.selected:#item selected
393       if isinstance(self.currentPanel.selected,Items.ItemComposedNode):
394         #can add node
395         self.currentPanel.selected.addNode(node)
396
397   def zoomIn(self):
398     if self.currentPanel and self.currentPanel.panelManager.visible:
399       if isinstance(self.currentPanel.panelManager.visible,Items.ItemComposedNode):
400         #we can zoom
401         self.currentPanel.panelManager.visible.graph.editor.zoomIn()
402
403   def zoomOut(self):
404     if self.currentPanel and self.currentPanel.panelManager.visible:
405       if isinstance(self.currentPanel.panelManager.visible,Items.ItemComposedNode):
406         #we can unzoom 
407         self.currentPanel.panelManager.visible.graph.editor.zoomOut()
408
409   def orthoLinks(self):
410     if self.currentPanel and self.currentPanel.panelManager.visible:
411       if isinstance(self.currentPanel.panelManager.visible,Items.ItemComposedNode):
412         #it is a composed node with a graph
413         self.currentPanel.panelManager.visible.graph.orthoLinks()
414
415   def clearLinks(self):
416     if self.currentPanel and self.currentPanel.panelManager.visible:
417       if isinstance(self.currentPanel.panelManager.visible,Items.ItemComposedNode):
418         #it is a composed node with a graph
419         self.currentPanel.panelManager.visible.graph.clearLinks()
420
421   def handlePreferences(self):
422     pass
423
424   def handleWindowMenu(self):
425     pass
426
427   def about(self):
428     QMessageBox.about(self,'YACS browser GUI', 'YACS browser GUI')
429
430   def aboutQt(self):
431     QMessageBox.aboutQt(self,'YACS browser GUI')
432
433   def run(self):
434     if self.currentPanel:
435       self.currentPanel.run()
436
437   def susp(self):
438     if self.currentPanel:
439       self.currentPanel.susp()
440
441   def step(self):
442     if self.currentPanel:
443       self.currentPanel.step()
444
445   def stop(self):
446     if self.currentPanel:
447       self.currentPanel.stop()
448
449   def initToolbar(self):
450     tb = QToolBar(self)
451     self.newAct.addTo(tb)
452     self.runAct.addTo(tb)
453     self.suspAct.addTo(tb)
454     self.stepAct.addTo(tb)
455     self.stopAct.addTo(tb)
456     self.toolbars={}
457     self.toolbars['File']=tb
458
459   def initStatusbar(self):
460     sb = self.statusBar()
461     self.SBfile=QLabel(sb)
462     sb.addWidget(self.SBfile)
463     QWhatsThis.add(self.SBfile,
464                    """<p>Partie de la statusbar qui donne le nom"""
465                    """du fichier courant. </p>""")
466     self.SBfile.setText("")
467
468
469 if __name__ == "__main__":
470   from .Item import Item
471   app = QApplication(sys.argv)
472   t=Appli()
473   t.objectBrowser.additem(Item("item1"))
474   n=t.objectBrowser.additem(Item("item2"))
475   n.additem(Item("item3"))
476   app.setMainWidget(t)
477   t.show()
478   app.exec_loop()
479
480