1 # Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE
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.
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.
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
17 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 ## \defgroup studyedit studyedit
23 # This module provides a new class \bStudyEditor to complement \bStudy
24 # and \bStudyBuilder classes.
28 This module provides a new class :class:`StudyEditor` to complement
29 :class:`Study` and :class:`StudyBuilder` classes.
35 from salome.kernel.logger import Logger
36 from salome.kernel import termcolor
37 logger = Logger("salome.kernel.studyedit", color = termcolor.PURPLE)
40 _DEFAULT_CONTAINER = "FactoryServer"
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"
48 ## Return a \b StudyEditor instance to edit the study.
52 Return a :class:`StudyEditor` instance to edit the study.
55 _editor = StudyEditor()
58 ## This class provides utility methods to complement \b Study and
59 # \b StudyBuilder classes. Those methods may be moved in those classes
61 # The preferred way to get a StudyEditor object is through the method
62 # \b getStudyEditor which allows to reuse existing instances.
64 # \param study This instance attribute contains the underlying \b Study object.
65 # It can be used to access the study but the attribute itself should not
68 # \param builder This instance attribute contains the underlying \b StudyBuilder
69 # object. It can be used to edit the study but the attribute itself
70 # should not be modified.
74 This class provides utility methods to complement :class:`Study` and
75 :class:`StudyBuilder` classes. Those methods may be moved in those classes
77 The preferred way to get a StudyEditor object is through the method
78 :meth:`getStudyEditor` which allows to reuse existing instances.
82 This instance attribute contains the underlying :class:`Study` object.
83 It can be used to access the study but the attribute itself should not
86 .. attribute:: builder
88 This instance attribute contains the underlying :class:`StudyBuilder`
89 object. It can be used to edit the study but the attribute itself
90 should not be modified.
95 self.study = salome.myStudy
96 if self.study is None:
97 raise Exception("Can't create StudyEditor object: "
98 "Study doesn't exist")
99 self.builder = self.study.NewBuilder()
101 ## Find a component corresponding to the Salome module \b moduleName in
102 # the study. If none is found, create a new component and associate it
103 # with the corresponding engine (i.e. the engine named \b moduleName).
104 # Note that in Salome 5, the module name and engine name must be
105 # identical (every module must provide an engine with the same name).
106 # In Salome 6 it will be possible to define a different name for the
109 # \param moduleName (string) name of the module corresponding to the component
110 # (the module name is the string value in the
111 # attribute "AttributeComment" of the component)
113 # \param componentName (string) name of the new component if created.
114 # If \b None, use \b moduleName instead.
116 # \param icon (string) icon for the new component (attribute "AttributePixMap").
118 # \param containerName (string) name of the container in which the engine should be
121 # \return the SComponent found or created.
122 def findOrCreateComponent(self, moduleName, componentName = None,
123 icon = None, containerName = _DEFAULT_CONTAINER):
125 Find a component corresponding to the Salome module `moduleName` in
126 the study. If none is found, create a new component and associate it
127 with the corresponding engine (i.e. the engine named `moduleName`).
128 Note that in Salome 5, the module name and engine name must be
129 identical (every module must provide an engine with the same name).
130 In Salome 6 it will be possible to define a different name for the
133 :type moduleName: string
134 :param moduleName: name of the module corresponding to the component
135 (the module name is the string value in the
136 attribute "AttributeComment" of the component)
138 :type componentName: string
139 :param componentName: name of the new component if created. If
140 :const:`None`, use `moduleName` instead.
143 :param icon: icon for the new component (attribute "AttributePixMap").
145 :type containerName: string
146 :param containerName: name of the container in which the engine should be
149 :return: the SComponent found or created.
152 sComponent = self.study.FindComponent(moduleName)
153 if sComponent is None:
154 sComponent = self.builder.NewComponent(moduleName)
155 # Note that the NewComponent method set the "comment" attribute to the
156 # value of its argument (moduleName here)
157 if componentName is None:
158 componentName = moduleName
159 self.builder.SetName(sComponent, componentName)
161 # _MEM_ : This will be effective if and only if "moduleName"
162 # really corresponds to the module name (as specified in the
164 self.setIcon(sComponent, icon)
166 # This part will stay inactive until Salome 6. In Salome 6, the
167 # engine name will be stored separately from the module name.
168 # An internal convention (in this class) is to store the name of the
169 # associated engine in the parameter attribute of the scomponent (so that
170 # it could be retrieved in a future usage of this scomponent, for example,
171 # for the need of the function loadComponentEngine). The comment attribute
172 # SHOULD NOT be used for this purpose because it's used by the SALOME
173 # resources manager to identify the SALOME module and then localized
175 #attr = self.builder.FindOrCreateAttribute( sComponent, "AttributeParameter" )
176 #attr.SetString( "ENGINE_NAME", engineName )
178 engine = salome.lcc.FindOrLoadComponent(containerName, moduleName)
180 raise Exception("Cannot load engine %s in container %s. See "
181 "logs of container %s for more details." %
182 (moduleName, containerName, containerName))
183 self.builder.DefineComponentInstance(sComponent, engine)
187 ## Load the engine corresponding to \b sComponent in the container
188 # \b containerName, associate the engine with the component and load the
189 # CORBA objects of this component in the study.
190 def loadComponentEngine(self, sComponent,
191 containerName = _DEFAULT_CONTAINER):
193 Load the engine corresponding to `sComponent` in the container
194 `containerName`, associate the engine with the component and load the
195 CORBA objects of this component in the study.
197 # This part will stay inactive until Salome 6. In Salome 6, the
198 # engine name will be stored separately from the module name.
199 #attr = self.builder.FindOrCreateAttribute( sComponent, "AttributeParameter" )
200 #engineName = attr.GetString( "ENGINE_NAME" )
201 engine = salome.lcc.FindOrLoadComponent(containerName,
202 sComponent.GetComment())
204 raise Exception("Cannot load component %s in container %s. See "
205 "logs of container %s for more details." %
206 (sComponent.GetComment(), containerName,
208 self.builder.LoadWith(sComponent, engine)
210 ## Get the CORBA object associated with the SObject \b item, eventually by
211 # first loading it with the corresponding engine.
212 def getOrLoadObject(self, item):
214 Get the CORBA object associated with the SObject `item`, eventually by
215 first loading it with the corresponding engine.
217 object = item.GetObject()
218 if object is None: # the engine has not been loaded yet
219 sComponent = item.GetFatherComponent()
220 self.loadComponentEngine(sComponent)
221 object = item.GetObject()
224 ## Find an object under \b fatherItem in the study with the given
225 # attributes. Return the first one found if at least one exists,
226 # otherwise create a new one with the given attributes and return it.
228 # See \b setItem() for the description of the parameters.
229 def findOrCreateItem(self, fatherItem, name, fileType = None,
230 fileName = None, comment = None, icon = None,
231 IOR = None, typeId = None):
233 Find an object under `fatherItem` in the study with the given
234 attributes. Return the first one found if at least one exists,
235 otherwise create a new one with the given attributes and return it.
237 See :meth:`setItem` for the description of the parameters.
239 sObject = self.findItem(fatherItem, name, fileType, fileName, comment,
242 sObject = self.createItem(fatherItem, name, fileType, fileName,
243 comment, icon, IOR, typeId)
246 ## Find an item with given attributes under \b fatherItem in the study. If
247 # none is found, return \b None. If several items correspond to
248 # the parameters, only the first one is returned. The search is made
249 # only on given parameters (i.e. not \b None). To look explicitly
250 # for an empty attribute, use an empty string in the corresponding
253 # See \b setItem() for the description of the parameters.
254 def findItem(self, fatherItem, name = None, fileType = None,
255 fileName = None, comment = None, icon = None, IOR = None,
258 Find an item with given attributes under `fatherItem` in the study. If
259 none is found, return :const:`None`. If several items correspond to
260 the parameters, only the first one is returned. The search is made
261 only on given parameters (i.e. not :const:`None`). To look explicitly
262 for an empty attribute, use an empty string in the corresponding
265 See :meth:`setItem` for the description of the parameters.
268 childIterator = self.study.NewChildIterator(fatherItem)
269 while childIterator.More() and foundItem is None:
270 childItem = childIterator.Value()
272 (name is None or self.getName(childItem) == name) and \
273 (fileType is None or \
274 self.getFileType(childItem) == fileType) and \
275 (fileName is None or \
276 self.getFileName(childItem) == fileName) and \
277 (comment is None or self.getComment(childItem) == comment) and \
279 self.getIcon(childItem) == icon) and \
280 (IOR is None or childItem.GetIOR() == IOR) and \
282 self.getTypeId(childItem) == typeId):
283 foundItem = childItem
287 ## Create a new object named \b name under \b fatherItem in the study, with
288 # the given attributes. If an object named \b name already exists under
289 # the father object, the new object is created with a new name \b name_X
290 # where X is the first available index.
292 # param fatherItem (SObject) item under which the new item will be added.
293 # \return new SObject created in the study.
295 # See \b setItem() for the description of the other parameters.
296 def createItem(self, fatherItem, name, fileType = None, fileName = None,
297 comment = None, icon = None, IOR = None, typeId = None):
299 Create a new object named `name` under `fatherItem` in the study, with
300 the given attributes. If an object named `name` already exists under
301 the father object, the new object is created with a new name `name_X`
302 where X is the first available index.
304 :type fatherItem: SObject
305 :param fatherItem: item under which the new item will be added.
307 :return: new SObject created in the study
309 See :meth:`setItem` for the description of the other parameters.
311 aSObject = self.builder.NewObject(fatherItem)
313 aChildIterator = self.study.NewChildIterator(fatherItem)
317 anIdRE = re.compile("^" + aDelim + "[0-9]+")
318 aNameRE = re.compile("^" + name)
319 while aChildIterator.More():
320 aSObj = aChildIterator.Value()
321 aChildIterator.Next()
322 aName = aSObj.GetName()
323 if re.match(aNameRE,aName):
324 aTmp = aName[aLength:]
325 if re.match(anIdRE,aTmp):
327 anId = string.atol(aTmp[1:])
341 aName = aName + aDelim + str(aMaxId)
344 self.setItem(aSObject, aName, fileType, fileName, comment, icon,
349 ## Modify the attributes of an item in the study. Unspecified attributes
350 # (i.e. those set to \b None) are left unchanged.
352 # \param item (SObject) item to modify.
354 # \param name (string or unicode) item name (attribute \b AttributeName).
356 # \param fileType (string or unicode) item file type (attribute \b AttributeFileType).
358 # \param fileName (string or unicode) item file name (attribute \b AttributeExternalFileDef).
360 # \param comment (string or unicode) item comment (attribute \b AttributeComment). Note that
361 # this attribute will appear in the \b Value column in the object browser.
363 # \param icon (string or unicode) item icon name (attribute \b AttributePixMap).
365 # \param IOR (string) IOR of a CORBA object associated with the item
366 # (attribute \b AttributeIOR).
368 # \param typeId (integer) item type (attribute \b AttributeLocalID).
369 def setItem(self, item, name = None, fileType = None, fileName = None,
370 comment = None, icon = None, IOR = None, typeId = None):
372 Modify the attributes of an item in the study. Unspecified attributes
373 (i.e. those set to :const:`None`) are left unchanged.
376 :param item: item to modify.
378 :type name: string or unicode
379 :param name: item name (attribute 'AttributeName').
381 :type fileType: string or unicode
382 :param fileType: item file type (attribute 'AttributeFileType').
384 :type fileName: string or unicode
385 :param fileName: item file name (attribute
386 'AttributeExternalFileDef').
388 :type comment: string or unicode
389 :param comment: item comment (attribute 'AttributeComment'). Note that
390 this attribute will appear in the 'Value' column in
393 :type icon: string or unicode
394 :param icon: item icon name (attribute 'AttributePixMap').
397 :param IOR: IOR of a CORBA object associated with the item
398 (attribute 'AttributeIOR').
400 :type typeId: integer
401 :param typeId: item type (attribute 'AttributeLocalID').
403 logger.debug("setItem (ID=%s): name=%s, fileType=%s, fileName=%s, "
404 "comment=%s, icon=%s, IOR=%s" %
405 (item.GetID(), name, fileType, fileName, comment,
408 self.setName(item, name)
409 if fileType is not None:
410 self.setFileType(item, fileType)
411 if fileName is not None:
412 self.setFileName(item, fileName)
413 if comment is not None:
414 self.setComment(item, comment)
416 self.setIcon(item, icon)
418 self.builder.SetIOR(item, IOR)
419 if typeId is not None:
420 self.setTypeId(item, typeId)
422 ## Remove the given item from the study. Note that the items are never
423 # really deleted. They just don't appear in the study anymore.
425 # \param item (SObject) the item to be removed
427 # \param withChildren (boolean) if \b True, also remove the children of item
429 # \return \b True if the item was removed successfully, or
430 # \b False if an error happened.
431 def removeItem(self, item, withChildren = False ):
433 Remove the given item from the study. Note that the items are never
434 really deleted. They just don't appear in the study anymore.
437 :param item: the item to be removed
439 :type withChildren: boolean
440 :param withChildren: if :const:`True`, also remove the children of
443 :return: :const:`True` if the item was removed successfully, or
444 :const:`False` if an error happened.
449 self.builder.RemoveObjectWithChildren(item)
451 self.builder.RemoveObject(item)
457 ## Find an item tagged \b tag under \b fatherItem in the study tree or
458 # create it if there is none, then set its attributes.
460 # \param fatherItem (SObject) item under which the tagged item will be looked for
461 # and eventually created.
463 # \param tag integer) tag of the item to look for.
465 # \return the SObject at \b tag if found or created successfully, or
466 # \b None if an error happened.
468 # See \b setItem() for the description of the other parameters.
469 def setItemAtTag(self, fatherItem, tag, name = None, fileType = None,
470 fileName = None, comment = None, icon = None, IOR = None,
473 Find an item tagged `tag` under `fatherItem` in the study tree or
474 create it if there is none, then set its attributes.
476 :type fatherItem: SObject
477 :param fatherItem: item under which the tagged item will be looked for
478 and eventually created.
481 :param tag: tag of the item to look for.
483 :return: the SObject at `tag` if found or created successfully, or
484 :const:`None` if an error happened.
486 See :meth:`setItem` for the description of the other parameters.
488 found, sObj = fatherItem.FindSubObject(tag)
490 sObj = self.builder.NewObjectToTag(fatherItem, tag)
491 self.setItem(sObj, name, fileType, fileName, comment, icon,
495 ## Return the name of the object sObject
496 def getName(self, sObject):
497 val = sObject.GetName()
498 return unicode(val, ENCODING_FOR_SALOME_STUDY)
500 ## Set the name of the object sObject
501 def setName(self, sObject, name):
502 self.builder.SetName(sObject, name.encode(ENCODING_FOR_SALOME_STUDY))
504 ## Return the comment of the object sObject
505 def getComment(self, sObject):
506 val = sObject.GetComment()
507 return unicode(val, ENCODING_FOR_SALOME_STUDY)
509 ## Set the comment of the object sObject
510 def setComment(self, sObject, comment):
511 self.builder.SetComment(sObject, comment.encode(ENCODING_FOR_SALOME_STUDY))
513 ## Return the value of the attribute named \b attributeName on the object
514 # sObject, or \b default if the attribute doesn't exist.
515 def getAttributeValue(self, sObject, attributeName, default = None):
517 Return the value of the attribute named `attributeName` on the object
518 `sObject`, or `default` if the attribute doesn't exist.
521 found, attr = self.builder.FindAttribute(sObject, attributeName)
526 ## Set the value of the attribute named \b attributeName on the object
527 # sObject to the value \b attributeValue.
528 def setAttributeValue(self, sObject, attributeName, attributeValue):
530 Set the value of the attribute named `attributeName` on the object
531 `sObject` to the value `attributeValue`.
533 attr = self.builder.FindOrCreateAttribute(sObject, attributeName)
534 attr.SetValue(attributeValue)
536 ## Return the value of the attribute "AttributeLocalID" of the object
537 # sObject, or \b None if it is not set.
538 def getTypeId(self, sObject):
540 Return the value of the attribute "AttributeLocalID" of the object
541 `sObject`, or :const:`None` if it is not set.
543 return self.getAttributeValue(sObject, "AttributeLocalID")
545 ## Set the attribute "AttributeLocalID" of the object \b sObject to the
547 def setTypeId(self, sObject, value):
549 Set the attribute "AttributeLocalID" of the object `sObject` to the
552 self.setAttributeValue(sObject, "AttributeLocalID", value)
554 ## Return the value of the attribute "AttributeFileType" of the object
555 # sObject, or an empty string if it is not set.
556 def getFileType(self, sObject):
558 Return the value of the attribute "AttributeFileType" of the object
559 `sObject`, or an empty string if it is not set.
561 val = self.getAttributeValue(sObject, "AttributeFileType", "")
562 return unicode(val, ENCODING_FOR_SALOME_STUDY)
564 ## Set the attribute "AttributeFileType" of the object sObject to the
566 def setFileType(self, sObject, value):
568 Set the attribute "AttributeFileType" of the object `sObject` to the
571 self.setAttributeValue(sObject, "AttributeFileType",
572 value.encode(ENCODING_FOR_SALOME_STUDY))
574 ## Return the value of the attribute "AttributeExternalFileDef" of the
575 # object sObject, or an empty string if it is not set.
576 def getFileName(self, sObject):
578 Return the value of the attribute "AttributeExternalFileDef" of the
579 object `sObject`, or an empty string if it is not set.
581 val = self.getAttributeValue(sObject, "AttributeExternalFileDef", "")
582 return unicode(val, ENCODING_FOR_SALOME_STUDY)
584 ## Set the attribute "AttributeExternalFileDef" of the object sObject
585 # to the value value.
586 def setFileName(self, sObject, value):
588 Set the attribute "AttributeExternalFileDef" of the object `sObject`
589 to the value `value`.
591 self.setAttributeValue(sObject, "AttributeExternalFileDef",
592 value.encode(ENCODING_FOR_SALOME_STUDY))
594 ## Return the value of the attribute "AttributePixMap" of the object
595 # sObject, or an empty string if it is not set.
596 def getIcon(self, sObject):
598 Return the value of the attribute "AttributePixMap" of the object
599 `sObject`, or an empty string if it is not set.
602 found, attr = self.builder.FindAttribute(sObject, "AttributePixMap")
603 if found and attr.HasPixMap():
604 value = attr.GetPixMap()
605 return unicode(value, ENCODING_FOR_SALOME_STUDY)
607 ## Set the attribute "AttributePixMap" of the object sObject to the
609 def setIcon(self, sObject, value):
611 Set the attribute "AttributePixMap" of the object `sObject` to the
614 attr = self.builder.FindOrCreateAttribute(sObject, "AttributePixMap")
615 attr.SetPixMap(value.encode(ENCODING_FOR_SALOME_STUDY))