plugger.py
changeset 361 331d698e1118
parent 356 e9698d0ee5f3
child 363 e0c4d3549369
equal deleted inserted replaced
360:32339ad7d9ae 361:331d698e1118
   197             XMLFile.close()
   197             XMLFile.close()
   198         
   198         
   199         # Call the plugin specific OnPlugSave method
   199         # Call the plugin specific OnPlugSave method
   200         result = self.OnPlugSave()
   200         result = self.OnPlugSave()
   201         if not result:
   201         if not result:
   202             return "Error while saving \"%s\"\n"%self.PlugPath()
   202             return _("Error while saving \"%s\"\n")%self.PlugPath()
   203 
   203 
   204         # mark plugin as saved
   204         # mark plugin as saved
   205         self.ChangesToSave = False        
   205         self.ChangesToSave = False        
   206         # go through all childs and do the same
   206         # go through all childs and do the same
   207         for PlugChild in self.IterChilds():
   207         for PlugChild in self.IterChilds():
   233         # Generate plugins [(Cfiles, CFLAGS)], LDFLAGS, DoCalls, extra_files
   233         # Generate plugins [(Cfiles, CFLAGS)], LDFLAGS, DoCalls, extra_files
   234         # extra_files = [(fname,fobject), ...]
   234         # extra_files = [(fname,fobject), ...]
   235         gen_result = self.PlugGenerate_C(buildpath, locations)
   235         gen_result = self.PlugGenerate_C(buildpath, locations)
   236         PlugCFilesAndCFLAGS, PlugLDFLAGS, DoCalls = gen_result[:3]
   236         PlugCFilesAndCFLAGS, PlugLDFLAGS, DoCalls = gen_result[:3]
   237         extra_files = gen_result[3:]
   237         extra_files = gen_result[3:]
   238         # if some files heve been generated put them in the list with their location
   238         # if some files have been generated put them in the list with their location
   239         if PlugCFilesAndCFLAGS:
   239         if PlugCFilesAndCFLAGS:
   240             LocationCFilesAndCFLAGS = [(self.GetCurrentLocation(), PlugCFilesAndCFLAGS, DoCalls)]
   240             LocationCFilesAndCFLAGS = [(self.GetCurrentLocation(), PlugCFilesAndCFLAGS, DoCalls)]
   241         else:
   241         else:
   242             LocationCFilesAndCFLAGS = []
   242             LocationCFilesAndCFLAGS = []
   243 
   243 
   390         # Rename plugin dir if exist
   390         # Rename plugin dir if exist
   391         if not dontexist:
   391         if not dontexist:
   392             shutil.move(oldname, self.PlugPath())
   392             shutil.move(oldname, self.PlugPath())
   393         # warn user he has two left hands
   393         # warn user he has two left hands
   394         if DesiredName != res:
   394         if DesiredName != res:
   395             self.logger.write_warning("A child names \"%s\" already exist -> \"%s\"\n"%(DesiredName,res))
   395             self.logger.write_warning(_("A child names \"%s\" already exist -> \"%s\"\n")%(DesiredName,res))
   396         return res
   396         return res
   397 
   397 
   398     def FindNewIEC_Channel(self, DesiredChannel):
   398     def FindNewIEC_Channel(self, DesiredChannel):
   399         """
   399         """
   400         Changes IEC Channel number to DesiredChannel if available, nearest available if not.
   400         Changes IEC Channel number to DesiredChannel if available, nearest available if not.
   415         res = DesiredChannel
   415         res = DesiredChannel
   416         while res in AllChannels: # While channel not free
   416         while res in AllChannels: # While channel not free
   417             if res < CurrentChannel: # Want to go down ?
   417             if res < CurrentChannel: # Want to go down ?
   418                 res -=  1 # Test for n-1
   418                 res -=  1 # Test for n-1
   419                 if res < 0 :
   419                 if res < 0 :
   420                     self.logger.write_warning("Cannot find lower free IEC channel than %d\n"%CurrentChannel)
   420                     self.logger.write_warning(_("Cannot find lower free IEC channel than %d\n")%CurrentChannel)
   421                     return CurrentChannel # Can't go bellow 0, do nothing
   421                     return CurrentChannel # Can't go bellow 0, do nothing
   422             else : # Want to go up ?
   422             else : # Want to go up ?
   423                 res +=  1 # Test for n-1
   423                 res +=  1 # Test for n-1
   424         # Finally set IEC Channel
   424         # Finally set IEC Channel
   425         self.BaseParams.setIEC_Channel(res)
   425         self.BaseParams.setIEC_Channel(res)
   426         if DesiredChannel != res:
   426         if DesiredChannel != res:
   427             self.logger.write_warning("A child with IEC channel %d already exist -> %d\n"%(DesiredChannel,res))
   427             self.logger.write_warning(_("A child with IEC channel %d already exist -> %d\n")%(DesiredChannel,res))
   428         return res
   428         return res
   429 
   429 
   430     def OnPlugClose(self):
   430     def OnPlugClose(self):
   431         return True
   431         return True
   432 
   432 
   460         PlugChildsTypes = dict(zip(transpose[0],zip(transpose[1],transpose[2])))
   460         PlugChildsTypes = dict(zip(transpose[0],zip(transpose[1],transpose[2])))
   461         # Check that adding this plugin is allowed
   461         # Check that adding this plugin is allowed
   462         try:
   462         try:
   463             PlugClass, PlugHelp = PlugChildsTypes[PlugType]
   463             PlugClass, PlugHelp = PlugChildsTypes[PlugType]
   464         except KeyError:
   464         except KeyError:
   465             raise Exception, "Cannot create child %s of type %s "%(PlugName, PlugType)
   465             raise Exception, _("Cannot create child %s of type %s ")%(PlugName, PlugType)
   466         
   466         
   467         # if PlugClass is a class factory, call it. (prevent unneeded imports)
   467         # if PlugClass is a class factory, call it. (prevent unneeded imports)
   468         if type(PlugClass) == types.FunctionType:
   468         if type(PlugClass) == types.FunctionType:
   469             PlugClass = PlugClass()
   469             PlugClass = PlugClass()
   470         
   470         
   471         # Eventualy Initialize child instance list for this class of plugin
   471         # Eventualy Initialize child instance list for this class of plugin
   472         PluggedChildsWithSameClass = self.PluggedChilds.setdefault(PlugType, list())
   472         PluggedChildsWithSameClass = self.PluggedChilds.setdefault(PlugType, list())
   473         # Check count
   473         # Check count
   474         if getattr(PlugClass, "PlugMaxCount", None) and len(PluggedChildsWithSameClass) >= PlugClass.PlugMaxCount:
   474         if getattr(PlugClass, "PlugMaxCount", None) and len(PluggedChildsWithSameClass) >= PlugClass.PlugMaxCount:
   475             raise Exception, "Max count (%d) reached for this plugin of type %s "%(PlugClass.PlugMaxCount, PlugType)
   475             raise Exception, _("Max count (%d) reached for this plugin of type %s ")%(PlugClass.PlugMaxCount, PlugType)
   476         
   476         
   477         # create the final class, derived of provided plugin and template
   477         # create the final class, derived of provided plugin and template
   478         class FinalPlugClass(PlugClass, PlugTemplate):
   478         class FinalPlugClass(PlugClass, PlugTemplate):
   479             """
   479             """
   480             Plugin class is derivated into FinalPlugClass before being instanciated
   480             Plugin class is derivated into FinalPlugClass before being instanciated
   498                 if os.path.isdir(_self.PlugPath(NewPlugName)): #and os.path.isfile(_self.PluginXmlFilePath(PlugName)):
   498                 if os.path.isdir(_self.PlugPath(NewPlugName)): #and os.path.isfile(_self.PluginXmlFilePath(PlugName)):
   499                     #Load the plugin.xml file into parameters members
   499                     #Load the plugin.xml file into parameters members
   500                     _self.LoadXMLParams(NewPlugName)
   500                     _self.LoadXMLParams(NewPlugName)
   501                     # Basic check. Better to fail immediately.
   501                     # Basic check. Better to fail immediately.
   502                     if (_self.BaseParams.getName() != NewPlugName):
   502                     if (_self.BaseParams.getName() != NewPlugName):
   503                         raise Exception, "Project tree layout do not match plugin.xml %s!=%s "%(NewPlugName, _self.BaseParams.getName())
   503                         raise Exception, _("Project tree layout do not match plugin.xml %s!=%s ")%(NewPlugName, _self.BaseParams.getName())
   504 
   504 
   505                     # Now, self.PlugPath() should be OK
   505                     # Now, self.PlugPath() should be OK
   506                     
   506                     
   507                     # Check that IEC_Channel is not already in use.
   507                     # Check that IEC_Channel is not already in use.
   508                     _self.FindNewIEC_Channel(_self.BaseParams.getIEC_Channel())
   508                     _self.FindNewIEC_Channel(_self.BaseParams.getIEC_Channel())
   553                 basexmlfile = open(self.PluginBaseXmlFilePath(PlugName), 'r')
   553                 basexmlfile = open(self.PluginBaseXmlFilePath(PlugName), 'r')
   554                 basetree = minidom.parse(basexmlfile)
   554                 basetree = minidom.parse(basexmlfile)
   555                 self.MandatoryParams[1].loadXMLTree(basetree.childNodes[0])
   555                 self.MandatoryParams[1].loadXMLTree(basetree.childNodes[0])
   556                 basexmlfile.close()
   556                 basexmlfile.close()
   557             except Exception, exc:
   557             except Exception, exc:
   558                 self.logger.write_error("Couldn't load plugin base parameters %s :\n %s" % (PlugName, str(exc)))
   558                 self.logger.write_error(_("Couldn't load plugin base parameters %s :\n %s") % (PlugName, str(exc)))
   559                 self.logger.write_error(traceback.format_exc())
   559                 self.logger.write_error(traceback.format_exc())
   560         
   560         
   561         # Get the xml tree
   561         # Get the xml tree
   562         if self.PlugParams:
   562         if self.PlugParams:
   563             try:
   563             try:
   564                 xmlfile = open(self.PluginXmlFilePath(PlugName), 'r')
   564                 xmlfile = open(self.PluginXmlFilePath(PlugName), 'r')
   565                 tree = minidom.parse(xmlfile)
   565                 tree = minidom.parse(xmlfile)
   566                 self.PlugParams[1].loadXMLTree(tree.childNodes[0])
   566                 self.PlugParams[1].loadXMLTree(tree.childNodes[0])
   567                 xmlfile.close()
   567                 xmlfile.close()
   568             except Exception, exc:
   568             except Exception, exc:
   569                 self.logger.write_error("Couldn't load plugin parameters %s :\n %s" % (PlugName, str(exc)))
   569                 self.logger.write_error(_("Couldn't load plugin parameters %s :\n %s") % (PlugName, str(exc)))
   570                 self.logger.write_error(traceback.format_exc())
   570                 self.logger.write_error(traceback.format_exc())
   571         
   571         
   572     def LoadChilds(self):
   572     def LoadChilds(self):
   573         # Iterate over all PlugName@PlugType in plugin directory, and try to open them
   573         # Iterate over all PlugName@PlugType in plugin directory, and try to open them
   574         for PlugDir in os.listdir(self.PlugPath()):
   574         for PlugDir in os.listdir(self.PlugPath()):
   576                PlugDir.count(NameTypeSeparator) == 1:
   576                PlugDir.count(NameTypeSeparator) == 1:
   577                 pname, ptype = PlugDir.split(NameTypeSeparator)
   577                 pname, ptype = PlugDir.split(NameTypeSeparator)
   578                 try:
   578                 try:
   579                     self.PlugAddChild(pname, ptype)
   579                     self.PlugAddChild(pname, ptype)
   580                 except Exception, exc:
   580                 except Exception, exc:
   581                     self.logger.write_error("Could not add child \"%s\", type %s :\n%s\n"%(pname, ptype, str(exc)))
   581                     self.logger.write_error(_("Could not add child \"%s\", type %s :\n%s\n")%(pname, ptype, str(exc)))
   582                     self.logger.write_error(traceback.format_exc())
   582                     self.logger.write_error(traceback.format_exc())
   583 
   583 
   584     def EnableMethod(self, method, value):
   584     def EnableMethod(self, method, value):
   585         for d in self.PluginMethods:
   585         for d in self.PluginMethods:
   586             if d["method"]==method:
   586             if d["method"]==method:
   775         @param ProjectPath: path of the folder where project have to be created
   775         @param ProjectPath: path of the folder where project have to be created
   776         @param PLCParams: properties of the PLCOpen program created
   776         @param PLCParams: properties of the PLCOpen program created
   777         """
   777         """
   778         # Verify that choosen folder is empty
   778         # Verify that choosen folder is empty
   779         if not os.path.isdir(ProjectPath) or len(os.listdir(ProjectPath)) > 0:
   779         if not os.path.isdir(ProjectPath) or len(os.listdir(ProjectPath)) > 0:
   780             return "Folder choosen isn't empty. You can't use it for a new project!"
   780             return _("Folder choosen isn't empty. You can't use it for a new project!")
   781         
   781         
   782         dialog = ProjectDialog(self.AppFrame)
   782         dialog = ProjectDialog(self.AppFrame)
   783         if dialog.ShowModal() == wx.ID_OK:
   783         if dialog.ShowModal() == wx.ID_OK:
   784             values = dialog.GetValues()
   784             values = dialog.GetValues()
   785             values["creationDateTime"] = datetime(*localtime()[:6])
   785             values["creationDateTime"] = datetime(*localtime()[:6])
   786             dialog.Destroy()
   786             dialog.Destroy()
   787         else:
   787         else:
   788             dialog.Destroy()
   788             dialog.Destroy()
   789             return "Project not created"
   789             return _("Project not created")
   790         
   790         
   791         # Create PLCOpen program
   791         # Create PLCOpen program
   792         self.CreateNewProject(values)
   792         self.CreateNewProject(values)
   793         # Change XSD into class members
   793         # Change XSD into class members
   794         self._AddParamsMembers()
   794         self._AddParamsMembers()
   810         if os.path.basename(ProjectPath) == "":
   810         if os.path.basename(ProjectPath) == "":
   811             ProjectPath = os.path.dirname(ProjectPath)
   811             ProjectPath = os.path.dirname(ProjectPath)
   812 		# Verify that project contains a PLCOpen program
   812 		# Verify that project contains a PLCOpen program
   813         plc_file = os.path.join(ProjectPath, "plc.xml")
   813         plc_file = os.path.join(ProjectPath, "plc.xml")
   814         if not os.path.isfile(plc_file):
   814         if not os.path.isfile(plc_file):
   815             return "Folder choosen doesn't contain a program. It's not a valid project!"
   815             return _("Folder choosen doesn't contain a program. It's not a valid project!")
   816         # Load PLCOpen file
   816         # Load PLCOpen file
   817         result = self.OpenXMLFile(plc_file)
   817         result = self.OpenXMLFile(plc_file)
   818         if result:
   818         if result:
   819             return result
   819             return result
   820         # Change XSD into class members
   820         # Change XSD into class members
   926         """
   926         """
   927 
   927 
   928         # Update PLCOpenEditor Plugin Block types before generate ST code
   928         # Update PLCOpenEditor Plugin Block types before generate ST code
   929         self.RefreshPluginsBlockLists()
   929         self.RefreshPluginsBlockLists()
   930         
   930         
   931         self.logger.write("Generating SoftPLC IEC-61131 ST/IL/SFC code...\n")
   931         self.logger.write(_("Generating SoftPLC IEC-61131 ST/IL/SFC code...\n"))
   932         buildpath = self._getBuildPath()
   932         buildpath = self._getBuildPath()
   933         # ask PLCOpenEditor controller to write ST/IL/SFC code file
   933         # ask PLCOpenEditor controller to write ST/IL/SFC code file
   934         program, errors, warnings = self.GenerateProgram(self._getIECgeneratedcodepath())
   934         program, errors, warnings = self.GenerateProgram(self._getIECgeneratedcodepath())
   935         if len(warnings) > 0:
   935         if len(warnings) > 0:
   936             self.logger.write_warning("Warnings in ST/IL/SFC code generator :\n")
   936             self.logger.write_warning(_("Warnings in ST/IL/SFC code generator :\n"))
   937             for warning in warnings:
   937             for warning in warnings:
   938                 self.logger.write_warning("%s\n"%warning)
   938                 self.logger.write_warning("%s\n"%warning)
   939         if len(errors) > 0:
   939         if len(errors) > 0:
   940             # Failed !
   940             # Failed !
   941             self.logger.write_error("Error in ST/IL/SFC code generator :\n%s\n"%errors[0])
   941             self.logger.write_error(_("Error in ST/IL/SFC code generator :\n%s\n")%errors[0])
   942             return False
   942             return False
   943         plc_file = open(self._getIECcodepath(), "w")
   943         plc_file = open(self._getIECcodepath(), "w")
   944         if getattr(self, "PluggedChilds", None) is not None:
   944         if getattr(self, "PluggedChilds", None) is not None:
   945             # Add ST Library from plugins
   945             # Add ST Library from plugins
   946             plc_file.write(self.STLibraryFactory())
   946             plc_file.write(self.STLibraryFactory())
   958             self.ProgramOffset += 1
   958             self.ProgramOffset += 1
   959         plc_file.close()
   959         plc_file.close()
   960         plc_file = open(self._getIECcodepath(), "a")
   960         plc_file = open(self._getIECcodepath(), "a")
   961         plc_file.write(open(self._getIECgeneratedcodepath(), "r").read())
   961         plc_file.write(open(self._getIECgeneratedcodepath(), "r").read())
   962         plc_file.close()
   962         plc_file.close()
   963         self.logger.write("Compiling IEC Program in to C code...\n")
   963         self.logger.write(_("Compiling IEC Program in to C code...\n"))
   964         # Now compile IEC code into many C files
   964         # Now compile IEC code into many C files
   965         # files are listed to stdout, and errors to stderr. 
   965         # files are listed to stdout, and errors to stderr. 
   966         status, result, err_result = ProcessLogger(
   966         status, result, err_result = ProcessLogger(
   967                self.logger,
   967                self.logger,
   968                "\"%s\" -f -I \"%s\" -T \"%s\" \"%s\""%(
   968                "\"%s\" -f -I \"%s\" -T \"%s\" \"%s\""%(
   997                                 last_section = None # only write section once
   997                                 last_section = None # only write section once
   998                             self.logger.write_warning("%04d: %s" % (i, line))
   998                             self.logger.write_warning("%04d: %s" % (i, line))
   999 
   999 
  1000                     f.close()
  1000                     f.close()
  1001             
  1001             
  1002             self.logger.write_error("Error : IEC to C compiler returned %d\n"%status)
  1002             self.logger.write_error(_("Error : IEC to C compiler returned %d\n")%status)
  1003             return False
  1003             return False
  1004         
  1004         
  1005         # Now extract C files of stdout
  1005         # Now extract C files of stdout
  1006         C_files = [ fname for fname in result.splitlines() if fname[-2:]==".c" or fname[-2:]==".C" ]
  1006         C_files = [ fname for fname in result.splitlines() if fname[-2:]==".c" or fname[-2:]==".C" ]
  1007         # remove those that are not to be compiled because included by others
  1007         # remove those that are not to be compiled because included by others
  1008         C_files.remove("POUS.c")
  1008         C_files.remove("POUS.c")
  1009         if not C_files:
  1009         if not C_files:
  1010             self.logger.write_error("Error : At least one configuration and one ressource must be declared in PLC !\n")
  1010             self.logger.write_error(_("Error : At least one configuration and one ressource must be declared in PLC !\n"))
  1011             return False
  1011             return False
  1012         # transform those base names to full names with path
  1012         # transform those base names to full names with path
  1013         C_files = map(lambda filename:os.path.join(buildpath, filename), C_files)
  1013         C_files = map(lambda filename:os.path.join(buildpath, filename), C_files)
  1014         self.logger.write("Extracting Located Variables...\n")
  1014         self.logger.write(_("Extracting Located Variables...\n"))
  1015         # Keep track of generated located variables for later use by self._Generate_C
  1015         # Keep track of generated located variables for later use by self._Generate_C
  1016         self.PLCGeneratedLocatedVars = self.GetLocations()
  1016         self.PLCGeneratedLocatedVars = self.GetLocations()
  1017         # Keep track of generated C files for later use by self.PlugGenerate_C
  1017         # Keep track of generated C files for later use by self.PlugGenerate_C
  1018         self.PLCGeneratedCFiles = C_files
  1018         self.PLCGeneratedCFiles = C_files
  1019         # compute CFLAGS for plc
  1019         # compute CFLAGS for plc
  1032         # Get module reference
  1032         # Get module reference
  1033         try :
  1033         try :
  1034             targetmodule = getattr(__import__(modulename), targetname)
  1034             targetmodule = getattr(__import__(modulename), targetname)
  1035 
  1035 
  1036         except Exception, msg:
  1036         except Exception, msg:
  1037             self.logger.write_error("Can't find module for target %s!\n"%targetname)
  1037             self.logger.write_error(_("Can't find module for target %s!\n")%targetname)
  1038             self.logger.write_error(str(msg))
  1038             self.logger.write_error(str(msg))
  1039             return None
  1039             return None
  1040         
  1040         
  1041         # Get target class
  1041         # Get target class
  1042         targetclass = getattr(targetmodule, classname)
  1042         targetclass = getattr(targetmodule, classname)
  1156                     # Fill in IEC<->C translation dicts
  1156                     # Fill in IEC<->C translation dicts
  1157                     IEC_path=attrs["IEC_path"]
  1157                     IEC_path=attrs["IEC_path"]
  1158                     Idx=int(attrs["num"])
  1158                     Idx=int(attrs["num"])
  1159                     self._IECPathToIdx[IEC_path]=Idx
  1159                     self._IECPathToIdx[IEC_path]=Idx
  1160             except Exception,e:
  1160             except Exception,e:
  1161                 self.logger.write_error("Cannot open/parse VARIABLES.csv!\n")
  1161                 self.logger.write_error(_("Cannot open/parse VARIABLES.csv!\n"))
  1162                 self.logger.write_error(traceback.format_exc())
  1162                 self.logger.write_error(traceback.format_exc())
  1163                 self.ResetIECProgramsAndVariables()
  1163                 self.ResetIECProgramsAndVariables()
  1164                 return False
  1164                 return False
  1165 
  1165 
  1166         return True
  1166         return True
  1268             os.mkdir(buildpath)
  1268             os.mkdir(buildpath)
  1269         # There is something to clean
  1269         # There is something to clean
  1270         self.EnableMethod("_Clean", True)
  1270         self.EnableMethod("_Clean", True)
  1271 
  1271 
  1272         self.logger.flush()
  1272         self.logger.flush()
  1273         self.logger.write("Start build in %s\n" % buildpath)
  1273         self.logger.write(_("Start build in %s\n") % buildpath)
  1274 
  1274 
  1275         # Generate SoftPLC IEC code
  1275         # Generate SoftPLC IEC code
  1276         IECGenRes = self._Generate_SoftPLC()
  1276         IECGenRes = self._Generate_SoftPLC()
  1277         self.ShowMethod("_showIECcode", True)
  1277         self.ShowMethod("_showIECcode", True)
  1278 
  1278 
  1279         # If IEC code gen fail, bail out.
  1279         # If IEC code gen fail, bail out.
  1280         if not IECGenRes:
  1280         if not IECGenRes:
  1281             self.logger.write_error("IEC-61131-3 code generation failed !\n")
  1281             self.logger.write_error(_("IEC-61131-3 code generation failed !\n"))
  1282             return False
  1282             return False
  1283 
  1283 
  1284         # Reset variable and program list that are parsed from
  1284         # Reset variable and program list that are parsed from
  1285         # CSV file generated by IEC2C compiler.
  1285         # CSV file generated by IEC2C compiler.
  1286         self.ResetIECProgramsAndVariables()
  1286         self.ResetIECProgramsAndVariables()
  1287         
  1287         
  1288         # Generate C code and compilation params from plugin hierarchy
  1288         # Generate C code and compilation params from plugin hierarchy
  1289         self.logger.write("Generating plugins C code\n")
  1289         self.logger.write(_("Generating plugins C code\n"))
  1290         try:
  1290         try:
  1291             self.LocationCFilesAndCFLAGS, self.LDFLAGS, ExtraFiles = self._Generate_C(
  1291             self.LocationCFilesAndCFLAGS, self.LDFLAGS, ExtraFiles = self._Generate_C(
  1292                 buildpath, 
  1292                 buildpath, 
  1293                 self.PLCGeneratedLocatedVars)
  1293                 self.PLCGeneratedLocatedVars)
  1294         except Exception, exc:
  1294         except Exception, exc:
  1295             self.logger.write_error("Plugins code generation failed !\n")
  1295             self.logger.write_error(_("Plugins code generation failed !\n"))
  1296             self.logger.write_error(traceback.format_exc())
  1296             self.logger.write_error(traceback.format_exc())
  1297             return False
  1297             return False
  1298 
  1298 
  1299         # Get temprary directory path
  1299         # Get temporary directory path
  1300         extrafilespath = self._getExtraFilesPath()
  1300         extrafilespath = self._getExtraFilesPath()
  1301         # Remove old directory
  1301         # Remove old directory
  1302         if os.path.exists(extrafilespath):
  1302         if os.path.exists(extrafilespath):
  1303             shutil.rmtree(extrafilespath)
  1303             shutil.rmtree(extrafilespath)
  1304         # Recreate directory
  1304         # Recreate directory
  1327                 code_path = os.path.join(buildpath,filename)
  1327                 code_path = os.path.join(buildpath,filename)
  1328                 open(code_path, "w").write(code)
  1328                 open(code_path, "w").write(code)
  1329                 # Insert this file as first file to be compiled at root plugin
  1329                 # Insert this file as first file to be compiled at root plugin
  1330                 self.LocationCFilesAndCFLAGS[0][1].insert(0,(code_path, self.plcCFLAGS))
  1330                 self.LocationCFilesAndCFLAGS[0][1].insert(0,(code_path, self.plcCFLAGS))
  1331             except Exception, exc:
  1331             except Exception, exc:
  1332                 self.logger.write_error(name+" generation failed !\n")
  1332                 self.logger.write_error(name+_(" generation failed !\n"))
  1333                 self.logger.write_error(traceback.format_exc())
  1333                 self.logger.write_error(traceback.format_exc())
  1334                 return False
  1334                 return False
  1335 
  1335 
  1336         self.logger.write("C code generated successfully.\n")
  1336         self.logger.write(_("C code generated successfully.\n"))
  1337 
  1337 
  1338         # Get current or fresh builder
  1338         # Get current or fresh builder
  1339         builder = self.GetBuilder()
  1339         builder = self.GetBuilder()
  1340         if builder is None:
  1340         if builder is None:
  1341             self.logger.write_error("Fatal : cannot get builder.\n")
  1341             self.logger.write_error(_("Fatal : cannot get builder.\n"))
  1342             return False
  1342             return False
  1343 
  1343 
  1344         # Build
  1344         # Build
  1345         try:
  1345         try:
  1346             if not builder.build() :
  1346             if not builder.build() :
  1347                 self.logger.write_error("C Build failed.\n")
  1347                 self.logger.write_error(_("C Build failed.\n"))
  1348                 return False
  1348                 return False
  1349         except Exception, exc:
  1349         except Exception, exc:
  1350             self.logger.write_error("C Build crashed !\n")
  1350             self.logger.write_error(_("C Build crashed !\n"))
  1351             self.logger.write_error(traceback.format_exc())
  1351             self.logger.write_error(traceback.format_exc())
  1352             return False
  1352             return False
  1353 
  1353 
  1354         # Update GUI status about need for transfer
  1354         # Update GUI status about need for transfer
  1355         self.CompareLocalAndRemotePLC()
  1355         self.CompareLocalAndRemotePLC()
  1426             self.PLCEditor._onsave = _onsave
  1426             self.PLCEditor._onsave = _onsave
  1427             self.PLCEditor.Show()
  1427             self.PLCEditor.Show()
  1428 
  1428 
  1429     def _Clean(self):
  1429     def _Clean(self):
  1430         if os.path.isdir(os.path.join(self._getBuildPath())):
  1430         if os.path.isdir(os.path.join(self._getBuildPath())):
  1431             self.logger.write("Cleaning the build directory\n")
  1431             self.logger.write(_("Cleaning the build directory\n"))
  1432             shutil.rmtree(os.path.join(self._getBuildPath()))
  1432             shutil.rmtree(os.path.join(self._getBuildPath()))
  1433         else:
  1433         else:
  1434             self.logger.write_error("Build directory already clean\n")
  1434             self.logger.write_error(_("Build directory already clean\n"))
  1435         self.ShowMethod("_showIECcode", False)
  1435         self.ShowMethod("_showIECcode", False)
  1436         self.EnableMethod("_Clean", False)
  1436         self.EnableMethod("_Clean", False)
  1437         # kill the builder
  1437         # kill the builder
  1438         self._builder = None
  1438         self._builder = None
  1439         self.CompareLocalAndRemotePLC()
  1439         self.CompareLocalAndRemotePLC()
  1444         # TODO : use explicit status instead of boolean
  1444         # TODO : use explicit status instead of boolean
  1445         if self._connector is not None:
  1445         if self._connector is not None:
  1446             status = self._connector.GetPLCstatus()
  1446             status = self._connector.GetPLCstatus()
  1447         else:
  1447         else:
  1448             status = "Disconnected"
  1448             status = "Disconnected"
       
  1449         _ = lambda x : x
  1449         for args in {
  1450         for args in {
  1450                "Started":[("_Run", False),
  1451                _("Started"):     [("_Run", False),
  1451                           ("_Debug", False),
  1452                                   ("_Debug", False),
  1452                           ("_Stop", True)],
  1453                                   ("_Stop", True)],
  1453                "Stopped":[("_Run", True),
  1454                _("Stopped"):     [("_Run", True),
  1454                           ("_Debug", True),
  1455                                   ("_Debug", True),
  1455                           ("_Stop", False)],
  1456                                   ("_Stop", False)],
  1456                "Empty":  [("_Run", False),
  1457                _("Empty"):       [("_Run", False),
  1457                           ("_Debug", False),
  1458                                   ("_Debug", False),
  1458                           ("_Stop", False)],
  1459                                   ("_Stop", False)],
  1459                "Dirty":  [("_Run", True),
  1460                _("Dirty"):       [("_Run", True),
  1460                           ("_Debug", True),
  1461                                   ("_Debug", True),
  1461                           ("_Stop", False)],
  1462                                   ("_Stop", False)],
  1462                "Broken": [("_Run", True),
  1463                _("Broken"):      [("_Run", True),
  1463                           ("_Debug", True),
  1464                                   ("_Debug", True),
  1464                           ("_Stop", False)],
  1465                                   ("_Stop", False)],
  1465                "Disconnected":  [("_Run", False),
  1466                _("Disconnected"):[("_Run", False),
  1466                                  ("_Debug", False),
  1467                                   ("_Debug", False),
  1467                                  ("_Stop", False),
  1468                                   ("_Stop", False),
  1468                                  ("_Transfer", False),
  1469                                   ("_Transfer", False),
  1469                                  ("_Connect", True),
  1470                                   ("_Connect", True),
  1470                                  ("_Disconnect", False)],
  1471                                   ("_Disconnect", False)],
  1471                }.get(status,[]):
  1472                }.get(status,[]):
  1472             self.ShowMethod(*args)
  1473             self.ShowMethod(*args)
  1473         return status
  1474         return status
  1474     
  1475     
  1475     def PullPLCStatusProc(self, event): 
  1476     def PullPLCStatusProc(self, event): 
  1476         if self._connector is None:
  1477         if self._connector is None:
  1477             self.StatusTimer.Stop()
  1478             self.StatusTimer.Stop()
  1478         current_status = self.UpdateMethodsFromPLCStatus()
  1479         current_status = self.UpdateMethodsFromPLCStatus()
  1479         if current_status != self.previous_plcstate:
  1480         if current_status != self.previous_plcstate:
  1480             self.previous_plcstate = current_status
  1481             self.previous_plcstate = current_status
  1481             self.StatusPrint.get(current_status, self.logger.write)("PLC is %s\n"%current_status)
  1482             if current_status is not None:
       
  1483                 status = _(current_status)
       
  1484             else:
       
  1485                 status = ""
       
  1486             self.StatusPrint.get(current_status, self.logger.write)(_("PLC is %s\n")%status)
  1482             self.AppFrame.RefreshAll()
  1487             self.AppFrame.RefreshAll()
  1483         
  1488         
  1484     def _Run(self):
  1489     def _Run(self):
  1485         """
  1490         """
  1486         Start PLC
  1491         Start PLC
  1507                     Idx = self._IECPathToIdx.get(IECPath,None)
  1512                     Idx = self._IECPathToIdx.get(IECPath,None)
  1508                     if Idx is not None:
  1513                     if Idx is not None:
  1509                         Idxs.append(Idx)
  1514                         Idxs.append(Idx)
  1510                         self.TracedIECPath.append(IECPath)
  1515                         self.TracedIECPath.append(IECPath)
  1511                     else:
  1516                     else:
  1512                         self.logger.write_warning("Debug : Unknown variable %s\n"%IECPath)
  1517                         self.logger.write_warning(_("Debug : Unknown variable %s\n")%IECPath)
  1513             for IECPathToPop in IECPathsToPop:
  1518             for IECPathToPop in IECPathsToPop:
  1514                 self.IECdebug_datas.pop(IECPathToPop)
  1519                 self.IECdebug_datas.pop(IECPathToPop)
  1515 
  1520 
  1516             self._connector.SetTraceVariablesList(Idxs)
  1521             self._connector.SetTraceVariablesList(Idxs)
  1517             self.IECdebug_lock.release()
  1522             self.IECdebug_lock.release()
  1602                     if value is not None:
  1607                     if value is not None:
  1603                         self.CallWeakcallables(IECPath, "NewValue", debug_tick, value)
  1608                         self.CallWeakcallables(IECPath, "NewValue", debug_tick, value)
  1604                 self.CallWeakcallables("__tick__", "NewDataAvailable")
  1609                 self.CallWeakcallables("__tick__", "NewDataAvailable")
  1605             elif debug_vars is not None:
  1610             elif debug_vars is not None:
  1606                 wx.CallAfter(self.logger.write_warning, 
  1611                 wx.CallAfter(self.logger.write_warning, 
  1607                              "Debug data not coherent %d != %d\n"%(len(debug_vars), len(self.TracedIECPath)))
  1612                              _("Debug data not coherent %d != %d\n")%(len(debug_vars), len(self.TracedIECPath)))
  1608             elif debug_tick == -1:
  1613             elif debug_tick == -1:
  1609                 #wx.CallAfter(self.logger.write, "Debugger unavailable\n")
  1614                 #wx.CallAfter(self.logger.write, "Debugger unavailable\n")
  1610                 pass
  1615                 pass
  1611             else:
  1616             else:
  1612                 wx.CallAfter(self.logger.write, "Debugger disabled\n")
  1617                 wx.CallAfter(self.logger.write, _("Debugger disabled\n"))
  1613                 self.debug_break = True
  1618                 self.debug_break = True
  1614             self.IECdebug_lock.release()
  1619             self.IECdebug_lock.release()
  1615 
  1620 
  1616     def KillDebugThread(self):
  1621     def KillDebugThread(self):
  1617         self.debug_break = True
  1622         self.debug_break = True
  1618         self.DebugThread.join(timeout=1)
  1623         self.DebugThread.join(timeout=1)
  1619         if self.DebugThread.isAlive():
  1624         if self.DebugThread.isAlive():
  1620             self.logger.write_warning("Debug Thread couldn't be killed")
  1625             self.logger.write_warning(_("Debug Thread couldn't be killed"))
  1621         self.DebugThread = None
  1626         self.DebugThread = None
  1622 
  1627 
  1623     def _Debug(self):
  1628     def _Debug(self):
  1624         """
  1629         """
  1625         Start PLC (Debug Mode)
  1630         Start PLC (Debug Mode)
  1626         """
  1631         """
  1627         if self.GetIECProgramsAndVariables():
  1632         if self.GetIECProgramsAndVariables():
  1628             self._connector.StartPLC(debug=True)
  1633             self._connector.StartPLC(debug=True)
  1629             self.logger.write("Starting PLC (debug mode)\n")
  1634             self.logger.write(_("Starting PLC (debug mode)\n"))
  1630             if self.PLCDebug is None:
  1635             if self.PLCDebug is None:
  1631                 self.RefreshPluginsBlockLists()
  1636                 self.RefreshPluginsBlockLists()
  1632                 def _onclose():
  1637                 def _onclose():
  1633                     self.PLCDebug = None
  1638                     self.PLCDebug = None
  1634                 self.PLCDebug = PLCOpenEditor(self.AppFrame, self, debug=True)
  1639                 self.PLCDebug = PLCOpenEditor(self.AppFrame, self, debug=True)
  1637             else:
  1642             else:
  1638                 self.PLCDebug.ResetGraphicViewers()
  1643                 self.PLCDebug.ResetGraphicViewers()
  1639             self.DebugThread = Thread(target=self.DebugThreadProc)
  1644             self.DebugThread = Thread(target=self.DebugThreadProc)
  1640             self.DebugThread.start()
  1645             self.DebugThread.start()
  1641         else:
  1646         else:
  1642             self.logger.write_error("Couldn't start PLC debug !\n")
  1647             self.logger.write_error(_("Couldn't start PLC debug !\n"))
  1643         self.UpdateMethodsFromPLCStatus()
  1648         self.UpdateMethodsFromPLCStatus()
  1644 
  1649 
  1645 
  1650 
  1646 #    def _Do_Test_Debug(self):
  1651 #    def _Do_Test_Debug(self):
  1647 #        # debug code
  1652 #        # debug code
  1663     def _Stop(self):
  1668     def _Stop(self):
  1664         """
  1669         """
  1665         Stop PLC
  1670         Stop PLC
  1666         """
  1671         """
  1667         if self.DebugThread is not None:
  1672         if self.DebugThread is not None:
  1668             self.logger.write("Stopping debug\n")
  1673             self.logger.write(_("Stopping debug\n"))
  1669             self.KillDebugThread()
  1674             self.KillDebugThread()
  1670         
  1675         
  1671         if not self._connector.StopPLC():
  1676         if not self._connector.StopPLC():
  1672             self.logger.write_error("Couldn't stop PLC !\n")
  1677             self.logger.write_error(_("Couldn't stop PLC !\n"))
  1673         self.UpdateMethodsFromPLCStatus()
  1678         self.UpdateMethodsFromPLCStatus()
  1674 
  1679 
  1675     def _Connect(self):
  1680     def _Connect(self):
  1676         # don't accept re-connetion is already connected
  1681         # don't accept re-connetion is already connected
  1677         if self._connector is not None:
  1682         if self._connector is not None:
  1678             self.logger.write_error("Already connected. Please disconnect\n")
  1683             self.logger.write_error(_("Already connected. Please disconnect\n"))
  1679             return
  1684             return
  1680         
  1685         
  1681         # Get connector uri
  1686         # Get connector uri
  1682         uri = self.\
  1687         uri = self.\
  1683               BeremizRoot.\
  1688               BeremizRoot.\
  1700        
  1705        
  1701         # Get connector from uri
  1706         # Get connector from uri
  1702         try:
  1707         try:
  1703             self._connector = connectors.ConnectorFactory(uri, self)
  1708             self._connector = connectors.ConnectorFactory(uri, self)
  1704         except Exception, msg:
  1709         except Exception, msg:
  1705             self.logger.write_error("Exception while connecting %s!\n"%uri)
  1710             self.logger.write_error(_("Exception while connecting %s!\n")%uri)
  1706             self.logger.write_error(traceback.format_exc())
  1711             self.logger.write_error(traceback.format_exc())
  1707 
  1712 
  1708         # Did connection success ?
  1713         # Did connection success ?
  1709         if self._connector is None:
  1714         if self._connector is None:
  1710             # Oups.
  1715             # Oups.
  1711             self.logger.write_error("Connection failed to %s!\n"%uri)
  1716             self.logger.write_error(_("Connection failed to %s!\n")%uri)
  1712         else:
  1717         else:
  1713             self.ShowMethod("_Connect", False)
  1718             self.ShowMethod("_Connect", False)
  1714             self.ShowMethod("_Disconnect", True)
  1719             self.ShowMethod("_Disconnect", True)
  1715             self.ShowMethod("_Transfer", True)
  1720             self.ShowMethod("_Transfer", True)
  1716 
  1721 
  1717             self.CompareLocalAndRemotePLC()
  1722             self.CompareLocalAndRemotePLC()
  1718             
  1723             
  1719             # Init with actual PLC status and print it
  1724             # Init with actual PLC status and print it
  1720             self.previous_plcstate = self.UpdateMethodsFromPLCStatus()
  1725             self.previous_plcstate = self.UpdateMethodsFromPLCStatus()
  1721             self.logger.write("PLC is %s\n"%self.previous_plcstate)
  1726             if self.previous_plcstate is not None:
       
  1727                 status = _(self.previous_plcstate)
       
  1728             else:
       
  1729                 status = ""
       
  1730             self.logger.write(_("PLC is %s\n")%status)
  1722             
  1731             
  1723             # Start the status Timer
  1732             # Start the status Timer
  1724             self.StatusTimer.Start(milliseconds=500, oneShot=False)
  1733             self.StatusTimer.Start(milliseconds=500, oneShot=False)
  1725 
  1734 
  1726     def CompareLocalAndRemotePLC(self):
  1735     def CompareLocalAndRemotePLC(self):
  1730         MD5 = self.GetLastBuildMD5()
  1739         MD5 = self.GetLastBuildMD5()
  1731         # Check remote target PLC correspondance to that md5
  1740         # Check remote target PLC correspondance to that md5
  1732         if MD5 is not None:
  1741         if MD5 is not None:
  1733             if not self._connector.MatchMD5(MD5):
  1742             if not self._connector.MatchMD5(MD5):
  1734                 self.logger.write_warning(
  1743                 self.logger.write_warning(
  1735                    "Latest build do not match with target, please transfer.\n")
  1744                    _("Latest build do not match with target, please transfer.\n"))
  1736                 self.EnableMethod("_Transfer", True)
  1745                 self.EnableMethod("_Transfer", True)
  1737             else:
  1746             else:
  1738                 self.logger.write(
  1747                 self.logger.write(
  1739                    "Latest build match target, no transfer needed.\n")
  1748                    _("Latest build match target, no transfer needed.\n"))
  1740                 self.EnableMethod("_Transfer", True)
  1749                 self.EnableMethod("_Transfer", True)
  1741                 #self.EnableMethod("_Transfer", False)
  1750                 #self.EnableMethod("_Transfer", False)
  1742         else:
  1751         else:
  1743             self.logger.write_warning(
  1752             self.logger.write_warning(
  1744                 "Cannot compare latest build to target. Please build.\n")
  1753                 _("Cannot compare latest build to target. Please build.\n"))
  1745             self.EnableMethod("_Transfer", False)
  1754             self.EnableMethod("_Transfer", False)
  1746 
  1755 
  1747 
  1756 
  1748     def _Disconnect(self):
  1757     def _Disconnect(self):
  1749         self._connector = None
  1758         self._connector = None
  1754         # Get the last build PLC's 
  1763         # Get the last build PLC's 
  1755         MD5 = self.GetLastBuildMD5()
  1764         MD5 = self.GetLastBuildMD5()
  1756         
  1765         
  1757         # Check if md5 file is empty : ask user to build PLC 
  1766         # Check if md5 file is empty : ask user to build PLC 
  1758         if MD5 is None :
  1767         if MD5 is None :
  1759             self.logger.write_error("Failed : Must build before transfer.\n")
  1768             self.logger.write_error(_("Failed : Must build before transfer.\n"))
  1760             return False
  1769             return False
  1761 
  1770 
  1762         # Compare PLC project with PLC on target
  1771         # Compare PLC project with PLC on target
  1763         if self._connector.MatchMD5(MD5):
  1772         if self._connector.MatchMD5(MD5):
  1764             self.logger.write(
  1773             self.logger.write(
  1765                 "Latest build already match current target. Transfering anyway...\n")
  1774                 _("Latest build already match current target. Transfering anyway...\n"))
  1766 
  1775 
  1767         # Get temprary directory path
  1776         # Get temprary directory path
  1768         extrafilespath = self._getExtraFilesPath()
  1777         extrafilespath = self._getExtraFilesPath()
  1769         extrafiles = [(name, open(os.path.join(extrafilespath, name), 
  1778         extrafiles = [(name, open(os.path.join(extrafilespath, name), 
  1770                                   'rb').read()) \
  1779                                   'rb').read()) \
  1780                     if self.PLCDebug is not None:
  1789                     if self.PLCDebug is not None:
  1781                         self.PLCDebug.Close()
  1790                         self.PLCDebug.Close()
  1782                         self.PLCDebug = None
  1791                         self.PLCDebug = None
  1783                     self.UnsubscribeAllDebugIECVariable()
  1792                     self.UnsubscribeAllDebugIECVariable()
  1784                     self.ProgramTransferred()
  1793                     self.ProgramTransferred()
  1785                     self.logger.write("Transfer completed successfully.\n")
  1794                     self.logger.write(_("Transfer completed successfully.\n"))
  1786                 else:
  1795                 else:
  1787                     self.logger.write_error("Transfer failed\n")
  1796                     self.logger.write_error(_("Transfer failed\n"))
  1788             else:
  1797             else:
  1789                 self.logger.write_error("No PLC to transfer (did build success ?)\n")
  1798                 self.logger.write_error(_("No PLC to transfer (did build success ?)\n"))
  1790         self.UpdateMethodsFromPLCStatus()
  1799         self.UpdateMethodsFromPLCStatus()
  1791 
  1800 
  1792     PluginMethods = [
  1801     PluginMethods = [
  1793         {"bitmap" : opjimg("editPLC"),
  1802         {"bitmap" : opjimg("editPLC"),
  1794          "name" : "Edit PLC",
  1803          "name" : _("Edit PLC"),
  1795          "tooltip" : "Edit PLC program with PLCOpenEditor",
  1804          "tooltip" : _("Edit PLC program with PLCOpenEditor"),
  1796          "method" : "_EditPLC"},
  1805          "method" : "_EditPLC"},
  1797         {"bitmap" : opjimg("Build"),
  1806         {"bitmap" : opjimg("Build"),
  1798          "name" : "Build",
  1807          "name" : _("Build"),
  1799          "tooltip" : "Build project into build folder",
  1808          "tooltip" : _("Build project into build folder"),
  1800          "method" : "_build"},
  1809          "method" : "_build"},
  1801         {"bitmap" : opjimg("Clean"),
  1810         {"bitmap" : opjimg("Clean"),
  1802          "name" : "Clean",
  1811          "name" : _("Clean"),
  1803          "enabled" : False,
  1812          "enabled" : False,
  1804          "tooltip" : "Clean project build folder",
  1813          "tooltip" : _("Clean project build folder"),
  1805          "method" : "_Clean"},
  1814          "method" : "_Clean"},
  1806         {"bitmap" : opjimg("Run"),
  1815         {"bitmap" : opjimg("Run"),
  1807          "name" : "Run",
  1816          "name" : _("Run"),
  1808          "shown" : False,
  1817          "shown" : False,
  1809          "tooltip" : "Start PLC",
  1818          "tooltip" : _("Start PLC"),
  1810          "method" : "_Run"},
  1819          "method" : "_Run"},
  1811         {"bitmap" : opjimg("Debug"),
  1820         {"bitmap" : opjimg("Debug"),
  1812          "name" : "Debug",
  1821          "name" : _("Debug"),
  1813          "shown" : False,
  1822          "shown" : False,
  1814          "tooltip" : "Start PLC (debug mode)",
  1823          "tooltip" : _("Start PLC (debug mode)"),
  1815          "method" : "_Debug"},
  1824          "method" : "_Debug"},
  1816 #        {"bitmap" : opjimg("Debug"),
  1825 #        {"bitmap" : opjimg("Debug"),
  1817 #         "name" : "Do_Test_Debug",
  1826 #         "name" : "Do_Test_Debug",
  1818 #         "tooltip" : "Test debug mode)",
  1827 #         "tooltip" : "Test debug mode)",
  1819 #         "method" : "_Do_Test_Debug"},
  1828 #         "method" : "_Do_Test_Debug"},
  1820         {"bitmap" : opjimg("Stop"),
  1829         {"bitmap" : opjimg("Stop"),
  1821          "name" : "Stop",
  1830          "name" : _("Stop"),
  1822          "shown" : False,
  1831          "shown" : False,
  1823          "tooltip" : "Stop Running PLC",
  1832          "tooltip" : _("Stop Running PLC"),
  1824          "method" : "_Stop"},
  1833          "method" : "_Stop"},
  1825         {"bitmap" : opjimg("Connect"),
  1834         {"bitmap" : opjimg("Connect"),
  1826          "name" : "Connect",
  1835          "name" : _("Connect"),
  1827          "tooltip" : "Connect to the target PLC",
  1836          "tooltip" : _("Connect to the target PLC"),
  1828          "method" : "_Connect"},
  1837          "method" : "_Connect"},
  1829         {"bitmap" : opjimg("Transfer"),
  1838         {"bitmap" : opjimg("Transfer"),
  1830          "name" : "Transfer",
  1839          "name" : _("Transfer"),
  1831          "shown" : False,
  1840          "shown" : False,
  1832          "tooltip" : "Transfer PLC",
  1841          "tooltip" : _("Transfer PLC"),
  1833          "method" : "_Transfer"},
  1842          "method" : "_Transfer"},
  1834         {"bitmap" : opjimg("Disconnect"),
  1843         {"bitmap" : opjimg("Disconnect"),
  1835          "name" : "Disconnect",
  1844          "name" : _("Disconnect"),
  1836          "shown" : False,
  1845          "shown" : False,
  1837          "tooltip" : "Disconnect from PLC",
  1846          "tooltip" : _("Disconnect from PLC"),
  1838          "method" : "_Disconnect"},
  1847          "method" : "_Disconnect"},
  1839         {"bitmap" : opjimg("ShowIECcode"),
  1848         {"bitmap" : opjimg("ShowIECcode"),
  1840          "name" : "Show code",
  1849          "name" : _("Show code"),
  1841          "shown" : False,
  1850          "shown" : False,
  1842          "tooltip" : "Show IEC code generated by PLCGenerator",
  1851          "tooltip" : _("Show IEC code generated by PLCGenerator"),
  1843          "method" : "_showIECcode"},
  1852          "method" : "_showIECcode"},
  1844         {"bitmap" : opjimg("editIECrawcode"),
  1853         {"bitmap" : opjimg("editIECrawcode"),
  1845          "name" : "Raw IEC code",
  1854          "name" : _("Raw IEC code"),
  1846          "tooltip" : "Edit raw IEC code added to code generated by PLCGenerator",
  1855          "tooltip" : _("Edit raw IEC code added to code generated by PLCGenerator"),
  1847          "method" : "_editIECrawcode"},
  1856          "method" : "_editIECrawcode"},
  1848         {"bitmap" : opjimg("editPYTHONcode"),
  1857         {"bitmap" : opjimg("editPYTHONcode"),
  1849          "name" : "Python code",
  1858          "name" : "Python code",
  1850          "tooltip" : "Write Python runtime code, for use with python_eval FBs",
  1859          "tooltip" : "Write Python runtime code, for use with python_eval FBs",
  1851          "method" : "_editPYTHONcode"},
  1860          "method" : "_editPYTHONcode"},