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