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