]> SALOME platform Git repositories - modules/adao.git/commitdiff
Salome HOME
Premier ebauche etude
authorAndré <andre.ribes@edf.fr>
Tue, 27 Apr 2010 15:17:47 +0000 (17:17 +0200)
committerAndré <andre.ribes@edf.fr>
Tue, 27 Apr 2010 15:17:47 +0000 (17:17 +0200)
12 files changed:
configure.ac
src/daSalome/daGUI/Makefile.am
src/daSalome/daGUI/daEficasWrapper/Makefile.am [new file with mode: 0644]
src/daSalome/daGUI/daEficasWrapper/__init__.py [new file with mode: 0644]
src/daSalome/daGUI/daEficasWrapper/datassimEficasWrapper.py [new file with mode: 0644]
src/daSalome/daGUI/daEficasWrapper/eficasWrapper.py.in [new file with mode: 0644]
src/daSalome/daGUI/daGuiImpl/Makefile.am
src/daSalome/daGUI/daGuiImpl/datassimGuiHelper.py [new file with mode: 0644]
src/daSalome/daGUI/daGuiImpl/datassimGuiManager.py
src/daSalome/daGUI/daGuiImpl/datassimModuleHelper.py [new file with mode: 0644]
src/daSalome/daGUI/daGuiImpl/datassimStudyEditor.py [new file with mode: 0644]
src/daSalome/daGUI/daGuiImpl/studyedit.py [new file with mode: 0644]

index 17c07236e3e22ea7b3ea4ed8439d1fa95b4dc8b7..ac4803ca624b29bf71d26b2f11ce3accba4a39a5 100644 (file)
@@ -71,6 +71,8 @@ AC_CONFIG_FILES([
         src/daSalome/Makefile
         src/daSalome/daGUI/Makefile
         src/daSalome/daGUI/daGuiImpl/Makefile
+        src/daSalome/daGUI/daEficasWrapper/Makefile
+        src/daSalome/daGUI/daEficasWrapper/eficasWrapper.py
         bin/Makefile
         bin/qtEficas_datassim_study.py
         ])
index f71a46b629c8ebf34a87cd15cbd4aba58b4125f9..738c844b9f63b551381e8115ca2334b3dfe415e0 100644 (file)
@@ -17,7 +17,7 @@
 #  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 #
 
-SUBDIRS = daGuiImpl
+SUBDIRS = daGuiImpl daEficasWrapper
 
 include $(top_srcdir)/adm_local/make_common_starter.am
 
