1 # -*- coding: utf-8 -*-
3 # Copyright (C) 2007-2011 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.
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 if salome.hasDesktop():
44 return salome.sg.getActiveStudyId()
46 return salome.myStudyId
48 def getStudyEditor(studyId = None):
50 Return a :class:`StudyEditor` instance to edit the study with ID
51 `studyId`. If `studyId` is :const:`None`, return an editor for the current
55 studyId = getActiveStudyId()
56 if not _editors.has_key(studyId):
57 _editors[studyId] = StudyEditor(studyId)
58 return _editors[studyId]
63 This class provides utility methods to complement :class:`Study` and
64 :class:`StudyBuilder` classes. Those methods may be moved in those classes
65 in the future. The parameter `studyId` defines the ID of the study to
66 edit. If it is :const:`None`, the edited study will be the current study.
67 The preferred way to get a StudyEditor object is through the method
68 :meth:`getStudyEditor` which allows to reuse existing instances.
70 .. attribute:: studyId
72 This instance attribute contains the ID of the edited study. This
73 attribute should not be modified.
77 This instance attribute contains the underlying :class:`Study` object.
78 It can be used to access the study but the attribute itself should not
81 .. attribute:: builder
83 This instance attribute contains the underlying :class:`StudyBuilder`
84 object. It can be used to edit the study but the attribute itself
85 should not be modified.
88 def __init__(self, studyId = None):
91 studyId = getActiveStudyId()
92 self.studyId = studyId
93 self.study = salome.myStudyManager.GetStudyByID(studyId)
94 if self.study is None:
95 raise Exception("Can't create StudyEditor object: "
96 "Study %d doesn't exist" % studyId)
97 self.builder = self.study.NewBuilder()
99 def findOrCreateComponent(self, moduleName, componentName = None,
100 icon = None, containerName = _DEFAULT_CONTAINER):
102 Find a component corresponding to the Salome module `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 `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
110 :type moduleName: string
111 :param moduleName: name of the module corresponding to the component
112 (the module name is the string value in the
113 attribute "AttributeComment" of the component)
115 :type componentName: string
116 :param componentName: name of the new component if created. If
117 :const:`None`, use `moduleName` instead.
120 :param icon: icon for the new component (attribute "AttributePixMap").
122 :type containerName: string
123 :param containerName: name of the container in which the engine should be
126 :return: the SComponent found or created.
129 sComponent = self.study.FindComponent(moduleName)
130 if sComponent is None:
131 sComponent = self.builder.NewComponent(moduleName)
132 # Note that the NewComponent method set the "comment" attribute to the
133 # value of its argument (moduleName here)
134 if componentName is None:
135 componentName = moduleName
136 self.builder.SetName(sComponent, componentName)
138 # _MEM_ : This will be effective if and only if "moduleName"
139 # really corresponds to the module name (as specified in the
141 self.setIcon(sComponent, icon)
143 # This part will stay inactive until Salome 6. In Salome 6, the
144 # engine name will be stored separately from the module name.
145 # An internal convention (in this class) is to store the name of the
146 # associated engine in the parameter attribute of the scomponent (so that
147 # it could be retrieved in a future usage of this scomponent, for example,
148 # for the need of the function loadComponentEngine). The comment attribute
149 # SHOULD NOT be used for this purpose because it's used by the SALOME
150 # resources manager to identify the SALOME module and then localized
152 #attr = self.builder.FindOrCreateAttribute( sComponent, "AttributeParameter" )
153 #attr.SetString( "ENGINE_NAME", engineName )
155 engine = salome.lcc.FindOrLoadComponent(containerName, moduleName)
157 raise Exception("Cannot load engine %s in container %s. See "
158 "logs of container %s for more details." %
159 (moduleName, containerName, containerName))
160 self.builder.DefineComponentInstance(sComponent, engine)
164 def loadComponentEngine(self, sComponent,
165 containerName = _DEFAULT_CONTAINER):
167 Load the engine corresponding to `sComponent` in the container
168 `containerName`, associate the engine with the component and load the
169 CORBA objects of this component in the study.
171 # This part will stay inactive until Salome 6. In Salome 6, the
172 # engine name will be stored separately from the module name.
173 #attr = self.builder.FindOrCreateAttribute( sComponent, "AttributeParameter" )
174 #engineName = attr.GetString( "ENGINE_NAME" )
175 engine = salome.lcc.FindOrLoadComponent(containerName,
176 sComponent.GetComment())
178 raise Exception("Cannot load component %s in container %s. See "
179 "logs of container %s for more details." %
180 (sComponent.GetComment(), containerName,
182 self.builder.LoadWith(sComponent, engine)
184 def getOrLoadObject(self, item):
186 Get the CORBA object associated with the SObject `item`, eventually by
187 first loading it with the corresponding engine.
189 object = item.GetObject()
190 if object is None: # the engine has not been loaded yet
191 sComponent = item.GetFatherComponent()
192 self.loadComponentEngine(sComponent)
193 object = item.GetObject()
196 def findOrCreateItem(self, fatherItem, name, fileType = None,
197 fileName = None, comment = None, icon = None,
198 IOR = None, typeId = None):
200 Find an object under `fatherItem` in the study with the given
201 attributes. Return the first one found if at least one exists,
202 otherwise create a new one with the given attributes and return it.
204 See :meth:`setItem` for the description of the parameters.
206 sObject = self.findItem(fatherItem, name, fileType, fileName, comment,
209 sObject = self.createItem(fatherItem, name, fileType, fileName,
210 comment, icon, IOR, typeId)
213 def findItem(self, fatherItem, name = None, fileType = None,
214 fileName = None, comment = None, icon = None, IOR = None,
217 Find an item with given attributes under `fatherItem` in the study. If
218 none is found, return :const:`None`. If several items correspond to
219 the parameters, only the first one is returned. The search is made
220 only on given parameters (i.e. not :const:`None`). To look explicitly
221 for an empty attribute, use an empty string in the corresponding
224 See :meth:`setItem` for the description of the parameters.
227 childIterator = self.study.NewChildIterator(fatherItem)
228 while childIterator.More() and foundItem is None:
229 childItem = childIterator.Value()
231 (name is None or childItem.GetName() == name) and \
232 (fileType is None or \
233 self.getFileType(childItem) == fileType) and \
234 (fileName is None or \
235 self.getFileName(childItem) == fileName) and \
236 (comment is None or childItem.GetComment() == comment) and \
238 self.getIcon(childItem) == icon) and \
239 (IOR is None or childItem.GetIOR() == IOR) and \
241 self.getTypeId(childItem) == typeId):
242 foundItem = childItem
246 def createItem(self, fatherItem, name, fileType = None, fileName = None,
247 comment = None, icon = None, IOR = None, typeId = None):
249 Create a new object named `name` under `fatherItem` in the study, with
250 the given attributes. If an object named `name` already exists under
251 the father object, the new object is created with a new name `name_X`
252 where X is the first available index.
254 :type fatherItem: SObject
255 :param fatherItem: item under which the new item will be added.
257 :return: new SObject created in the study
259 See :meth:`setItem` for the description of the other parameters.
261 aSObject = self.builder.NewObject(fatherItem)
263 aChildIterator = self.study.NewChildIterator(fatherItem)
267 anIdRE = re.compile("^" + aDelim + "[0-9]+")
268 aNameRE = re.compile("^" + name)
269 while aChildIterator.More():
270 aSObj = aChildIterator.Value()
271 aChildIterator.Next()
272 aName = aSObj.GetName()
273 if re.match(aNameRE,aName):
274 aTmp = aName[aLength:]
275 if re.match(anIdRE,aTmp):
277 anId = string.atol(aTmp[1:])
291 aName = aName + aDelim + str(aMaxId)
294 self.setItem(aSObject, aName, fileType, fileName, comment, icon,
299 def setItem(self, item, name = None, fileType = None, fileName = None,
300 comment = None, icon = None, IOR = None, typeId = None):
302 Modify the attributes of an item in the study. Unspecified attributes
303 (i.e. those set to :const:`None`) are left unchanged.
306 :param item: item to modify.
309 :param name: item name (attribute 'AttributeName').
311 :type fileType: string
312 :param fileType: item file type (attribute 'AttributeFileType').
314 :type fileName: string
315 :param fileName: item file name (attribute
316 'AttributeExternalFileDef').
318 :type comment: string
319 :param comment: item comment (attribute 'AttributeComment'). Note that
320 this attribute will appear in the 'Value' column in
324 :param icon: item icon name (attribute 'AttributePixMap').
327 :param IOR: IOR of a CORBA object associated with the item
328 (attribute 'AttributeIOR').
330 :type typeId: integer
331 :param typeId: item type (attribute 'AttributeLocalID').
333 logger.debug("setItem (ID=%s): name=%s, fileType=%s, fileName=%s, "
334 "comment=%s, icon=%s, IOR=%s" %
335 (item.GetID(), name, fileType, fileName, comment,
337 # Explicit cast is necessary for unicode to string conversion
339 self.builder.SetName(item, str(name))
340 if fileType is not None:
341 self.setFileType(item, fileType)
342 if fileName is not None:
343 self.setFileName(item, fileName)
344 if comment is not None:
345 self.builder.SetComment(item, str(comment))
347 self.setIcon(item, icon)
349 self.builder.SetIOR(item, str(IOR))
350 if typeId is not None:
351 self.setTypeId(item, typeId)
353 def removeItem(self, item, withChildren = False ):
355 Remove the given item from the study. Note that the items are never
356 really deleted. They just don't appear in the study anymore.
359 :param item: the item to be removed
361 :type withChildren: boolean
362 :param withChildren: if :const:`True`, also remove the children of
365 :return: :const:`True` if the item was removed successfully, or
366 :const:`False` if an error happened.
371 self.builder.RemoveObjectWithChildren(item)
373 self.builder.RemoveObject(item)
379 def setItemAtTag(self, fatherItem, tag, name = None, fileType = None,
380 fileName = None, comment = None, icon = None, IOR = None,
383 Find an item tagged `tag` under `fatherItem` in the study tree or
384 create it if there is none, then set its attributes.
386 :type fatherItem: SObject
387 :param fatherItem: item under which the tagged item will be looked for
388 and eventually created.
391 :param tag: tag of the item to look for.
393 :return: the SObject at `tag` if found or created successfully, or
394 :const:`None` if an error happened.
396 See :meth:`setItem` for the description of the other parameters.
398 found, sObj = fatherItem.FindSubObject(tag)
400 sObj = self.builder.NewObjectToTag(fatherItem, tag)
401 self.setItem(sObj, name, fileType, fileName, comment, icon,
405 def getAttributeValue(self, sObject, attributeName, default = None):
407 Return the value of the attribute named `attributeName` on the object
408 `sObject`, or `default` if the attribute doesn't exist.
411 found, attr = self.builder.FindAttribute(sObject, attributeName)
416 def setAttributeValue(self, sObject, attributeName, attributeValue):
418 Set the value of the attribute named `attributeName` on the object
419 `sObject` to the value `attributeValue`.
421 attr = self.builder.FindOrCreateAttribute(sObject, attributeName)
422 attr.SetValue(attributeValue)
424 def getTypeId(self, sObject):
426 Return the value of the attribute "AttributeLocalID" of the object
427 `sObject`, or :const:`None` if it is not set.
429 return self.getAttributeValue(sObject, "AttributeLocalID")
431 def setTypeId(self, sObject, value):
433 Set the attribute "AttributeLocalID" of the object `sObject` to the
436 self.setAttributeValue(sObject, "AttributeLocalID", value)
438 def getFileType(self, sObject):
440 Return the value of the attribute "AttributeFileType" of the object
441 `sObject`, or an empty string if it is not set.
443 return self.getAttributeValue(sObject, "AttributeFileType", "")
445 def setFileType(self, sObject, value):
447 Set the attribute "AttributeFileType" of the object `sObject` to the
450 # Explicit cast is necessary for unicode to string conversion
451 self.setAttributeValue(sObject, "AttributeFileType", str(value))
453 def getFileName(self, sObject):
455 Return the value of the attribute "AttributeExternalFileDef" of the
456 object `sObject`, or an empty string if it is not set.
458 return self.getAttributeValue(sObject, "AttributeExternalFileDef", "")
460 def setFileName(self, sObject, value):
462 Set the attribute "AttributeExternalFileDef" of the object `sObject`
463 to the value `value`.
465 # Explicit cast is necessary for unicode to string conversion
466 self.setAttributeValue(sObject, "AttributeExternalFileDef",
469 def getIcon(self, sObject):
471 Return the value of the attribute "AttributePixMap" of the object
472 `sObject`, or an empty string if it is not set.
475 found, attr = self.builder.FindAttribute(sObject, "AttributePixMap")
476 if found and attr.HasPixMap():
477 value = attr.GetPixMap()
480 def setIcon(self, sObject, value):
482 Set the attribute "AttributePixMap" of the object `sObject` to the
485 attr = self.builder.FindOrCreateAttribute(sObject, "AttributePixMap")
486 # Explicit cast is necessary for unicode to string conversion
487 attr.SetPixMap(str(value))