1 # -*- coding: utf-8 -*-
3 # Copyright (C) 2007-2014 CEA/DEN, EDF R&D, OPEN CASCADE
5 # This library is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU Lesser General Public
7 # License as published by the Free Software Foundation; either
8 # version 2.1 of the License, or (at your option) any later version.
10 # This library is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # Lesser General Public License for more details.
15 # You should have received a copy of the GNU Lesser General Public
16 # License along with this library; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
22 This module provides a new class :class:`StudyEditor` to complement
23 :class:`Study` and :class:`StudyBuilder` classes.
29 from salome.kernel.logger import Logger
30 from salome.kernel import termcolor
31 logger = Logger("salome.kernel.studyedit", color = termcolor.PURPLE)
34 _DEFAULT_CONTAINER = "FactoryServer"
36 def getActiveStudyId():
38 Return the ID of the active study. In GUI mode, this function is equivalent
39 to ``salome.sg.getActiveStudyId()``. Outside GUI, it returns
40 ``salome.myStudyId`` variable.
43 # Warning: we don't use salome.getActiveStudy() here because it doesn't
44 # work properly when called from Salome modules (multi-study interpreter
46 if salome.hasDesktop():
47 return salome.sg.getActiveStudyId()
49 return salome.myStudyId
52 return getStudyFromStudyId(getActiveStudyId())
54 def getStudyFromStudyId(studyId):
56 study = salome.myStudyManager.GetStudyByID(studyId)
59 def getStudyIdFromStudy(study):
60 studyId = study._get_StudyId()
63 def getStudyEditor(studyId = None):
65 Return a :class:`StudyEditor` instance to edit the study with ID
66 `studyId`. If `studyId` is :const:`None`, return an editor for the current
70 studyId = getActiveStudyId()
71 if not _editors.has_key(studyId):
72 _editors[studyId] = StudyEditor(studyId)
73 return _editors[studyId]
77 This class provides utility methods to complement :class:`Study` and
78 :class:`StudyBuilder` classes. Those methods may be moved in those classes
79 in the future. The parameter `studyId` defines the ID of the study to
80 edit. If it is :const:`None`, the edited study will be the current study.
81 The preferred way to get a StudyEditor object is through the method
82 :meth:`getStudyEditor` which allows to reuse existing instances.
84 .. attribute:: studyId
86 This instance attribute contains the ID of the edited study. This
87 attribute should not be modified.
91 This instance attribute contains the underlying :class:`Study` object.
92 It can be used to access the study but the attribute itself should not
95 .. attribute:: builder
97 This instance attribute contains the underlying :class:`StudyBuilder`
98 object. It can be used to edit the study but the attribute itself
99 should not be modified.
102 def __init__(self, studyId = None):
105 studyId = getActiveStudyId()
106 self.studyId = studyId
107 self.study = salome.myStudyManager.GetStudyByID(studyId)
108 if self.study is None:
109 raise Exception("Can't create StudyEditor object: "
110 "Study %d doesn't exist" % studyId)
111 self.builder = self.study.NewBuilder()
113 def findOrCreateComponent(self, moduleName, componentName = None,
114 icon = None, containerName = _DEFAULT_CONTAINER):
116 Find a component corresponding to the Salome module `moduleName` in
117 the study. If none is found, create a new component and associate it
118 with the corresponding engine (i.e. the engine named `moduleName`).
119 Note that in Salome 5, the module name and engine name must be
120 identical (every module must provide an engine with the same name).
121 In Salome 6 it will be possible to define a different name for the
124 :type moduleName: string
125 :param moduleName: name of the module corresponding to the component
126 (the module name is the string value in the
127 attribute "AttributeComment" of the component)
129 :type componentName: string
130 :param componentName: name of the new component if created. If
131 :const:`None`, use `moduleName` instead.
134 :param icon: icon for the new component (attribute "AttributePixMap").
136 :type containerName: string
137 :param containerName: name of the container in which the engine should be
140 :return: the SComponent found or created.
143 sComponent = self.study.FindComponent(moduleName)
144 if sComponent is None:
145 sComponent = self.builder.NewComponent(moduleName)
146 # Note that the NewComponent method set the "comment" attribute to the
147 # value of its argument (moduleName here)
148 if componentName is None:
149 componentName = moduleName
150 self.builder.SetName(sComponent, componentName)
152 # _MEM_ : This will be effective if and only if "moduleName"
153 # really corresponds to the module name (as specified in the
155 self.setIcon(sComponent, icon)
157 # This part will stay inactive until Salome 6. In Salome 6, the
158 # engine name will be stored separately from the module name.
159 # An internal convention (in this class) is to store the name of the
160 # associated engine in the parameter attribute of the scomponent (so that
161 # it could be retrieved in a future usage of this scomponent, for example,
162 # for the need of the function loadComponentEngine). The comment attribute
163 # SHOULD NOT be used for this purpose because it's used by the SALOME
164 # resources manager to identify the SALOME module and then localized
166 #attr = self.builder.FindOrCreateAttribute( sComponent, "AttributeParameter" )
167 #attr.SetString( "ENGINE_NAME", engineName )
169 engine = salome.lcc.FindOrLoadComponent(containerName, moduleName)
171 raise Exception("Cannot load engine %s in container %s. See "
172 "logs of container %s for more details." %
173 (moduleName, containerName, containerName))
174 self.builder.DefineComponentInstance(sComponent, engine)
178 def loadComponentEngine(self, sComponent,
179 containerName = _DEFAULT_CONTAINER):
181 Load the engine corresponding to `sComponent` in the container
182 `containerName`, associate the engine with the component and load the
183 CORBA objects of this component in the study.
185 # This part will stay inactive until Salome 6. In Salome 6, the
186 # engine name will be stored separately from the module name.
187 #attr = self.builder.FindOrCreateAttribute( sComponent, "AttributeParameter" )
188 #engineName = attr.GetString( "ENGINE_NAME" )
189 engine = salome.lcc.FindOrLoadComponent(containerName,
190 sComponent.GetComment())
192 raise Exception("Cannot load component %s in container %s. See "
193 "logs of container %s for more details." %
194 (sComponent.GetComment(), containerName,
196 self.builder.LoadWith(sComponent, engine)
198 def getOrLoadObject(self, item):
200 Get the CORBA object associated with the SObject `item`, eventually by
201 first loading it with the corresponding engine.
203 object = item.GetObject()
204 if object is None: # the engine has not been loaded yet
205 sComponent = item.GetFatherComponent()
206 self.loadComponentEngine(sComponent)
207 object = item.GetObject()
210 def findOrCreateItem(self, fatherItem, name, fileType = None,
211 fileName = None, comment = None, icon = None,
212 IOR = None, typeId = None):
214 Find an object under `fatherItem` in the study with the given
215 attributes. Return the first one found if at least one exists,
216 otherwise create a new one with the given attributes and return it.
218 See :meth:`setItem` for the description of the parameters.
220 sObject = self.findItem(fatherItem, name, fileType, fileName, comment,
223 sObject = self.createItem(fatherItem, name, fileType, fileName,
224 comment, icon, IOR, typeId)
227 def findItem(self, fatherItem, name = None, fileType = None,
228 fileName = None, comment = None, icon = None, IOR = None,
231 Find an item with given attributes under `fatherItem` in the study. If
232 none is found, return :const:`None`. If several items correspond to
233 the parameters, only the first one is returned. The search is made
234 only on given parameters (i.e. not :const:`None`). To look explicitly
235 for an empty attribute, use an empty string in the corresponding
238 See :meth:`setItem` for the description of the parameters.
241 childIterator = self.study.NewChildIterator(fatherItem)
242 while childIterator.More() and foundItem is None:
243 childItem = childIterator.Value()
245 (name is None or childItem.GetName() == name) and \
246 (fileType is None or \
247 self.getFileType(childItem) == fileType) and \
248 (fileName is None or \
249 self.getFileName(childItem) == fileName) and \
250 (comment is None or childItem.GetComment() == comment) and \
252 self.getIcon(childItem) == icon) and \
253 (IOR is None or childItem.GetIOR() == IOR) and \
255 self.getTypeId(childItem) == typeId):
256 foundItem = childItem
260 def createItem(self, fatherItem, name, fileType = None, fileName = None,
261 comment = None, icon = None, IOR = None, typeId = None):
263 Create a new object named `name` under `fatherItem` in the study, with
264 the given attributes. If an object named `name` already exists under
265 the father object, the new object is created with a new name `name_X`
266 where X is the first available index.
268 :type fatherItem: SObject
269 :param fatherItem: item under which the new item will be added.
271 :return: new SObject created in the study
273 See :meth:`setItem` for the description of the other parameters.
275 aSObject = self.builder.NewObject(fatherItem)
277 aChildIterator = self.study.NewChildIterator(fatherItem)
281 anIdRE = re.compile("^" + aDelim + "[0-9]+")
282 aNameRE = re.compile("^" + name)
283 while aChildIterator.More():
284 aSObj = aChildIterator.Value()
285 aChildIterator.Next()
286 aName = aSObj.GetName()
287 if re.match(aNameRE,aName):
288 aTmp = aName[aLength:]
289 if re.match(anIdRE,aTmp):
291 anId = string.atol(aTmp[1:])
305 aName = aName + aDelim + str(aMaxId)
308 self.setItem(aSObject, aName, fileType, fileName, comment, icon,
313 def setItem(self, item, name = None, fileType = None, fileName = None,
314 comment = None, icon = None, IOR = None, typeId = None):
316 Modify the attributes of an item in the study. Unspecified attributes
317 (i.e. those set to :const:`None`) are left unchanged.
320 :param item: item to modify.
323 :param name: item name (attribute 'AttributeName').
325 :type fileType: string
326 :param fileType: item file type (attribute 'AttributeFileType').
328 :type fileName: string
329 :param fileName: item file name (attribute
330 'AttributeExternalFileDef').
332 :type comment: string
333 :param comment: item comment (attribute 'AttributeComment'). Note that
334 this attribute will appear in the 'Value' column in
338 :param icon: item icon name (attribute 'AttributePixMap').
341 :param IOR: IOR of a CORBA object associated with the item
342 (attribute 'AttributeIOR').
344 :type typeId: integer
345 :param typeId: item type (attribute 'AttributeLocalID').
347 logger.debug("setItem (ID=%s): name=%s, fileType=%s, fileName=%s, "
348 "comment=%s, icon=%s, IOR=%s" %
349 (item.GetID(), name, fileType, fileName, comment,
351 # Explicit cast is necessary for unicode to string conversion
353 self.builder.SetName(item, str(name))
354 if fileType is not None:
355 self.setFileType(item, fileType)
356 if fileName is not None:
357 self.setFileName(item, fileName)
358 if comment is not None:
359 self.builder.SetComment(item, str(comment))
361 self.setIcon(item, icon)
363 self.builder.SetIOR(item, str(IOR))
364 if typeId is not None:
365 self.setTypeId(item, typeId)
367 def removeItem(self, item, withChildren = False ):
369 Remove the given item from the study. Note that the items are never
370 really deleted. They just don't appear in the study anymore.
373 :param item: the item to be removed
375 :type withChildren: boolean
376 :param withChildren: if :const:`True`, also remove the children of
379 :return: :const:`True` if the item was removed successfully, or
380 :const:`False` if an error happened.
385 self.builder.RemoveObjectWithChildren(item)
387 self.builder.RemoveObject(item)
393 def setItemAtTag(self, fatherItem, tag, name = None, fileType = None,
394 fileName = None, comment = None, icon = None, IOR = None,
397 Find an item tagged `tag` under `fatherItem` in the study tree or
398 create it if there is none, then set its attributes.
400 :type fatherItem: SObject
401 :param fatherItem: item under which the tagged item will be looked for
402 and eventually created.
405 :param tag: tag of the item to look for.
407 :return: the SObject at `tag` if found or created successfully, or
408 :const:`None` if an error happened.
410 See :meth:`setItem` for the description of the other parameters.
412 found, sObj = fatherItem.FindSubObject(tag)
414 sObj = self.builder.NewObjectToTag(fatherItem, tag)
415 self.setItem(sObj, name, fileType, fileName, comment, icon,
419 def getAttributeValue(self, sObject, attributeName, default = None):
421 Return the value of the attribute named `attributeName` on the object
422 `sObject`, or `default` if the attribute doesn't exist.
425 found, attr = self.builder.FindAttribute(sObject, attributeName)
430 def setAttributeValue(self, sObject, attributeName, attributeValue):
432 Set the value of the attribute named `attributeName` on the object
433 `sObject` to the value `attributeValue`.
435 attr = self.builder.FindOrCreateAttribute(sObject, attributeName)
436 attr.SetValue(attributeValue)
438 def getTypeId(self, sObject):
440 Return the value of the attribute "AttributeLocalID" of the object
441 `sObject`, or :const:`None` if it is not set.
443 return self.getAttributeValue(sObject, "AttributeLocalID")
445 def setTypeId(self, sObject, value):
447 Set the attribute "AttributeLocalID" of the object `sObject` to the
450 self.setAttributeValue(sObject, "AttributeLocalID", value)
452 def getFileType(self, sObject):
454 Return the value of the attribute "AttributeFileType" of the object
455 `sObject`, or an empty string if it is not set.
457 return self.getAttributeValue(sObject, "AttributeFileType", "")
459 def setFileType(self, sObject, value):
461 Set the attribute "AttributeFileType" of the object `sObject` to the
464 # Explicit cast is necessary for unicode to string conversion
465 self.setAttributeValue(sObject, "AttributeFileType", str(value))
467 def getFileName(self, sObject):
469 Return the value of the attribute "AttributeExternalFileDef" of the
470 object `sObject`, or an empty string if it is not set.
472 return self.getAttributeValue(sObject, "AttributeExternalFileDef", "")
474 def setFileName(self, sObject, value):
476 Set the attribute "AttributeExternalFileDef" of the object `sObject`
477 to the value `value`.
479 # Explicit cast is necessary for unicode to string conversion
480 self.setAttributeValue(sObject, "AttributeExternalFileDef",
483 def getIcon(self, sObject):
485 Return the value of the attribute "AttributePixMap" of the object
486 `sObject`, or an empty string if it is not set.
489 found, attr = self.builder.FindAttribute(sObject, "AttributePixMap")
490 if found and attr.HasPixMap():
491 value = attr.GetPixMap()
494 def setIcon(self, sObject, value):
496 Set the attribute "AttributePixMap" of the object `sObject` to the
499 attr = self.builder.FindOrCreateAttribute(sObject, "AttributePixMap")
500 # Explicit cast is necessary for unicode to string conversion
501 attr.SetPixMap(str(value))