Salome HOME
Python3: print => print()
[samples/pyhello.git] / src / PYHELLOGUI / PYHELLOGUI.py
1 # Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
2 #
3 # Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 # CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 #
6 # This library is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU Lesser General Public
8 # License as published by the Free Software Foundation; either
9 # version 2.1 of the License, or (at your option) any later version.
10 #
11 # This library is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 # Lesser General Public License for more details.
15 #
16 # You should have received a copy of the GNU Lesser General Public
17 # License along with this library; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 #
20 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 #
22
23 # ---
24 # File   : PYHELLOGUI.py
25 # Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
26 # ---
27 #
28 import traceback
29
30 from PYHELLO_utils import (moduleName, getStudyManager, getObjectID, verbose,
31                            moduleID, objectID, getEngineIOR, getEngine)
32 from SalomePyQt import (SalomePyQt, WT_ObjectBrowser, WT_PyConsole, PT_Selector,  # @UnresolvedImport
33                         PT_String)  # @UnresolvedImport
34 from qtsalome import (QDialog, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit,  # @UnresolvedImport
35                       QPushButton, QMessageBox, QInputDialog, Qt)  # @UnresolvedImport
36 from salome.kernel import termcolor
37 from salome.kernel.logger import Logger
38 import libSALOME_Swig
39
40
41 logger = Logger(moduleName(), color=termcolor.RED_FG)
42
43 ################################################
44 # GUI context class
45 # Used to store actions, menus, toolbars, etc...
46 ################################################
47
48 class GUIcontext:
49     # menus/toolbars/actions IDs
50     PYHELLO_MENU_ID  = 90
51     HELLO_ID         = 941
52     CREATE_OBJECT_ID = 942
53     OPTIONS_ID       = 943
54     OPTION_1_ID      = 944
55     OPTION_2_ID      = 945
56     OPTION_3_ID      = 946
57     PASSWORD_ID      = 947
58     PYHELLO_TB_ID    = 90
59     DELETE_ALL_ID    = 951
60     SHOW_ME_ID       = 952
61     DELETE_ME_ID     = 953
62     RENAME_ME_ID     = 954
63     # default object name
64     DEFAULT_NAME     = "Object"
65     # default password
66     DEFAULT_PASSWD   = "Passwd"
67
68     # constructor
69     def __init__( self ):
70         # create top-level menu
71         mid = sgPyQt.createMenu( "PyHello", -1, GUIcontext.PYHELLO_MENU_ID, sgPyQt.defaultMenuGroup() )
72         # create toolbar
73         tid = sgPyQt.createTool( "PyHello" )
74         # create actions and fill menu and toolbar with actions
75         a = sgPyQt.createAction( GUIcontext.HELLO_ID, "Hello", "Hello", "Show hello dialog box", "ExecPYHELLO.png" )
76         sgPyQt.createMenu( a, mid )
77         sgPyQt.createTool( a, tid )
78         a = sgPyQt.createSeparator()
79         sgPyQt.createMenu( a, mid )
80         a = sgPyQt.createAction( GUIcontext.CREATE_OBJECT_ID, "Create object", "Create object", "Create object" )
81         sgPyQt.createMenu( a, mid )
82         a = sgPyQt.createSeparator()
83         sgPyQt.createMenu( a, mid )
84         try:
85             ag = sgPyQt.createActionGroup( GUIcontext.OPTIONS_ID )
86             ag.setText( "Creation mode" )
87             ag.setUsesDropDown(True)
88             a = sgPyQt.createAction( GUIcontext.OPTION_1_ID, "Default name", "Default name", "Use default name for the objects" )
89             a.setCheckable( True )
90             ag.add( a )
91             a = sgPyQt.createAction( GUIcontext.OPTION_2_ID, "Generate name", "Generate name", "Generate name for the objects" )
92             a.setCheckable( True )
93             ag.add( a )
94             a = sgPyQt.createAction( GUIcontext.OPTION_3_ID, "Ask name", "Ask name", "Request object name from the user" )
95             a.setCheckable( True )
96             ag.add( a )
97             sgPyQt.createMenu( ag, mid )
98             sgPyQt.createTool( ag, tid )
99             default_mode = sgPyQt.integerSetting( "PYHELLO", "creation_mode", 0 )
100             sgPyQt.action( GUIcontext.OPTION_1_ID + default_mode ).setChecked( True )
101         except:
102             pass
103         a = sgPyQt.createSeparator()
104         a = sgPyQt.createAction( GUIcontext.PASSWORD_ID, "Display password", "Display password", "Display password" )
105         sgPyQt.createMenu( a, mid )
106         
107         # the following action are used in context popup
108         a = sgPyQt.createAction( GUIcontext.DELETE_ALL_ID, "Delete all", "Delete all", "Delete all objects" )
109         a = sgPyQt.createAction( GUIcontext.SHOW_ME_ID,    "Show",       "Show",       "Show object name" )
110         a = sgPyQt.createAction( GUIcontext.DELETE_ME_ID,  "Delete",     "Delete",     "Remove object" )
111         a = sgPyQt.createAction( GUIcontext.RENAME_ME_ID,  "Rename",     "Rename",     "Rename object" )
112         pass
113     pass
114
115 ################################################
116 # Global variables
117 ################################################
118
119 # study-to-context map
120 __study2context__   = {}
121 # current context
122 __current_context__ = None
123 # object counter
124 __objectid__ = 0
125
126 ################################################
127        
128 # Get SALOME PyQt interface
129 sgPyQt = SalomePyQt()
130
131 # Get SALOME Swig interface
132 sg = libSALOME_Swig.SALOMEGUI_Swig()
133
134 ################################################
135
136 ################################################
137 # Internal methods
138 ################################################
139
140 ###
141 # get active study ID
142 ###
143 def _getStudyId():
144     return sgPyQt.getStudyId()
145
146 ###
147 # get active study
148 ###
149 def _getStudy():
150     studyId = _getStudyId()
151     study = getStudyManager().GetStudyByID( studyId )
152     return study
153
154 ###
155 # returns True if object has children
156 ###
157 def _hasChildren( sobj ):
158     if sobj:
159         study = _getStudy()
160         iter  = study.NewChildIterator( sobj )
161         while iter.More():
162             name = iter.Value().GetName()
163             if name:
164                 return True
165             iter.Next()
166             pass
167         pass
168     return False
169
170 ###
171 # get current GUI context
172 ###
173 def _getContext():
174     global __current_context__
175     return __current_context__
176
177 ###
178 # set and return current GUI context
179 # study ID is passed as parameter
180 ###
181 def _setContext( studyID ):
182     global __study2context__, __current_context__
183     if studyID not in __study2context__:
184         __study2context__[studyID] = GUIcontext()
185         pass
186     __current_context__ = __study2context__[studyID]
187     return __current_context__
188
189 ###
190 # increment object counter in the map
191 ###
192 def _incObjToMap( m, id ):
193     if id not in m: m[id] = 0
194     m[id] += 1
195     pass
196
197 ###
198 # analyse selection
199 ###
200 def _getSelection():
201     selcount = sg.SelectedCount()
202     seltypes = {}
203     for i in range( selcount ):
204         _incObjToMap( seltypes, getObjectID( _getStudy(), sg.getSelected( i ) ) )
205         pass
206     return selcount, seltypes
207
208 ################################################
209 # Callback functions
210 ################################################
211
212 # called when module is initialized
213 # perform initialization actions
214 def initialize():
215     if verbose() : print("PYHELLOGUI.initialize() : study : %d" % _getStudyId())
216     # set default preferences values
217     if not sgPyQt.hasSetting( "PYHELLO", "def_obj_name"):
218         sgPyQt.addSetting( "PYHELLO", "def_obj_name", GUIcontext.DEFAULT_NAME )
219     if not sgPyQt.hasSetting( "PYHELLO", "creation_mode"):
220         sgPyQt.addSetting( "PYHELLO", "creation_mode", 0 )
221     if not sgPyQt.hasSetting( "PYHELLO", "Password"):
222         sgPyQt.addSetting( "PYHELLO", "Password", GUIcontext.DEFAULT_PASSWD )
223     pass
224
225 # called when module is initialized
226 # return map of popup windows to be used by the module
227 def windows():
228     if verbose() : print("PYHELLOGUI.windows() : study : %d" % _getStudyId())
229     wm = {}
230     wm[WT_ObjectBrowser] = Qt.LeftDockWidgetArea
231     wm[WT_PyConsole] = Qt.BottomDockWidgetArea
232     return wm
233
234 # called when module is initialized
235 # return list of 2d/3d views to be used ny the module
236 def views():
237     if verbose() : print("PYHELLOGUI.views() : study : %d" % _getStudyId())
238     return []
239
240 # called when module is initialized
241 # export module's preferences
242 def createPreferences():
243     if verbose():
244         print("PYHELLOGUI.createPreferences() : study : %d" % _getStudyId())
245     gid = sgPyQt.addPreference("General")
246     gid = sgPyQt.addPreference("Object creation", gid)
247     sgPyQt.addPreference("Default name", gid, PT_String, "PYHELLO", "def_obj_name")
248     pid = sgPyQt.addPreference("Default creation mode", gid, PT_Selector, "PYHELLO", "creation_mode")
249     strings = ["Default name", "Generate name", "Ask name"]
250     indexes = [0, 1, 2]
251     sgPyQt.setPreferenceProperty(pid, "strings", strings)
252     sgPyQt.setPreferenceProperty(pid, "indexes", indexes)
253     pid = sgPyQt.addPreference("Password", gid, PT_String, "PYHELLO", "Password")
254     sgPyQt.setPreferenceProperty(pid, "echo", 2)
255     pass
256
257 # called when module is activated
258 # returns True if activating is successfull and False otherwise
259 def activate():
260     if verbose() : print("PYHELLOGUI.activate() : study : %d" % _getStudyId())
261     ctx = _setContext( _getStudyId() )
262     return True
263
264 # called when module is deactivated
265 def deactivate():
266     if verbose() : print("PYHELLOGUI.deactivate() : study : %d" % _getStudyId())
267     pass
268
269 # called when active study is changed
270 # active study ID is passed as parameter
271 def activeStudyChanged( studyID ):
272     if verbose() : print("PYHELLOGUI.activeStudyChanged(): study : %d" % studyID)
273     ctx = _setContext( _getStudyId() )
274     pass
275
276 # called when popup menu is invoked
277 # popup menu and menu context are passed as parameters
278 def createPopupMenu( popup, context ):
279     if verbose() : print("PYHELLOGUI.createPopupMenu(): context = %s" % context)
280     ctx = _setContext( _getStudyId() )
281     study = _getStudy()
282     selcount, selected = _getSelection()
283     if verbose() : print(selcount, selected)
284     if selcount == 1:
285         # one object is selected
286         if moduleID() in selected:
287             # menu for component
288             popup.addAction( sgPyQt.action( GUIcontext.DELETE_ALL_ID ) )
289         elif objectID() in selected:
290             # menu for object
291             popup.addAction( sgPyQt.action( GUIcontext.SHOW_ME_ID ) )
292             popup.addAction( sgPyQt.action( GUIcontext.RENAME_ME_ID ) )
293             popup.addSeparator()
294             popup.addAction( sgPyQt.action( GUIcontext.DELETE_ME_ID ) )
295             pass
296         pass
297     elif selcount > 1:
298         # several objects are selected
299         if len( selected ) == 1:
300             if moduleID() in selected:
301                 # menu for component
302                 popup.addAction( sgPyQt.action( GUIcontext.DELETE_ALL_ID ) )
303             elif objectID() in selected:
304                 # menu for list of objects
305                 popup.addAction( sgPyQt.action( GUIcontext.DELETE_ME_ID ) )
306                 pass
307             pass
308         pass
309     pass
310
311 # called when GUI action is activated
312 # action ID is passed as parameter
313 def OnGUIEvent( commandID ):
314     if verbose() : print("PYHELLOGUI.OnGUIEvent(): command = %d" % commandID)
315     if commandID in dict_command:
316         try:
317             dict_command[commandID]()
318         except:
319             traceback.print_exc()
320     else:
321         if verbose() : print("The command is not implemented: %d" % commandID)
322     pass
323
324 # called when module's preferences are changed
325 # preference's resources section and setting name are passed as parameters
326 def preferenceChanged( section, setting ):
327     if verbose() : print("PYHELLOGUI.preferenceChanged(): %s / %s" % ( section, setting ))
328     pass
329
330 # called when active view is changed
331 # view ID is passed as parameter
332 def activeViewChanged( viewID ):
333     if verbose() : print("PYHELLOGUI.activeViewChanged(): %d" % viewID)
334     pass
335
336 # called when active view is cloned
337 # cloned view ID is passed as parameter
338 def viewCloned( viewID ):
339     if verbose() : print("PYHELLOGUI.viewCloned(): %d" % viewID)
340     pass
341
342 # called when active view is viewClosed
343 # view ID is passed as parameter
344 def viewClosed( viewID ):
345     if verbose() : print("PYHELLOGUI.viewClosed(): %d" % viewID)
346     pass
347
348 # called when study is opened
349 # returns engine IOR
350 def engineIOR():
351     if verbose() : print("PYHELLOGUI.engineIOR()")
352     return getEngineIOR()
353
354 # called to check if object can be dragged
355 # returns True if drag operation is allowed for this object
356 def isDraggable(what):
357     if verbose() : print("PYHELLOGUI.isDraggable()")
358     # return True if object is draggable
359     return False
360
361 # called to check if object allows dropping on it
362 # returns True if drop operation is allowed for this object
363 def isDropAccepted(where):
364     if verbose() : print("PYHELLOGUI.isDropAccepted()")
365     # return True if object accept drops
366     return False
367
368 # called when drag and drop operation is finished
369 # performs corresponding data re-arrangement if allowed
370 def dropObjects(what, where, row, action):
371     if verbose() :
372         print("PYHELLOGUI.dropObjects()")
373         # 'what' is a list of entries of objects being dropped
374         for i in what: print("- dropped:", i)
375         # 'where' is a parent object's entry
376         print("- dropping on:", where)
377         # 'row' is an position in the parent's children list;
378         # -1 if appending to the end of children list is performed
379         print("- dropping position:", row)
380         # 'action' is a dropping action being performed:
381         # - 0x01 (Qt::CopyAction) for copy
382         # - 0x02 (Qt::MoveAction) for move
383         print("- drop action:", action)
384         pass
385     pass
386
387 ################################################
388 # GUI actions implementation
389 ################################################
390
391 ###
392 # 'HELLO' dialog box
393 ###
394 class MyDialog( QDialog ):
395     # constructor
396     def __init__( self, parent = None, modal = 0):
397         QDialog.__init__( self, parent )
398         self.setObjectName( "MyDialog" )
399         self.setModal( modal )
400         self.setWindowTitle( "HELLO!" )
401         vb = QVBoxLayout( self )
402         vb.setContentsMargins( 8, 8, 8, 8 )
403
404         hb0 = QHBoxLayout( self )
405         label = QLabel( "Prenom: ", self )
406         hb0.addWidget( label )
407         self.entry = QLineEdit( self )
408         self.entry.setMinimumWidth( 200 )
409         hb0.addWidget( self.entry )
410         vb.addLayout( hb0 )
411         
412         hb1 = QHBoxLayout( self )
413         bOk = QPushButton( "&OK", self )
414         bOk.setIcon( sgPyQt.loadIcon( 'PYHELLO', 'ICO_HANDSHAKE' ) )
415         bOk.clicked.connect(self.accept)
416         hb1.addWidget( bOk )
417         
418         hb1.addStretch( 10 )
419         
420         bCancel = QPushButton( "&Cancel", self )
421         bCancel.setIcon( sgPyQt.loadIcon( 'PYHELLO', 'ICO_STOP' ) )
422         bCancel.clicked.connect(self.close)
423         hb1.addWidget( bCancel )
424         vb.addLayout( hb1 )
425         pass
426     
427     # OK button slot
428     def accept( self ):
429         name = str( self.entry.text() )
430         if name != "":
431             banner = getEngine().makeBanner( name )
432             QMessageBox.information( self, 'Info', banner )
433             self.close()
434         else:
435             QMessageBox.warning( self, 'Error!', 'Please, enter the name!' )
436         pass
437
438 ###
439 # Show 'HELLO' dialog box
440 ###
441 def ShowHELLO():
442     # create dialog box
443     d = MyDialog( sgPyQt.getDesktop(), 1 )
444     # show dialog box
445     d.exec_()
446     pass
447
448 ###
449 # Create new object
450 ###
451 def CreateObject():
452     global __objectid__
453     default_name = sgPyQt.stringSetting("PYHELLO", "def_obj_name", GUIcontext.DEFAULT_NAME).strip()
454     try:
455         if sgPyQt.action(GUIcontext.OPTION_3_ID).isChecked():
456             # request object name from the user
457             name, ok = QInputDialog.getText(sgPyQt.getDesktop(),
458                                                       "Create Object",
459                                                       "Enter object name:",
460                                                       QLineEdit.Normal,
461                                                       default_name)
462             if not ok:
463                 return
464             name = name.strip()
465         elif sgPyQt.action(GUIcontext.OPTION_2_ID).isChecked():
466             # generate object name
467             __objectid__ = __objectid__ + 1
468             name = "%s %d" % (default_name, __objectid__)
469         else:
470             name = default_name
471             pass
472         pass
473     except Exception as e:
474         logger.debug(e)
475         # generate object name
476         __objectid__ = __objectid__ + 1
477         name = "%s %d" % (default_name, __objectid__)
478         pass
479     if not name:
480         return
481     getEngine().createObject(_getStudy(), name)
482     sg.updateObjBrowser(True)
483     pass
484
485 ###
486 # Delete all objects
487 ###
488 def DeleteAll():
489     study = _getStudy()
490     father = study.FindComponent( moduleName() )
491     if father:
492         iter = study.NewChildIterator( father )
493         builder = study.NewBuilder()
494         while iter.More():
495             sobj = iter.Value()
496             iter.Next()
497             builder.RemoveObjectWithChildren( sobj )
498             pass
499         sg.updateObjBrowser( True )
500         pass
501     pass
502
503 ###
504 # Show object's name
505 ###
506 def ShowMe():
507     study = _getStudy()
508     entry = sg.getSelected( 0 )
509     if entry != '':
510         sobj = study.FindObjectID( entry )
511         if ( sobj ):
512             test, attr = sobj.FindAttribute( "AttributeName" )
513             if test:
514                 QMessageBox.information( sgPyQt.getDesktop(), 'Info', "My name is '%s'" % attr.Value() )
515                 pass
516             pass
517         pass
518     pass
519
520 ###
521 # Delete selected object(s)
522 ###
523 def Delete():
524     study = _getStudy()
525     builder = study.NewBuilder()
526     if sg.SelectedCount() <= 0: return
527     for i in range( sg.SelectedCount() ):
528         entry = sg.getSelected( i )
529         if entry != '':
530             sobj = study.FindObjectID( entry )
531             if ( sobj ):
532                 builder.RemoveObject( sobj )
533                 pass
534             pass
535         pass
536     sg.updateObjBrowser( True )
537     pass
538
539 ###
540 # Rename selected object
541 ###
542 def Rename():
543     study = _getStudy()
544     builder = study.NewBuilder()
545     entry = sg.getSelected( 0 )
546     if entry != '':
547         sobj = study.FindObjectID( entry )
548         if ( sobj ):
549             name, ok = QInputDialog.getText( sgPyQt.getDesktop(),
550                                              "Object name",
551                                              "Enter object name:",
552                                              QLineEdit.Normal,
553                                              sobj.GetName() )
554             name = str( name ).strip()
555             if not ok or not name: return
556             attr = builder.FindOrCreateAttribute( sobj, "AttributeName" )
557             attr.SetValue( name )
558             sg.updateObjBrowser( True )
559             pass
560         pass
561     pass
562
563 ###
564 # Display password stored in the preferences
565 ###
566 def Password():
567   passwd = str( sgPyQt.stringSetting( "PYHELLO", "Password", GUIcontext.DEFAULT_PASSWD ) ).strip()
568   QMessageBox.information(sgPyQt.getDesktop(),
569                           "Password",
570                           passwd)
571
572 ###
573 # Commands dictionary
574 ###
575 dict_command = {
576     GUIcontext.HELLO_ID         : ShowHELLO,
577     GUIcontext.CREATE_OBJECT_ID : CreateObject,
578     GUIcontext.DELETE_ALL_ID    : DeleteAll,
579     GUIcontext.SHOW_ME_ID       : ShowMe,
580     GUIcontext.DELETE_ME_ID     : Delete,
581     GUIcontext.RENAME_ME_ID     : Rename,
582     GUIcontext.PASSWORD_ID      : Password,
583     }