diff --git a/src/daSalome/daGUI/daEficasWrapper/Makefile.am b/src/daSalome/daGUI/daEficasWrapper/Makefile.am
new file mode 100644 (file)
index 0000000..7b0f6a3
--- /dev/null
@@ -0,0 +1,32 @@
+#  Copyright (C) 2010 EDF R&D
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+#  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+include $(top_srcdir)/adm_local/make_common_starter.am
+
+mypkgpythondir =$(salomepythondir)/daEficasWrapper
+
+mypkgpython_PYTHON = \
+                    eficasWrapper.py \
+                    __init__.py \
+                    datassimEficasWrapper.py
+
+EXTRA_DIST = eficasWrapper.py.in
+
+
+
diff --git a/src/daSalome/daGUI/daEficasWrapper/__init__.py b/src/daSalome/daGUI/daEficasWrapper/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/src/daSalome/daGUI/daEficasWrapper/datassimEficasWrapper.py b/src/daSalome/daGUI/daEficasWrapper/datassimEficasWrapper.py
new file mode 100644 (file)
index 0000000..5963037
--- /dev/null
@@ -0,0 +1,58 @@
+# -*- coding: iso-8859-1 -*-
+#  Copyright (C) 2010 EDF R&D
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+#  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+from eficasWrapper import *
+import sys
+
+# Configuration de l'installation
+my_path = os.path.dirname(os.path.abspath(__file__))
+DATASSIM_INSTALL_DIR = my_path + "/../daEficas"
+sys.path[:0]=[DATASSIM_INSTALL_DIR]
+
+#
+# ================================================
+# Specialization of the EficasWrapper for DATASSIM
+# ================================================
+#
+class DatassimEficasWrapper(EficasWrapper):
+    def __init__(self, parent, code="DATASSIM"):
+        EficasWrapper.__init__(self, parent, code)
+
+    def fileSave(self):
+        """
+        @overload
+        """
+        qtEficas.Appli.fileSave(self)
+        self.notifyObserver(EficasEvent.EVENT_TYPES.SAVE)
+
+    def fileSaveAs(self):
+        """
+        @overload
+        """
+        qtEficas.Appli.fileSaveAs(self)
+        self.notifyObserver(EficasEvent.EVENT_TYPES.SAVE)
+
+    def getCurrentFileName(self):
+       index = self.viewmanager.myQtab.currentIndex()
+       print index
+       rtn = ""
+       if index > 0 :
+         rtn  = self.viewmanager.myQtab.tabText(index)
+       return rtn
diff --git a/src/daSalome/daGUI/daEficasWrapper/eficasWrapper.py.in b/src/daSalome/daGUI/daEficasWrapper/eficasWrapper.py.in
new file mode 100644 (file)
index 0000000..4b646df
--- /dev/null
@@ -0,0 +1,278 @@
+# -*- coding: iso-8859-1 -*-
+#  Copyright (C) 2010 EDF R&D
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+#  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+__author__="aribes/gboulant"
+
+# HACK - Pour l'instant
+import logging
+logging.basicConfig(level=logging.DEBUG, format='%(levelname)-8s %(message)s')
+logger = logging.getLogger()
+
+class DevelException(Exception):
+    def __init__(self, message):
+        """Canonical constructor"""
+        Exception.__init__(self,message)
+
+#
+# ==============================================================================
+# Interface of an eficas observer (for implementing the subject/observer pattern)
+# ==============================================================================
+#
+from daGuiImpl.enumerate import Enumerate
+class EficasObserver:
+    """
+    This class specifies the interface of an eficas observer. See example at the
+    bottom of this file.
+    """
+    def processEficasEvent(self, eficasWrapper, eficasEvent):
+        """
+        This function should be implemented in the concrete Observer.
+        @param eficasWrapper the instance of the source EficasWrapper
+        @param eficasEvent the emitted event (instance of EficasEvent)
+        """
+        raise DevelException("processEficasEvent not implemented yet")
+
+class EficasEvent:
+    EVENT_TYPES=Enumerate([
+        'CLOSE',
+        'SAVE'
+    ])
+
+    def __init__(self,eventType,callbackId=None):
+        """
+        Creates an eficas event to be used by an EficasWrapper to notify an
+        EficasObserver.
+
+        The eventType depends of the context of creation. It specify the nature
+        of the event inside EficasWrapper that triggers the creation of this instance.
+        
+        The callbackId is an object used by the EficasObserver to map the
+        notification (this received event) with the initial event (callback)
+        This object can be anything and has to be defined through a convention
+        that both the EficasWrapper and the EficasObserver can understand.
+        Typically, the eficas observer set the callback id to the eficas wrapper
+        before running the asynchronous show. Then, when an event is raised by
+        the eficas wrapper toward its observer, it embeds the callback id so that
+        the observer can match the received event to the initial trigger context.
+        
+        @param the eventType to be choosen in the EVENT_TYPES
+        @param callbackId an arbitrary data object
+        """
+        if not self.EVENT_TYPES.isValid(eventType):
+            raise DevelException("The event type "+str(eventType)+" is not defined")
+
+        self.eventType = eventType
+        self.callbackId = callbackId
+
+#
+# ==============================================================================
+# Definition of an Eficas wrapper for integration to the SALOME framework
+# This wrapper is not specific to the OMA context and is intended not to be.
+# ==============================================================================
+#
+eficasPath = '@EFICAS_DIR@'
+import os
+if os.environ.has_key( "EFICAS_ROOT"):
+    eficasPath = os.environ["EFICAS_ROOT"]
+import sys
+sys.path[:0]=[eficasPath,
+              os.path.join( eficasPath,'Editeur'),
+              os.path.join( eficasPath,'UiQT4'),
+             ]
+
+import Editeur
+from InterfaceQT4 import qtEficas
+
+class EficasWrapper(qtEficas.Appli):
+
+    def __init__(self, parent, code , fichier=None, module="Eficas", version=None, salome=0):
+
+        self.__codetype = code
+        self.__jdc = None
+
+        # variables for the notification procedure
+        self.__observer  = None
+        self.__callbackId = None
+
+        # The convention is that the python pref associated to the code are in
+        # a folder whose name is the code name with lower letters but the
+        # first that is in capital letter.
+        pathCode=code[0]+code[1:].lower()
+        sys.path[:0]=[os.path.join(eficasPath,pathCode)]
+
+        if Editeur.__dict__.has_key( 'session' ):
+            from Editeur import session
+            eficasArg = []
+            eficasArg += sys.argv
+            if fichier:
+                eficasArg += [ fichier ]
+            if version:
+                eficasArg += [ "-c", version ]
+            else :
+                print "noversion"
+            session.parse( eficasArg )
+
+        qtEficas.Appli.__init__( self,code=code,salome=salome,parent=parent)
+
+    def setCodeType(self,code):
+        self.__codetype = code
+
+    def setJdc(self, value, name=None):
+        self.__jdc = value
+        if self.__jdc is None:
+            editor = self.viewmanager.getEditor()
+            editor.fichier = os.path.abspath(unicode("/tmp/eficasfile.comm"))
+        else:
+            fichier = os.path.abspath(unicode("/tmp/eficasfile.comm"))
+            f = open(fichier,'w')
+            f.write(self.__jdc)
+            f.close()
+            editor=self.viewmanager.getEditor( fichier,units=None)
+
+        # _TODO_ set the name and indicate that it's not used to ask a filename
+        #index=self.viewmanager.myQtab.currentIndex()
+        #self.viewmanager.myQtab.setTabText(index,fileName)
+
+    def getJdc(self):
+        # First update the jdc attribute and return the value
+        self.__jdc = self.__getJdcText()
+        return self.__jdc
+
+    # ==========================================================================
+    # Function for the notification interface between an EficasWrapper an an
+    # EficasObserver.
+    #
+    def addObserver(self, observer):
+        """
+        In fact, only one observer may be defined for the moment.
+        """
+        try:
+            observer.processEficasEvent
+        except:
+            raise DevelException("the argument should implement the function processEficasEvent")
+        self.__observer = observer
+
+    def notifyObserver(self, eventType):
+        eficasEvent = EficasEvent(eventType, self.getCallbackId())
+        self.__observer.processEficasEvent(self, eficasEvent)
+
+    def setCallbackId(self, callbackId):
+        """
+        This function should be used to define the callback identifier that
+        will be used by the observer to map the notifcation event with the source
+        event.
+        @param callbackId Any object to be used in the notification interface
+        """
+        self.__callbackId = callbackId
+
+    def getCallbackId(self):
+        return self.__callbackId
+
+    # ==========================================================================
+    # Functions to handle the Eficas callback functions
+    #
+    def closeEvent(self,event):
+        """
+        This method is a notification function called at the end of the eficas
+        processes quit/exit.
+        This close event has to be overload to handle the management of data
+        saving process, and to prevent the application from bug when reopen
+        eficas after a first close operation inside SALOME.
+        @overload
+        """
+        logger.debug("#### Handle closeEvent")
+
+        # Get the data and notify the observers of the event
+        # _TODO_ get data
+        self.notifyObserver(EficasEvent.EVENT_TYPES.CLOSE)
+        self.fileCloseAll()
+
+        # This is to prevent from bug when reopen eficas after a first close
+        # operation inside SALOME.
+        import InterfaceQT4.readercata
+        if hasattr(InterfaceQT4.readercata,'reader') :
+           del InterfaceQT4.readercata.reader
+        event.accept()
+
+
+    def fileSave(self):
+        """
+        @overload
+        """
+        logger.debug("This is my fileSave")
+        # Notify the observers of the event
+        self.notifyObserver(EficasEvent.EVENT_TYPES.SAVE)
+
+        qtEficas.Appli.fileSave(self)
+
+
+    def fileSaveAs(self):
+        """
+        @overload
+        """
+        logger.debug("This is my fileSaveAs")
+        self.fileSave()
+
+    def fileClose(self):
+        """
+        @overload
+        """
+        logger.debug("This is my fileClose")
+        qtEficas.Appli.fileClose(self)
+
+    def fileCloseAll(self):
+        """
+        @overload
+        """
+        logger.debug("This is my fileCloseAll")
+        qtEficas.Appli.fileCloseAll(self)
+
+    # ==========================================================================
+    # helper functions
+    #
+    def __getJdcText(self):
+        """
+        This function returns the current jdc in text format.
+        """
+        index=self.viewmanager.myQtab.currentIndex()
+        if index < 0 : return
+
+        editor=self.viewmanager.dict_editors[index]
+        format = self.format_fichier
+        strSource = str( editor.get_text_JDC(format) )
+        return strSource
+
+    def displayNew(self):
+        self.fileNew()
+        self.show()
+
+    # ==========================================================================
+    # Test functions ...
+    #
+    def __displayData(self, textjdc):
+        index=self.viewmanager.myQtab.currentIndex()
+        if index < 0 : return
+
+        editor=self.viewmanager.dict_editors[index]
+
+        jdc=editor.readercata.cata[0].JdC(procedure=textjdc,appli=editor,cata=editor.readercata.cata,cata_ord_dico=editor.readercata.cata_ordonne_dico,nom="JDC name",rep_mat=editor.CONFIGURATION.rep_mat)
+        self.viewmanager.getEditor("toto.com",jdc)
+
+
index b0781de2fbcd7ba258d2f46c4a1d7d5d1711e925..2c142b4df8ede714256ddcce292e6881d77fb815 100644 (file)
@@ -25,6 +25,10 @@ mypkgpython_PYTHON = \
                     __init__.py \
                     DATASSIMGUI_impl.py \
                     datassimGuiManager.py \
