Salome HOME
Update copyright information
[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 qt 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.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         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.setToggleAction( True )
90         ag.add( a )
91         a = sgPyQt.createAction( GUIcontext.OPTION_2_ID, "Generate name", "Generate name", "Generate name for the objects" )
92         a.setToggleAction( 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.setToggleAction( 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 ).setOn( True )
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             sgPyQt.action( GUIcontext.DELETE_ALL_ID ).addTo( popup )
354         elif GUIcontext.OBJECT_ID in selected:
355             # menu for object
356             sgPyQt.action( GUIcontext.SHOW_ME_ID ).addTo( popup )
357             sgPyQt.action( GUIcontext.RENAME_ME_ID ).addTo( popup )
358             popup.insertSeparator()
359             sgPyQt.action( GUIcontext.DELETE_ME_ID ).addTo( popup )
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                 sgPyQt.action( GUIcontext.DELETE_ALL_ID ).addTo( popup )
368             elif GUIcontext.OBJECT_ID in selected:
369                 # menu for list of objects
370                 sgPyQt.action( GUIcontext.DELETE_ME_ID ).addTo( popup )
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, "MyDialog", modal )
424         self.setCaption( "HELLO!" )
425         vb = QVBoxLayout( self, 8 )
426         vb.setAutoAdd( 1 )
427         hb0 = QHBox( self )
428         label = QLabel( "Prenom: ", hb0 )
429         self.entry = QLineEdit( hb0 )
430         self.entry.setMinimumWidth( 200 )
431         
432         hb1 = QHBox( self )
433         bOk = QPushButton( "&OK", hb1 )
434         self.connect( bOk, SIGNAL( 'clicked()' ), self, SLOT( 'accept()' ) )
435         dummy = QWidget( hb1 )
436         bCancel = QPushButton( "&Cancel", hb1 )
437         self.connect( bCancel, SIGNAL( 'clicked()' ), self, SLOT( 'close()' ) )
438         hb1.setStretchFactor( dummy, 10 )
439         pass
440     
441     # OK button slot
442     def accept( self ):
443         name = str( self.entry.text() )
444         if name != "":
445             banner = _getEngine().makeBanner( name )
446             QMessageBox.information( self, 'Info', banner )
447             self.close()
448         else:
449             QMessageBox.warning( self, 'Error!', 'Please, enter the name!' )
450         pass
451
452 ###
453 # Show 'HELLO' dialog box
454 ###
455 def ShowHELLO():
456     # create dialog box
457     d = MyDialog( sgPyQt.getDesktop(), 1 )
458     # show dialog box
459     d.exec_loop()
460     pass
461
462 ###
463 # Create new object
464 ###
465 def CreateObject():
466     default_name = str( sgPyQt.stringSetting( "PYHELLO", "def_obj_name", GUIcontext.DEFAULT_NAME ).stripWhiteSpace() )
467     if sgPyQt.action( GUIcontext.OPTION_3_ID ).isOn():
468         # request object name from the user
469         name, ok = QInputDialog.getText( "Create Object", "Enter object name:", QLineEdit.Normal, default_name )
470         if not ok: return
471         name = str( name.stripWhiteSpace() )
472     elif sgPyQt.action( GUIcontext.OPTION_2_ID ).isOn():
473         # generate object name
474         global __id__
475         __id__  = __id__ + 1
476         name = "%s %d" % ( default_name, __id__ )
477     else:
478         name = default_name
479         pass
480     if not name: return
481     study   = _getStudy()
482     builder = study.NewBuilder()
483     father  = _findOrCreateComponent()
484     object  = builder.NewObject( father )
485     attr    = builder.FindOrCreateAttribute( object, "AttributeName" )
486     attr.SetValue( name )
487     attr    = builder.FindOrCreateAttribute( object, "AttributeLocalID" )
488     attr.SetValue( GUIcontext.OBJECT_ID )
489     sg.updateObjBrowser( True )
490     pass
491
492 ###
493 # Delete all objects
494 ###
495 def DeleteAll():
496     study = _getStudy()
497     father = study.FindComponent( GUIcontext.MODULE_NAME )
498     if father:
499         iter = study.NewChildIterator( father )
500         builder = study.NewBuilder()
501         while iter.More():
502             sobj = iter.Value()
503             iter.Next()
504             builder.RemoveObjectWithChildren( sobj )
505             pass
506         sg.updateObjBrowser(True)
507         pass
508     pass
509
510 ###
511 # Show object's name
512 ###
513 def ShowMe():
514     study = _getStudy()
515     entry = sg.getSelected( 0 )
516     if entry != '':
517         sobj = study.FindObjectID( entry )
518         if ( sobj ):
519             test, attr = sobj.FindAttribute( "AttributeName" )
520             if test:
521                 QMessageBox.information( sgPyQt.getDesktop(), 'Info', "My name is '%s'" % attr.Value() )
522                 pass
523             pass
524         pass
525     pass
526
527 ###
528 # Delete selected object(s)
529 ###
530 def Delete():
531     study = _getStudy()
532     builder = study.NewBuilder()
533     if sg.SelectedCount() <= 0: return
534     for i in range( sg.SelectedCount() ):
535         entry = sg.getSelected( i )
536         if entry != '':
537             sobj = study.FindObjectID( entry )
538             if ( sobj ):
539                 builder.RemoveObject( sobj )
540                 pass
541             pass
542         pass
543     sg.updateObjBrowser( True )
544     pass
545
546 ###
547 # Rename selected object
548 ###
549 def Rename():
550     study = _getStudy()
551     builder = study.NewBuilder()
552     entry = sg.getSelected( 0 )
553     if entry != '':
554         sobj = study.FindObjectID( entry )
555         if ( sobj ):
556             name, ok = QInputDialog.getText( "Object name", "Enter object name:", QLineEdit.Normal, sobj.GetName() )
557             name = str( name.stripWhiteSpace() )
558             if not ok or not name: return
559             attr = builder.FindOrCreateAttribute( sobj, "AttributeName" )
560             attr.SetValue( name )
561             sg.updateObjBrowser( True )
562             pass
563         pass
564     pass
565
566 ###
567 # Commands dictionary
568 ###
569 dict_command = {
570     GUIcontext.HELLO_ID         : ShowHELLO,
571     GUIcontext.CREATE_OBJECT_ID : CreateObject,
572     GUIcontext.DELETE_ALL_ID    : DeleteAll,
573     GUIcontext.SHOW_ME_ID       : ShowMe,
574     GUIcontext.DELETE_ME_ID     : Delete,
575     GUIcontext.RENAME_ME_ID     : Rename,
576     }