LPCManager.py
changeset 2 0c697b8fc443
parent 1 4f6d393cb36e
child 3 169d552a345c
child 4 e8a0af6b89d9
equal deleted inserted replaced
1:4f6d393cb36e 2:0c697b8fc443
    57 
    57 
    58 if __name__ == '__main__':
    58 if __name__ == '__main__':
    59     __builtin__.__dict__['_'] = wx.GetTranslation#unicode_translation
    59     __builtin__.__dict__['_'] = wx.GetTranslation#unicode_translation
    60 
    60 
    61 _base_folder = os.path.split(sys.path[0])[0]
    61 _base_folder = os.path.split(sys.path[0])[0]
    62 sys.path.append(os.path.join(base_folder, "beremiz"))
    62 sys.path.append(os.path.join(_base_folder, "beremiz"))
    63 
    63 
    64 _base_path = path.split(__file__)[0]
    64 _base_path = os.path.split(__file__)[0]
       
    65 
       
    66 import connectors
       
    67 from LPCconnector import LPC_connector_factory
       
    68 connectors.connectors["LPC"]=lambda:LPC_connector_factory
       
    69 
       
    70 import targets
       
    71 from LPCtarget import LPC_target 
       
    72 targets.targets["LPC"] = {"xsd": os.path.join(_base_path, "LPCtarget", "XSD"),
       
    73                           "class": lambda:LPC_target,
       
    74                           "code": os.path.join(_base_path,"LPCtarget","plc_LPC_main.c")} 
       
    75 targets.toolchains["makefile"] = os.path.join(_base_path, "LPCtarget", "XSD_toolchain_makefile")
       
    76 
       
    77 # helper func to get path to images
       
    78 from util import misc
       
    79 misc.opjimg = lambda imgname: os.path.join(_base_folder, "beremiz", "images", imgname+".png")
    65 
    80 
    66 from Beremiz import *
    81 from Beremiz import *
    67 from ProjectController import ProjectController
    82 from ProjectController import ProjectController
    68 from ConfigTreeNode import ConfigTreeNode
    83 from ConfigTreeNode import ConfigTreeNode
    69 
    84 from ProjectNodeEditor import ProjectNodeEditor
    70 import connectors
    85 
    71 from LPCconnector import LPC_connector_factory
       
    72 connectors.connectors["LPC"]=lambda:LPC_connector_factory
       
    73 
       
    74 import targets
       
    75 from LPCtarget import LPC_target 
       
    76 targets.targets["LPC"]={"xsd": path.join(_base_path, "LPCtarget", "XSD"),
       
    77                         "class": LPC_target,
       
    78                         "code": path.join(_base_path,"LPCtarget","plc_LPC_main.c")} 
       
    79 targets.toolchains["makefile"]= path.join(_base_path, "LPCtarget", "XSD_toolchain_makefile"),
       
    80 
       
    81 from util import opjimg
       
    82 from plcopen.structures import LOCATIONDATATYPES
    86 from plcopen.structures import LOCATIONDATATYPES
    83 from PLCControler import LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP,\
    87 from PLCControler import PLCControler, LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP,\
    84                          LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY
    88                          LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY
    85 from PLCOpenEditor import IDEFrame, ProjectDialog
    89 from PLCOpenEditor import IDEFrame, ProjectDialog
    86 
    90 
    87 havecanfestival = False
    91 havecanfestival = False
    88 try:
    92 try:
    89     from canfestival import RootClass as CanOpenRootClass
    93     from canfestival import RootClass as CanOpenRootClass
    90     from canfestival.canfestival import _SlaveCTN, _NodeListCTN, NodeManager
    94     from canfestival.canfestival import _SlaveCTN, _NodeListCTN, NodeManager
       
    95     from canfestival.NetworkEditor import NetworkEditor
       
    96     from canfestival.SlaveEditor import SlaveEditor
    91     havecanfestival = True
    97     havecanfestival = True
    92 except:
    98 except:
    93     havecanfestival = False
    99     havecanfestival = False
    94     
   100     
       
   101 SCROLLBAR_UNIT = 10
       
   102 WINDOW_COLOUR = wx.Colour(240,240,240)
       
   103 TITLE_COLOUR = wx.Colour(200,200,220)
       
   104 CHANGED_TITLE_COLOUR = wx.Colour(220,200,220)
       
   105 CHANGED_WINDOW_COLOUR = wx.Colour(255,240,240)
       
   106 
       
   107 if wx.Platform == '__WXMSW__':
       
   108     faces = { 'times': 'Times New Roman',
       
   109               'mono' : 'Courier New',
       
   110               'helv' : 'Arial',
       
   111               'other': 'Comic Sans MS',
       
   112               'size' : 16,
       
   113              }
       
   114 else:
       
   115     faces = { 'times': 'Times',
       
   116               'mono' : 'Courier',
       
   117               'helv' : 'Helvetica',
       
   118               'other': 'new century schoolbook',
       
   119               'size' : 18,
       
   120              }
       
   121 
       
   122 # Some helpers to tweak GenBitmapTextButtons
       
   123 # TODO: declare customized classes instead.
       
   124 gen_mini_GetBackgroundBrush = lambda obj:lambda dc: wx.Brush(obj.GetParent().GetBackgroundColour(), wx.SOLID)
       
   125 gen_textbutton_GetLabelSize = lambda obj:lambda:(wx.lib.buttons.GenButton._GetLabelSize(obj)[:-1] + (False,))
       
   126 
       
   127 def make_genbitmaptogglebutton_flat(button):
       
   128     button.GetBackgroundBrush = gen_mini_GetBackgroundBrush(button)
       
   129     button.labelDelta = 0
       
   130     button.SetBezelWidth(0)
       
   131     button.SetUseFocusIndicator(False)
       
   132 
       
   133 # Patch wx.lib.imageutils so that gray is supported on alpha images
       
   134 import wx.lib.imageutils
       
   135 from wx.lib.imageutils import grayOut as old_grayOut
       
   136 def grayOut(anImage):
       
   137     if anImage.HasAlpha():
       
   138         AlphaData = anImage.GetAlphaData()
       
   139     else :
       
   140         AlphaData = None
       
   141 
       
   142     old_grayOut(anImage)
       
   143 
       
   144     if AlphaData is not None:
       
   145         anImage.SetAlphaData(AlphaData)
       
   146 
       
   147 wx.lib.imageutils.grayOut = grayOut
       
   148 
       
   149 class GenBitmapTextButton(wx.lib.buttons.GenBitmapTextButton):
       
   150     def _GetLabelSize(self):
       
   151         """ used internally """
       
   152         w, h = self.GetTextExtent(self.GetLabel())
       
   153         if not self.bmpLabel:
       
   154             return w, h, False       # if there isn't a bitmap use the size of the text
       
   155 
       
   156         w_bmp = self.bmpLabel.GetWidth()+2
       
   157         h_bmp = self.bmpLabel.GetHeight()+2
       
   158         height = h + h_bmp
       
   159         if w_bmp > w:
       
   160             width = w_bmp
       
   161         else:
       
   162             width = w
       
   163         return width, height, False
       
   164 
       
   165     def DrawLabel(self, dc, width, height, dw=0, dy=0):
       
   166         bmp = self.bmpLabel
       
   167         if bmp != None:     # if the bitmap is used
       
   168             if self.bmpDisabled and not self.IsEnabled():
       
   169                 bmp = self.bmpDisabled
       
   170             if self.bmpFocus and self.hasFocus:
       
   171                 bmp = self.bmpFocus
       
   172             if self.bmpSelected and not self.up:
       
   173                 bmp = self.bmpSelected
       
   174             bw,bh = bmp.GetWidth(), bmp.GetHeight()
       
   175             if not self.up:
       
   176                 dw = dy = self.labelDelta
       
   177             hasMask = bmp.GetMask() != None
       
   178         else:
       
   179             bw = bh = 0     # no bitmap -> size is zero
       
   180 
       
   181         dc.SetFont(self.GetFont())
       
   182         if self.IsEnabled():
       
   183             dc.SetTextForeground(self.GetForegroundColour())
       
   184         else:
       
   185             dc.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT))
       
   186 
       
   187         label = self.GetLabel()
       
   188         tw, th = dc.GetTextExtent(label)        # size of text
       
   189         if not self.up:
       
   190             dw = dy = self.labelDelta
       
   191 
       
   192         pos_x = (width-bw)/2+dw      # adjust for bitmap and text to centre
       
   193         pos_y = (height-bh-th)/2+dy
       
   194         if bmp !=None:
       
   195             dc.DrawBitmap(bmp, pos_x, pos_y, hasMask) # draw bitmap if available
       
   196             pos_x = (width-tw)/2+dw      # adjust for bitmap and text to centre
       
   197             pos_y += bh + 2
       
   198 
       
   199         dc.DrawText(label, pos_x, pos_y)      # draw the text
       
   200 
    95 
   201 
    96 #-------------------------------------------------------------------------------
   202 #-------------------------------------------------------------------------------
    97 #                          CANFESTIVAL CONFNODE HACK
   203 #                          CANFESTIVAL CONFNODE HACK
    98 #-------------------------------------------------------------------------------
   204 #-------------------------------------------------------------------------------
    99 # from canfestival import canfestival
   205 # from canfestival import canfestival
   395         "CAN_Baudrate": "125K",
   501         "CAN_Baudrate": "125K",
   396         "Slave_NodeId": 2,
   502         "Slave_NodeId": 2,
   397         "Master_NodeId": 1,
   503         "Master_NodeId": 1,
   398     }
   504     }
   399     
   505     
       
   506     class LPCSlaveEditor(SlaveEditor):
       
   507         SHOW_PARAMS = False
       
   508     
   400     class LPCCanOpenSlave(_SlaveCTN):
   509     class LPCCanOpenSlave(_SlaveCTN):
   401         XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
   510         XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
   402         <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   511         <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   403           <xsd:element name="CanFestivalSlaveNode">
   512           <xsd:element name="CanFestivalSlaveNode">
   404             <xsd:complexType>
   513             <xsd:complexType>
   416             </xsd:complexType>
   525             </xsd:complexType>
   417           </xsd:element>
   526           </xsd:element>
   418         </xsd:schema>
   527         </xsd:schema>
   419         """ % DEFAULT_SETTINGS
   528         """ % DEFAULT_SETTINGS
   420         
   529         
       
   530         EditorType = LPCSlaveEditor
       
   531         
   421         def __init__(self):
   532         def __init__(self):
   422             # TODO change netname when name change
   533             # TODO change netname when name change
   423             NodeManager.__init__(self)
   534             NodeManager.__init__(self)
   424             odfilepath = self.GetSlaveODPath()
   535             odfilepath = self.GetSlaveODPath()
   425             if(os.path.isfile(odfilepath)):
   536             if(os.path.isfile(odfilepath)):
   435                                    [])           # options
   546                                    [])           # options
   436                 self.OnCTNSave()
   547                 self.OnCTNSave()
   437         
   548         
   438         def GetCanDevice(self):
   549         def GetCanDevice(self):
   439             return str(self.BaseParams.getIEC_Channel())
   550             return str(self.BaseParams.getIEC_Channel())
       
   551     
       
   552     class LPCNetworkEditor(NetworkEditor):
       
   553         SHOW_PARAMS = False
   440         
   554         
   441     class LPCCanOpenMaster(_NodeListCTN):
   555     class LPCCanOpenMaster(_NodeListCTN):
   442         XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
   556         XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
   443         <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   557         <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   444           <xsd:element name="CanFestivalNode">
   558           <xsd:element name="CanFestivalNode">
   448               <xsd:attribute name="Sync_TPDOs" type="xsd:boolean" use="optional" default="true"/>
   562               <xsd:attribute name="Sync_TPDOs" type="xsd:boolean" use="optional" default="true"/>
   449             </xsd:complexType>
   563             </xsd:complexType>
   450           </xsd:element>
   564           </xsd:element>
   451         </xsd:schema>
   565         </xsd:schema>
   452         """ % DEFAULT_SETTINGS
   566         """ % DEFAULT_SETTINGS
   453     
   567         
       
   568         EditorType = LPCNetworkEditor
       
   569         
   454         def GetCanDevice(self):
   570         def GetCanDevice(self):
   455             return str(self.BaseParams.getIEC_Channel())
   571             return str(self.BaseParams.getIEC_Channel())
   456     
   572     
   457     class LPCCanOpen(CanOpenRootClass):
   573     class LPCCanOpen(CanOpenRootClass):
   458         XSD = None
   574         XSD = None
   466             ConfigTreeNode.LoadChildren(self)
   582             ConfigTreeNode.LoadChildren(self)
   467             
   583             
   468             if self.GetChildByName("Master") is None:
   584             if self.GetChildByName("Master") is None:
   469                 master = self.CTNAddChild("Master", "CanOpenNode", 0)
   585                 master = self.CTNAddChild("Master", "CanOpenNode", 0)
   470                 master.BaseParams.setEnabled(False)
   586                 master.BaseParams.setEnabled(False)
       
   587                 master.CTNRequestSave()
   471             
   588             
   472             if self.GetChildByName("Slave") is None:
   589             if self.GetChildByName("Slave") is None:
   473                 slave = self.CTNAddChild("Slave", "CanOpenSlave", 1)
   590                 slave = self.CTNAddChild("Slave", "CanOpenSlave", 1)
   474                 slave.BaseParams.setEnabled(False)
   591                 slave.BaseParams.setEnabled(False)
       
   592                 slave.CTNRequestSave()
   475     
   593     
   476 
   594 
   477 #-------------------------------------------------------------------------------
   595 #-------------------------------------------------------------------------------
   478 #                              LPCProjectController Class
   596 #                              LPCProjectController Class
   479 #-------------------------------------------------------------------------------
   597 #-------------------------------------------------------------------------------
   496             elif os.path.isfile(srcpath):
   614             elif os.path.isfile(srcpath):
   497                 shutil.copy2(srcpath, dstpath)
   615                 shutil.copy2(srcpath, dstpath)
   498 
   616 
   499 [SIMULATION_MODE, TRANSFER_MODE] = range(2)
   617 [SIMULATION_MODE, TRANSFER_MODE] = range(2)
   500 
   618 
       
   619 class LPCProjectNodeEditor(ProjectNodeEditor):
       
   620     SHOW_PARAMS = False
       
   621     ENABLE_REQUIRED = False
       
   622 
   501 class LPCProjectController(ProjectController):
   623 class LPCProjectController(ProjectController):
   502 
   624 
   503     ConfNodeMethods = [
   625     StatusMethods = [
   504         {"bitmap" : opjimg("Debug"),
   626         {"bitmap" : "Debug",
   505          "name" : _("Simulate"),
   627          "name" : _("Simulate"),
   506          "tooltip" : _("Simulate PLC"),
   628          "tooltip" : _("Simulate PLC"),
   507          "method" : "_Simulate"},
   629          "method" : "_Simulate"},
   508         {"bitmap" : opjimg("Run"),
   630         {"bitmap" : "Run",
   509          "name" : _("Run"),
   631          "name" : _("Run"),
   510          "shown" : False,
   632          "shown" : False,
   511          "tooltip" : _("Start PLC"),
   633          "tooltip" : _("Start PLC"),
   512          "method" : "_Run"},
   634          "method" : "_Run"},
   513         {"bitmap" : opjimg("Stop"),
   635         {"bitmap" : "Stop",
   514          "name" : _("Stop"),
   636          "name" : _("Stop"),
   515          "shown" : False,
   637          "shown" : False,
   516          "tooltip" : _("Stop Running PLC"),
   638          "tooltip" : _("Stop Running PLC"),
   517          "method" : "_Stop"},
   639          "method" : "_Stop"},
   518         {"bitmap" : opjimg("Build"),
   640         {"bitmap" : "Build",
   519          "name" : _("Build"),
   641          "name" : _("Build"),
   520          "tooltip" : _("Build project into build folder"),
   642          "tooltip" : _("Build project into build folder"),
   521          "method" : "_Build"},
   643          "method" : "_Build"},
   522         {"bitmap" : opjimg("Transfer"),
   644         {"bitmap" : "Transfer",
   523          "name" : _("Transfer"),
   645          "name" : _("Transfer"),
   524          "shown" : False,
   646          "shown" : False,
   525          "tooltip" : _("Transfer PLC"),
   647          "tooltip" : _("Transfer PLC"),
   526          "method" : "_Transfer"},
   648          "method" : "_Transfer"},
   527     ]
   649     ]
   528 
   650     
       
   651     ConfNodeMethods = []
       
   652     
       
   653     EditorType = LPCProjectNodeEditor
       
   654     
   529     def __init__(self, frame, logger, buildpath):
   655     def __init__(self, frame, logger, buildpath):
   530         self.OrigBuildPath = buildpath
   656         self.OrigBuildPath = buildpath
   531         
   657         
   532         ProjectController.__init__(self, frame, logger)
   658         ProjectController.__init__(self, frame, logger)
   533         
   659         
   544         self.previous_mode = None
   670         self.previous_mode = None
   545         
   671         
   546         self.SimulationBuildPath = None
   672         self.SimulationBuildPath = None
   547         
   673         
   548         self.AbortTransferTimer = None
   674         self.AbortTransferTimer = None
       
   675     
       
   676     def GetProjectInfos(self):
       
   677         infos = PLCControler.GetProjectInfos(self)
       
   678         configurations = infos["values"].pop(-1)
       
   679         resources = None
       
   680         for config_infos in configurations["values"]:
       
   681             if resources is None:
       
   682                 resources = config_infos["values"][0]
       
   683             else:
       
   684                 resources["values"].extend(config_infos["values"][0]["values"])
       
   685         if resources is not None:
       
   686             infos["values"].append(resources)
       
   687         return infos
   549     
   688     
   550     def ConfNodeLibraryFilePath(self):
   689     def ConfNodeLibraryFilePath(self):
   551         if self.OrigBuildPath is not None:
   690         if self.OrigBuildPath is not None:
   552             return os.path.join(self.OrigBuildPath, "pous.xml")
   691             return os.path.join(self.OrigBuildPath, "pous.xml")
   553         else:
   692         else:
   715         
   854         
   716         if havecanfestival and self.GetChildByName("CanOpen") is None:
   855         if havecanfestival and self.GetChildByName("CanOpen") is None:
   717             canopen = self.CTNAddChild("CanOpen", "CanOpen", 0)
   856             canopen = self.CTNAddChild("CanOpen", "CanOpen", 0)
   718             canopen.BaseParams.setEnabled(False)
   857             canopen.BaseParams.setEnabled(False)
   719             canopen.LoadChildren()
   858             canopen.LoadChildren()
       
   859             canopen.CTNRequestSave()
   720         
   860         
   721         if self.CTNTestModified():
   861         if self.CTNTestModified():
   722             self.SaveProject()
   862             self.SaveProject()
   723         
   863         
   724         if wx.GetApp() is None:
   864         if wx.GetApp() is None:
  1082         AppendMenu(parent, help='', id=wx.ID_PREVIEW,
  1222         AppendMenu(parent, help='', id=wx.ID_PREVIEW,
  1083               kind=wx.ITEM_NORMAL, text=_(u'Preview'))
  1223               kind=wx.ITEM_NORMAL, text=_(u'Preview'))
  1084         AppendMenu(parent, help='', id=wx.ID_PRINT,
  1224         AppendMenu(parent, help='', id=wx.ID_PRINT,
  1085               kind=wx.ITEM_NORMAL, text=_(u'Print'))
  1225               kind=wx.ITEM_NORMAL, text=_(u'Print'))
  1086         parent.AppendSeparator()
  1226         parent.AppendSeparator()
  1087         AppendMenu(parent, help='', id=wx.ID_PROPERTIES,
       
  1088               kind=wx.ITEM_NORMAL, text=_(u'Properties'))
       
  1089         parent.AppendSeparator()
       
  1090         AppendMenu(parent, help='', id=wx.ID_EXIT,
  1227         AppendMenu(parent, help='', id=wx.ID_EXIT,
  1091               kind=wx.ITEM_NORMAL, text=_(u'Quit\tCTRL+Q'))
  1228               kind=wx.ITEM_NORMAL, text=_(u'Quit\tCTRL+Q'))
  1092         
  1229         
  1093         self.Bind(wx.EVT_MENU, self.OnSaveProjectMenu, id=wx.ID_SAVE)
  1230         self.Bind(wx.EVT_MENU, self.OnSaveProjectMenu, id=wx.ID_SAVE)
  1094         self.Bind(wx.EVT_MENU, self.OnCloseTabMenu, id=wx.ID_CLOSE)
  1231         self.Bind(wx.EVT_MENU, self.OnCloseTabMenu, id=wx.ID_CLOSE)
  1095         self.Bind(wx.EVT_MENU, self.OnPageSetupMenu, id=wx.ID_PAGE_SETUP)
  1232         self.Bind(wx.EVT_MENU, self.OnPageSetupMenu, id=wx.ID_PAGE_SETUP)
  1096         self.Bind(wx.EVT_MENU, self.OnPreviewMenu, id=wx.ID_PREVIEW)
  1233         self.Bind(wx.EVT_MENU, self.OnPreviewMenu, id=wx.ID_PREVIEW)
  1097         self.Bind(wx.EVT_MENU, self.OnPrintMenu, id=wx.ID_PRINT)
  1234         self.Bind(wx.EVT_MENU, self.OnPrintMenu, id=wx.ID_PRINT)
  1098         self.Bind(wx.EVT_MENU, self.OnPropertiesMenu, id=wx.ID_PROPERTIES)
       
  1099         self.Bind(wx.EVT_MENU, self.OnQuitMenu, id=wx.ID_EXIT)
  1235         self.Bind(wx.EVT_MENU, self.OnQuitMenu, id=wx.ID_EXIT)
  1100     
  1236     
  1101         self.AddToMenuToolBar([(wx.ID_SAVE, "save.png", _(u'Save'), None),
  1237         self.AddToMenuToolBar([(wx.ID_SAVE, "save.png", _(u'Save'), None),
  1102                                (wx.ID_PRINT, "print.png", _(u'Print'), None)])
  1238                                (wx.ID_PRINT, "print.png", _(u'Print'), None)])
  1103     
  1239     
       
  1240     def _init_coll_AddMenu_Items(self, parent):
       
  1241         IDEFrame._init_coll_AddMenu_Items(self, parent, False)
       
  1242         new_id = wx.NewId()
       
  1243         AppendMenu(parent, help='', id=new_id,
       
  1244                   kind=wx.ITEM_NORMAL, text=_(u'&Resource'))
       
  1245         self.Bind(wx.EVT_MENU, self.AddResourceMenu, id=new_id)
       
  1246     
  1104     def _init_ctrls(self, prnt):
  1247     def _init_ctrls(self, prnt):
  1105         IDEFrame._init_ctrls(self, prnt)
  1248         Beremiz._init_ctrls(self, prnt)
  1106         
       
  1107         self.Bind(wx.EVT_MENU, self.OnOpenWidgetInspector, id=ID_BEREMIZINSPECTOR)
       
  1108         accel = wx.AcceleratorTable([wx.AcceleratorEntry(wx.ACCEL_CTRL|wx.ACCEL_ALT, ord('I'), ID_BEREMIZINSPECTOR)])
       
  1109         self.SetAcceleratorTable(accel)
       
  1110         
  1249         
  1111         self.PLCConfig = wx.ScrolledWindow(id=ID_BEREMIZPLCCONFIG,
  1250         self.PLCConfig = wx.ScrolledWindow(id=ID_BEREMIZPLCCONFIG,
  1112               name='PLCConfig', parent=self.LeftNoteBook, pos=wx.Point(0, 0),
  1251               name='PLCConfig', parent=self.LeftNoteBook, pos=wx.Point(0, 0),
  1113               size=wx.Size(-1, -1), style=wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER|wx.HSCROLL|wx.VSCROLL)
  1252               size=wx.Size(-1, -1), style=wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER|wx.HSCROLL|wx.VSCROLL)
  1114         self.PLCConfig.SetBackgroundColour(wx.WHITE)
  1253         self.PLCConfig.SetBackgroundColour(wx.WHITE)
  1115         self.PLCConfig.Bind(wx.EVT_LEFT_DOWN, self.OnPanelLeftDown)
  1254         self.PLCConfig.Bind(wx.EVT_LEFT_DOWN, self.OnPanelLeftDown)
  1116         self.PLCConfig.Bind(wx.EVT_SIZE, self.OnMoveWindow)
  1255         self.PLCConfig.Bind(wx.EVT_SIZE, self.OnMoveWindow)
       
  1256         self.MainTabs["PLCConfig"] = (self.PLCConfig, _("Topology"))
  1117         self.LeftNoteBook.InsertPage(0, self.PLCConfig, _("Topology"), True)
  1257         self.LeftNoteBook.InsertPage(0, self.PLCConfig, _("Topology"), True)
  1118         
  1258         
  1119         self.LogConsole = wx.TextCtrl(id=ID_BEREMIZLOGCONSOLE, value='',
  1259         self.PLCConfigMainSizer = wx.FlexGridSizer(cols=1, hgap=2, rows=2, vgap=2)
  1120                   name='LogConsole', parent=self.BottomNoteBook, pos=wx.Point(0, 0),
  1260         self.PLCParamsSizer = wx.BoxSizer(wx.VERTICAL)
  1121                   size=wx.Size(0, 0), style=wx.TE_MULTILINE|wx.TE_RICH2)
  1261         self.ConfNodeTreeSizer = wx.FlexGridSizer(cols=2, hgap=0, rows=0, vgap=2)
  1122         self.LogConsole.Bind(wx.EVT_LEFT_DCLICK, self.OnLogConsoleDClick)
  1262         self.ConfNodeTreeSizer.AddGrowableCol(0)
  1123         self.BottomNoteBook.AddPage(self.LogConsole, _("Log Console"))
  1263         self.ConfNodeTreeSizer.AddGrowableCol(1)
  1124         
  1264         
  1125         self._init_beremiz_sizers()
  1265         self.PLCConfigMainSizer.AddSizer(self.PLCParamsSizer, 0, border=10, flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT)
  1126 
  1266         self.PLCConfigMainSizer.AddSizer(self.ConfNodeTreeSizer, 0, border=10, flag=wx.BOTTOM|wx.LEFT|wx.RIGHT)
       
  1267         self.PLCConfigMainSizer.AddGrowableCol(0)
       
  1268         self.PLCConfigMainSizer.AddGrowableRow(1)
       
  1269         
       
  1270         self.PLCConfig.SetSizer(self.PLCConfigMainSizer)
       
  1271         
       
  1272         self.AUIManager.Update()
       
  1273 
       
  1274     def __init__(self, parent, projectOpen=None, buildpath=None, ctr=None, debug=True):
       
  1275         self.ConfNodeInfos = {}
       
  1276         
       
  1277         Beremiz.__init__(self, parent, projectOpen, buildpath, ctr, debug)
       
  1278         
  1127     def OnCloseFrame(self, event):
  1279     def OnCloseFrame(self, event):
  1128         global frame
  1280         global frame
  1129         
  1281         
  1130         if self.CheckSaveBeforeClosing(_("Close Application")):
  1282         if self.CheckSaveBeforeClosing(_("Close Application")):
  1131             
  1283             
  1142             
  1294             
  1143             lpcberemiz_cmd.Log.write("Closed\n")
  1295             lpcberemiz_cmd.Log.write("Closed\n")
  1144             
  1296             
  1145         event.Veto()
  1297         event.Veto()
  1146 
  1298 
  1147     def ShowProperties(self):
  1299     def OnMoveWindow(self, event):
  1148         old_values = self.Controler.GetProjectProperties()
  1300         self.GetBestSize()
  1149         dialog = ProjectDialog(self ,False)
  1301         self.RefreshScrollBars()
  1150         dialog.SetValues(old_values)
  1302         event.Skip()
  1151         if dialog.ShowModal() == wx.ID_OK:
  1303 
  1152             new_values = dialog.GetValues()
  1304     def OnPanelLeftDown(self, event):
  1153             new_values["creationDateTime"] = old_values["creationDateTime"]
  1305         focused = self.FindFocus()
  1154             if new_values != old_values:
  1306         if isinstance(focused, TextCtrlAutoComplete):
  1155                 self.Controler.SetProjectProperties(None, new_values)
  1307             focused.DismissListBox()
  1156                 self._Refresh(TITLE, EDITORTOOLBAR, FILEMENU, EDITMENU, DISPLAYMENU, 
  1308         event.Skip()
  1157                               PROJECTTREE, POUINSTANCEVARIABLESPANEL, SCALING)
       
  1158         dialog.Destroy()
       
  1159 
  1309 
  1160     def RefreshFileMenu(self):
  1310     def RefreshFileMenu(self):
  1161         MenuToolBar = self.Panes["MenuToolBar"]
  1311         MenuToolBar = self.Panes["MenuToolBar"]
  1162         if self.CTR is not None:
  1312         if self.CTR is not None:
  1163             selected = self.TabsOpened.GetSelection()
  1313             selected = self.TabsOpened.GetSelection()
  1182                 MenuToolBar.EnableTool(wx.ID_PRINT, False)
  1332                 MenuToolBar.EnableTool(wx.ID_PRINT, False)
  1183             self.FileMenu.Enable(wx.ID_PAGE_SETUP, True)
  1333             self.FileMenu.Enable(wx.ID_PAGE_SETUP, True)
  1184             project_modified = self.CTR.ProjectTestModified()
  1334             project_modified = self.CTR.ProjectTestModified()
  1185             self.FileMenu.Enable(wx.ID_SAVE, project_modified)
  1335             self.FileMenu.Enable(wx.ID_SAVE, project_modified)
  1186             MenuToolBar.EnableTool(wx.ID_SAVE, project_modified)
  1336             MenuToolBar.EnableTool(wx.ID_SAVE, project_modified)
  1187             self.FileMenu.Enable(wx.ID_PROPERTIES, True)
       
  1188         else:
  1337         else:
  1189             self.FileMenu.Enable(wx.ID_CLOSE, False)
  1338             self.FileMenu.Enable(wx.ID_CLOSE, False)
  1190             self.FileMenu.Enable(wx.ID_PAGE_SETUP, False)
  1339             self.FileMenu.Enable(wx.ID_PAGE_SETUP, False)
  1191             self.FileMenu.Enable(wx.ID_PREVIEW, False)
  1340             self.FileMenu.Enable(wx.ID_PREVIEW, False)
  1192             self.FileMenu.Enable(wx.ID_PRINT, False)
  1341             self.FileMenu.Enable(wx.ID_PRINT, False)
  1193             MenuToolBar.EnableTool(wx.ID_PRINT, False)
  1342             MenuToolBar.EnableTool(wx.ID_PRINT, False)
  1194             self.FileMenu.Enable(wx.ID_SAVE, False)
  1343             self.FileMenu.Enable(wx.ID_SAVE, False)
  1195             MenuToolBar.EnableTool(wx.ID_SAVE, False)
  1344             MenuToolBar.EnableTool(wx.ID_SAVE, False)
  1196             self.FileMenu.Enable(wx.ID_PROPERTIES, False)
  1345             
  1197         
  1346     def RefreshScrollBars(self):
       
  1347         xstart, ystart = self.PLCConfig.GetViewStart()
       
  1348         window_size = self.PLCConfig.GetClientSize()
       
  1349         sizer = self.PLCConfig.GetSizer()
       
  1350         if sizer:
       
  1351             maxx, maxy = sizer.GetMinSize()
       
  1352             posx = max(0, min(xstart, (maxx - window_size[0]) / SCROLLBAR_UNIT))
       
  1353             posy = max(0, min(ystart, (maxy - window_size[1]) / SCROLLBAR_UNIT))
       
  1354             self.PLCConfig.Scroll(posx, posy)
       
  1355             self.PLCConfig.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT, 
       
  1356                 maxx / SCROLLBAR_UNIT, maxy / SCROLLBAR_UNIT, posx, posy)
       
  1357 
  1198     def RefreshPLCParams(self):
  1358     def RefreshPLCParams(self):
  1199         self.Freeze()
  1359         self.Freeze()
  1200         self.ClearSizer(self.PLCParamsSizer)
  1360         self.ClearSizer(self.PLCParamsSizer)
  1201         
  1361         
  1202         if self.CTR is not None:    
  1362         if self.CTR is not None:    
  1228             plcwindowmainsizer.AddSizer(plcwindowbuttonsizer, 0, border=0, flag=wx.ALIGN_CENTER)
  1388             plcwindowmainsizer.AddSizer(plcwindowbuttonsizer, 0, border=0, flag=wx.ALIGN_CENTER)
  1229             
  1389             
  1230             msizer = self.GenerateMethodButtonSizer(self.CTR, plcwindow, not self.ConfNodeInfos[self.CTR]["right_visible"])
  1390             msizer = self.GenerateMethodButtonSizer(self.CTR, plcwindow, not self.ConfNodeInfos[self.CTR]["right_visible"])
  1231             plcwindowbuttonsizer.AddSizer(msizer, 0, border=0, flag=wx.GROW)
  1391             plcwindowbuttonsizer.AddSizer(msizer, 0, border=0, flag=wx.GROW)
  1232             
  1392             
       
  1393         self.PLCConfigMainSizer.Layout()
       
  1394         self.RefreshScrollBars()
       
  1395         self.Thaw()
       
  1396 
       
  1397     def GenerateMethodButtonSizer(self, confnode, parent, horizontal = True):
       
  1398         normal_bt_font=wx.Font(faces["size"] / 3, wx.DEFAULT, wx.NORMAL, wx.NORMAL, faceName = faces["helv"])
       
  1399         mouseover_bt_font=wx.Font(faces["size"] / 3, wx.DEFAULT, wx.NORMAL, wx.NORMAL, underline=True, faceName = faces["helv"])
       
  1400         if horizontal:
       
  1401             msizer = wx.FlexGridSizer(cols=len(confnode.ConfNodeMethods))
       
  1402         else:
       
  1403             msizer = wx.FlexGridSizer(cols=1)
       
  1404         for confnode_method in confnode.ConfNodeMethods:
       
  1405             if "method" in confnode_method and confnode_method.get("shown",True):
       
  1406                 id = wx.NewId()
       
  1407                 label = confnode_method["name"]
       
  1408                 button = GenBitmapTextButton(id=id, parent=parent,
       
  1409                     bitmap=wx.Bitmap(Bpath("images", "%s.png"%confnode_method.get("bitmap", "Unknown"))), label=label, 
       
  1410                     name=label, pos=wx.DefaultPosition, style=wx.NO_BORDER)
       
  1411                 button.SetFont(normal_bt_font)
       
  1412                 button.SetToolTipString(confnode_method["tooltip"])
       
  1413                 button.Bind(wx.EVT_BUTTON, self.GetButtonCallBackFunction(confnode, confnode_method["method"]), id=id)
       
  1414                 # a fancy underline on mouseover
       
  1415                 def setFontStyle(b, s):
       
  1416                     def fn(event):
       
  1417                         b.SetFont(s)
       
  1418                         b.Refresh()
       
  1419                         event.Skip()
       
  1420                     return fn
       
  1421                 button.Bind(wx.EVT_ENTER_WINDOW, setFontStyle(button, mouseover_bt_font))
       
  1422                 button.Bind(wx.EVT_LEAVE_WINDOW, setFontStyle(button, normal_bt_font))
       
  1423                 #hack to force size to mini
       
  1424                 if not confnode_method.get("enabled",True):
       
  1425                     button.Disable()
       
  1426                 msizer.AddWindow(button, 0, border=0, flag=wx.ALIGN_CENTER)
       
  1427         return msizer
       
  1428 
       
  1429     def GenerateEnableButton(self, parent, sizer, confnode):
       
  1430         enabled = confnode.CTNEnabled()
       
  1431         if enabled is not None:
       
  1432             enablebutton_id = wx.NewId()
       
  1433             enablebutton = wx.lib.buttons.GenBitmapToggleButton(id=enablebutton_id, bitmap=wx.Bitmap(Bpath( 'images', 'Disabled.png')),
       
  1434                   name='EnableButton', parent=parent, size=wx.Size(16, 16), pos=wx.Point(0, 0), style=0)#wx.NO_BORDER)
       
  1435             enablebutton.SetToolTipString(_("Enable/Disable this confnode"))
       
  1436             make_genbitmaptogglebutton_flat(enablebutton)
       
  1437             enablebutton.SetBitmapSelected(wx.Bitmap(Bpath( 'images', 'Enabled.png')))
       
  1438             enablebutton.SetToggle(enabled)
       
  1439             def toggleenablebutton(event):
       
  1440                 res = self.SetConfNodeParamsAttribute(confnode, "BaseParams.Enabled", enablebutton.GetToggle())
       
  1441                 enablebutton.SetToggle(res)
       
  1442                 event.Skip()
       
  1443             enablebutton.Bind(wx.EVT_BUTTON, toggleenablebutton, id=enablebutton_id)
       
  1444             sizer.AddWindow(enablebutton, 0, border=0, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
       
  1445         else:
       
  1446             sizer.AddSpacer(wx.Size(16, 16))
       
  1447 
       
  1448     def RefreshConfNodeTree(self):
       
  1449         self.Freeze()
       
  1450         self.ClearSizer(self.ConfNodeTreeSizer)
       
  1451         if self.CTR is not None:
       
  1452             for child in self.CTR.IECSortedChildren():
       
  1453                 self.GenerateTreeBranch(child)
       
  1454                 if not self.ConfNodeInfos[child]["expanded"]:
       
  1455                     self.CollapseConfNode(child)
  1233         self.PLCConfigMainSizer.Layout()
  1456         self.PLCConfigMainSizer.Layout()
  1234         self.RefreshScrollBars()
  1457         self.RefreshScrollBars()
  1235         self.Thaw()
  1458         self.Thaw()
  1236 
  1459 
  1237     def GenerateTreeBranch(self, confnode):
  1460     def GenerateTreeBranch(self, confnode):
  1325         st = wx.StaticText(leftwindow, st_id, size=wx.DefaultSize, style=wx.NO_BORDER)
  1548         st = wx.StaticText(leftwindow, st_id, size=wx.DefaultSize, style=wx.NO_BORDER)
  1326         st.SetFont(wx.Font(faces["size"] * 0.75, wx.DEFAULT, wx.NORMAL, wx.BOLD, faceName = faces["helv"]))
  1549         st.SetFont(wx.Font(faces["size"] * 0.75, wx.DEFAULT, wx.NORMAL, wx.BOLD, faceName = faces["helv"]))
  1327         st.SetLabel(confnode.MandatoryParams[1].getName())
  1550         st.SetLabel(confnode.MandatoryParams[1].getName())
  1328         leftwindowsizer.AddWindow(st, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
  1551         leftwindowsizer.AddWindow(st, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
  1329         
  1552         
  1330         rightwindow = self.GenerateParamsPanel(confnode, bkgdclr)
  1553         rightwindow = wx.Panel(self.PLCConfig, -1, size=wx.Size(-1, -1))
       
  1554         rightwindow.SetBackgroundColour(bkgdclr) 
       
  1555         rightwindowsizer = self.GenerateMethodButtonSizer(confnode, rightwindow, not self.ConfNodeInfos[confnode]["right_visible"])
       
  1556         rightwindow.SetSizer(rightwindowsizer)
  1331         self.ConfNodeTreeSizer.AddWindow(rightwindow, 0, border=0, flag=wx.GROW)
  1557         self.ConfNodeTreeSizer.AddWindow(rightwindow, 0, border=0, flag=wx.GROW)
  1332 
  1558 
  1333         self.ConfNodeInfos[confnode]["left"] = leftwindow
  1559         self.ConfNodeInfos[confnode]["left"] = leftwindow
  1334         self.ConfNodeInfos[confnode]["right"] = rightwindow
  1560         self.ConfNodeInfos[confnode]["right"] = rightwindow
  1335         for child in self.ConfNodeInfos[confnode]["children"]:
  1561         for child in self.ConfNodeInfos[confnode]["children"]:
  1358             for location in confnode_locations:
  1584             for location in confnode_locations:
  1359                 locations_infos["root"]["children"].append("root.%s" % location["name"])
  1585                 locations_infos["root"]["children"].append("root.%s" % location["name"])
  1360                 self.GenerateLocationTreeBranch(treectrl, treectrl.GetRootItem(), locations_infos, "root", location)
  1586                 self.GenerateLocationTreeBranch(treectrl, treectrl.GetRootItem(), locations_infos, "root", location)
  1361             if locations_infos["root"]["expanded"]:
  1587             if locations_infos["root"]["expanded"]:
  1362                 self.ExpandLocation(locations_infos, "root")
  1588                 self.ExpandLocation(locations_infos, "root")
       
  1589 
       
  1590     def ExpandConfNode(self, confnode, force = False):
       
  1591         for child in self.ConfNodeInfos[confnode]["children"]:
       
  1592             self.ConfNodeInfos[child]["left"].Show()
       
  1593             self.ConfNodeInfos[child]["right"].Show()
       
  1594             if force or self.ConfNodeInfos[child]["expanded"]:
       
  1595                 self.ExpandConfNode(child, force)
       
  1596                 if force:
       
  1597                     self.ConfNodeInfos[child]["expanded"] = True
       
  1598         locations_infos = self.ConfNodeInfos[confnode].get("locations_infos", None)
       
  1599         if locations_infos is not None:
       
  1600             if force or locations_infos["root"]["expanded"]:
       
  1601                 self.ExpandLocation(locations_infos, "root", force)
       
  1602                 if force:
       
  1603                     locations_infos["root"]["expanded"] = True
       
  1604     
       
  1605     def CollapseConfNode(self, confnode, force = False):
       
  1606         for child in self.ConfNodeInfos[confnode]["children"]:
       
  1607             self.ConfNodeInfos[child]["left"].Hide()
       
  1608             self.ConfNodeInfos[child]["right"].Hide()
       
  1609             self.CollapseConfNode(child, force)
       
  1610             if force:
       
  1611                 self.ConfNodeInfos[child]["expanded"] = False
       
  1612         locations_infos = self.ConfNodeInfos[confnode].get("locations_infos", None)
       
  1613         if locations_infos is not None:
       
  1614             self.CollapseLocation(locations_infos, "root", force)
       
  1615             if force:
       
  1616                 locations_infos["root"]["expanded"] = False
       
  1617 
       
  1618     def ExpandLocation(self, locations_infos, group, force = False, refresh_size=True):
       
  1619         locations_infos[group]["expanded"] = True
       
  1620         if group == "root":
       
  1621             if locations_infos[group]["left"] is not None:
       
  1622                 locations_infos[group]["left"].Show()
       
  1623             if locations_infos[group]["right"] is not None:
       
  1624                 locations_infos[group]["right"].Show()
       
  1625         elif locations_infos["root"]["left"] is not None:
       
  1626             locations_infos["root"]["left"].Expand(locations_infos[group]["item"])
       
  1627             if force:
       
  1628                 for child in locations_infos[group]["children"]:
       
  1629                     self.ExpandLocation(locations_infos, child, force, False)
       
  1630         if locations_infos["root"]["left"] is not None and refresh_size:
       
  1631             self.RefreshTreeCtrlSize(locations_infos["root"]["left"])
       
  1632         
       
  1633     def CollapseLocation(self, locations_infos, group, force = False, refresh_size=True):
       
  1634         locations_infos[group]["expanded"] = False
       
  1635         if group == "root":
       
  1636             if locations_infos[group]["left"] is not None:
       
  1637                 locations_infos[group]["left"].Hide()
       
  1638             if locations_infos[group]["right"] is not None:
       
  1639                 locations_infos[group]["right"].Hide()
       
  1640         elif locations_infos["root"]["left"] is not None:
       
  1641             locations_infos["root"]["left"].Collapse(locations_infos[group]["item"])
       
  1642             if force:
       
  1643                 for child in locations_infos[group]["children"]:
       
  1644                     self.CollapseLocation(locations_infos, child, force, False)
       
  1645         if locations_infos["root"]["left"] is not None and refresh_size:
       
  1646             self.RefreshTreeCtrlSize(locations_infos["root"]["left"])
       
  1647 
       
  1648     def GenerateLocationTreeBranch(self, treectrl, root, locations_infos, parent, location):
       
  1649         location_name = "%s.%s" % (parent, location["name"])
       
  1650         if not locations_infos.has_key(location_name):
       
  1651             locations_infos[location_name] = {"expanded" : False}
       
  1652         
       
  1653         if location["type"] in [LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY]:
       
  1654             label = "%(name)s (%(location)s)" % location
       
  1655         elif location["location"] != "":
       
  1656             label = "%(location)s: %(name)s" % location
       
  1657         else:
       
  1658             label = location["name"]
       
  1659         item = treectrl.AppendItem(root, label)
       
  1660         treectrl.SetPyData(item, location_name)
       
  1661         treectrl.SetItemImage(item, self.LocationImageDict[location["type"]])
       
  1662         
       
  1663         locations_infos[location_name]["item"] = item
       
  1664         locations_infos[location_name]["children"] = []
       
  1665         infos = location.copy()
       
  1666         infos.pop("children")
       
  1667         locations_infos[location_name]["infos"] = infos
       
  1668         for child in location["children"]:
       
  1669             child_name = "%s.%s" % (location_name, child["name"])
       
  1670             locations_infos[location_name]["children"].append(child_name)
       
  1671             self.GenerateLocationTreeBranch(treectrl, item, locations_infos, location_name, child)
       
  1672         if locations_infos[location_name]["expanded"]:
       
  1673             self.ExpandLocation(locations_infos, location_name)
       
  1674     
       
  1675     def GenerateLocationBeginDragFunction(self, locations_infos):
       
  1676         def OnLocationBeginDragFunction(event):
       
  1677             item = event.GetItem()
       
  1678             location_name = locations_infos["root"]["left"].GetPyData(item)
       
  1679             if location_name is not None:
       
  1680                 infos = locations_infos[location_name]["infos"]
       
  1681                 if infos["type"] in [LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY]:
       
  1682                     data = wx.TextDataObject(str((infos["location"], "location", infos["IEC_type"], infos["var_name"], infos["description"])))
       
  1683                     dragSource = wx.DropSource(self)
       
  1684                     dragSource.SetData(data)
       
  1685                     dragSource.DoDragDrop()
       
  1686         return OnLocationBeginDragFunction
       
  1687     
       
  1688     def RefreshTreeCtrlSize(self, treectrl):
       
  1689         rect = self.GetTreeCtrlItemRect(treectrl, treectrl.GetRootItem())
       
  1690         treectrl.SetMinSize(wx.Size(max(rect.width, rect.x + rect.width) + 20, max(rect.height, rect.y + rect.height)))
       
  1691         self.PLCConfigMainSizer.Layout()
       
  1692         self.PLCConfig.Refresh()
       
  1693         wx.CallAfter(self.RefreshScrollBars)
       
  1694 
       
  1695     def GetTreeCtrlItemRect(self, treectrl, item):
       
  1696         item_rect = treectrl.GetBoundingRect(item, True)
       
  1697         if item_rect is not None:
       
  1698             minx, miny = item_rect.x, item_rect.y
       
  1699             maxx, maxy = item_rect.x + item_rect.width, item_rect.y + item_rect.height
       
  1700         else:
       
  1701             minx = miny = maxx = maxy = 0
       
  1702         
       
  1703         if treectrl.ItemHasChildren(item) and (item == treectrl.GetRootItem() or treectrl.IsExpanded(item)):
       
  1704             if wx.VERSION >= (2, 6, 0):
       
  1705                 child, item_cookie = treectrl.GetFirstChild(item)
       
  1706             else:
       
  1707                 child, item_cookie = treectrl.GetFirstChild(item, 0)
       
  1708             while child.IsOk():
       
  1709                 child_rect = self.GetTreeCtrlItemRect(treectrl, child)
       
  1710                 minx = min(minx, child_rect.x)
       
  1711                 miny = min(miny, child_rect.y)
       
  1712                 maxx = max(maxx, child_rect.x + child_rect.width)
       
  1713                 maxy = max(maxy, child_rect.y + child_rect.height)
       
  1714                 child, item_cookie = treectrl.GetNextChild(item, item_cookie)
       
  1715                 
       
  1716         return wx.Rect(minx, miny, maxx - minx, maxy - miny)
       
  1717     
       
  1718     def GenerateLocationExpandCollapseFunction(self, locations_infos, expand):
       
  1719         def OnLocationExpandedFunction(event):
       
  1720             item = event.GetItem()
       
  1721             location_name = locations_infos["root"]["left"].GetPyData(item)
       
  1722             if location_name is not None:
       
  1723                 locations_infos[location_name]["expanded"] = expand
       
  1724                 self.RefreshTreeCtrlSize(locations_infos["root"]["left"])
       
  1725             event.Skip()
       
  1726         return OnLocationExpandedFunction
       
  1727     
       
  1728     def GetButtonCallBackFunction(self, confnode, method):
       
  1729         """ Generate the callbackfunc for a given confnode method"""
       
  1730         def OnButtonClick(event):
       
  1731             # Disable button to prevent re-entrant call 
       
  1732             event.GetEventObject().Disable()
       
  1733             # Call
       
  1734             getattr(confnode,method)()
       
  1735             # Re-enable button 
       
  1736             event.GetEventObject().Enable()
       
  1737             # Trigger refresh on Idle
       
  1738             wx.CallAfter(self.RefreshAll)
       
  1739             event.Skip()
       
  1740         return OnButtonClick
       
  1741     
       
  1742     def ClearSizer(self, sizer):
       
  1743         staticboxes = []
       
  1744         for item in sizer.GetChildren():
       
  1745             if item.IsSizer():
       
  1746                 item_sizer = item.GetSizer()
       
  1747                 self.ClearSizer(item_sizer)
       
  1748                 if isinstance(item_sizer, wx.StaticBoxSizer):
       
  1749                     staticboxes.append(item_sizer.GetStaticBox())
       
  1750         sizer.Clear(True)
       
  1751         for staticbox in staticboxes:
       
  1752             staticbox.Destroy()
       
  1753                 
       
  1754     def RefreshAll(self):
       
  1755         Beremiz.RefreshAll(self)
       
  1756         self.RefreshPLCParams()
       
  1757         self.RefreshConfNodeTree()
  1363 
  1758 
  1364 class StdoutPseudoFile:
  1759 class StdoutPseudoFile:
  1365     
  1760     
  1366     def __init__(self, port):
  1761     def __init__(self, port):
  1367         self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  1762         self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)