]> SALOME platform Git repositories - modules/kernel.git/blob - src/KERNEL_PY/kernel/studyedit.py
Salome HOME
add prefix "global" for method variable
[modules/kernel.git] / src / KERNEL_PY / kernel / studyedit.py
1 # Copyright (C) 2007-2016  CEA/DEN, EDF R&D, OPEN CASCADE
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, or (at your option) any later version.
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 ## \defgroup studyedit studyedit
21 #  \{ 
22 #  \details
23 #  This module provides a new class \bStudyEditor to complement \bStudy
24 #  and \bStudyBuilder classes.
25 #  \}
26
27 """
28 This module provides a new class :class:`StudyEditor` to complement
29 :class:`Study` and :class:`StudyBuilder` classes.
30 """
31
32 import re
33
34 import salome
35 from salome.kernel.logger import Logger
36 from salome.kernel import termcolor
37 logger = Logger("salome.kernel.studyedit", color = termcolor.PURPLE)
38
39 _editor = None
40 _DEFAULT_CONTAINER = "FactoryServer"
41
42 # The codec to use for strings that are displayed in Salome study tree is Latin-1
43 ENCODING_FOR_SALOME_STUDY = "iso-8859-1"
44
45 def getStudy():
46     return salome.myStudy
47
48 ## Return a \b StudyEditor instance to edit the study. 
49 #  \ingroup studyedit
50 def getStudyEditor():
51     """
52     Return a :class:`StudyEditor` instance to edit the study.
53     """
54     global _editor
55     if _editor is None:
56         _editor = StudyEditor()
57     return _editor
58
59 ## This class provides utility methods to complement \b Study and
60 #  \b StudyBuilder classes. Those methods may be moved in those classes
61 #  in the future.
62 #  The preferred way to get a StudyEditor object is through the method
63 #  \b getStudyEditor which allows to reuse existing instances.
64 #
65 #  \param study This instance attribute contains the underlying \b Study object.
66 #  It can be used to access the study but the attribute itself should not
67 #  be modified.
68 #
69 #  \param builder This instance attribute contains the underlying \b StudyBuilder
70 #  object. It can be used to edit the study but the attribute itself
71 #  should not be modified.
72 #  \ingroup studyedit
73 class StudyEditor:
74     """
75     This class provides utility methods to complement :class:`Study` and
76     :class:`StudyBuilder` classes. Those methods may be moved in those classes
77     in the future.
78     The preferred way to get a StudyEditor object is through the method
79     :meth:`getStudyEditor` which allows to reuse existing instances.
80
81     .. attribute:: study
82     
83        This instance attribute contains the underlying :class:`Study` object.
84        It can be used to access the study but the attribute itself should not
85        be modified.
86
87     .. attribute:: builder
88
89        This instance attribute contains the underlying :class:`StudyBuilder`
90        object. It can be used to edit the study but the attribute itself
91        should not be modified.
92
93     """
94     def __init__(self):
95         salome.salome_init()
96         self.study = salome.myStudy
97         if self.study is None:
98             raise Exception("Can't create StudyEditor object: "
99                             "Study doesn't exist")
100         self.builder = self.study.NewBuilder()
101
102     ## Find a component corresponding to the Salome module \b moduleName in
103     #  the study. If none is found, create a new component and associate it
104     #  with the corresponding engine (i.e. the engine named \b moduleName).
105     #  Note that in Salome 5, the module name and engine name must be
106     #  identical (every module must provide an engine with the same name).
107     #  In Salome 6 it will be possible to define a different name for the
108     #  engine.
109     #
110     #  \param moduleName (string) name of the module corresponding to the component
111     #  (the module name is the string value in the
112     #  attribute "AttributeComment" of the component)
113     #
114     #  \param componentName (string) name of the new component if created. 
115     #  If \b None, use \b moduleName instead.
116     #
117     #  \param icon (string) icon for the new component (attribute "AttributePixMap").
118     #
119     #  \param containerName (string) name of the container in which the engine should be
120     #  loaded.
121     #
122     #  \return the SComponent found or created.
123     def findOrCreateComponent(self, moduleName, componentName = None,
124                               icon = None, containerName = _DEFAULT_CONTAINER):
125         """
126         Find a component corresponding to the Salome module `moduleName` in
127         the study. If none is found, create a new component and associate it
128         with the corresponding engine (i.e. the engine named `moduleName`).
129         Note that in Salome 5, the module name and engine name must be
130         identical (every module must provide an engine with the same name).
131         In Salome 6 it will be possible to define a different name for the
132         engine.
133
134         :type  moduleName: string
135         :param moduleName: name of the module corresponding to the component
136                            (the module name is the string value in the
137                            attribute "AttributeComment" of the component)
138
139         :type  componentName: string
140         :param componentName: name of the new component if created. If
141                               :const:`None`, use `moduleName` instead.
142
143         :type  icon: string
144         :param icon: icon for the new component (attribute "AttributePixMap").
145
146         :type  containerName: string
147         :param containerName: name of the container in which the engine should be
148                               loaded.
149
150         :return: the SComponent found or created.
151
152         """
153         sComponent = self.study.FindComponent(moduleName)
154         if sComponent is None:
155             sComponent = self.builder.NewComponent(moduleName)
156             # Note that the NewComponent method set the "comment" attribute to the
157             # value of its argument (moduleName here)
158             if componentName is None:
159                 componentName = moduleName
160             self.builder.SetName(sComponent, componentName)
161             if icon is not None:
162                 # _MEM_ : This will be effective if and only if "moduleName"
163                 # really corresponds to the module name (as specified in the
164                 # SalomeApp.xml)
165                 self.setIcon(sComponent, icon)
166
167             # This part will stay inactive until Salome 6. In Salome 6, the
168             # engine name will be stored separately from the module name.
169             # An internal convention (in this class) is to store the name of the
170             # associated engine in the parameter attribute of the scomponent (so that
171             # it could be retrieved in a future usage of this scomponent, for example,
172             # for the need of the function loadComponentEngine). The comment attribute
173             # SHOULD NOT be used for this purpose  because it's used by the SALOME
174             # resources manager to identify the SALOME module and then localized
175             # the resource files
176             #attr = self.builder.FindOrCreateAttribute( sComponent, "AttributeParameter" )
177             #attr.SetString( "ENGINE_NAME", engineName )
178
179             engine = salome.lcc.FindOrLoadComponent(containerName, moduleName)
180             if engine is None:
181                 raise Exception("Cannot load engine %s in container %s. See "
182                                 "logs of container %s for more details." %
183                                 (moduleName, containerName, containerName))
184             self.builder.DefineComponentInstance(sComponent, engine)
185
186         return sComponent
187
188     ## Load the engine corresponding to \b sComponent in the container
189     #  \b containerName, associate the engine with the component and load the
190     #  CORBA objects of this component in the study.
191     def loadComponentEngine(self, sComponent,
192                             containerName = _DEFAULT_CONTAINER):
193         """
194         Load the engine corresponding to `sComponent` in the container
195         `containerName`, associate the engine with the component and load the
196         CORBA objects of this component in the study.
197         """
198         # This part will stay inactive until Salome 6. In Salome 6, the
199         # engine name will be stored separately from the module name.
200         #attr = self.builder.FindOrCreateAttribute( sComponent, "AttributeParameter" )
201         #engineName = attr.GetString( "ENGINE_NAME" )
202         engine = salome.lcc.FindOrLoadComponent(containerName,
203                                                 sComponent.GetComment())
204         if engine is None:
205             raise Exception("Cannot load component %s in container %s. See "
206                             "logs of container %s for more details." %
207                             (sComponent.GetComment(), containerName,
208                              containerName))
209         self.builder.LoadWith(sComponent, engine)
210
211     ## Get the CORBA object associated with the SObject \b item, eventually by
212     #  first loading it with the corresponding engine.
213     def getOrLoadObject(self, item):
214         """
215         Get the CORBA object associated with the SObject `item`, eventually by
216         first loading it with the corresponding engine.
217         """
218         object = item.GetObject()
219         if object is None: # the engine has not been loaded yet
220             sComponent = item.GetFatherComponent()
221             self.loadComponentEngine(sComponent)
222             object = item.GetObject()
223         return object
224
225     ## Find an object under \b fatherItem in the study with the given
226     #  attributes. Return the first one found if at least one exists,
227     #  otherwise create a new one with the given attributes and return it.
228     #
229     #  See \b setItem() for the description of the parameters.
230     def findOrCreateItem(self, fatherItem, name, fileType = None,
231                          fileName = None, comment = None, icon = None,
232                          IOR = None, typeId = None):
233         """
234         Find an object under `fatherItem` in the study with the given
235         attributes. Return the first one found if at least one exists,
236         otherwise create a new one with the given attributes and return it.
237         
238         See :meth:`setItem` for the description of the parameters.
239         """
240         sObject = self.findItem(fatherItem, name, fileType, fileName, comment,
241                                 icon, IOR, typeId)
242         if sObject is None:
243             sObject = self.createItem(fatherItem, name, fileType, fileName,
244                                       comment, icon, IOR, typeId)
245         return sObject
246
247     ## Find an item with given attributes under \b fatherItem in the study. If
248     #  none is found, return \b None. If several items correspond to
249     #  the parameters, only the first one is returned. The search is made
250     #  only on given parameters (i.e. not \b None). To look explicitly
251     #  for an empty attribute, use an empty string in the corresponding
252     #  parameter.
253     #    
254     #  See \b setItem() for the description of the parameters.
255     def findItem(self, fatherItem, name = None, fileType = None,
256                  fileName = None, comment = None, icon = None, IOR = None,
257                  typeId = None):
258         """
259         Find an item with given attributes under `fatherItem` in the study. If
260         none is found, return :const:`None`. If several items correspond to
261         the parameters, only the first one is returned. The search is made
262         only on given parameters (i.e. not :const:`None`). To look explicitly
263         for an empty attribute, use an empty string in the corresponding
264         parameter.
265         
266         See :meth:`setItem` for the description of the parameters.
267         """
268         foundItem = None;
269         childIterator = self.study.NewChildIterator(fatherItem)
270         while childIterator.More() and foundItem is None:
271             childItem = childIterator.Value()
272             if childItem and \
273                (name is None or self.getName(childItem) == name) and \
274                (fileType is None or \
275                 self.getFileType(childItem) == fileType) and \
276                (fileName is None or \
277                 self.getFileName(childItem) == fileName) and \
278                (comment is None or self.getComment(childItem) == comment) and \
279                (icon is None or \
280                 self.getIcon(childItem) == icon) and \
281                (IOR is None or childItem.GetIOR() == IOR) and \
282                (typeId is None or \
283                 self.getTypeId(childItem) == typeId):
284                 foundItem = childItem
285             childIterator.Next()
286         return foundItem
287
288     ## Create a new object named \b name under \b fatherItem in the study, with
289     #  the given attributes. If an object named \b name already exists under
290     #  the father object, the new object is created with a new name \b name_X
291     #  where X is the first available index.
292     #
293     #  param fatherItem (SObject) item under which the new item will be added.
294     #  \return new SObject created in the study.
295     #
296     #  See \b setItem() for the description of the other parameters.
297     def createItem(self, fatherItem, name, fileType = None, fileName = None,
298                    comment = None, icon = None, IOR = None, typeId = None):
299         """
300         Create a new object named `name` under `fatherItem` in the study, with
301         the given attributes. If an object named `name` already exists under
302         the father object, the new object is created with a new name `name_X`
303         where X is the first available index.
304         
305         :type  fatherItem: SObject
306         :param fatherItem: item under which the new item will be added.
307                 
308         :return: new SObject created in the study
309         
310         See :meth:`setItem` for the description of the other parameters.
311         """
312         aSObject = self.builder.NewObject(fatherItem)
313
314         aChildIterator = self.study.NewChildIterator(fatherItem)
315         aMaxId = -1
316         aLength = len(name)
317         aDelim = "_"
318         anIdRE = re.compile("^" + aDelim + "[0-9]+")
319         aNameRE = re.compile("^" + name)
320         while aChildIterator.More():
321             aSObj = aChildIterator.Value()
322             aChildIterator.Next()
323             aName = aSObj.GetName()
324             if re.match(aNameRE,aName):
325                 aTmp = aName[aLength:]
326                 if re.match(anIdRE,aTmp):
327                     import string
328                     anId = string.atol(aTmp[1:])
329                     if aMaxId < anId:
330                         aMaxId = anId
331                         pass
332                     pass
333                 elif aMaxId < 0:
334                     aMaxId = 0
335                     pass
336                 pass
337             pass
338         
339         aMaxId = aMaxId + 1
340         aName = name
341         if aMaxId > 0:
342             aName = aName + aDelim + str(aMaxId)
343             pass
344         
345         self.setItem(aSObject, aName, fileType, fileName, comment, icon,
346                      IOR, typeId)
347     
348         return aSObject
349
350     ## Modify the attributes of an item in the study. Unspecified attributes
351     #  (i.e. those set to \b None) are left unchanged.
352     #
353     #  \param item (SObject) item to modify.
354     #
355     #  \param name (string or unicode) item name (attribute \b AttributeName).
356     #
357     #  \param fileType (string or unicode) item file type (attribute \b AttributeFileType).
358     #
359     #  \param fileName (string or unicode) item file name (attribute \b AttributeExternalFileDef).
360     #
361     #  \param comment (string or unicode) item comment (attribute \b AttributeComment). Note that
362     #  this attribute will appear in the \b Value column in the object browser.
363     #
364     #  \param icon (string or unicode) item icon name (attribute \b AttributePixMap).
365     #
366     #  \param IOR (string) IOR of a CORBA object associated with the item
367     #  (attribute \b AttributeIOR).
368     #
369     #  \param typeId (integer) item type (attribute \b AttributeLocalID).
370     def setItem(self, item, name = None, fileType = None, fileName = None,
371                 comment = None, icon = None, IOR = None, typeId = None):
372         """
373         Modify the attributes of an item in the study. Unspecified attributes
374         (i.e. those set to :const:`None`) are left unchanged.
375
376         :type  item: SObject
377         :param item: item to modify.
378
379         :type  name: string or unicode
380         :param name: item name (attribute 'AttributeName').
381
382         :type  fileType: string or unicode
383         :param fileType: item file type (attribute 'AttributeFileType').
384
385         :type  fileName: string or unicode
386         :param fileName: item file name (attribute
387                          'AttributeExternalFileDef').
388
389         :type  comment: string or unicode
390         :param comment: item comment (attribute 'AttributeComment'). Note that
391                         this attribute will appear in the 'Value' column in
392                         the object browser.
393
394         :type  icon: string or unicode
395         :param icon: item icon name (attribute 'AttributePixMap').
396
397         :type  IOR: string
398         :param IOR: IOR of a CORBA object associated with the item
399                     (attribute 'AttributeIOR').
400
401         :type  typeId: integer
402         :param typeId: item type (attribute 'AttributeLocalID').
403         """
404         logger.debug("setItem (ID=%s): name=%s, fileType=%s, fileName=%s, "
405                      "comment=%s, icon=%s, IOR=%s" %
406                      (item.GetID(), name, fileType, fileName, comment,
407                       icon, IOR))
408         if name is not None:
409             self.setName(item, name)
410         if fileType is not None:
411             self.setFileType(item, fileType)
412         if fileName is not None:
413             self.setFileName(item, fileName)
414         if comment is not None:
415             self.setComment(item, comment)
416         if icon is not None:
417             self.setIcon(item, icon)
418         if IOR is not None:
419             self.builder.SetIOR(item, IOR)
420         if typeId is not None:
421             self.setTypeId(item, typeId)
422
423     ## Remove the given item from the study. Note that the items are never
424     #  really deleted. They just don't appear in the study anymore.
425     #
426     #  \param item (SObject) the item to be removed
427     #
428     #  \param withChildren (boolean) if \b True, also remove the children of item
429     #
430     #  \return \b True if the item was removed successfully, or 
431     #  \b False if an error happened.
432     def removeItem(self, item, withChildren = False ):
433         """
434         Remove the given item from the study. Note that the items are never
435         really deleted. They just don't appear in the study anymore.
436
437         :type  item: SObject
438         :param item: the item to be removed
439
440         :type  withChildren: boolean
441         :param withChildren: if :const:`True`, also remove the children of
442                              `item`
443
444         :return: :const:`True` if the item was removed successfully, or
445                  :const:`False` if an error happened.
446         """
447         ok = False
448         try:
449             if withChildren:
450                 self.builder.RemoveObjectWithChildren(item)
451             else:
452                 self.builder.RemoveObject(item)
453             ok = True
454         except:
455             ok = False
456         return ok
457
458     ## Find an item tagged \b tag under \b fatherItem in the study tree or
459     #  create it if there is none, then set its attributes.
460     #
461     #  \param fatherItem (SObject) item under which the tagged item will be looked for
462     #  and eventually created.
463     #
464     #  \param tag integer) tag of the item to look for.
465     #
466     #  \return the SObject at \b tag if found or created successfully, or
467     #  \b None if an error happened.
468     #    
469     #  See \b setItem() for the description of the other parameters.
470     def setItemAtTag(self, fatherItem, tag, name = None, fileType = None,
471                      fileName = None, comment = None, icon = None, IOR = None,
472                      typeId = None):
473         """
474         Find an item tagged `tag` under `fatherItem` in the study tree or
475         create it if there is none, then set its attributes.
476         
477         :type  fatherItem: SObject
478         :param fatherItem: item under which the tagged item will be looked for
479                            and eventually created.
480
481         :type  tag: integer
482         :param tag: tag of the item to look for.
483
484         :return: the SObject at `tag` if found or created successfully, or
485                  :const:`None` if an error happened.
486         
487         See :meth:`setItem` for the description of the other parameters.
488         """
489         found, sObj = fatherItem.FindSubObject(tag)
490         if not found:
491             sObj = self.builder.NewObjectToTag(fatherItem, tag)
492         self.setItem(sObj, name, fileType, fileName, comment, icon,
493                      IOR, typeId)
494         return sObj
495
496     ## Return the name of the object sObject
497     def getName(self, sObject):
498         val = sObject.GetName()
499         return unicode(val, ENCODING_FOR_SALOME_STUDY)
500
501     ## Set the name of the object sObject
502     def setName(self, sObject, name):
503         self.builder.SetName(sObject, name.encode(ENCODING_FOR_SALOME_STUDY))
504
505     ## Return the comment of the object sObject
506     def getComment(self, sObject):
507         val = sObject.GetComment()
508         return unicode(val, ENCODING_FOR_SALOME_STUDY)
509
510     ## Set the comment of the object sObject
511     def setComment(self, sObject, comment):
512         self.builder.SetComment(sObject, comment.encode(ENCODING_FOR_SALOME_STUDY))
513
514     ## Return the value of the attribute named \b attributeName on the object
515     #  sObject, or \b default if the attribute doesn't exist.
516     def getAttributeValue(self, sObject, attributeName, default = None):
517         """
518         Return the value of the attribute named `attributeName` on the object
519         `sObject`, or `default` if the attribute doesn't exist.
520         """
521         value = default
522         found, attr = self.builder.FindAttribute(sObject, attributeName)
523         if found:
524             value = attr.Value()
525         return value
526
527     ## Set the value of the attribute named \b attributeName on the object
528     #  sObject to the value \b attributeValue.
529     def setAttributeValue(self, sObject, attributeName, attributeValue):
530         """
531         Set the value of the attribute named `attributeName` on the object
532         `sObject` to the value `attributeValue`.
533         """        
534         attr = self.builder.FindOrCreateAttribute(sObject, attributeName)
535         attr.SetValue(attributeValue)
536
537     ## Return the value of the attribute "AttributeLocalID" of the object
538     #  sObject, or \b None if it is not set.
539     def getTypeId(self, sObject):
540         """
541         Return the value of the attribute "AttributeLocalID" of the object
542         `sObject`, or :const:`None` if it is not set.
543         """
544         return self.getAttributeValue(sObject, "AttributeLocalID")
545
546     ## Set the attribute "AttributeLocalID" of the object \b sObject to the
547     #  value \b value.
548     def setTypeId(self, sObject, value):
549         """
550         Set the attribute "AttributeLocalID" of the object `sObject` to the
551         value `value`.
552         """
553         self.setAttributeValue(sObject, "AttributeLocalID", value)
554
555     ## Return the value of the attribute "AttributeFileType" of the object
556     #  sObject, or an empty string if it is not set.
557     def getFileType(self, sObject):
558         """
559         Return the value of the attribute "AttributeFileType" of the object
560         `sObject`, or an empty string if it is not set.
561         """
562         val = self.getAttributeValue(sObject, "AttributeFileType", "")
563         return unicode(val, ENCODING_FOR_SALOME_STUDY)
564
565     ## Set the attribute "AttributeFileType" of the object sObject to the
566     #  value value.
567     def setFileType(self, sObject, value):
568         """
569         Set the attribute "AttributeFileType" of the object `sObject` to the
570         value `value`.
571         """
572         self.setAttributeValue(sObject, "AttributeFileType",
573                                value.encode(ENCODING_FOR_SALOME_STUDY))
574
575     ## Return the value of the attribute "AttributeExternalFileDef" of the
576     #  object sObject, or an empty string if it is not set.
577     def getFileName(self, sObject):
578         """
579         Return the value of the attribute "AttributeExternalFileDef" of the
580         object `sObject`, or an empty string if it is not set.
581         """
582         val = self.getAttributeValue(sObject, "AttributeExternalFileDef", "")
583         return unicode(val, ENCODING_FOR_SALOME_STUDY)
584
585     ## Set the attribute "AttributeExternalFileDef" of the object sObject
586     #  to the value value.
587     def setFileName(self, sObject, value):
588         """
589         Set the attribute "AttributeExternalFileDef" of the object `sObject`
590         to the value `value`.
591         """
592         self.setAttributeValue(sObject, "AttributeExternalFileDef",
593                                value.encode(ENCODING_FOR_SALOME_STUDY))
594
595     ## Return the value of the attribute "AttributePixMap" of the object
596     #  sObject, or an empty string if it is not set.
597     def getIcon(self, sObject):
598         """
599         Return the value of the attribute "AttributePixMap" of the object
600         `sObject`, or an empty string if it is not set.
601         """
602         value = ""
603         found, attr = self.builder.FindAttribute(sObject, "AttributePixMap")
604         if found and attr.HasPixMap():
605             value = attr.GetPixMap()
606         return unicode(value, ENCODING_FOR_SALOME_STUDY)
607
608     ## Set the attribute "AttributePixMap" of the object sObject to the
609     #  value value.
610     def setIcon(self, sObject, value):
611         """
612         Set the attribute "AttributePixMap" of the object `sObject` to the
613         value `value`.
614         """
615         attr = self.builder.FindOrCreateAttribute(sObject, "AttributePixMap")
616         attr.SetPixMap(value.encode(ENCODING_FOR_SALOME_STUDY))