Salome HOME
Merge from V6_main 01/04/2013
[modules/yacs.git] / src / pyqt / gui / Appli.py
1 # Copyright (C) 2006-2013  CEA/DEN, EDF R&D
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.
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 import Tree
25 import PanelManager
26 import BoxManager
27 import Icons
28 import Items
29 import adapt
30 import Item
31 import logview
32 import pilot
33 import threading
34 import time
35 import CONNECTOR
36 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,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