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