+                    datassimGuiHelper.py \
+                    datassimModuleHelper.py \
+                    datassimStudyEditor.py \
+                    studyedit.py \
                     enumerate.py
 
 
diff --git a/src/daSalome/daGUI/daGuiImpl/datassimGuiHelper.py b/src/daSalome/daGUI/daGuiImpl/datassimGuiHelper.py
new file mode 100644 (file)
index 0000000..be7bee9
--- /dev/null
@@ -0,0 +1,121 @@
+# -*- coding: iso-8859-1 -*-
+#  Copyright (C) 2010 EDF R&D
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+#  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+__author__="aribes/gboulant"
+
+import salome
+# Get SALOME PyQt interface
+import SalomePyQt
+__sgPyQt = SalomePyQt.SalomePyQt()
+
+import datassimModuleHelper
+from PyQt4 import QtGui,QtCore
+
+def waitCursor():
+    QtGui.QApplication.setOverrideCursor(QtGui.QCursor(QtCore.Qt.WaitCursor))
+
+def restoreCursor():
+    QtGui.QApplication.restoreOverrideCursor()
+
+def gui_warning(parent, msg="An error occurs" ):
+    """
+    This function displays a message dialog box displaying the specified message.
+    """
+    QtGui.QMessageBox.warning( parent, "Alerte", msg)
+
+def getActiveStudyId():
+    """
+    This function returns the id of the active study. The concept of active study
+    makes sens only in the GUI context.
+    """
+    return __sgPyQt.getStudyId()
+
+
+def getActiveStudy():
+    """
+    This function returns the active study reference. The concept of active study
+    makes sens only in the GUI context.
+    """
+    studyId = getActiveStudyId()()
+    study = datassimModuleHelper.getStudyManager().GetStudyByID( studyId )
+    return study
+
+def refreshObjectBrowser():
+    """
+    Refresh the graphical representation of the SALOME study, in case where the
+    GUI is working.
+    """
+    if salome.sg is not None:
+        salome.sg.updateObjBrowser(0)
+
+def getSelectedItem(salomeStudyId=getActiveStudyId()):
+    """
+    Get the current selection. If more than one item are selected, the
+    only first is considered. The object is return (not the id).
+    The item can be of any type, no control is done in this function.
+    """
+    if salome.sg is None:
+        raise Exception("GuiHelper.getSelectedItem can't be used without the GUI context")
+
+    salomeStudy = datassimModuleHelper.getStudyManager().GetStudyByID( salomeStudyId )
+
+    item = None
+    listEntries=salome.sg.getAllSelected()
+    if len(listEntries) >= 1:
+        entry = listEntries[0]
+        item = salomeStudy.FindObjectID( entry )
+
+    return item
+
+def getAllSelected(salomeStudyId):
+    """
+    Returns all selected items in the specified study.
+    """
+    if salome.sg is None:
+        raise OmaException("getSelectedItem can't be used without the GUI context", OmaException.TYPES.DEVEL)
+
+    study = datassimModuleHelper.getStudyManager().GetStudyByID( salomeStudyId )
+    selcount = salome.sg.SelectedCount()
+    seltypes = {}
+    for i in range( selcount ):
+        __incObjToMap( seltypes, datassimModuleHelper.getObjectID( study, salome.sg.getSelected( i ) ) )
+        pass
+    return selcount, seltypes
+
+def __incObjToMap( m, id ):
+    """
+    Increment object counter in the specified map.
+    Not to be used outside this module.
+    """
+    if id not in m: m[id] = 0
+    m[id] += 1
+    pass
+
+def getDesktop():
+    """
+    Returns the active Desktop. Usefull to set the relative position of a dialog box
+    """
+    return __sgPyQt.getDesktop()
+
+def warning(msg):
+    """
+    This function displays a message dialog box displaying the specified message.
+    """
+    gui_warning(getDesktop(),msg)
index 811ef9db962e65b2c07d0cd9ecdb02bb256ae5ef..9d53d56a4dc5cc58a6663d5b56d48d010357cadf 100644 (file)
@@ -31,6 +31,12 @@ import SalomePyQt
 sgPyQt = SalomePyQt.SalomePyQt()
 
 from daGuiImpl.enumerate import Enumerate
