Salome HOME
Merge from V4_1_0_maintainance branch (from tag mergeto_BR_QT4_Dev_08Jul08)
[samples/pyhello.git] / src / PYHELLOGUI / PYHELLOGUI.py
1 # Copyright (C) 2005  CEA/DEN, EDF R&D
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 #
21 # File   : PYHELLOGUI.py
22 # Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
23 #
24 # ---
25
26 import traceback
27 import os
28 from PyQt4.QtGui import *
29 from PyQt4.QtCore import *
30
31 from omniORB import CORBA
32 from SALOME_NamingServicePy import *
33 from LifeCycleCORBA import *
34 import SALOMEDS
35 import SALOMEDS_Attributes_idl
36
37 import PYHELLO_ORB
38
39 ################################################
40 # GUI context class
41 # Used to store actions, menus, toolbars, etc...
42 ################################################
43
44 class GUIcontext:
45     # module name
46     MODULE_NAME      = "PYHELLO"
47     # module icon
48     MODULE_PIXMAP    = "PYHELLO_small.png"
49     # data objects IDs
50     MODULE_ID        = 1000
51     OBJECT_ID        = 1010
52     FOREIGN_ID       = -1
53     # menus/toolbars/actions IDs
54     PYHELLO_MENU_ID  = 90
55     HELLO_ID         = 941
56     CREATE_OBJECT_ID = 942
57     OPTIONS_ID       = 943
58     OPTION_1_ID      = 944
59     OPTION_2_ID      = 945
60     OPTION_3_ID      = 946
61     PYHELLO_TB_ID    = 90
62     DELETE_ALL_ID    = 951
63     SHOW_ME_ID       = 952
64     DELETE_ME_ID     = 953
65     RENAME_ME_ID     = 954
66     # default object name
67     DEFAULT_NAME     = "Object"
68
69     # constructor
70     def __init__( self ):
71         # create top-level menu
72         mid = sgPyQt.createMenu( "PyHello", -1, GUIcontext.PYHELLO_MENU_ID, sgPyQt.defaultMenuGroup() )
73         # create toolbar
74         tid = sgPyQt.createTool( "PyHello" )
75         # create actions and fill menu and toolbar with actions
76         a = sgPyQt.createAction( GUIcontext.HELLO_ID, "Hello", "Hello", "Show hello dialog box", "ExecPYHELLO.png" )
77         sgPyQt.createMenu( a, mid )
78         sgPyQt.createTool( a, tid )
79         a = sgPyQt.createSeparator()
80         sgPyQt.createMenu( a, mid )
81         a = sgPyQt.createAction( GUIcontext.CREATE_OBJECT_ID, "Create object", "Create object", "Create object" )
82         sgPyQt.createMenu( a, mid )
83         a = sgPyQt.createSeparator()
84         sgPyQt.createMenu( a, mid )
85         try:
86             ag = sgPyQt.createActionGroup( GUIcontext.OPTIONS_ID )
87             a = sgPyQt.createAction( GUIcontext.OPTION_1_ID, "Default name", "Default name", "Use default name for the objects" )
88             a.setToggleAction( True )
89             ag.add( a )
90             a = sgPyQt.createAction( GUIcontext.OPTION_2_ID, "Generate name", "Generate name", "Generate name for the objects" )
91             a.setToggleAction( True )
92             ag.add( a )
93             a = sgPyQt.createAction( GUIcontext.OPTION_3_ID, "Ask name", "Ask name", "Request object name from the user" )
94             a.setToggleAction( True )
95             ag.add( a )
96             sgPyQt.createMenu( ag, mid )
97             default_mode = sgPyQt.integerSetting( "PYHELLO", "creation_mode", 0 )
98             sgPyQt.action( GUIcontext.OPTION_1_ID + default_mode ).setOn( True )
99         except:
100             pass
101         # the following action are used in context popup
102         a = sgPyQt.createAction( GUIcontext.DELETE_ALL_ID, "Delete all", "Delete all", "Delete all objects" )
103         a = sgPyQt.createAction( GUIcontext.SHOW_ME_ID,    "Show",       "Show",       "Show object name" )
104         a = sgPyQt.createAction( GUIcontext.DELETE_ME_ID,  "Delete",     "Delete",     "Remove object" )
105         a = sgPyQt.createAction( GUIcontext.RENAME_ME_ID,  "Rename",     "Rename",     "Rename object" )
106         pass
107     pass
108
109 ################################################
110 # Global variables
111 ################################################
112
113 # study-to-context map
114 __study2context__   = {}
115 # current context
116 __current_context__ = None
117 # object counter
118 __id__ = 0
119
120 ################################################
121        
122 # Get SALOME PyQt interface
123 import SalomePyQt
124 sgPyQt = SalomePyQt.SalomePyQt()
125
126 # Get SALOME Swig interface
127 import libSALOME_Swig
128 sg = libSALOME_Swig.SALOMEGUI_Swig()
129
130 ################################################
131
132 # init ORB
133 orb = CORBA.ORB_init( [''], CORBA.ORB_ID )
134
135 # create naming service instance
136 naming_service = SALOME_NamingServicePy_i( orb )
137
138 # create life cycle CORBA instance
139 lcc = LifeCycleCORBA( orb )
140
141 # get study manager
142 obj = naming_service.Resolve( '/myStudyManager' )
143 studyManager = obj._narrow( SALOMEDS.StudyManager )
144
145 ################################################
146 # Internal methods
147 ################################################
148
149 ###
150 # Check verbose mode
151 ### 
152 __verbose__ = None
153 def verbose():
154     global __verbose__
155     if __verbose__ is None:
156         try:
157             __verbose__ = int( os.getenv('SALOME_VERBOSE', 0) )
158         except:
159             __verbose__ = 0
160             pass
161         pass
162     return __verbose__
163
164 ###
165 # get PYHELLO engine
166 ###
167 def _getEngine():
168     engine = lcc.FindOrLoadComponent( "FactoryServerPy", GUIcontext.MODULE_NAME )
169     return engine
170
171 ###
172 # get active study ID
173 ###
174 def _getStudyId():
175     return sgPyQt.getStudyId()
176
177 ###
178 # get active study
179 ###
180 def _getStudy():
181     studyId = _getStudyId()
182     study = studyManager.GetStudyByID( studyId )
183     return study
184
185 ###
186 # returns True if object has children
187 ###
188 def _hasChildren( sobj ):
189     if sobj:
190         study = _getStudy()
191         iter  = study.NewChildIterator( sobj )
192         while iter.More():
193             name = iter.Value().GetName()
194             if name:
195                 return True
196             iter.Next()
197             pass
198         pass
199     return False
200
201 ###
202 # finds or creates component object
203 ###
204 def _findOrCreateComponent():
205     study = _getStudy()
206     father = study.FindComponent( GUIcontext.MODULE_NAME )
207     if father is None:
208         builder = study.NewBuilder()
209         father = builder.NewComponent( GUIcontext.MODULE_NAME )
210         attr = builder.FindOrCreateAttribute( father, "AttributeName" )
211         attr.SetValue( GUIcontext.MODULE_NAME )
212         attr = builder.FindOrCreateAttribute( father, "AttributePixMap" )
213         attr.SetPixMap( GUIcontext.MODULE_PIXMAP )
214         attr = builder.FindOrCreateAttribute( father, "AttributeLocalID" )
215         attr.SetValue( GUIcontext.MODULE_ID )
216         try:
217             builder.DefineComponentInstance( father, _getEngine() )
218             pass
219         except:
220             pass
221         pass
222     return father
223
224 ###
225 # get current GUI context
226 ###
227 def _getContext():
228     global __current_context__
229     return __current_context__
230
231 ###
232 # set and return current GUI context
233 # study ID is passed as parameter
234 ###
235 def _setContext( studyID ):
236     global __study2context__, __current_context__
237     if not __study2context__.has_key(studyID):
238         __study2context__[studyID] = GUIcontext()
239         pass
240     __current_context__ = __study2context__[studyID]
241     return __current_context__
242
243 ###
244 # increment object counter in the map
245 ###
246 def _incObjToMap( m, id ):
247     if id not in m: m[id] = 0
248     m[id] += 1
249     pass
250
251 ###
252 # analyse selection
253 ###
254 def _getSelection():
255     selcount = sg.SelectedCount()
256     seltypes = {}
257     study = _getStudy()
258     for i in range( selcount ):
259         entry = sg.getSelected( i )
260         if entry:
261             sobj = study.FindObjectID( entry )
262             if sobj is not None:
263                 test, anAttr = sobj.FindAttribute( "AttributeLocalID" )
264                 if test:
265                     ID = anAttr._narrow( SALOMEDS.AttributeLocalID ).Value()
266                     if ID >= 0:
267                         _incObjToMap( seltypes, ID )
268                         continue
269                     pass
270                 pass
271             pass
272         _incObjToMap( seltypes, GUIcontext.FOREIGN_ID )
273         pass
274     return selcount, seltypes
275
276 ################################################
277 # Callback functions
278 ################################################
279
280 # called when module is initialized
281 # perform initialization actions
282 def initialize():
283     if verbose() : print "PYHELLOGUI.initialize() : study : %d" % _getStudyId()
284     # set default preferences values
285     if not sgPyQt.hasSetting( "PYHELLO", "def_obj_name"):
286         sgPyQt.addSetting( "PYHELLO", "def_obj_name", GUIcontext.DEFAULT_NAME )
287     if not sgPyQt.hasSetting( "PYHELLO", "creation_mode"):
288         sgPyQt.addSetting( "PYHELLO", "creation_mode", 0 )
289     pass
290
291 # called when module is initialized
292 # return map of popup windows to be used by the module
293 def windows():
294     if verbose() : print "PYHELLOGUI.windows() : study : %d" % _getStudyId()
295     wm = {}
296     wm[SalomePyQt.WT_ObjectBrowser] = Qt.DockLeft
297     wm[SalomePyQt.WT_PyConsole]     = Qt.DockBottom
298     return wm
299
300 # called when module is initialized
301 # return list of 2d/3d views to be used ny the module
302 def views():
303     if verbose() : print "PYHELLOGUI.views() : study : %d" % _getStudyId()
304     return []
305
306 # called when module is initialized
307 # export module's preferences
308 def createPreferences():
309     if verbose() : print "PYHELLOGUI.createPreferences() : study : %d" % _getStudyId()
310     gid = sgPyQt.addPreference( "General" )
311     gid = sgPyQt.addPreference( "Object creation", gid )
312     pid = sgPyQt.addPreference( "Default name",  gid, SalomePyQt.PT_String,   "PYHELLO", "def_obj_name" )
313     pid = sgPyQt.addPreference( "Default creation mode", gid, SalomePyQt.PT_Selector, "PYHELLO", "creation_mode" )
314     sgPyQt.addPreferenceProperty( pid, "strings", 0, QVariant( "Default name" ) )
315     sgPyQt.addPreferenceProperty( pid, "indexes", 0, QVariant( 0 ) )
316     sgPyQt.addPreferenceProperty( pid, "strings", 1, QVariant( "Generate name" ) )
317     sgPyQt.addPreferenceProperty( pid, "indexes", 1, QVariant( 1 ) )
318     sgPyQt.addPreferenceProperty( pid, "strings", 2, QVariant( "Ask name" ) )
319     sgPyQt.addPreferenceProperty( pid, "indexes", 2, QVariant( 2 ) )
320     pass
321
322 # called when module is activated
323 # returns True if activating is successfull and False otherwise
324 def activate():
325     if verbose() : print "PYHELLOGUI.activate() : study : %d" % _getStudyId()
326     ctx = _setContext( _getStudyId() )
327     return True
328
329 # called when module is deactivated
330 def deactivate():
331     if verbose() : print "PYHELLOGUI.deactivate() : study : %d" % _getStudyId()
332     pass
333
334 # called when active study is changed
335 # active study ID is passed as parameter
336 def activeStudyChanged( studyID ):
337     if verbose() : print "PYHELLOGUI.activeStudyChanged(): study : %d" % studyID
338     ctx = _setContext( _getStudyId() )
339     pass
340
341 # called when popup menu is invoked
342 # popup menu and menu context are passed as parameters
343 def createPopupMenu( popup, context ):
344     if verbose() : print "PYHELLOGUI.createPopupMenu(): context = %s" % context
345     ctx = _setContext( _getStudyId() )
346     study = _getStudy()
347     selcount, selected = _getSelection()
348     print selcount, selected
349     if selcount == 1:
350         # one object is selected
351         if GUIcontext.MODULE_ID in selected:
352             # menu for component
353             popup.addAction( sgPyQt.action( GUIcontext.DELETE_ALL_ID ) )
354         elif GUIcontext.OBJECT_ID in selected:
355             # menu for object
356             popup.addAction( sgPyQt.action( GUIcontext.SHOW_ME_ID ) )
357             popup.addAction( sgPyQt.action( GUIcontext.RENAME_ME_ID ) )
358             popup.addSeparator()
359             popup.addAction( sgPyQt.action( GUIcontext.DELETE_ME_ID ) )
360             pass
361         pass
362     elif selcount > 1:
363         # several objects are selected
364         if len( selected ) == 1:
365             if GUIcontext.MODULE_ID in selected:
366                 # menu for component
367                 popup.addAction( sgPyQt.action( GUIcontext.DELETE_ALL_ID ) )
368             elif GUIcontext.OBJECT_ID in selected:
369                 # menu for list of objects
370                 popup.addAction( sgPyQt.action( GUIcontext.DELETE_ME_ID ) )
371                 pass
372             pass
373         pass
374     pass
375
376 # called when GUI action is activated
377 # action ID is passed as parameter
378 def OnGUIEvent( commandID ):
379     if verbose() : print "PYHELLOGUI.OnGUIEvent(): command = %d" % commandID
380     if dict_command.has_key( commandID ):
381         try:
382             dict_command[commandID]()
383         except:
384             traceback.print_exc()
385     else:
386         if verbose() : print "The command is not implemented: %d" % commandID
387     pass
388
389 # called when module's preferences are changed
390 # preference's resources section and setting name are passed as parameters
391 def preferenceChanged( section, setting ):
392     if verbose() : print "PYHELLOGUI.preferenceChanged(): %s / %s" % ( section, setting )
393     pass
394
395 # called when active view is changed
396 # view ID is passed as parameter
397 def activeViewChanged( viewID ):
398     if verbose() : print "PYHELLOGUI.activeViewChanged(): %d" % viewID
399     pass
400
401 # called when active view is cloned
402 # cloned view ID is passed as parameter
403 def viewCloned( viewID ):
404     if verbose() : print "PYHELLOGUI.viewCloned(): %d" % viewID
405     pass
406
407 # called when active view is viewClosed
408 # view ID is passed as parameter
409 def viewClosed( viewID ):
410     if verbose() : print "PYHELLOGUI.viewClosed(): %d" % viewID
411     pass
412
413 ################################################
414 # GUI actions implementation
415 ################################################
416
417 ###
418 # 'HELLO' dialog box
419 ###
420 class MyDialog( QDialog ):
421     # constructor
422     def __init__( self, parent = None, modal = 0):
423         QDialog.__init__( self, parent )
424         self.setObjectName( "MyDialog" )
425         self.setModal( modal )
426         self.setWindowTitle( "HELLO!" )
427         vb = QVBoxLayout( self )
428         vb.setMargin( 8 )
429
430         hb0 = QHBoxLayout( self )
431         label = QLabel( "Prenom: ", self )
432         hb0.addWidget( label )
433         self.entry = QLineEdit( self )
434         self.entry.setMinimumWidth( 200 )
435         hb0.addWidget( self.entry )
436         vb.addLayout( hb0 )
437         
438         hb1 = QHBoxLayout( self )
439         bOk = QPushButton( "&OK", self )
440         self.connect( bOk, SIGNAL( 'clicked()' ), self, SLOT( 'accept()' ) )
441         hb1.addWidget( bOk )
442         
443         hb1.addStretch( 10 )
444         
445         bCancel = QPushButton( "&Cancel", self )
446         self.connect( bCancel, SIGNAL( 'clicked()' ), self, SLOT( 'close()' ) )
447         hb1.addWidget( bCancel )
448         
449         vb.addLayout( hb1 )
450         pass
451     
452     # OK button slot
453     def accept( self ):
454         name = str( self.entry.text() )
455         if name != "":
456             banner = _getEngine().makeBanner( name )
457             QMessageBox.information( self, 'Info', banner )
458             self.close()
459         else:
460             QMessageBox.warning( self, 'Error!', 'Please, enter the name!' )
461         pass
462
463 ###
464 # Show 'HELLO' dialog box
465 ###
466 def ShowHELLO():
467     # create dialog box
468     d = MyDialog( sgPyQt.getDesktop(), 1 )
469     # show dialog box
470     d.exec_()
471     pass
472
473 ###
474 # Create new object
475 ###
476 def CreateObject():
477     default_name = str( sgPyQt.stringSetting( "PYHELLO", "def_obj_name", GUIcontext.DEFAULT_NAME ).trimmed() )
478     try:
479         if sgPyQt.action( GUIcontext.OPTION_3_ID ).isOn():
480             # request object name from the user
481             name, ok = QInputDialog.getText( sgPyQt.getDesktop(),
482                                              "Create Object",
483                                              "Enter object name:",
484                                              QLineEdit.Normal,
485                                              default_name )
486             if not ok: return
487             name = str( name.trimmed() )
488         elif sgPyQt.action( GUIcontext.OPTION_2_ID ).isOn():
489             # generate object name
490             global __id__
491             __id__  = __id__ + 1
492             name = "%s %d" % ( default_name, __id__ )
493         else:
494             name = default_name
495             pass
496         pass
497     except:
498         # generate object name
499         global __id__
500         __id__  = __id__ + 1
501         name = "%s %d" % ( default_name, __id__ )
502         pass
503     if not name: return
504     study   = _getStudy()
505     builder = study.NewBuilder()
506     father  = _findOrCreateComponent()
507     object  = builder.NewObject( father )
508     attr    = builder.FindOrCreateAttribute( object, "AttributeName" )
509     attr.SetValue( name )
510     attr    = builder.FindOrCreateAttribute( object, "AttributeLocalID" )
511     attr.SetValue( GUIcontext.OBJECT_ID )
512     sg.updateObjBrowser( True )
513     pass
514
515 ###
516 # Delete all objects
517 ###
518 def DeleteAll():
519     study = _getStudy()
520     father = study.FindComponent( GUIcontext.MODULE_NAME )
521     if father:
522         iter = study.NewChildIterator( father )
523         builder = study.NewBuilder()
524         while iter.More():
525             sobj = iter.Value()
526             iter.Next()
527             builder.RemoveObjectWithChildren( sobj )
528             pass
529         sg.updateObjBrowser( True )
530         pass
531     pass
532
533 ###
534 # Show object's name
535 ###
536 def ShowMe():
537     study = _getStudy()
538     entry = sg.getSelected( 0 )
539     if entry != '':
540         sobj = study.FindObjectID( entry )
541         if ( sobj ):
542             test, attr = sobj.FindAttribute( "AttributeName" )
543             if test:
544                 QMessageBox.information( sgPyQt.getDesktop(), 'Info', "My name is '%s'" % attr.Value() )
545                 pass
546             pass
547         pass
548     pass
549
550 ###
551 # Delete selected object(s)
552 ###
553 def Delete():
554     study = _getStudy()
555     builder = study.NewBuilder()
556     if sg.SelectedCount() <= 0: return
557     for i in range( sg.SelectedCount() ):
558         entry = sg.getSelected( i )
559         if entry != '':
560             sobj = study.FindObjectID( entry )
561             if ( sobj ):
562                 builder.RemoveObject( sobj )
563                 pass
564             pass
565         pass
566     sg.updateObjBrowser( True )
567     pass
568
569 ###
570 # Rename selected object
571 ###
572 def Rename():
573     study = _getStudy()
574     builder = study.NewBuilder()
575     entry = sg.getSelected( 0 )
576     if entry != '':
577         sobj = study.FindObjectID( entry )
578         if ( sobj ):
579             name, ok = QInputDialog.getText( sgPyQt.getDesktop(),
580                                              "Object name",
581                                              "Enter object name:",
582                                              QLineEdit.Normal,
583                                              sobj.GetName() )
584             name = str( name.trimmed() )
585             if not ok or not name: return
586             attr = builder.FindOrCreateAttribute( sobj, "AttributeName" )
587             attr.SetValue( name )
588             sg.updateObjBrowser( True )
589             pass
590         pass
591     pass
592
593 ###
594 # Commands dictionary
595 ###
596 dict_command = {
597     GUIcontext.HELLO_ID         : ShowHELLO,
598     GUIcontext.CREATE_OBJECT_ID : CreateObject,
599     GUIcontext.DELETE_ALL_ID    : DeleteAll,
600     GUIcontext.SHOW_ME_ID       : ShowMe,
601     GUIcontext.DELETE_ME_ID     : Delete,
602     GUIcontext.RENAME_ME_ID     : Rename,
603     }