Salome HOME
Merge from V6_main_20120808 08Aug12
[samples/pylight.git] / src / PYLIGHTGUI / PYLIGHTGUI.py
1 # Copyright (C) 2009-2012  OPEN CASCADE
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 #  Author : Roman NIKOLAEV, Open CASCADE S.A.S. (roman.nikolaev@opencascade.com)
21 #  Date   : 13/04/2009
22 #
23 import traceback
24 from SalomePyQt import *
25 import PYLIGHT_DataModel
26 from PyQt4.QtGui import *
27 from PyQt4.QtCore import *
28 import libSALOME_Swig
29
30 import os
31 import libSalomePy
32 import vtk
33
34 # Get SALOME PyQt interface
35 sgPyQt = SalomePyQt()
36 # Get SALOME Swig interface
37 sg = libSALOME_Swig.SALOMEGUI_Swig()
38
39 ################################################
40 # GUI context class
41 # Used to store actions, menus, toolbars, etc...
42 ################################################
43
44 class GUIcontext:
45
46     # constructor
47     def __init__( self ):
48         # Load File action
49         sgPyQt.createAction(dict_actions["loadfile"], "Load text File", "Load text file")
50         # Save File action
51         sgPyQt.createAction(dict_actions["savefile"], "Save text File", "Save text file")
52         # Insert Line action
53         sgPyQt.createAction(dict_actions["insertLine"], "Insert Line", "Insert new text line")
54         # Insert new line action
55         sgPyQt.createAction(dict_actions["insertLine"], "Insert Line", "Insert new line")
56         # Edit selected line action
57         sgPyQt.createAction(dict_actions["editLine"], "Edit Line", "Edit selected line")
58         # Remove selected line action
59         sgPyQt.createAction(dict_actions["removeLine"], "Remove Lines", "Remove selected lines")
60         # Clear all paragraphs
61         sgPyQt.createAction(dict_actions["clearAll"], "Clear All", "Clear all paragraphs")
62         # Display line
63         sgPyQt.createAction(dict_actions["displayLine"], "Display Line", "Display selected line")
64         # Erase line
65         sgPyQt.createAction(dict_actions["eraseLine"], "Erase Line", "Erase selected line")
66         # Separator
67         separator = sgPyQt.createSeparator()
68
69         # Get Menu 'File'
70         menuFile = sgPyQt.createMenu( "File", -1, -1 )
71         # Add actions in the menu 'File'
72         sgPyQt.createMenu( separator,                menuFile, -1, 10)
73         sgPyQt.createMenu( dict_actions["loadfile"], menuFile, 10 );
74         sgPyQt.createMenu( dict_actions["savefile"], menuFile, 10 );
75         sgPyQt.createMenu( separator,                menuFile, -1, 10)
76         # Create 'PyLight' menu 
77         menuPyLight = sgPyQt.createMenu( "PyLight", -1, -1, 50)
78         # Add actions in the menu 'PyLight'
79         sgPyQt.createMenu( dict_actions["insertLine"],  menuPyLight, 10 );
80         sgPyQt.createMenu( dict_actions["editLine"],    menuPyLight, 10 );
81         sgPyQt.createMenu( dict_actions["removeLine"],  menuPyLight, 10 );
82         sgPyQt.createMenu( separator,                   menuPyLight, -1, 10);
83         sgPyQt.createMenu( dict_actions["clearAll"],    menuPyLight, 10 );
84         sgPyQt.createMenu( separator,                   menuPyLight, -1, 10);
85         sgPyQt.createMenu( dict_actions["displayLine"], menuPyLight, 10 );
86         sgPyQt.createMenu( dict_actions["eraseLine"],   menuPyLight, 10 );
87
88         # Create DataModel
89         self.DM = PYLIGHT_DataModel.PYLIGHT_DataModel()
90
91         pass # def __init__( self )
92
93     pass # class GUIcontext
94
95 ################################################
96 # Global variables and functions
97 ################################################
98
99 ###
100 # get active study ID
101 ###
102 def _getStudyId():
103     return sgPyQt.getStudyId()
104
105 # verbosity level
106 __verbose__ = None
107
108 ###
109 # Get verbose level
110 ###
111 def verbose():
112     global __verbose__
113     if __verbose__ is None:
114         try:
115             __verbose__ = int( os.getenv( 'SALOME_VERBOSE', 0 ) )
116         except:
117             __verbose__ = 0
118             pass
119         pass
120     return __verbose__
121
122 # study-to-context map
123 __study2context__   = {}
124 # current context
125 __current_context__ = None
126
127 ###
128 # get current GUI context
129 ###
130 def _getContext():
131     global __current_context__
132     return __current_context__
133
134 ###
135 # set and return current GUI context
136 # study ID is passed as parameter
137 ###
138 def _setContext( studyID ):
139     global __study2context__, __current_context__
140     if not __study2context__.has_key(studyID):
141         __study2context__[studyID] = GUIcontext()
142         pass
143     __current_context__ = __study2context__[studyID]
144     return __current_context__
145
146 ################################################
147
148 # Create actions and menus
149 def initialize():
150     if verbose(): print "PYLIGHTGUI::initialize()"
151     return
152
153 # called when module is activated
154 # returns True if activating is successfull and False otherwise
155 def activate():
156     if verbose() : print "PYLIGHTGUI.activate() : study : %d" % _getStudyId()
157     ctx = _setContext( _getStudyId() )
158     return True
159
160 # called when module is deactivated
161 def deactivate():
162     if verbose() : print "PYLIGHTGUI.deactivate() : study : %d" % _getStudyId()
163     pass
164
165 # called when active study is changed
166 # active study ID is passed as parameter
167 def activeStudyChanged( studyID ):
168     if verbose() : print "PYLIGHTGUI.activeStudyChanged(): study : %d" % studyID
169     ctx = _setContext( _getStudyId() )
170     pass
171
172 # Process GUI action
173 def OnGUIEvent(commandID):
174     if verbose() : print "PYLIGHTGUI::OnGUIEvent : commandID = %d" % commandID
175     if dict_command.has_key( commandID ):
176         try:
177             dict_command[commandID]()
178         except:
179             traceback.print_exc()
180     else:
181        if verbose() : print "The command is not implemented: %d" % commandID
182     pass
183
184 # Customize popup menu
185 def createPopupMenu(popup, context):
186     if verbose() : print "PYLIGHTGUI.createPopupMenu(): context = %s" % context
187
188     if context != 'ObjectBrowser':
189         return
190     
191     studyId = _getStudyId()
192     ctx = _setContext( studyId )
193     selcount = sg.SelectedCount()
194     if selcount == 1:
195         entry = sg.getSelected( 0 )
196         obj = ctx.DM.getObject(entry)
197         if obj is not None:
198             if obj.getText() != "\n":
199                 # Line is selected
200                 popup.addAction(sgPyQt.action(dict_actions["editLine"]))
201                 popup.addAction(sgPyQt.action(dict_actions["removeLine"]))
202                 popup.addSeparator()
203                 popup.addAction(sgPyQt.action(dict_actions["displayLine"]))
204                 popup.addAction(sgPyQt.action(dict_actions["displayLine"]))
205                 popup.addAction(sgPyQt.action(dict_actions["eraseLine"]))
206                 pass
207             else:
208                 # Paragraph is selected
209                 popup.addAction(sgPyQt.action(dict_actions["insertLine"]))
210                 popup.addAction(sgPyQt.action(dict_actions["clearParagraph"]))
211                 pass
212             pass
213         else:
214             onlyLines = True
215             pass
216         pass # if selcount == 1
217     pass
218
219 # For saving data in the study
220 def saveFiles(prefix):
221     if verbose(): print "PYLIGHTGUI::saveFile()"
222     ctx = _setContext( _getStudyId() )
223     postfix = "PYLIGHT.txt"
224     filename = prefix+postfix
225     ctx.DM.saveFile(QString(filename))
226     return postfix
227
228 # For restore data from the study
229 def openFiles(filelist):
230     if verbose(): print "PYLIGHTGUI::openFile()"
231     ctx = _setContext( _getStudyId() )
232     filename =  filelist[0]
233     filename.append(filelist[1])
234     ctx.DM.loadFile(filename)
235     return True
236
237 # Loading a text file
238 def loadfile():
239     ctx = _setContext( _getStudyId() )
240     aFilter = "Text files (*.txt)"
241     filename = QFileDialog.getOpenFileName(sgPyQt.getDesktop(), "Open text file", "", aFilter, "Choose a text file to open")
242     if filename.isEmpty():
243         return
244     
245     if os.access(str(filename),os.R_OK):
246         ctx.DM.loadFile(filename)
247     else:
248         QMessageBox.warning(sgPyQt.getDesktop(),
249                             "Error!",
250                             QString("Can not read file:\n%1").arg(filename))
251         pass
252     sg.updateObjBrowser(True)
253     pass
254
255 # Saving a text file
256 def savefile():
257     ctx = _setContext( _getStudyId() )
258     aFilter = "Text files (*.txt)"
259     filename = QFileDialog.getSaveFileName(sgPyQt.getDesktop(),"Save text file", "", aFilter, "Choose a text file to save")
260     if filename.contains(".txt") == 0:
261         filename.append(".txt")
262         pass
263     fn = filename
264     # Get directory name and check access
265     if os.access(str(fn.left(fn.lastIndexOf("/"))), os.W_OK):
266         ctx.DM.saveFile(filename)
267     else:
268         QMessageBox.warning(sgPyQt.getDesktop(),
269                             "Error!",
270                             QString("Can not save file:\n%1").arg(filename))
271         pass
272     pass
273
274 def insertLine():
275     '''
276     Insert new line in the selected paragraph.
277     '''
278     ctx = _setContext( _getStudyId() )
279     #Get result
280     res = QInputDialog.getText(sgPyQt.getDesktop(),
281                                "Add new line",
282                                "Enter the text",
283                                QLineEdit.Normal)
284     if not res[1]: ### user click cancel button
285         return
286     
287     text = res[0]
288     # Nb selected objects
289     selcount = sg.SelectedCount()
290     # Nb object in the Data Model
291     paragrCount = len(ctx.DM.getParagraphs())
292
293     # Create first paragraph
294     if paragrCount == 0:
295         ctx.DM.createObject()
296         # If line not empty create first line
297         if text != "\n":
298             ctx.DM.createObject(text,ctx.DM.getParagraphs()[0])
299         sg.updateObjBrowser(True)
300         return
301     # Create paragraph
302     if text == "\n":
303         ctx.DM.createObject()
304         sg.updateObjBrowser(True)
305         return
306     else:
307         if selcount == 0:
308             QMessageBox.warning(sgPyQt.getDesktop(),
309                                 'Error!',
310                                 'Please, select paragraph!')
311             return
312         if selcount == 1:
313             entry = sg.getSelected( 0 )
314             obj = ctx.DM.getObject(entry)
315             if obj is not None:
316                 # Create line
317                 if(obj.getText() == "\n"):
318                     ctx.DM.createObject(text,entry)
319                     sg.updateObjBrowser(True);
320                     return
321                 else:
322                     QMessageBox.warning(sgPyQt.getDesktop(),
323                                         'Error!',
324                                         'Please, select paragraph!')
325             elif selcount > 1:
326                 QMessageBox.warning(sgPyQt.getDesktop(),
327                                     'Error!',
328                                     'Please, select only one paragraph!')
329     pass
330         
331         
332 # Edit selected line
333 def editLine():
334     ctx = _setContext( _getStudyId() )
335     if sg.SelectedCount() == 1:
336         entry = sg.getSelected( 0 )
337         obj = ctx.DM.getObject(entry)
338         if(obj.getText() != "\n"):
339             #Get text line
340             res = QInputDialog.getText(sgPyQt.getDesktop(),
341                                        "Edit line",
342                                        "Enter the text",
343                                        QLineEdit.Normal,
344                                        PYLIGHT_DataModel.processText(obj.getText()))
345             if not res[1]: ### user click cancel button
346                 return
347             text = res[0]
348             
349             obj.setText(text)
350         else:
351             QMessageBox.information(sgPyQt.getDesktop(),
352                                     'Info',
353                                     'Please, select line!') 
354     else:
355         QMessageBox.information(sgPyQt.getDesktop(),
356                                 'Info',
357                                 'Please, select one line!')
358     sg.updateObjBrowser(True);
359     pass
360
361 # Remove selected lines
362 def removeLine():
363     ctx = _setContext( _getStudyId() )
364     selcount = sg.SelectedCount()
365     onlyLines = True
366     lines = []
367     while selcount != 0:
368         entry = sg.getSelected( selcount - 1)
369         #Check what only lines selected
370         if ctx.DM.getObject(entry).getText() == "\n":
371             onlyLines = False
372             break
373         lines.append(entry)
374         selcount = selcount-1
375         pass
376     if not onlyLines:
377         return
378     else:
379         renderer=libSalomePy.getRenderer()
380         for ln in lines:
381             actor = getActor(ln)
382             if actor is not None:
383                 renderer.RemoveActor(actor)
384                 pass
385             pass
386         ctx.DM.removeObjects(lines)
387         sg.updateObjBrowser(True)
388         pass
389     pass
390
391 # Remove all lines from all paragraphs
392 def clearAll():
393     ctx = _setContext( _getStudyId() )
394     paragraphs = ctx.DM.getParagraphs()
395     for paragr in paragraphs:
396         lines = sgPyQt.getChildren(paragr)
397         ctx.DM.removeObjects(lines)
398         renderer=libSalomePy.getRenderer()
399         for l in lines:
400             actor = getActor(l)
401             if actor is not None:
402                 renderer.RemoveActor(actor)
403                 pass
404             pass
405     sg.updateObjBrowser(True)
406     pass
407
408 # Display the selected line
409 def displayLine():
410     ctx = _setContext( _getStudyId() )
411     if sg.SelectedCount() != 1:
412         return
413     entry = sg.getSelected(0)
414     text = ctx.DM.getObject(entry).getText()
415     if text == "\n":
416         return
417     renderer=libSalomePy.getRenderer()
418     actor = getActor(entry)
419     if actor is None:
420         actor = vtk.vtkTextActor()
421         dict_actors[entry] = actor
422         pass
423     center = renderer.GetCenter()
424     actor.SetInput(str(text))
425     actor.SetPosition(center[0],center[1])
426     txtPr = vtk.vtkTextProperty()
427     txtPr.SetFontSize(30)
428     actor.SetTextProperty(txtPr)
429     for act in  dict_actors.values():
430         renderer.RemoveActor(act)
431     renderer.AddActor(actor)
432     pass
433
434 # Clear remove all lines under selected paragraph
435 def clearParagraph():
436     ctx = _setContext( _getStudyId() )
437     lines = sgPyQt.getChildren(sg.getSelected(0))
438     ctx.DM.removeObjects(lines)
439     sg.updateObjBrowser(True)
440     pass
441
442 # Erase the selected line
443 def eraseLine():
444     ctx = _setContext( _getStudyId() )
445     if sg.SelectedCount() != 1:
446         return
447     entry = sg.getSelected(0)
448     text = ctx.DM.getObject(entry).getText()
449     if text == "\n":
450         return
451     renderer=libSalomePy.getRenderer()
452     actor = getActor(entry)
453     if actor is not None:
454         renderer.RemoveActor(actor)
455         pass
456     pass
457
458 # Return vtkActor by entry
459 def getActor(entry):
460     if isinstance(entry,QString):
461         entry = entry.toLatin1().data()
462     if dict_actors.has_key(entry):
463         return dict_actors[entry]
464     return None
465
466 # Define commands
467 dict_command = {
468     951 : loadfile,
469     952 : savefile,
470     961 : insertLine,
471     962 : editLine,
472     963 : removeLine,
473     964 : clearAll,
474     971 : displayLine,
475     972 : eraseLine,
476     973 : clearParagraph,
477     }
478
479 # Define actions
480 dict_actions = {
481     "loadfile"   :    951,
482     "savefile"   :    952,
483     "insertLine" :    961,
484     "editLine"   :    962,
485     "removeLine" :    963,
486     "clearAll"   :    964,
487     "displayLine":    971,
488     "eraseLine"  :    972,
489     "clearParagraph": 973,
490     }
491
492 # Define Actors
493 dict_actors = {}