Back to index

salome-kernel  6.5.0
studyedit.py
Go to the documentation of this file.
00001 # -*- coding: utf-8 -*-
00002 #
00003 # Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
00004 #
00005 # This library is free software; you can redistribute it and/or
00006 # modify it under the terms of the GNU Lesser General Public
00007 # License as published by the Free Software Foundation; either
00008 # version 2.1 of the License.
00009 #
00010 # This library is distributed in the hope that it will be useful,
00011 # but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 # Lesser General Public License for more details.
00014 #
00015 # You should have received a copy of the GNU Lesser General Public
00016 # License along with this library; if not, write to the Free Software
00017 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00018 #
00019 # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
00020 #
00021 """
00022 This module provides a new class :class:`StudyEditor` to complement
00023 :class:`Study` and :class:`StudyBuilder` classes.
00024 """
00025 
00026 import re
00027 
00028 import salome
00029 from salome.kernel.logger import Logger
00030 from salome.kernel import termcolor
00031 logger = Logger("salome.kernel.studyedit", color = termcolor.PURPLE)
00032 
00033 _editors = {}
00034 _DEFAULT_CONTAINER = "FactoryServer"
00035 
00036 def getActiveStudyId():
00037     """
00038     Return the ID of the active study. In GUI mode, this function is equivalent
00039     to ``salome.sg.getActiveStudyId()``. Outside GUI, it returns
00040     ``salome.myStudyId`` variable.
00041     """
00042     salome.salome_init()
00043     # Warning: we don't use salome.getActiveStudy() here because it doesn't
00044     # work properly when called from Salome modules (multi-study interpreter
00045     # issue)
00046     if salome.hasDesktop():
00047         return salome.sg.getActiveStudyId()
00048     else:
00049         return salome.myStudyId
00050 
00051 def getActiveStudy():
00052     return getStudyFromStudyId(getActiveStudyId())
00053 
00054 def getStudyFromStudyId(studyId):
00055     salome.salome_init()
00056     study = salome.myStudyManager.GetStudyByID(studyId)
00057     return study
00058 
00059 def getStudyIdFromStudy(study):
00060     studyId = study._get_StudyId()
00061     return studyId
00062 
00063 def getStudyEditor(studyId = None):
00064     """
00065     Return a :class:`StudyEditor` instance to edit the study with ID
00066     `studyId`. If `studyId` is :const:`None`, return an editor for the current
00067     study.
00068     """
00069     if studyId is None:
00070         studyId = getActiveStudyId()
00071     if not _editors.has_key(studyId):
00072         _editors[studyId] = StudyEditor(studyId)
00073     return _editors[studyId]
00074 
00075 class StudyEditor:
00076     """
00077     This class provides utility methods to complement :class:`Study` and
00078     :class:`StudyBuilder` classes. Those methods may be moved in those classes
00079     in the future. The parameter `studyId` defines the ID of the study to
00080     edit. If it is :const:`None`, the edited study will be the current study.
00081     The preferred way to get a StudyEditor object is through the method
00082     :meth:`getStudyEditor` which allows to reuse existing instances.
00083 
00084     .. attribute:: studyId
00085     
00086        This instance attribute contains the ID of the edited study. This
00087        attribute should not be modified.
00088 
00089     .. attribute:: study
00090     
00091        This instance attribute contains the underlying :class:`Study` object.
00092        It can be used to access the study but the attribute itself should not
00093        be modified.
00094 
00095     .. attribute:: builder
00096 
00097        This instance attribute contains the underlying :class:`StudyBuilder`
00098        object. It can be used to edit the study but the attribute itself
00099        should not be modified.
00100 
00101     """
00102     def __init__(self, studyId = None):
00103         salome.salome_init()
00104         if studyId is None:
00105             studyId = getActiveStudyId()
00106         self.studyId = studyId
00107         self.study = salome.myStudyManager.GetStudyByID(studyId)
00108         if self.study is None:
00109             raise Exception("Can't create StudyEditor object: "
00110                             "Study %d doesn't exist" % studyId)
00111         self.builder = self.study.NewBuilder()
00112 
00113     def findOrCreateComponent(self, moduleName, componentName = None,
00114                               icon = None, containerName = _DEFAULT_CONTAINER):
00115         """
00116         Find a component corresponding to the Salome module `moduleName` in
00117         the study. If none is found, create a new component and associate it
00118         with the corresponding engine (i.e. the engine named `moduleName`).
00119         Note that in Salome 5, the module name and engine name must be
00120         identical (every module must provide an engine with the same name).
00121         In Salome 6 it will be possible to define a different name for the
00122         engine.
00123 
00124         :type  moduleName: string
00125         :param moduleName: name of the module corresponding to the component
00126                            (the module name is the string value in the
00127                            attribute "AttributeComment" of the component)
00128 
00129         :type  componentName: string
00130         :param componentName: name of the new component if created. If
00131                               :const:`None`, use `moduleName` instead.
00132 
00133         :type  icon: string
00134         :param icon: icon for the new component (attribute "AttributePixMap").
00135 
00136         :type  containerName: string
00137         :param containerName: name of the container in which the engine should be
00138                               loaded.
00139 
00140         :return: the SComponent found or created.
00141 
00142         """
00143         sComponent = self.study.FindComponent(moduleName)
00144         if sComponent is None:
00145             sComponent = self.builder.NewComponent(moduleName)
00146             # Note that the NewComponent method set the "comment" attribute to the
00147             # value of its argument (moduleName here)
00148             if componentName is None:
00149                 componentName = moduleName
00150             self.builder.SetName(sComponent, componentName)
00151             if icon is not None:
00152                 # _MEM_ : This will be effective if and only if "moduleName"
00153                 # really corresponds to the module name (as specified in the
00154                 # SalomeApp.xml)
00155                 self.setIcon(sComponent, icon)
00156 
00157             # This part will stay inactive until Salome 6. In Salome 6, the
00158             # engine name will be stored separately from the module name.
00159             # An internal convention (in this class) is to store the name of the
00160             # associated engine in the parameter attribute of the scomponent (so that
00161             # it could be retrieved in a future usage of this scomponent, for example,
00162             # for the need of the function loadComponentEngine). The comment attribute
00163             # SHOULD NOT be used for this purpose  because it's used by the SALOME
00164             # resources manager to identify the SALOME module and then localized
00165             # the resource files
00166             #attr = self.builder.FindOrCreateAttribute( sComponent, "AttributeParameter" )
00167             #attr.SetString( "ENGINE_NAME", engineName )
00168 
00169             engine = salome.lcc.FindOrLoadComponent(containerName, moduleName)
00170             if engine is None:
00171                 raise Exception("Cannot load engine %s in container %s. See "
00172                                 "logs of container %s for more details." %
00173                                 (moduleName, containerName, containerName))
00174             self.builder.DefineComponentInstance(sComponent, engine)
00175 
00176         return sComponent
00177 
00178     def loadComponentEngine(self, sComponent,
00179                             containerName = _DEFAULT_CONTAINER):
00180         """
00181         Load the engine corresponding to `sComponent` in the container
00182         `containerName`, associate the engine with the component and load the
00183         CORBA objects of this component in the study.
00184         """
00185         # This part will stay inactive until Salome 6. In Salome 6, the
00186         # engine name will be stored separately from the module name.
00187         #attr = self.builder.FindOrCreateAttribute( sComponent, "AttributeParameter" )
00188         #engineName = attr.GetString( "ENGINE_NAME" )
00189         engine = salome.lcc.FindOrLoadComponent(containerName,
00190                                                 sComponent.GetComment())
00191         if engine is None:
00192             raise Exception("Cannot load component %s in container %s. See "
00193                             "logs of container %s for more details." %
00194                             (sComponent.GetComment(), containerName,
00195                              containerName))
00196         self.builder.LoadWith(sComponent, engine)
00197 
00198     def getOrLoadObject(self, item):
00199         """
00200         Get the CORBA object associated with the SObject `item`, eventually by
00201         first loading it with the corresponding engine.
00202         """
00203         object = item.GetObject()
00204         if object is None: # the engine has not been loaded yet
00205             sComponent = item.GetFatherComponent()
00206             self.loadComponentEngine(sComponent)
00207             object = item.GetObject()
00208         return object
00209 
00210     def findOrCreateItem(self, fatherItem, name, fileType = None,
00211                          fileName = None, comment = None, icon = None,
00212                          IOR = None, typeId = None):
00213         """
00214         Find an object under `fatherItem` in the study with the given
00215         attributes. Return the first one found if at least one exists,
00216         otherwise create a new one with the given attributes and return it.
00217         
00218         See :meth:`setItem` for the description of the parameters.
00219         """
00220         sObject = self.findItem(fatherItem, name, fileType, fileName, comment,
00221                                 icon, IOR, typeId)
00222         if sObject is None:
00223             sObject = self.createItem(fatherItem, name, fileType, fileName,
00224                                       comment, icon, IOR, typeId)
00225         return sObject
00226 
00227     def findItem(self, fatherItem, name = None, fileType = None,
00228                  fileName = None, comment = None, icon = None, IOR = None,
00229                  typeId = None):
00230         """
00231         Find an item with given attributes under `fatherItem` in the study. If
00232         none is found, return :const:`None`. If several items correspond to
00233         the parameters, only the first one is returned. The search is made
00234         only on given parameters (i.e. not :const:`None`). To look explicitly
00235         for an empty attribute, use an empty string in the corresponding
00236         parameter.
00237         
00238         See :meth:`setItem` for the description of the parameters.
00239         """
00240         foundItem = None;
00241         childIterator = self.study.NewChildIterator(fatherItem)
00242         while childIterator.More() and foundItem is None:
00243             childItem = childIterator.Value()
00244             if childItem and \
00245                (name is None or childItem.GetName() == name) and \
00246                (fileType is None or \
00247                 self.getFileType(childItem) == fileType) and \
00248                (fileName is None or \
00249                 self.getFileName(childItem) == fileName) and \
00250                (comment is None or childItem.GetComment() == comment) and \
00251                (icon is None or \
00252                 self.getIcon(childItem) == icon) and \
00253                (IOR is None or childItem.GetIOR() == IOR) and \
00254                (typeId is None or \
00255                 self.getTypeId(childItem) == typeId):
00256                 foundItem = childItem
00257             childIterator.Next()
00258         return foundItem
00259 
00260     def createItem(self, fatherItem, name, fileType = None, fileName = None,
00261                    comment = None, icon = None, IOR = None, typeId = None):
00262         """
00263         Create a new object named `name` under `fatherItem` in the study, with
00264         the given attributes. If an object named `name` already exists under
00265         the father object, the new object is created with a new name `name_X`
00266         where X is the first available index.
00267         
00268         :type  fatherItem: SObject
00269         :param fatherItem: item under which the new item will be added.
00270                 
00271         :return: new SObject created in the study
00272         
00273         See :meth:`setItem` for the description of the other parameters.
00274         """
00275         aSObject = self.builder.NewObject(fatherItem)
00276 
00277         aChildIterator = self.study.NewChildIterator(fatherItem)
00278         aMaxId = -1
00279         aLength = len(name)
00280         aDelim = "_"
00281         anIdRE = re.compile("^" + aDelim + "[0-9]+")
00282         aNameRE = re.compile("^" + name)
00283         while aChildIterator.More():
00284             aSObj = aChildIterator.Value()
00285             aChildIterator.Next()
00286             aName = aSObj.GetName()
00287             if re.match(aNameRE,aName):
00288                 aTmp = aName[aLength:]
00289                 if re.match(anIdRE,aTmp):
00290                     import string
00291                     anId = string.atol(aTmp[1:])
00292                     if aMaxId < anId:
00293                         aMaxId = anId
00294                         pass
00295                     pass
00296                 elif aMaxId < 0:
00297                     aMaxId = 0
00298                     pass
00299                 pass
00300             pass
00301         
00302         aMaxId = aMaxId + 1
00303         aName = name
00304         if aMaxId > 0:
00305             aName = aName + aDelim + str(aMaxId)
00306             pass
00307         
00308         self.setItem(aSObject, aName, fileType, fileName, comment, icon,
00309                      IOR, typeId)
00310     
00311         return aSObject
00312 
00313     def setItem(self, item, name = None, fileType = None, fileName = None,
00314                 comment = None, icon = None, IOR = None, typeId = None):
00315         """
00316         Modify the attributes of an item in the study. Unspecified attributes
00317         (i.e. those set to :const:`None`) are left unchanged.
00318 
00319         :type  item: SObject
00320         :param item: item to modify.
00321 
00322         :type  name: string
00323         :param name: item name (attribute 'AttributeName').
00324 
00325         :type  fileType: string
00326         :param fileType: item file type (attribute 'AttributeFileType').
00327 
00328         :type  fileName: string
00329         :param fileName: item file name (attribute
00330                          'AttributeExternalFileDef').
00331 
00332         :type  comment: string
00333         :param comment: item comment (attribute 'AttributeComment'). Note that
00334                         this attribute will appear in the 'Value' column in
00335                         the object browser.
00336 
00337         :type  icon: string
00338         :param icon: item icon name (attribute 'AttributePixMap').
00339 
00340         :type  IOR: string
00341         :param IOR: IOR of a CORBA object associated with the item
00342                     (attribute 'AttributeIOR').
00343 
00344         :type  typeId: integer
00345         :param typeId: item type (attribute 'AttributeLocalID').
00346         """
00347         logger.debug("setItem (ID=%s): name=%s, fileType=%s, fileName=%s, "
00348                      "comment=%s, icon=%s, IOR=%s" %
00349                      (item.GetID(), name, fileType, fileName, comment,
00350                       icon, IOR))
00351         # Explicit cast is necessary for unicode to string conversion
00352         if name is not None:
00353             self.builder.SetName(item, str(name))
00354         if fileType is not None:
00355             self.setFileType(item, fileType)
00356         if fileName is not None:
00357             self.setFileName(item, fileName)
00358         if comment is not None:
00359             self.builder.SetComment(item, str(comment))
00360         if icon is not None:
00361             self.setIcon(item, icon)
00362         if IOR is not None:
00363             self.builder.SetIOR(item, str(IOR))
00364         if typeId is not None:
00365             self.setTypeId(item, typeId)
00366 
00367     def removeItem(self, item, withChildren = False ):
00368         """
00369         Remove the given item from the study. Note that the items are never
00370         really deleted. They just don't appear in the study anymore.
00371 
00372         :type  item: SObject
00373         :param item: the item to be removed
00374 
00375         :type  withChildren: boolean
00376         :param withChildren: if :const:`True`, also remove the children of
00377                              `item`
00378 
00379         :return: :const:`True` if the item was removed successfully, or
00380                  :const:`False` if an error happened.
00381         """
00382         ok = False
00383         try:
00384             if withChildren:
00385                 self.builder.RemoveObjectWithChildren(item)
00386             else:
00387                 self.builder.RemoveObject(item)
00388             ok = True
00389         except:
00390             ok = False
00391         return ok
00392 
00393     def setItemAtTag(self, fatherItem, tag, name = None, fileType = None,
00394                      fileName = None, comment = None, icon = None, IOR = None,
00395                      typeId = None):
00396         """
00397         Find an item tagged `tag` under `fatherItem` in the study tree or
00398         create it if there is none, then set its attributes.
00399         
00400         :type  fatherItem: SObject
00401         :param fatherItem: item under which the tagged item will be looked for
00402                            and eventually created.
00403 
00404         :type  tag: integer
00405         :param tag: tag of the item to look for.
00406 
00407         :return: the SObject at `tag` if found or created successfully, or
00408                  :const:`None` if an error happened.
00409         
00410         See :meth:`setItem` for the description of the other parameters.
00411         """
00412         found, sObj = fatherItem.FindSubObject(tag)
00413         if not found:
00414             sObj = self.builder.NewObjectToTag(fatherItem, tag)
00415         self.setItem(sObj, name, fileType, fileName, comment, icon,
00416                      IOR, typeId)
00417         return sObj
00418 
00419     def getAttributeValue(self, sObject, attributeName, default = None):
00420         """
00421         Return the value of the attribute named `attributeName` on the object
00422         `sObject`, or `default` if the attribute doesn't exist.
00423         """
00424         value = default
00425         found, attr = self.builder.FindAttribute(sObject, attributeName)
00426         if found:
00427             value = attr.Value()
00428         return value
00429 
00430     def setAttributeValue(self, sObject, attributeName, attributeValue):
00431         """
00432         Set the value of the attribute named `attributeName` on the object
00433         `sObject` to the value `attributeValue`.
00434         """        
00435         attr = self.builder.FindOrCreateAttribute(sObject, attributeName)
00436         attr.SetValue(attributeValue)
00437 
00438     def getTypeId(self, sObject):
00439         """
00440         Return the value of the attribute "AttributeLocalID" of the object
00441         `sObject`, or :const:`None` if it is not set.
00442         """
00443         return self.getAttributeValue(sObject, "AttributeLocalID")
00444 
00445     def setTypeId(self, sObject, value):
00446         """
00447         Set the attribute "AttributeLocalID" of the object `sObject` to the
00448         value `value`.
00449         """
00450         self.setAttributeValue(sObject, "AttributeLocalID", value)
00451 
00452     def getFileType(self, sObject):
00453         """
00454         Return the value of the attribute "AttributeFileType" of the object
00455         `sObject`, or an empty string if it is not set.
00456         """
00457         return self.getAttributeValue(sObject, "AttributeFileType", "")
00458 
00459     def setFileType(self, sObject, value):
00460         """
00461         Set the attribute "AttributeFileType" of the object `sObject` to the
00462         value `value`.
00463         """
00464         # Explicit cast is necessary for unicode to string conversion
00465         self.setAttributeValue(sObject, "AttributeFileType", str(value))
00466 
00467     def getFileName(self, sObject):
00468         """
00469         Return the value of the attribute "AttributeExternalFileDef" of the
00470         object `sObject`, or an empty string if it is not set.
00471         """
00472         return self.getAttributeValue(sObject, "AttributeExternalFileDef", "")
00473 
00474     def setFileName(self, sObject, value):
00475         """
00476         Set the attribute "AttributeExternalFileDef" of the object `sObject`
00477         to the value `value`.
00478         """
00479         # Explicit cast is necessary for unicode to string conversion
00480         self.setAttributeValue(sObject, "AttributeExternalFileDef",
00481                                str(value))
00482 
00483     def getIcon(self, sObject):
00484         """
00485         Return the value of the attribute "AttributePixMap" of the object
00486         `sObject`, or an empty string if it is not set.
00487         """
00488         value = ""
00489         found, attr = self.builder.FindAttribute(sObject, "AttributePixMap")
00490         if found and attr.HasPixMap():
00491             value = attr.GetPixMap()
00492         return value
00493 
00494     def setIcon(self, sObject, value):
00495         """
00496         Set the attribute "AttributePixMap" of the object `sObject` to the
00497         value `value`.
00498         """
00499         attr = self.builder.FindOrCreateAttribute(sObject, "AttributePixMap")
00500         # Explicit cast is necessary for unicode to string conversion
00501         attr.SetPixMap(str(value))