1 # Copyright (C) 2007-2020 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.
34 from salome.kernel import termcolor
35 from salome.kernel.logger import Logger
38 logger = Logger("salome.kernel.studyedit", color=termcolor.PURPLE)
40 _DEFAULT_CONTAINER = "FactoryServer"
43 ## This class provides utility methods to complement \b Study and
44 # \b StudyBuilder classes. Those methods may be moved in those classes
46 # The preferred way to get a StudyEditor object is through the method
47 # \b getStudyEditor which allows to reuse existing instance or through
48 # the global module attribute \b EDITOR.
50 # \param lcc This instance attribute provides access to the SALOME life cycle
53 # \param study This instance attribute provides access to the \b Study object.
54 # It can be used to access the study but the attribute itself cannot
57 # \param builder This instance attribute provides access to the \b StudyBuilder
58 # object. It can be used to edit the study but the attribute itself
63 This class provides utility methods to complement :class:`Study` and
64 :class:`StudyBuilder` classes. Those methods may be moved in those classes
66 The preferred way to get a StudyEditor object is through the method
67 :meth:`getStudyEditor` which allows to reuse existing instances.
71 This instance attribute provides access to the SALOME life cycle
76 This instance attribute provides access to the :class:`Study` object.
77 It can be used to access the study but the attribute itself cannot
80 .. attribute:: builder
82 This instance attribute provides access to the :class:`StudyBuilder`
83 object. It can be used to edit the study but the attribute itself
90 """Attribute that provides access to the study."""
93 if salome.myStudy is None:
94 raise Exception("Study doesn't exist")
99 """Attribute that provides access to the study builder."""
102 if salome.myStudy is None:
103 raise Exception("Study doesn't exist")
104 return salome.myStudy.NewBuilder()
108 """Attribute that providess access to the SALOME life cycle CORBA service."""
113 ## Find a component corresponding to the Salome module \b moduleName in
114 # the study. If none is found, create a new component and associate it
115 # with the corresponding engine (i.e. the engine named \b moduleName).
116 # Note that in Salome 5, the module name and engine name must be
117 # identical (every module must provide an engine with the same name).
118 # In Salome 6 it will be possible to define a different name for the
121 # \param moduleName (string) name of the module corresponding to the component
122 # (the module name is the string value in the
123 # attribute "AttributeComment" of the component)
125 # \param componentName (string) name of the new component if created.
126 # If \b None, use \b moduleName instead.
128 # \param icon (string) icon for the new component (attribute "AttributePixMap").
130 # \param containerName (string) name of the container in which the engine should be
133 # \return the SComponent found or created.
134 def findOrCreateComponent(self, moduleName, componentName = None,
135 icon = None, containerName = _DEFAULT_CONTAINER):
137 Find a component corresponding to the Salome module `moduleName` in
138 the study. If none is found, create a new component and associate it
139 with the corresponding engine (i.e. the engine named `moduleName`).
140 Note that in Salome 5, the module name and engine name must be
141 identical (every module must provide an engine with the same name).
142 In Salome 6 it will be possible to define a different name for the
145 :type moduleName: string
146 :param moduleName: name of the module corresponding to the component
147 (the module name is the string value in the
148 attribute "AttributeComment" of the component)
150 :type componentName: string
151 :param componentName: name of the new component if created. If
152 :const:`None`, use `moduleName` instead.
155 :param icon: icon for the new component (attribute "AttributePixMap").
157 :type containerName: string
158 :param containerName: name of the container in which the engine should be
161 :return: the SComponent found or created.
164 sComponent = self.study.FindComponent(moduleName)
165 if sComponent is None:
166 sComponent = self.builder.NewComponent(moduleName)
167 # Note that the NewComponent method set the "comment" attribute to the
168 # value of its argument (moduleName here)
169 if componentName is None:
170 componentName = moduleName
171 self.builder.SetName(sComponent, componentName)
173 # _MEM_ : This will be effective if and only if "moduleName"
174 # really corresponds to the module name (as specified in the
176 self.setIcon(sComponent, icon)
178 # This part will stay inactive until Salome 6. In Salome 6, the
179 # engine name will be stored separately from the module name.
180 # An internal convention (in this class) is to store the name of the
181 # associated engine in the parameter attribute of the scomponent (so that
182 # it could be retrieved in a future usage of this scomponent, for example,
183 # for the need of the function loadComponentEngine). The comment attribute
184 # SHOULD NOT be used for this purpose because it's used by the SALOME
185 # resources manager to identify the SALOME module and then localized
187 #attr = self.builder.FindOrCreateAttribute( sComponent, "AttributeParameter" )
188 #attr.SetString( "ENGINE_NAME", engineName )
190 engine = self.lcc.FindOrLoadComponent(containerName, moduleName)
192 raise Exception("Cannot load engine %s in container %s. See "
193 "logs of container %s for more details." %
194 (moduleName, containerName, containerName))
195 self.builder.DefineComponentInstance(sComponent, engine)
199 ## Load the engine corresponding to \b sComponent in the container
200 # \b containerName, associate the engine with the component and load the
201 # CORBA objects of this component in the study.
202 def loadComponentEngine(self, sComponent,
203 containerName = _DEFAULT_CONTAINER):
205 Load the engine corresponding to `sComponent` in the container
206 `containerName`, associate the engine with the component and load the
207 CORBA objects of this component in the study.
209 # This part will stay inactive until Salome 6. In Salome 6, the
210 # engine name will be stored separately from the module name.
211 #attr = self.builder.FindOrCreateAttribute( sComponent, "AttributeParameter" )
212 #engineName = attr.GetString( "ENGINE_NAME" )
213 engine = self.lcc.FindOrLoadComponent(containerName,
214 sComponent.GetComment())
216 raise Exception("Cannot load component %s in container %s. See "
217 "logs of container %s for more details." %
218 (sComponent.GetComment(), containerName,
220 self.builder.LoadWith(sComponent, engine)
222 ## Get the CORBA object associated with the SObject \b item, eventually by
223 # first loading it with the corresponding engine.
224 def getOrLoadObject(self, item):
226 Get the CORBA object associated with the SObject `item`, eventually by
227 first loading it with the corresponding engine.
229 object = item.GetObject()
230 if object is None: # the engine has not been loaded yet
231 sComponent = item.GetFatherComponent()
232 self.loadComponentEngine(sComponent)
233 object = item.GetObject()
236 ## Find an object under \b fatherItem in the study with the given
237 # attributes. Return the first one found if at least one exists,
238 # otherwise create a new one with the given attributes and return it.
240 # See \b setItem() for the description of the parameters.
241 def findOrCreateItem(self, fatherItem, name, fileType = None,
242 fileName = None, comment = None, icon = None,
243 IOR = None, typeId = None):
245 Find an object under `fatherItem` in the study with the given
246 attributes. Return the first one found if at least one exists,
247 otherwise create a new one with the given attributes and return it.
249 See :meth:`setItem` for the description of the parameters.
251 sObject = self.findItem(fatherItem, name, fileType, fileName, comment,
254 sObject = self.createItem(fatherItem, name, fileType, fileName,
255 comment, icon, IOR, typeId)
258 ## Find an item with given attributes under \b fatherItem in the study. If
259 # none is found, return \b 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 \b None). To look explicitly
262 # for an empty attribute, use an empty string in the corresponding
265 # See \b setItem() for the description of the parameters.
266 def findItem(self, fatherItem, name = None, fileType = None,
267 fileName = None, comment = None, icon = None, IOR = None,
270 Find an item with given attributes under `fatherItem` in the study. If
271 none is found, return :const:`None`. If several items correspond to
272 the parameters, only the first one is returned. The search is made
273 only on given parameters (i.e. not :const:`None`). To look explicitly
274 for an empty attribute, use an empty string in the corresponding
277 See :meth:`setItem` for the description of the parameters.
280 childIterator = self.study.NewChildIterator(fatherItem)
281 while childIterator.More() and foundItem is None:
282 childItem = childIterator.Value()
284 (name is None or self.getName(childItem) == name) and \
285 (fileType is None or \
286 self.getFileType(childItem) == fileType) and \
287 (fileName is None or \
288 self.getFileName(childItem) == fileName) and \
289 (comment is None or self.getComment(childItem) == comment) and \
291 self.getIcon(childItem) == icon) and \
292 (IOR is None or childItem.GetIOR() == IOR) and \
294 self.getTypeId(childItem) == typeId):
295 foundItem = childItem
299 ## Create a new object named \b name under \b fatherItem in the study, with
300 # the given attributes. If an object named \b name already exists under
301 # the father object, the new object is created with a new name \b name_X
302 # where X is the first available index.
304 # param fatherItem (SObject) item under which the new item will be added.
305 # \return new SObject created in the study.
307 # See \b setItem() for the description of the other parameters.
308 def createItem(self, fatherItem, name, fileType=None, fileName=None,
309 comment=None, icon=None, IOR=None, typeId=None):
311 Create a new object named `name` under `fatherItem` in the study, with
312 the given attributes. If an object named `name` already exists under
313 the father object, the new object is created with a new name `name_X`
314 where X is the first available index.
316 :type fatherItem: SObject
317 :param fatherItem: item under which the new item will be added.
319 :return: new SObject created in the study
321 See :meth:`setItem` for the description of the other parameters.
323 aSObject = self.builder.NewObject(fatherItem)
325 aChildIterator = self.study.NewChildIterator(fatherItem)
329 anIdRE = re.compile("^" + aDelim + "[0-9]+")
330 aNameRE = re.compile("^" + name)
331 while aChildIterator.More():
332 aSObj = aChildIterator.Value()
333 aChildIterator.Next()
334 aName = aSObj.GetName()
335 if re.match(aNameRE, aName):
336 aTmp = aName[aLength:]
337 if re.match(anIdRE, aTmp):
352 aName = aName + aDelim + str(aMaxId)
355 self.setItem(aSObject, aName, fileType, fileName, comment, icon,
360 ## Modify the attributes of an item in the study. Unspecified attributes
361 # (i.e. those set to \b None) are left unchanged.
363 # \param item (SObject) item to modify.
365 # \param name (string or unicode) item name (attribute \b AttributeName).
367 # \param fileType (string or unicode) item file type (attribute \b AttributeFileType).
369 # \param fileName (string or unicode) item file name (attribute \b AttributeExternalFileDef).
371 # \param comment (string or unicode) item comment (attribute \b AttributeComment). Note that
372 # this attribute will appear in the \b Value column in the object browser.
374 # \param icon (string or unicode) item icon name (attribute \b AttributePixMap).
376 # \param IOR (string) IOR of a CORBA object associated with the item
377 # (attribute \b AttributeIOR).
379 # \param typeId (integer) item type (attribute \b AttributeLocalID).
380 def setItem(self, item, name = None, fileType = None, fileName = None,
381 comment = None, icon = None, IOR = None, typeId = None):
383 Modify the attributes of an item in the study. Unspecified attributes
384 (i.e. those set to :const:`None`) are left unchanged.
387 :param item: item to modify.
389 :type name: string or unicode
390 :param name: item name (attribute 'AttributeName').
392 :type fileType: string or unicode
393 :param fileType: item file type (attribute 'AttributeFileType').
395 :type fileName: string or unicode
396 :param fileName: item file name (attribute
397 'AttributeExternalFileDef').
399 :type comment: string or unicode
400 :param comment: item comment (attribute 'AttributeComment'). Note that
401 this attribute will appear in the 'Value' column in
404 :type icon: string or unicode
405 :param icon: item icon name (attribute 'AttributePixMap').
408 :param IOR: IOR of a CORBA object associated with the item
409 (attribute 'AttributeIOR').
411 :type typeId: integer
412 :param typeId: item type (attribute 'AttributeLocalID').
414 logger.debug("setItem (ID=%s): name=%s, fileType=%s, fileName=%s, "
415 "comment=%s, icon=%s, IOR=%s" %
416 (item.GetID(), name, fileType, fileName, comment,
419 self.setName(item, name)
420 if fileType is not None:
421 self.setFileType(item, fileType)
422 if fileName is not None:
423 self.setFileName(item, fileName)
424 if comment is not None:
425 self.setComment(item, comment)
427 self.setIcon(item, icon)
429 self.builder.SetIOR(item, IOR)
430 if typeId is not None:
431 self.setTypeId(item, typeId)
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.
436 # \param item (SObject) the item to be removed
438 # \param withChildren (boolean) if \b True, also remove the children of item
440 # \return \b True if the item was removed successfully, or
441 # \b False if an error happened.
442 def removeItem(self, item, withChildren = False ):
444 Remove the given item from the study. Note that the items are never
445 really deleted. They just don't appear in the study anymore.
448 :param item: the item to be removed
450 :type withChildren: boolean
451 :param withChildren: if :const:`True`, also remove the children of
454 :return: :const:`True` if the item was removed successfully, or
455 :const:`False` if an error happened.
460 self.builder.RemoveObjectWithChildren(item)
462 self.builder.RemoveObject(item)
468 ## Find an item tagged \b tag under \b fatherItem in the study tree or
469 # create it if there is none, then set its attributes.
471 # \param fatherItem (SObject) item under which the tagged item will be looked for
472 # and eventually created.
474 # \param tag integer) tag of the item to look for.
476 # \return the SObject at \b tag if found or created successfully, or
477 # \b None if an error happened.
479 # See \b setItem() for the description of the other parameters.
480 def setItemAtTag(self, fatherItem, tag, name = None, fileType = None,
481 fileName = None, comment = None, icon = None, IOR = None,
484 Find an item tagged `tag` under `fatherItem` in the study tree or
485 create it if there is none, then set its attributes.
487 :type fatherItem: SObject
488 :param fatherItem: item under which the tagged item will be looked for
489 and eventually created.
492 :param tag: tag of the item to look for.
494 :return: the SObject at `tag` if found or created successfully, or
495 :const:`None` if an error happened.
497 See :meth:`setItem` for the description of the other parameters.
499 found, sObj = fatherItem.FindSubObject(tag)
501 sObj = self.builder.NewObjectToTag(fatherItem, tag)
502 self.setItem(sObj, name, fileType, fileName, comment, icon,
506 ## Return the name of the object sObject
507 def getName(self, sObject):
508 return sObject.GetName()
510 ## Set the name of the object sObject
511 def setName(self, sObject, name):
512 self.builder.SetName(sObject, name)
514 ## Return the comment of the object sObject
515 def getComment(self, sObject):
516 return sObject.GetComment()
518 ## Set the comment of the object sObject
519 def setComment(self, sObject, comment):
520 self.builder.SetComment(sObject, comment)
522 ## Return the value of the attribute named \b attributeName on the object
523 # sObject, or \b default if the attribute doesn't exist.
524 def getAttributeValue(self, sObject, attributeName, default = None):
526 Return the value of the attribute named `attributeName` on the object
527 `sObject`, or `default` if the attribute doesn't exist.
530 found, attr = self.builder.FindAttribute(sObject, attributeName)
535 ## Set the value of the attribute named \b attributeName on the object
536 # sObject to the value \b attributeValue.
537 def setAttributeValue(self, sObject, attributeName, attributeValue):
539 Set the value of the attribute named `attributeName` on the object
540 `sObject` to the value `attributeValue`.
542 attr = self.builder.FindOrCreateAttribute(sObject, attributeName)
543 attr.SetValue(attributeValue)
545 ## Return the value of the attribute "AttributeLocalID" of the object
546 # sObject, or \b None if it is not set.
547 def getTypeId(self, sObject):
549 Return the value of the attribute "AttributeLocalID" of the object
550 `sObject`, or :const:`None` if it is not set.
552 return self.getAttributeValue(sObject, "AttributeLocalID")
554 ## Set the attribute "AttributeLocalID" of the object \b sObject to the
556 def setTypeId(self, sObject, value):
558 Set the attribute "AttributeLocalID" of the object `sObject` to the
561 self.setAttributeValue(sObject, "AttributeLocalID", value)
563 ## Return the value of the attribute "AttributeFileType" of the object
564 # sObject, or an empty string if it is not set.
565 def getFileType(self, sObject):
567 Return the value of the attribute "AttributeFileType" of the object
568 `sObject`, or an empty string if it is not set.
570 return self.getAttributeValue(sObject, "AttributeFileType", "")
572 ## Set the attribute "AttributeFileType" of the object sObject to the
574 def setFileType(self, sObject, value):
576 Set the attribute "AttributeFileType" of the object `sObject` to the
579 self.setAttributeValue(sObject, "AttributeFileType",
582 ## Return the value of the attribute "AttributeExternalFileDef" of the
583 # object sObject, or an empty string if it is not set.
584 def getFileName(self, sObject):
586 Return the value of the attribute "AttributeExternalFileDef" of the
587 object `sObject`, or an empty string if it is not set.
589 return self.getAttributeValue(sObject, "AttributeExternalFileDef", "")
591 ## Set the attribute "AttributeExternalFileDef" of the object sObject
592 # to the value value.
593 def setFileName(self, sObject, value):
595 Set the attribute "AttributeExternalFileDef" of the object `sObject`
596 to the value `value`.
598 self.setAttributeValue(sObject, "AttributeExternalFileDef",
601 ## Return the value of the attribute "AttributePixMap" of the object
602 # sObject, or an empty string if it is not set.
603 def getIcon(self, sObject):
605 Return the value of the attribute "AttributePixMap" of the object
606 `sObject`, or an empty string if it is not set.
609 found, attr = self.builder.FindAttribute(sObject, "AttributePixMap")
610 if found and attr.HasPixMap():
611 value = attr.GetPixMap()
614 ## Set the attribute "AttributePixMap" of the object sObject to the
616 def setIcon(self, sObject, value):
618 Set the attribute "AttributePixMap" of the object `sObject` to the
621 attr = self.builder.FindOrCreateAttribute(sObject, "AttributePixMap")
622 attr.SetPixMap(value)
624 ## Singleton study editor instance.
626 EDITOR = StudyEditor()
627 """Singleton study editor instance."""
629 ## Return a \b StudyEditor instance to edit the study.
630 # \deprecated This function is kept for backward compatibility. Use \a EDITOR instead.
632 def getStudyEditor():
634 Return a :class:`StudyEditor` instance to edit the study.