+from daEficasWrapper.datassimEficasWrapper import DatassimEficasWrapper
+from daEficasWrapper.eficasWrapper import EficasObserver
+from daEficasWrapper.eficasWrapper import EficasEvent
+import datassimGuiHelper
+import datassimStudyEditor
+
 #
 # ==============================================================================
 # Classes to manage the building of UI components
@@ -67,12 +73,11 @@ class DatassimGuiUiComponentBuilder:
         sgPyQt.createMenu(a, mid)
         sgPyQt.createTool(a, tid)
 
-class DatassimGuiActionImpl():
+class DatassimGuiActionImpl(EficasObserver):
     """
     This class implements the ui actions concerning the management of oma study
     cases.
     """
-    __dlgNewStudyCase = None
     __dlgEficasWrapper = None
 
     def __init__(self):
@@ -80,7 +85,8 @@ class DatassimGuiActionImpl():
         # This dialog is created once so that it can be recycled for each call
         # to newOmaCase().
         #self.__dlgNewStudyCase = DlgNewStudyCase()
-        #self.__dlgEficasWrapper = OmaEficasWrapper(parent=SalomePyQt.SalomePyQt().getDesktop())
+        self.__dlgEficasWrapper = DatassimEficasWrapper(parent=SalomePyQt.SalomePyQt().getDesktop())
+        self.__dlgEficasWrapper.addObserver(self)
 
     # ==========================================================================
     # Processing of ui actions
@@ -101,3 +107,47 @@ class DatassimGuiActionImpl():
 
     def newDatassimCase(self):
       print "newDatassimCase"
