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