Salome HOME
Edit popup
[modules/adao.git] / src / daSalome / daGUI / daGuiImpl / studyedit.py
1 # -*- coding: utf-8 -*-
2 #
3 #  Copyright (C) 2007-2009       EDF R&D
4
5 #    This file is part of PAL_SRC.
6 #
7 #    PAL_SRC is free software; you can redistribute it and/or modify
8 #    it under the terms of the GNU General Public License as published by
9 #    the Free Software Foundation; either version 2 of the License, or
10 #    (at your option) any later version.
11 #
12 #    PAL_SRC is distributed in the hope that it will be useful,
13 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
14 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 #    GNU General Public License for more details.
16 #
17 #    You should have received a copy of the GNU General Public License
18 #    along with PAL_SRC; if not, write to the Free Software
19 #    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
20 #
21 """
22 This module provides a new class :class:`StudyEditor` to complement
23 :class:`Study` and :class:`StudyBuilder` classes.
24 """
25
26 import re
27 import salome
28
29 _editors = {}
30 _DEFAULT_CONTAINER = "FactoryServer"
31
32 def getActiveStudyId():
33     """
34     Return the ID of the active study. In GUI mode, this function is equivalent
35     to ``salome.sg.getActiveStudyId()``. Outside GUI, it returns
36     ``salome.myStudyId`` variable.
37     """
38     salome.salome_init()
39     if salome.hasDesktop():
40         return salome.sg.getActiveStudyId()
41     else:
42         return salome.myStudyId
43
44 def getStudyEditor(studyId = None):
45     """
46     Return a :class:`StudyEditor` instance to edit the study with ID
47     `studyId`. If `studyId` is :const:`None`, return an editor for the current
48     study.
49     """
50     if studyId is None:
51         studyId = getActiveStudyId()
52     if not _editors.has_key(studyId):
53         _editors[studyId] = StudyEditor(studyId)
54     return _editors[studyId]
55
56
57 class StudyEditor:
58     """
59     This class provides utility methods to complement :class:`Study` and
60     :class:`StudyBuilder` classes. Those methods may be moved in those classes
61     in the future. The parameter `studyId` defines the ID of the study to
62     edit. If it is :const:`None`, the edited study will be the current study.
63     The preferred way to get a StudyEditor object is through the method
64     :meth:`getStudyEditor` which allows to reuse existing instances.
65
66     .. attribute:: studyId
67     
68        This instance attribute contains the ID of the edited study. This
69        attribute should not be modified.
70
71     .. attribute:: study
72     
73        This instance attribute contains the underlying :class:`Study` object.
74        It can be used to access the study but the attribute itself should not
75        be modified.
76
77     .. attribute:: builder
78
79        This instance attribute contains the underlying :class:`StudyBuilder`
80        object. It can be used to edit the study but the attribute itself
81        should not be modified.
82
83     """
84     def __init__(self, studyId = None):
85         salome.salome_init()
86         if studyId is None:
87             studyId = getActiveStudyId()
88         self.studyId = studyId
89         self.study = salome.myStudyManager.GetStudyByID(studyId)
90         if self.study is None:
91             raise Exception("Can't create StudyEditor object: "
92                             "Study %d doesn't exist" % studyId)
93         self.builder = self.study.NewBuilder()
94
95     def findOrCreateComponent(self, engineName, componentName = None,
96                               icon = None, loadEngine = True,
97                               containerName = _DEFAULT_CONTAINER):
98         """
99         Find a component corresponding to the engine named `engineName` in the
100         study, or create it if none is found. Then eventually load the
101         corresponding engine and the CORBA objects of this component.
102
103         :type  engineName: string
104         :param engineName: name of the engine corresponding to the component.
105                 
106         :type  componentName: string
107         :param componentName: name of the new component if created. If
108                               :const:`None`, use `engineName` instead.
109         
110         :type  icon: string
111         :param icon: icon for the new component (attribute "AttributePixMap").
112         
113         :type  loadEngine: boolean
114         :param loadEngine: If :const:`True`, find or load the corresponding
115                            engine and associate it with the component.
116
117         :type  containerName: string
118         :param containerName: name of the container in which the component
119                               should be loaded.
120
121         :return: the SComponent found or created.
122
123         """
124         sComponent = self.study.FindComponent(engineName)
125         if sComponent is None:
126             sComponent = self.builder.NewComponent(engineName)
127             if componentName is None:
128                 componentName = engineName
129             self.builder.SetName(sComponent, componentName)
130             
131             if icon is not None:
132                 self.setIcon(sComponent, icon)
133
134             if loadEngine:
135                 self.loadComponentEngine(sComponent, containerName)
136
137         return sComponent
138
139     def loadComponentEngine(self, sComponent,
140                             containerName = _DEFAULT_CONTAINER):
141         """
142         Load the engine corresponding to `sComponent` in the container
143         `containerName`, associate the engine with the component and load the
144         CORBA objects of this component in the study.
145         """
146         engine = salome.lcc.FindOrLoadComponent(containerName,
147                                                 sComponent.GetComment())
148         self.builder.LoadWith(sComponent, engine)
149
150     def getOrLoadObject(self, item):
151         """
152         Get the CORBA object associated with the SObject `item`, eventually by
153         first loading it with the corresponding engine.
154         """
155         object = item.GetObject()
156         if object is None: # the engine has not been loaded yet
157             sComponent = item.GetFatherComponent()
158             self.loadComponentEngine(sComponent)
159             object = item.GetObject()
160         return object
161
162     def findOrCreateItem(self, fatherItem, name, fileType = None,
163                          fileName = None, comment = None, icon = None,
164                          IOR = None, typeId = None):
165         """
166         Find an object under `fatherItem` in the study with the given
167         attributes. Return the first one found if at least one exists,
168         otherwise create a new one with the given attributes and return it.
169         
170         See :meth:`setItem` for the description of the parameters.
171         """
172         sObject = self.findItem(fatherItem, name, fileType, fileName, comment,
173                                 icon, IOR, typeId)
174         if sObject is None:
175             sObject = self.createItem(fatherItem, name, fileType, fileName,
176                                       comment, icon, IOR, typeId)
177         return sObject
178
179     def findItem(self, fatherItem, name = None, fileType = None,
180                  fileName = None, comment = None, icon = None, IOR = None,
181                  typeId = None):
182         """
183         Find an item with given attributes under `fatherItem` in the study. If
184         none is found, return :const:`None`. If several items correspond to
185         the parameters, only the first one is returned. The search is made
186         only on given parameters (i.e. not :const:`None`). To look explicitly
187         for an empty attribute, use an empty string in the corresponding
188         parameter.
189         
190         See :meth:`setItem` for the description of the parameters.
191         """
192         foundItem = None;
193         childIterator = self.study.NewChildIterator(fatherItem)
194         while childIterator.More() and foundItem is None:
195             childItem = childIterator.Value()
196             if childItem and \
197                (name is None or childItem.GetName() == name) and \
198                (fileType is None or \
199                 self.getFileType(childItem) == fileType) and \
200                (fileName is None or \
201                 self.getFileName(childItem) == fileName) and \
202                (comment is None or childItem.GetComment() == comment) and \
203                (icon is None or \
204                 self.getIcon(childItem) == icon) and \
205                (IOR is None or childItem.GetIOR() == IOR and \
206                (typeId is None or \
207                 self.getTypeId(childItem) == typeId)):
208                 foundItem = childItem
209             childIterator.Next()
210         return foundItem
211
212     def createItem(self, fatherItem, name, fileType = None, fileName = None,
213                    comment = None, icon = None, IOR = None, typeId = None):
214         """
215         Create a new object named `name` under `fatherItem` in the study, with
216         the given attributes. If an object named `name` already exists under
217         the father object, the new object is created with a new name `name_X`
218         where X is the first available index.
219         
220         :type  fatherItem: SObject
221         :param fatherItem: item under which the new item will be added.
222                 
223         :return: new SObject created in the study
224         
225         See :meth:`setItem` for the description of the other parameters.
226         """
227         aSObject = self.builder.NewObject(fatherItem)
228
229         aChildIterator = self.study.NewChildIterator(fatherItem)
230         aMaxId = -1
231         aLength = len(name)
232         aDelim = "_"
233         anIdRE = re.compile("^" + aDelim + "[0-9]+")
234         aNameRE = re.compile("^" + name)
235         while aChildIterator.More():
236             aSObj = aChildIterator.Value()
237             aChildIterator.Next()
238             aName = aSObj.GetName()
239             if re.match(aNameRE,aName):
240                 aTmp = aName[aLength:]
241                 if re.match(anIdRE,aTmp):
242                     import string
243                     anId = string.atol(aTmp[1:])
244                     if aMaxId < anId:
245                         aMaxId = anId
246                         pass
247                     pass
248                 elif aMaxId < 0:
249                     aMaxId = 0
250                     pass
251                 pass
252             pass
253         
254         aMaxId = aMaxId + 1
255         aName = name
256         if aMaxId > 0:
257             aName = aName + aDelim + str(aMaxId)
258             pass
259         
260         self.setItem(aSObject, aName, fileType, fileName, comment, icon,
261                      IOR, typeId)
262     
263         return aSObject
264
265     def setItem(self, item, name = None, fileType = None, fileName = None,
266                 comment = None, icon = None, IOR = None, typeId = None):
267         """
268         Modify the attributes of an item in the study. Unspecified attributes
269         (i.e. those set to :const:`None`) are left unchanged.
270
271         :type  item: SObject
272         :param item: item to modify.
273
274         :type  name: string
275         :param name: item name (attribute 'AttributeName').
276
277         :type  fileType: string
278         :param fileType: item file type (attribute 'AttributeFileType').
279
280         :type  fileName: string
281         :param fileName: item file name (attribute
282                          'AttributeExternalFileDef').
283
284         :type  comment: string
285         :param comment: item comment (attribute 'AttributeComment'). Note that
286                         this attribute will appear in the 'Value' column in
287                         the object browser.
288
289         :type  icon: string
290         :param icon: item icon name (attribute 'AttributePixMap').
291
292         :type  IOR: string
293         :param IOR: IOR of a CORBA object associated with the item
294                     (attribute 'AttributeIOR').
295
296         :type  typeId: integer
297         :param typeId: item type (attribute 'AttributeLocalID').
298         """
299         print "setItem (ID=%s): name=%s, fileType=%s, fileName=%s, comment=%s, icon=%s, IOR=%s" % (item.GetID(), name, fileType, fileName, comment, icon, IOR)
300         # Explicit cast is necessary for unicode to string conversion
301         if name is not None:
302             self.builder.SetName(item, str(name))
303         if fileType is not None:
304             self.setFileType(item, fileType)
305         if fileName is not None:
306             self.setFileName(item, fileName)
307         if comment is not None:
308             self.builder.SetComment(item, str(comment))
309         if icon is not None:
310             self.setIcon(item, icon)
311         if IOR is not None:
312             self.builder.SetIOR(item, str(IOR))
313         if typeId is not None:
314             self.setTypeId(item, typeId)
315
316     def removeItem(self, item, withChildren = False ):
317         """
318         Remove the given item from the study (the item still is in
319         the study after the removal)
320         @param   item: the browser object to be removed
321         @param   withChildren: remove children if True
322         """
323         ok = False
324         try:
325             if withChildren:
326                 self.builder.RemoveObjectWithChildren(item)
327             else:
328                 self.builder.RemoveObject(item)
329             ok = True
330         except:
331             ok = False
332
333         return ok
334
335     def setItemAtTag(self, fatherItem, tag, name = None, fileType = None,
336                      fileName = None, comment = None, icon = None, IOR = None,
337                      typeId = None):
338         """
339         Find an item tagged `tag` under `fatherItem` in the study tree or
340         create it if there is none, then set its attributes.
341         
342         :type  fatherItem: SObject
343         :param fatherItem: item under which the tagged item will be looked for
344                            and eventually created.
345
346         :type  tag: integer
347         :param tag: tag of the item to look for.
348
349         :return: the SObject at `tag` if found or created successfully, or
350                  :const:`None` if an error happened.
351         
352         See :meth:`setItem` for the description of the other parameters.
353         """
354         found, sObj = fatherItem.FindSubObject(tag)
355         if not found:
356             sObj = self.builder.NewObjectToTag(fatherItem, tag)
357         self.setItem(sObj, name, fileType, fileName, comment, icon,
358                      IOR, typeId)
359         return sObj
360
361     def getAttributeValue(self, sObject, attributeName, default = None):
362         """
363         Return the value of the attribute named `attributeName` on the object
364         `sObject`, or `default` if the attribute doesn't exist.
365         """
366         value = default
367         found, attr = self.builder.FindAttribute(sObject, attributeName)
368         if found:
369             value = attr.Value()
370         return value
371
372     def setAttributeValue(self, sObject, attributeName, attributeValue):
373         """
374         Set the value of the attribute named `attributeName` on the object
375         `sObject` to the value `attributeValue`.
376         """        
377         attr = self.builder.FindOrCreateAttribute(sObject, attributeName)
378         attr.SetValue(attributeValue)
379
380     def getTypeId(self, sObject):
381         """
382         Return the value of the attribute "AttributeLocalID" of the object
383         `sObject`, or :const:`None` if it is not set.
384         """
385         return self.getAttributeValue(sObject, "AttributeLocalID")
386
387     def setTypeId(self, sObject, value):
388         """
389         Set the attribute "AttributeLocalID" of the object `sObject` to the
390         value `value`.
391         """
392         self.setAttributeValue(sObject, "AttributeLocalID", value)
393
394     def getFileType(self, sObject):
395         """
396         Return the value of the attribute "AttributeFileType" of the object
397         `sObject`, or an empty string if it is not set.
398         """
399         return self.getAttributeValue(sObject, "AttributeFileType", "")
400
401     def setFileType(self, sObject, value):
402         """
403         Set the attribute "AttributeFileType" of the object `sObject` to the
404         value `value`.
405         """
406         # Explicit cast is necessary for unicode to string conversion
407         self.setAttributeValue(sObject, "AttributeFileType", str(value))
408
409     def getFileName(self, sObject):
410         """
411         Return the value of the attribute "AttributeExternalFileDef" of the
412         object `sObject`, or an empty string if it is not set.
413         """
414         return self.getAttributeValue(sObject, "AttributeExternalFileDef", "")
415
416     def setFileName(self, sObject, value):
417         """
418         Set the attribute "AttributeExternalFileDef" of the object `sObject`
419         to the value `value`.
420         """
421         # Explicit cast is necessary for unicode to string conversion
422         self.setAttributeValue(sObject, "AttributeExternalFileDef",
423                                str(value))
424
425     def getIcon(self, sObject):
426         """
427         Return the value of the attribute "AttributePixMap" of the object
428         `sObject`, or an empty string if it is not set.
429         """
430         value = ""
431         found, attr = self.builder.FindAttribute(sObject, "AttributePixMap")
432         if found and attr.HasPixMap():
433             value = attr.GetPixMap()
434         return value
435
436     def setIcon(self, sObject, value):
437         """
438         Set the attribute "AttributePixMap" of the object `sObject` to the
439         value `value`.
440         """
441         attr = self.builder.FindOrCreateAttribute(sObject, "AttributePixMap")
442         # Explicit cast is necessary for unicode to string conversion
443         attr.SetPixMap(str(value))