+      salomeStudyId   = datassimGuiHelper.getActiveStudyId()
+      salomeStudyItem = datassimStudyEditor.addInStudy(salomeStudyId, "newDatassimCase")
+      datassimGuiHelper.refreshObjectBrowser()
+      callbackId = [salomeStudyId, salomeStudyItem]
+      self.__dlgEficasWrapper.setCallbackId(callbackId)
+      self.__dlgEficasWrapper.displayNew()
+
+    # ==========================================================================
+    # Processing notifications from eficas
+    #
+    __processOptions={
+        EficasEvent.EVENT_TYPES.CLOSE : "_processEficasCloseEvent",
+        EficasEvent.EVENT_TYPES.SAVE  : "_processEficasSaveEvent"
+        }
+    def processEficasEvent(self, eficasWrapper, eficasEvent):
+        """
+        Implementation of the interface EficasObserver. The implementation is a
+        switch on the possible types of events defined in EficasEvent.EVENT_TYPES.
+        @overload
+        """
+        functionName = self.__processOptions.get(eficasEvent.eventType, lambda : "_processEficasUnknownEvent")
+        return getattr(self,functionName)(eficasWrapper, eficasEvent)
+
+    def _processEficasCloseEvent(self, eficasWrapper, eficasEvent):
+        print "This is the process of EficasCloseEvent"
+        print "Remove datassim case in study if empty..."
+        pass
+
+    def _processEficasSaveEvent(self, eficasWrapper, eficasEvent):
+        callbackId = eficasEvent.callbackId
+        if callbackId is None:
+            raise DevelException("the callback data should not be None. Can't guess what are the study and case")
+        [targetSalomeStudyId,targetSalomeStudyItem] = callbackId
+        if ( targetSalomeStudyId is None ) or ( targetSalomeStudyItem is None ):
+            raise DevelException("the parameters targetSalomeStudyId and targetSalomeStudyItem should not be None")
+
+        file_name = eficasWrapper.getCurrentFileName()
+        datassimStudyEditor.updateItem(targetSalomeStudyId, targetSalomeStudyItem, file_name)
+        #studyCase = omaStudyEditor.getOmaCaseFromItem(targetSalomeStudyId, targetSalomeStudyItem)
+        #studyCase = eficasWrapper.getData(studyCase)
+        #logger.debug("jdc="+str(studyCase.userdata.getJdc()))
+
+    def _processEficasUnknownEvent(self, eficasWrapper, eficasEvent):
+      print "Unknown Eficas Event"
diff --git a/src/daSalome/daGUI/daGuiImpl/datassimModuleHelper.py b/src/daSalome/daGUI/daGuiImpl/datassimModuleHelper.py
new file mode 100644 (file)
index 0000000..c30957f
--- /dev/null
@@ -0,0 +1,211 @@
+# -*- coding: iso-8859-1 -*-
+#  Copyright (C) 2007-2008  CEA/DEN, EDF R&D, OPEN CASCADE
+#
+#  Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+#  CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+#  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+# ---
+# Author : Vadim SANDLER, Open CASCADE S.A.S. (vadim.sandler@opencascade.com)
+# ---
+#
+
+__all__ = [
+    "moduleID",
+    "objectID",
+    "unknownID",
+    "componentName",
+    "modulePixmap",
+    "verbose",
+    "getORB",
+    "getNS",
+    "getLCC",
+    "getStudyManager",
+    "getEngine",
+    "getEngineIOR",
+    "findOrCreateComponent",
+    "getObjectID",
+    ]
+
+from omniORB import CORBA
+from SALOME_NamingServicePy import SALOME_NamingServicePy_i
+from LifeCycleCORBA import LifeCycleCORBA
+import SALOMEDS
+import SALOMEDS_Attributes_idl
+
+#import OMA_ORB
+
+###
+# Get OMA module's ID
+###
+def moduleID():
+    MODULE_ID = 1100
+    return MODULE_ID
+
+###
+# Get OMA object's ID
+###
+def objectID():
+    OBJECT_ID = 1110
+    return OBJECT_ID
+
+###
+# Get unknown ID
+###
+def unknownID():
+    FOREIGN_ID = -1
+    return FOREIGN_ID
+
+def componentName():
+    """
+    This provide the name of the module component to be associated to the study.
+    """
+    # Note that this name should be (i) the name used for the class implementing
+    # the component CORBA interface and (ii) the name used to declare the component
+    # in the catalog of the module.
+    return "DATASSIM"
+
+# _MEM_ we use here the tr() translation methode to manage constant parameters
+# in the application. We could have specified instead constant values directly
+# in the code below. It's a matter of convenience.
+from PyQt4.QtCore import QObject
+QObjectTR=QObject()
+
+def componentUserName():
+    return "DATASSIM"
+
+def modulePixmap():
+    """
+    Get the reference pixmap for this module.
+    """
+    return "DATASSIM_small.png"
+
+__verbose__ = None
+def verbose():
+    global __verbose__
+    if __verbose__ is None:
+        try:
+            __verbose__ = int( os.getenv( 'SALOME_VERBOSE', 0 ) )
+        except:
+            __verbose__ = 0
+            pass
+        pass
+    return __verbose__
+
+###
+# Get ORB reference
+###
+__orb__ = None
+def getORB():
+    global __orb__
+    if __orb__ is None:
+        __orb__ = CORBA.ORB_init( [''], CORBA.ORB_ID )
+        pass
+    return __orb__
+
+###
+# Get naming service instance
+###
+__naming_service__ = None
+def getNS():
+    global __naming_service__
+    if __naming_service__ is None:
+        __naming_service__ = SALOME_NamingServicePy_i( getORB() )
+        pass
+    return __naming_service__
+
+##
+# Get life cycle CORBA instance
+##
+__lcc__ = None
+def getLCC():
+    global __lcc__
+    if __lcc__ is None:
+        __lcc__ = LifeCycleCORBA( getORB() )
+        pass
+    return __lcc__
+
+##
+# Get study manager
+###
+__study_manager__ = None
+def getStudyManager():
+    global __study_manager__
+    if __study_manager__ is None:
+        obj = getNS().Resolve( '/myStudyManager' )
+        __study_manager__ = obj._narrow( SALOMEDS.StudyManager )
+        pass
+    return __study_manager__
+
+###
+# Get OMA engine
+###
+__engine__ = None
+def getEngine():
+    global __engine__
+    if __engine__ is None:
+        __engine__ = getLCC().FindOrLoadComponent( "FactoryServer", componentName() )
+        pass
+    return __engine__
+
+###
+# Get OMA engine IOR
+###
+def getEngineIOR():
+    IOR = ""
+    if getORB() and getEngine():
+        IOR = getORB().object_to_string( getEngine() )
+        pass
+    return IOR
+
+###
+# Find or create OMA component object in a study
+###
+def findOrCreateComponent( study ):
+    father = study.FindComponent( componentName() )
+    if father is None:
+        builder = study.NewBuilder()
+        father = builder.NewComponent( componentName() )
+        attr = builder.FindOrCreateAttribute( father, "AttributeName" )
+        attr.SetValue( componentName() )
+        attr = builder.FindOrCreateAttribute( father, "AttributePixMap" )
+        attr.SetPixMap( modulePixmap() )
+        attr = builder.FindOrCreateAttribute( father, "AttributeLocalID" )
+        attr.SetValue( moduleID() )
+        try:
+            builder.DefineComponentInstance( father, getEngine() )
+            pass
+        except:
+            pass
+        pass
+    return father
+
+###
+# Get object's ID
+###
+def getObjectID( study, entry ):
+    ID = unknownID()
+    if study and entry:
+        sobj = study.FindObjectID( entry )
+        if sobj is not None:
+            test, anAttr = sobj.FindAttribute( "AttributeLocalID" )
+            if test: ID = anAttr._narrow( SALOMEDS.AttributeLocalID ).Value()
+            pass
+        pass
+    return
+
diff --git a/src/daSalome/daGUI/daGuiImpl/datassimStudyEditor.py b/src/daSalome/daGUI/daGuiImpl/datassimStudyEditor.py
new file mode 100644 (file)
index 0000000..42eac25
--- /dev/null
@@ -0,0 +1,122 @@
+# -*- coding: iso-8859-1 -*-
+#  Copyright (C) 2010 EDF R&D
+#
+#  This library is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU Lesser General Public
+#  License as published by the Free Software Foundation; either
+#  version 2.1 of the License.
+#
+#  This library is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+#  Lesser General Public License for more details.
+#
+#  You should have received a copy of the GNU Lesser General Public
+#  License along with this library; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
+#
+#  See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+#
+
+__author__="aribes/gboulant"
+
+from enumerate import Enumerate
+import studyedit
+import datassimModuleHelper
+
+#
+# ==============================================================================
+# Constant parameters and identifiers
+# ==============================================================================
+#
+DATASSIM_ITEM_TYPES = Enumerate([
+    "DATASSIM_CASE",
+])
+
+#
+# ==============================================================================
+# Function dedicated to the data management in the salome study
+# ==============================================================================
+# 
+# For developpers, note that the data structures used here are:
+# - the SALOME study whose API is defined by SALOMEDS::Study
+# - an item in a study whose API is defined by SALOMEDS:SObject
+# - a study component, whose API is defined by SALOMEDS::SComponent
+#   a SComponent is a reference in a study toward a SALOME component
+#
+
+def addInStudy(salomeStudyId, datassimCase):
+    """
+    This function adds in the specified SALOME study a study entry that corresponds
+    to the specified datassim case. This study case is put in a folder under
+    the DATASSIM component and is identified by the case name.
+    """
+
+    studyEditor = studyedit.getStudyEditor(salomeStudyId)
+
+    datassimRootEntry = studyEditor.findOrCreateComponent(
+        engineName    = datassimModuleHelper.componentName(),
+        componentName = datassimModuleHelper.componentUserName())
+
+    itemName  = datassimCase
+    itemValue = ""
+    itemType  = DATASSIM_ITEM_TYPES.DATASSIM_CASE
+
+    salomeStudyItem = studyEditor.createItem(
+        datassimRootEntry, itemName,
+        comment = itemValue,
+        typeId  = itemType)
+    # _MEM_ Note that we use the comment attribute to store the serialize
+    # description of the data.
+
+    return salomeStudyItem
+
+def updateItem(salomeStudyId, salomeStudyItem, datassimCase):
+
+    studyEditor = studyedit.getStudyEditor(salomeStudyId)
+    
+    itemName  = datassimCase
+    itemValue = ""
+
+    studyEditor.setItem(salomeStudyItem,
+        name    = itemName,
+        comment = itemValue)
+
+def removeItem(salomeStudyId, item):
+    """
+    Remove the item from the specified study.
+    """
+    if not isValidDatassimCaseItem(salomeStudyId, item):
+        return False
+    studyEditor = studyedit.getStudyEditor(salomeStudyId)
+    return studyEditor.removeItem(item,True)
+
+
+def isValidDatassimCaseItem(salomeStudyId,item):
+    """
+    Return true if the specified item corresponds to a valid datassimCase
+    """
+    if item is None:
+        return False
+
+    studyEditor = studyedit.getStudyEditor(salomeStudyId)
+    itemType = studyEditor.getTypeId(item)
+    if itemType != DATASSIM_ITEM_TYPES.DATASSIM_CASE:
+        return False
+
+    return True
+
+
+def getDatassimCaseFromItem(salomeStudyId, item):
+    """
+    Get the datassim case from the selected item.
+    Note that the study must be specify to retrieve the attributes value from
+    the item reference. The attribute values are stored in the study object.
+    """
+    if not isValidDatassimCaseItem(salomeStudyId, item):
+        return None
+
+    itemName  = item.GetName()
+    itemValue = item.GetComment()
+    return itemName
+
diff --git a/src/daSalome/daGUI/daGuiImpl/studyedit.py b/src/daSalome/daGUI/daGuiImpl/studyedit.py
new file mode 100644 (file)
index 0000000..f513b14
--- /dev/null
@@ -0,0 +1,443 @@
+# -*- coding: utf-8 -*-
+#
+#  Copyright (C) 2007-2009      EDF R&D
+# 
+#    This file is part of PAL_SRC.
+#
+#    PAL_SRC is free software; you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation; either version 2 of the License, or
+#    (at your option) any later version.
+#
+#    PAL_SRC is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with PAL_SRC; if not, write to the Free Software
+#    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+#
+"""
+This module provides a new class :class:`StudyEditor` to complement
+:class:`Study` and :class:`StudyBuilder` classes.
+"""
+
+import re
+import salome
+
+_editors = {}
+_DEFAULT_CONTAINER = "FactoryServer"
+
+def getActiveStudyId():
+    """
+    Return the ID of the active study. In GUI mode, this function is equivalent
+    to ``salome.sg.getActiveStudyId()``. Outside GUI, it returns
+    ``salome.myStudyId`` variable.
+    """
+    salome.salome_init()
+    if salome.hasDesktop():
+        return salome.sg.getActiveStudyId()
+    else:
+        return salome.myStudyId
+
+def getStudyEditor(studyId = None):
+    """
+    Return a :class:`StudyEditor` instance to edit the study with ID
+    `studyId`. If `studyId` is :const:`None`, return an editor for the current
+    study.
+    """
+    if studyId is None:
+        studyId = getActiveStudyId()
+    if not _editors.has_key(studyId):
+        _editors[studyId] = StudyEditor(studyId)
+    return _editors[studyId]
+
+
+class StudyEditor:
+    """
+    This class provides utility methods to complement :class:`Study` and
+    :class:`StudyBuilder` classes. Those methods may be moved in those classes
+    in the future. The parameter `studyId` defines the ID of the study to
+    edit. If it is :const:`None`, the edited study will be the current study.
+    The preferred way to get a StudyEditor object is through the method
+    :meth:`getStudyEditor` which allows to reuse existing instances.
+
+    .. attribute:: studyId
+    
+       This instance attribute contains the ID of the edited study. This
+       attribute should not be modified.
+
+    .. attribute:: study
+    
+       This instance attribute contains the underlying :class:`Study` object.
+       It can be used to access the study but the attribute itself should not
+       be modified.
+
+    .. attribute:: builder
+
+       This instance attribute contains the underlying :class:`StudyBuilder`
+       object. It can be used to edit the study but the attribute itself
+       should not be modified.
+
+    """
+    def __init__(self, studyId = None):
+        salome.salome_init()
+        if studyId is None:
+            studyId = getActiveStudyId()
+        self.studyId = studyId
+        self.study = salome.myStudyManager.GetStudyByID(studyId)
+        if self.study is None:
+            raise Exception("Can't create StudyEditor object: "
+                            "Study %d doesn't exist" % studyId)
+        self.builder = self.study.NewBuilder()
+
+    def findOrCreateComponent(self, engineName, componentName = None,
+                              icon = None, loadEngine = True,
+                              containerName = _DEFAULT_CONTAINER):
+        """
+        Find a component corresponding to the engine named `engineName` in the
+        study, or create it if none is found. Then eventually load the
+        corresponding engine and the CORBA objects of this component.
+
+        :type  engineName: string
+        :param engineName: name of the engine corresponding to the component.
+                
+        :type  componentName: string
+        :param componentName: name of the new component if created. If
+                              :const:`None`, use `engineName` instead.
+        
+        :type  icon: string
+        :param icon: icon for the new component (attribute "AttributePixMap").
+        
+        :type  loadEngine: boolean
+        :param loadEngine: If :const:`True`, find or load the corresponding
+                           engine and associate it with the component.
+
+        :type  containerName: string
+        :param containerName: name of the container in which the component
+                              should be loaded.
+
+        :return: the SComponent found or created.
+
+        """
+        sComponent = self.study.FindComponent(engineName)
+        if sComponent is None:
+            sComponent = self.builder.NewComponent(engineName)
+            if componentName is None:
+                componentName = engineName
+            self.builder.SetName(sComponent, componentName)
+            
+            if icon is not None:
+                self.setIcon(sComponent, icon)
+
+            if loadEngine:
+                self.loadComponentEngine(sComponent, containerName)
+
+        return sComponent
+
+    def loadComponentEngine(self, sComponent,
+                            containerName = _DEFAULT_CONTAINER):
+        """
+        Load the engine corresponding to `sComponent` in the container
+        `containerName`, associate the engine with the component and load the
+        CORBA objects of this component in the study.
+        """
+        engine = salome.lcc.FindOrLoadComponent(containerName,
+                                                sComponent.GetComment())
+        self.builder.LoadWith(sComponent, engine)
+
+    def getOrLoadObject(self, item):
+        """
+        Get the CORBA object associated with the SObject `item`, eventually by
+        first loading it with the corresponding engine.
+        """
+        object = item.GetObject()
+        if object is None: # the engine has not been loaded yet
+            sComponent = item.GetFatherComponent()
+            self.loadComponentEngine(sComponent)
+            object = item.GetObject()
+        return object
+
+    def findOrCreateItem(self, fatherItem, name, fileType = None,
+                         fileName = None, comment = None, icon = None,
+                         IOR = None, typeId = None):
+        """
+        Find an object under `fatherItem` in the study with the given
+        attributes. Return the first one found if at least one exists,
+        otherwise create a new one with the given attributes and return it.
+        
+        See :meth:`setItem` for the description of the parameters.
+        """
+        sObject = self.findItem(fatherItem, name, fileType, fileName, comment,
+                                icon, IOR, typeId)
+        if sObject is None:
+            sObject = self.createItem(fatherItem, name, fileType, fileName,
+                                      comment, icon, IOR, typeId)
+        return sObject
+
+    def findItem(self, fatherItem, name = None, fileType = None,
+                 fileName = None, comment = None, icon = None, IOR = None,
+                 typeId = None):
+        """
+        Find an item with given attributes under `fatherItem` in the study. If
+        none is found, return :const:`None`. If several items correspond to
+        the parameters, only the first one is returned. The search is made
+        only on given parameters (i.e. not :const:`None`). To look explicitly
+        for an empty attribute, use an empty string in the corresponding
+        parameter.
+        
+        See :meth:`setItem` for the description of the parameters.
+        """
+        foundItem = None;
+        childIterator = self.study.NewChildIterator(fatherItem)
+        while childIterator.More() and foundItem is None:
+            childItem = childIterator.Value()
+            if childItem and \
+               (name is None or childItem.GetName() == name) and \
+               (fileType is None or \
+                self.getFileType(childItem) == fileType) and \
+               (fileName is None or \
+                self.getFileName(childItem) == fileName) and \
+               (comment is None or childItem.GetComment() == comment) and \
+               (icon is None or \
+                self.getIcon(childItem) == icon) and \
+               (IOR is None or childItem.GetIOR() == IOR and \
+               (typeId is None or \
+                self.getTypeId(childItem) == typeId)):
+                foundItem = childItem
+            childIterator.Next()
+        return foundItem
+
+    def createItem(self, fatherItem, name, fileType = None, fileName = None,
+                   comment = None, icon = None, IOR = None, typeId = None):
+        """
+        Create a new object named `name` under `fatherItem` in the study, with
+        the given attributes. If an object named `name` already exists under
+        the father object, the new object is created with a new name `name_X`
+        where X is the first available index.
+        
+        :type  fatherItem: SObject
+        :param fatherItem: item under which the new item will be added.
+                
+        :return: new SObject created in the study
+        
+        See :meth:`setItem` for the description of the other parameters.
+        """
+        aSObject = self.builder.NewObject(fatherItem)
+
+        aChildIterator = self.study.NewChildIterator(fatherItem)
+        aMaxId = -1
+        aLength = len(name)
+        aDelim = "_"
+        anIdRE = re.compile("^" + aDelim + "[0-9]+")
+        aNameRE = re.compile("^" + name)
+        while aChildIterator.More():
+            aSObj = aChildIterator.Value()
+            aChildIterator.Next()
+            aName = aSObj.GetName()
+            if re.match(aNameRE,aName):
+                aTmp = aName[aLength:]
+                if re.match(anIdRE,aTmp):
+                    import string
+                    anId = string.atol(aTmp[1:])
+                    if aMaxId < anId:
+                        aMaxId = anId
+                        pass
+                    pass
+                elif aMaxId < 0:
+                    aMaxId = 0
+                    pass
+                pass
+            pass
+        
+        aMaxId = aMaxId + 1
+        aName = name
+        if aMaxId > 0:
+            aName = aName + aDelim + str(aMaxId)
+            pass
+        
+        self.setItem(aSObject, aName, fileType, fileName, comment, icon,
+                     IOR, typeId)
+    
+        return aSObject
+
+    def setItem(self, item, name = None, fileType = None, fileName = None,
+                comment = None, icon = None, IOR = None, typeId = None):
+        """
+        Modify the attributes of an item in the study. Unspecified attributes
+        (i.e. those set to :const:`None`) are left unchanged.
+
+        :type  item: SObject
+        :param item: item to modify.
+
+        :type  name: string
+        :param name: item name (attribute 'AttributeName').
+
+        :type  fileType: string
+        :param fileType: item file type (attribute 'AttributeFileType').
+
+        :type  fileName: string
+        :param fileName: item file name (attribute
+                         'AttributeExternalFileDef').
+
+        :type  comment: string
+        :param comment: item comment (attribute 'AttributeComment'). Note that
+                        this attribute will appear in the 'Value' column in
+                        the object browser.
+
+        :type  icon: string
+        :param icon: item icon name (attribute 'AttributePixMap').
+
+        :type  IOR: string
+        :param IOR: IOR of a CORBA object associated with the item
+                    (attribute 'AttributeIOR').
+
+        :type  typeId: integer
+        :param typeId: item type (attribute 'AttributeLocalID').
+        """
+        print "setItem (ID=%s): name=%s, fileType=%s, fileName=%s, comment=%s, icon=%s, IOR=%s" % (item.GetID(), name, fileType, fileName, comment, icon, IOR)
+        # Explicit cast is necessary for unicode to string conversion
+        if name is not None:
+            self.builder.SetName(item, str(name))
+        if fileType is not None:
+            self.setFileType(item, fileType)
+        if fileName is not None:
+            self.setFileName(item, fileName)
+        if comment is not None:
+            self.builder.SetComment(item, str(comment))
+        if icon is not None:
+            self.setIcon(item, icon)
+        if IOR is not None:
+            self.builder.SetIOR(item, str(IOR))
+        if typeId is not None:
+            self.setTypeId(item, typeId)
+
+    def removeItem(self, item, withChildren = False ):
+        """
+        Remove the given item from the study (the item still is in
+        the study after the removal)
+        @param   item: the browser object to be removed
+        @param   withChildren: remove children if True
+        """
+        ok = False
+        try:
+            if withChildren:
+                self.builder.RemoveObjectWithChildren(item)
+            else:
+                self.builder.RemoveObject(item)
+            ok = True
+        except:
+            ok = False
+
+        return ok
+
+    def setItemAtTag(self, fatherItem, tag, name = None, fileType = None,
+                     fileName = None, comment = None, icon = None, IOR = None,
+                     typeId = None):
+        """
+        Find an item tagged `tag` under `fatherItem` in the study tree or
+        create it if there is none, then set its attributes.
+        
+        :type  fatherItem: SObject
+        :param fatherItem: item under which the tagged item will be looked for
+                           and eventually created.
+
+        :type  tag: integer
+        :param tag: tag of the item to look for.
+
+        :return: the SObject at `tag` if found or created successfully, or
+                 :const:`None` if an error happened.
+        
+        See :meth:`setItem` for the description of the other parameters.
+        """
+        found, sObj = fatherItem.FindSubObject(tag)
+        if not found:
+            sObj = self.builder.NewObjectToTag(fatherItem, tag)
+        self.setItem(sObj, name, fileType, fileName, comment, icon,
+                     IOR, typeId)
+        return sObj
+
+    def getAttributeValue(self, sObject, attributeName, default = None):
+        """
+        Return the value of the attribute named `attributeName` on the object
+        `sObject`, or `default` if the attribute doesn't exist.
+        """
+        value = default
+        found, attr = self.builder.FindAttribute(sObject, attributeName)
+        if found:
+            value = attr.Value()
+        return value
+
+    def setAttributeValue(self, sObject, attributeName, attributeValue):
+        """
+        Set the value of the attribute named `attributeName` on the object
+        `sObject` to the value `attributeValue`.
+        """        
+        attr = self.builder.FindOrCreateAttribute(sObject, attributeName)
+        attr.SetValue(attributeValue)
+
+    def getTypeId(self, sObject):
+        """
+        Return the value of the attribute "AttributeLocalID" of the object
+        `sObject`, or :const:`None` if it is not set.
+        """
+        return self.getAttributeValue(sObject, "AttributeLocalID")
+
+    def setTypeId(self, sObject, value):
+        """
+        Set the attribute "AttributeLocalID" of the object `sObject` to the
+        value `value`.
+        """
+        self.setAttributeValue(sObject, "AttributeLocalID", value)
+
+    def getFileType(self, sObject):
+        """
+        Return the value of the attribute "AttributeFileType" of the object
+        `sObject`, or an empty string if it is not set.
+        """
+        return self.getAttributeValue(sObject, "AttributeFileType", "")
+
+    def setFileType(self, sObject, value):
+        """
+        Set the attribute "AttributeFileType" of the object `sObject` to the
+        value `value`.
+        """
+        # Explicit cast is necessary for unicode to string conversion
+        self.setAttributeValue(sObject, "AttributeFileType", str(value))
+
+    def getFileName(self, sObject):
+        """
+        Return the value of the attribute "AttributeExternalFileDef" of the
+        object `sObject`, or an empty string if it is not set.
+        """
+        return self.getAttributeValue(sObject, "AttributeExternalFileDef", "")
+
+    def setFileName(self, sObject, value):
+        """
+        Set the attribute "AttributeExternalFileDef" of the object `sObject`
+        to the value `value`.
+        """
+        # Explicit cast is necessary for unicode to string conversion
+        self.setAttributeValue(sObject, "AttributeExternalFileDef",
+                               str(value))
+
+    def getIcon(self, sObject):
+        """
+        Return the value of the attribute "AttributePixMap" of the object
+        `sObject`, or an empty string if it is not set.
+        """
+        value = ""
+        found, attr = self.builder.FindAttribute(sObject, "AttributePixMap")
+        if found and attr.HasPixMap():
+            value = attr.GetPixMap()
+        return value
+
+    def setIcon(self, sObject, value):
+        """
+        Set the attribute "AttributePixMap" of the object `sObject` to the
+        value `value`.
+        """
+        attr = self.builder.FindOrCreateAttribute(sObject, "AttributePixMap")
+        # Explicit cast is necessary for unicode to string conversion
+        attr.SetPixMap(str(value))