Beremiz.py
changeset 17 ee8cb104dbe0
parent 13 f1f0edbeb313
child 18 0fac6d621a24
equal deleted inserted replaced
16:b2c02ca6271e 17:ee8cb104dbe0
    26 
    26 
    27 import wx
    27 import wx
    28 
    28 
    29 from time import localtime
    29 from time import localtime
    30 from datetime import datetime
    30 from datetime import datetime
       
    31 import types
    31 
    32 
    32 import os, re, platform, sys, time, traceback, getopt, commands
    33 import os, re, platform, sys, time, traceback, getopt, commands
    33 base_folder = os.path.split(sys.path[0])[0]
    34 base_folder = os.path.split(sys.path[0])[0]
    34 sys.path.append(os.path.join(base_folder, "plcopeneditor"))
    35 sys.path.append(os.path.join(base_folder, "plcopeneditor"))
    35 sys.path.append(os.path.join(base_folder, "CanFestival-3", "objdictgen"))
    36 sys.path.append(os.path.join(base_folder, "CanFestival-3", "objdictgen"))
    39 ieclib_path = os.path.join(base_folder, "matiec", "lib")
    40 ieclib_path = os.path.join(base_folder, "matiec", "lib")
    40 
    41 
    41 from PLCOpenEditor import PLCOpenEditor, ProjectDialog
    42 from PLCOpenEditor import PLCOpenEditor, ProjectDialog
    42 from TextViewer import TextViewer
    43 from TextViewer import TextViewer
    43 from plcopen.structures import IEC_KEYWORDS#, AddPlugin
    44 from plcopen.structures import IEC_KEYWORDS#, AddPlugin
    44 from PLCControler import PLCControler
    45 from plugger import PluginsRoot
    45 
    46 
    46 class LogPseudoFile:
    47 class LogPseudoFile:
    47     """ Base class for file like objects to facilitate StdOut for the Shell."""
    48     """ Base class for file like objects to facilitate StdOut for the Shell."""
    48     def __init__(self, output = None):
    49     def __init__(self, output = None):
    49         self.red_white = wx.TextAttr("RED", "WHITE")
    50         self.red_white = wx.TextAttr("RED", "WHITE")
    77         self.output.SetValue("")
    78         self.output.SetValue("")
    78     
    79     
    79     def isatty(self):
    80     def isatty(self):
    80         return false
    81         return false
    81 
    82 
    82 [ID_BEREMIZ, ID_BEREMIZLOGCONSOLE, ID_BEREMIZEDITPLCBUTTON,
    83 class AttributesTable(wx.grid.PyGridTableBase):
    83  ID_BEREMIZBUILDBUTTON, ID_BEREMIZSIMULATEBUTTON,
    84     
    84  ID_BEREMIZRUNBUTTON, ID_BEREMIZBUSLIST,
    85     """
    85  ID_BEREMIZADDBUSBUTTON, ID_BEREMIZDELETEBUSBUTTON,
    86     A custom wxGrid Table using user supplied data
    86 ] = [wx.NewId() for _init_ctrls in range(9)]
    87     """
       
    88     def __init__(self, parent, data, colnames):
       
    89         # The base class must be initialized *first*
       
    90         wx.grid.PyGridTableBase.__init__(self)
       
    91         self.data = data
       
    92         self.colnames = colnames
       
    93         self.Parent = parent
       
    94         # XXX
       
    95         # we need to store the row length and collength to
       
    96         # see if the table has changed size
       
    97         self._rows = self.GetNumberRows()
       
    98         self._cols = self.GetNumberCols()
       
    99     
       
   100     def GetNumberCols(self):
       
   101         return len(self.colnames)
       
   102         
       
   103     def GetNumberRows(self):
       
   104         return len(self.data)
       
   105 
       
   106     def GetColLabelValue(self, col):
       
   107         if col < len(self.colnames):
       
   108             return self.colnames[col]
       
   109 
       
   110     def GetRowLabelValues(self, row):
       
   111         return row
       
   112 
       
   113     def GetValue(self, row, col):
       
   114         if row < self.GetNumberRows():
       
   115             name = str(self.data[row].get(self.GetColLabelValue(col), ""))
       
   116             return name
       
   117     
       
   118     def GetValueByName(self, row, colname):
       
   119         return self.data[row].get(colname)
       
   120 
       
   121     def SetValue(self, row, col, value):
       
   122         if col < len(self.colnames):
       
   123             self.data[row][self.GetColLabelValue(col)] = value
       
   124         
       
   125     def ResetView(self, grid):
       
   126         """
       
   127         (wxGrid) -> Reset the grid view.   Call this to
       
   128         update the grid if rows and columns have been added or deleted
       
   129         """
       
   130         grid.BeginBatch()
       
   131         for current, new, delmsg, addmsg in [
       
   132             (self._rows, self.GetNumberRows(), wx.grid.GRIDTABLE_NOTIFY_ROWS_DELETED, wx.grid.GRIDTABLE_NOTIFY_ROWS_APPENDED),
       
   133             (self._cols, self.GetNumberCols(), wx.grid.GRIDTABLE_NOTIFY_COLS_DELETED, wx.grid.GRIDTABLE_NOTIFY_COLS_APPENDED),
       
   134         ]:
       
   135             if new < current:
       
   136                 msg = wx.grid.GridTableMessage(self,delmsg,new,current-new)
       
   137                 grid.ProcessTableMessage(msg)
       
   138             elif new > current:
       
   139                 msg = wx.grid.GridTableMessage(self,addmsg,new-current)
       
   140                 grid.ProcessTableMessage(msg)
       
   141                 self.UpdateValues(grid)
       
   142         grid.EndBatch()
       
   143 
       
   144         self._rows = self.GetNumberRows()
       
   145         self._cols = self.GetNumberCols()
       
   146         # update the column rendering scheme
       
   147         self._updateColAttrs(grid)
       
   148 
       
   149         # update the scrollbars and the displayed part of the grid
       
   150         grid.AdjustScrollbars()
       
   151         grid.ForceRefresh()
       
   152 
       
   153     def UpdateValues(self, grid):
       
   154         """Update all displayed values"""
       
   155         # This sends an event to the grid table to update all of the values
       
   156         msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_REQUEST_VIEW_GET_VALUES)
       
   157         grid.ProcessTableMessage(msg)
       
   158 
       
   159     def _updateColAttrs(self, grid):
       
   160         """
       
   161         wxGrid -> update the column attributes to add the
       
   162         appropriate renderer given the column name.
       
   163 
       
   164         Otherwise default to the default renderer.
       
   165         """
       
   166         
       
   167         for row in range(self.GetNumberRows()):
       
   168             for col in range(self.GetNumberCols()):
       
   169                 editor = None
       
   170                 renderer = None
       
   171                 align = wx.ALIGN_LEFT
       
   172                 colname = self.GetColLabelValue(col)
       
   173                 grid.SetReadOnly(row, col, False)
       
   174                 
       
   175                 if colname == "Value":
       
   176                     colSize = 100
       
   177                     value_type = self.data[row]["Type"]
       
   178                     if isinstance(value_type, types.ListType):
       
   179                         editor = wx.grid.GridCellChoiceEditor()
       
   180                         editor.SetParameters(",".join(value_type))
       
   181                     elif value_type == "boolean":
       
   182                         editor = wx.grid.GridCellChoiceEditor()
       
   183                         editor.SetParameters("True,False")
       
   184                     elif value_type in ["unsignedLong","long","integer"]:
       
   185                         editor = wx.grid.GridCellNumberEditor()
       
   186                         align = wx.ALIGN_RIGHT
       
   187                     elif value_type == "decimal":
       
   188                         editor = wx.grid.GridCellFloatEditor()
       
   189                         align = wx.ALIGN_RIGHT
       
   190                     else:
       
   191                         editor = wx.grid.GridCellTextEditor()
       
   192                 else:
       
   193                     colSize = 120
       
   194                     grid.SetReadOnly(row, col, True)
       
   195                 
       
   196                 attr = wx.grid.GridCellAttr()
       
   197                 attr.SetAlignment(align, wx.ALIGN_CENTRE)
       
   198                 grid.SetColAttr(col, attr)
       
   199                 grid.SetColSize(col, colSize)
       
   200                                     
       
   201                 grid.SetCellEditor(row, col, editor)
       
   202                 grid.SetCellRenderer(row, col, renderer)
       
   203                 
       
   204                 grid.SetCellBackgroundColour(row, col, wx.WHITE)
       
   205     
       
   206     def SetData(self, data):
       
   207         self.data = data
       
   208     
       
   209     def GetData(self):
       
   210         return self.data
       
   211     
       
   212     def AppendRow(self, row_content):
       
   213         self.data.append(row_content)
       
   214 
       
   215     def RemoveRow(self, row_index):
       
   216         self.data.pop(row_index)
       
   217 
       
   218     def GetRow(self, row_index):
       
   219         return self.data[row_index]
       
   220 
       
   221     def Empty(self):
       
   222         self.data = []
       
   223 
       
   224 [ID_BEREMIZ, ID_BEREMIZMAINSPLITTER, 
       
   225  ID_BEREMIZSECONDSPLITTER, ID_BEREMIZLEFTPANEL, 
       
   226  ID_BEREMIZPARAMSPANEL, ID_BEREMIZLOGCONSOLE, 
       
   227  ID_BEREMIZPLUGINTREE, ID_BEREMIZPLUGINCHILDS, 
       
   228  ID_BEREMIZADDBUTTON, ID_BEREMIZDELETEBUTTON,
       
   229  ID_BEREMIZPARAMSSTATICBOX, ID_BEREMIZPARAMSENABLE, 
       
   230  ID_BEREMIZPARAMSTARGETTYPE, ID_BEREMIZPARAMSIECCHANNEL, 
       
   231  ID_BEREMIZPARAMSSTATICTEXT1, ID_BEREMIZPARAMSSTATICTEXT2, 
       
   232  ID_BEREMIZPARAMSATTRIBUTESGRID,
       
   233 ] = [wx.NewId() for _init_ctrls in range(17)]
    87 
   234 
    88 [ID_BEREMIZFILEMENUITEMS0, ID_BEREMIZFILEMENUITEMS1, 
   235 [ID_BEREMIZFILEMENUITEMS0, ID_BEREMIZFILEMENUITEMS1, 
    89  ID_BEREMIZFILEMENUITEMS2, ID_BEREMIZFILEMENUITEMS3, 
   236  ID_BEREMIZFILEMENUITEMS2, ID_BEREMIZFILEMENUITEMS3, 
    90  ID_BEREMIZFILEMENUITEMS5, ID_BEREMIZFILEMENUITEMS7, 
   237  ID_BEREMIZFILEMENUITEMS5, ID_BEREMIZFILEMENUITEMS7, 
    91 ] = [wx.NewId() for _init_coll_FileMenu_Items in range(6)]
   238 ] = [wx.NewId() for _init_coll_FileMenu_Items in range(6)]
   134     def _init_coll_EditMenu_Items(self, parent):
   281     def _init_coll_EditMenu_Items(self, parent):
   135         parent.Append(help='', id=ID_BEREMIZEDITMENUITEMS0,
   282         parent.Append(help='', id=ID_BEREMIZEDITMENUITEMS0,
   136               kind=wx.ITEM_NORMAL, text=u'Edit PLC\tCTRL+R')
   283               kind=wx.ITEM_NORMAL, text=u'Edit PLC\tCTRL+R')
   137         parent.AppendSeparator()
   284         parent.AppendSeparator()
   138         parent.Append(help='', id=ID_BEREMIZEDITMENUITEMS2,
   285         parent.Append(help='', id=ID_BEREMIZEDITMENUITEMS2,
   139               kind=wx.ITEM_NORMAL, text=u'Add Bus')
   286               kind=wx.ITEM_NORMAL, text=u'Add Plugin')
   140         parent.Append(help='', id=ID_BEREMIZEDITMENUITEMS3,
   287         parent.Append(help='', id=ID_BEREMIZEDITMENUITEMS3,
   141               kind=wx.ITEM_NORMAL, text=u'Delete Bus')
   288               kind=wx.ITEM_NORMAL, text=u'Delete Plugin')
   142         self.Bind(wx.EVT_MENU, self.OnEditPLCMenu,
   289         self.Bind(wx.EVT_MENU, self.OnEditPLCMenu,
   143               id=ID_BEREMIZEDITMENUITEMS0)
   290               id=ID_BEREMIZEDITMENUITEMS0)
   144         self.Bind(wx.EVT_MENU, self.OnAddBusMenu,
   291         self.Bind(wx.EVT_MENU, self.OnAddMenu,
   145               id=ID_BEREMIZEDITMENUITEMS2)
   292               id=ID_BEREMIZEDITMENUITEMS2)
   146         self.Bind(wx.EVT_MENU, self.OnDeleteBusMenu,
   293         self.Bind(wx.EVT_MENU, self.OnDeleteMenu,
   147               id=ID_BEREMIZEDITMENUITEMS3)
   294               id=ID_BEREMIZEDITMENUITEMS3)
   148     
   295     
   149     def _init_coll_RunMenu_Items(self, parent):
   296     def _init_coll_RunMenu_Items(self, parent):
   150         parent.Append(help='', id=ID_BEREMIZRUNMENUITEMS0,
   297         parent.Append(help='', id=ID_BEREMIZRUNMENUITEMS0,
   151               kind=wx.ITEM_NORMAL, text=u'Build\tCTRL+R')
   298               kind=wx.ITEM_NORMAL, text=u'Build\tCTRL+R')
   193         self._init_coll_FileMenu_Items(self.FileMenu)
   340         self._init_coll_FileMenu_Items(self.FileMenu)
   194         self._init_coll_EditMenu_Items(self.EditMenu)
   341         self._init_coll_EditMenu_Items(self.EditMenu)
   195         self._init_coll_RunMenu_Items(self.RunMenu)
   342         self._init_coll_RunMenu_Items(self.RunMenu)
   196         self._init_coll_HelpMenu_Items(self.HelpMenu)
   343         self._init_coll_HelpMenu_Items(self.HelpMenu)
   197     
   344     
   198     def _init_coll_MainGridSizer_Items(self, parent):
   345     def _init_coll_LeftGridSizer_Items(self, parent):
   199         parent.AddSizer(self.ControlPanelSizer, 0, border=0, flag=wx.GROW)
   346         parent.AddWindow(self.PluginTree, 0, border=0, flag=wx.GROW)
   200         parent.AddWindow(self.LogConsole, 0, border=0, flag=wx.GROW)
   347         parent.AddSizer(self.ButtonGridSizer, 0, border=0, flag=wx.GROW)
   201         
   348         
   202     def _init_coll_MainGridSizer_Growables(self, parent):
   349     def _init_coll_LeftGridSizer_Growables(self, parent):
   203         parent.AddGrowableCol(0)
   350         parent.AddGrowableCol(0)
   204         parent.AddGrowableRow(1)
       
   205     
       
   206     def _init_coll_ControlPanelSizer_Items(self, parent):
       
   207         parent.AddSizer(self.ControlButtonSizer, 0, border=0, flag=0)
       
   208         parent.AddWindow(self.BusList, 0, border=0, flag=wx.GROW)
       
   209         parent.AddSizer(self.BusButtonSizer, 0, border=0, flag=0)
       
   210         
       
   211         
       
   212     def _init_coll_ControlPanelSizer_Growables(self, parent):
       
   213         parent.AddGrowableCol(1)
       
   214         parent.AddGrowableRow(0)
   351         parent.AddGrowableRow(0)
   215     
   352     
   216     def _init_coll_ControlButtonSizer_Items(self, parent):
   353     def _init_coll_ButtonGridSizer_Items(self, parent):
   217         parent.AddWindow(self.EditPLCButton, 0, border=0, flag=0)
   354         parent.AddWindow(self.PluginChilds, 0, border=0, flag=wx.GROW)
   218         parent.AddWindow(self.BuildButton, 0, border=0, flag=0)
   355         parent.AddWindow(self.AddButton, 0, border=0, flag=0)
   219         parent.AddWindow(self.SimulateButton, 0, border=0, flag=0)
   356         parent.AddWindow(self.DeleteButton, 0, border=0, flag=0)
   220         parent.AddWindow(self.RunButton, 0, border=0, flag=0)
   357         
   221 
   358     def _init_coll_ButtonGridSizer_Growables(self, parent):
   222     def _init_coll_BusButtonSizer_Items(self, parent):
   359         parent.AddGrowableCol(0)
   223         parent.AddWindow(self.AddBusButton, 0, border=0, flag=0)
   360         parent.AddGrowableRow(0)
   224         parent.AddWindow(self.DeleteBusButton, 0, border=0, flag=0)
   361     
       
   362     def _init_coll_ParamsPanelMainSizer_Items(self, parent):
       
   363         parent.AddSizer(self.ParamsPanelChildSizer, 1, border=10, flag=wx.GROW|wx.ALL)
       
   364         parent.AddSizer(self.ParamsPanelPluginSizer, 1, border=10, flag=wx.GROW|wx.ALL)
       
   365         parent.AddWindow(self.AttributesGrid, 2, border=10, flag=wx.GROW|wx.TOP|wx.RIGHT|wx.BOTTOM)
       
   366         
       
   367     def _init_coll_ParamsPanelChildSizer_Items(self, parent):
       
   368         parent.AddWindow(self.ParamsEnable, 0, border=5, flag=wx.GROW|wx.BOTTOM)
       
   369         parent.AddWindow(self.ParamsStaticText1, 0, border=5, flag=wx.GROW|wx.BOTTOM)
       
   370         parent.AddWindow(self.ParamsIECChannel, 0, border=0, flag=wx.GROW)
       
   371     
       
   372     def _init_coll_ParamsPanelPluginSizer_Items(self, parent):
       
   373         parent.AddWindow(self.ParamsStaticText2, 0, border=5, flag=wx.GROW|wx.BOTTOM)
       
   374         parent.AddWindow(self.ParamsTargetType, 0, border=0, flag=wx.GROW)
   225         
   375         
   226     def _init_sizers(self):
   376     def _init_sizers(self):
   227         self.MainGridSizer = wx.FlexGridSizer(cols=1, hgap=2, rows=2, vgap=2)
   377         self.LeftGridSizer = wx.FlexGridSizer(cols=1, hgap=2, rows=2, vgap=2)
   228         self.ControlPanelSizer = wx.FlexGridSizer(cols=3, hgap=2, rows=1, vgap=2)
   378         self.ButtonGridSizer = wx.FlexGridSizer(cols=3, hgap=2, rows=1, vgap=2)
   229         self.ControlButtonSizer = wx.GridSizer(cols=2, hgap=2, rows=2, vgap=2)
   379         self.ParamsPanelMainSizer = wx.StaticBoxSizer(self.ParamsStaticBox, wx.HORIZONTAL)
   230         self.BusButtonSizer = wx.BoxSizer(wx.VERTICAL)
   380         self.ParamsPanelChildSizer = wx.BoxSizer(wx.VERTICAL)
   231         
   381         self.ParamsPanelPluginSizer = wx.BoxSizer(wx.VERTICAL)
   232         self._init_coll_MainGridSizer_Growables(self.MainGridSizer)
   382         
   233         self._init_coll_MainGridSizer_Items(self.MainGridSizer)
   383         self._init_coll_LeftGridSizer_Growables(self.LeftGridSizer)
   234         self._init_coll_ControlPanelSizer_Growables(self.ControlPanelSizer)
   384         self._init_coll_LeftGridSizer_Items(self.LeftGridSizer)
   235         self._init_coll_ControlPanelSizer_Items(self.ControlPanelSizer)
   385         self._init_coll_ButtonGridSizer_Growables(self.ButtonGridSizer)
   236         self._init_coll_ControlButtonSizer_Items(self.ControlButtonSizer)
   386         self._init_coll_ButtonGridSizer_Items(self.ButtonGridSizer)
   237         self._init_coll_BusButtonSizer_Items(self.BusButtonSizer)
   387         self._init_coll_ParamsPanelMainSizer_Items(self.ParamsPanelMainSizer)
   238         
   388         self._init_coll_ParamsPanelChildSizer_Items(self.ParamsPanelChildSizer)
   239         self.SetSizer(self.MainGridSizer)
   389         self._init_coll_ParamsPanelPluginSizer_Items(self.ParamsPanelPluginSizer)
       
   390         
       
   391         self.LeftPanel.SetSizer(self.LeftGridSizer)
       
   392         self.ParamsPanel.SetSizer(self.ParamsPanelMainSizer)
   240     
   393     
   241     def _init_ctrls(self, prnt):
   394     def _init_ctrls(self, prnt):
   242         wx.Frame.__init__(self, id=ID_BEREMIZ, name=u'Beremiz',
   395         wx.Frame.__init__(self, id=ID_BEREMIZ, name=u'Beremiz',
   243               parent=prnt, pos=wx.Point(0, 0), size=wx.Size(600, 300),
   396               parent=prnt, pos=wx.Point(0, 0), size=wx.Size(1000, 600),
   244               style=wx.DEFAULT_FRAME_STYLE, title=u'Beremiz')
   397               style=wx.DEFAULT_FRAME_STYLE, title=u'Beremiz')
   245         self._init_utils()
   398         self._init_utils()
   246         self.SetClientSize(wx.Size(600, 300))
   399         self.SetClientSize(wx.Size(1000, 600))
   247         self.SetMenuBar(self.menuBar1)
   400         self.SetMenuBar(self.menuBar1)
   248         
   401         
       
   402         self.MainSplitter = wx.SplitterWindow(id=ID_BEREMIZMAINSPLITTER,
       
   403               name='MainSplitter', parent=self, point=wx.Point(0, 0),
       
   404               size=wx.Size(0, 0), style=wx.SP_3D)
       
   405         self.MainSplitter.SetNeedUpdating(True)
       
   406         self.MainSplitter.SetMinimumPaneSize(1)
       
   407         
       
   408         self.LeftPanel = wx.Panel(id=ID_BEREMIZLEFTPANEL, 
       
   409               name='LeftPanel', parent=self.MainSplitter, pos=wx.Point(0, 0),
       
   410               size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
       
   411         
       
   412         self.PluginTree = wx.TreeCtrl(id=ID_BEREMIZPLUGINTREE,
       
   413               name='PluginTree', parent=self.LeftPanel, pos=wx.Point(0, 0),
       
   414               size=wx.Size(-1, -1), style=wx.TR_HAS_BUTTONS|wx.TR_SINGLE|wx.SUNKEN_BORDER)
       
   415         self.PluginTree.Bind(wx.EVT_RIGHT_UP, self.OnPluginTreeRightUp)
       
   416         self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnPluginTreeItemSelected,
       
   417               id=ID_BEREMIZPLUGINTREE)
       
   418         
       
   419         self.PluginChilds = wx.Choice(id=ID_BEREMIZPLUGINCHILDS,
       
   420               name='PluginChilds', parent=self.LeftPanel, pos=wx.Point(0, 0),
       
   421               size=wx.Size(-1, -1), style=0)
       
   422         
       
   423         self.AddButton = wx.Button(id=ID_BEREMIZADDBUTTON, label='Add',
       
   424               name='AddBusButton', parent=self.LeftPanel, pos=wx.Point(0, 0),
       
   425               size=wx.Size(48, 30), style=0)
       
   426         self.AddButton.Bind(wx.EVT_BUTTON, self.OnAddButton,
       
   427               id=ID_BEREMIZADDBUTTON)
       
   428         
       
   429         self.DeleteButton = wx.Button(id=ID_BEREMIZDELETEBUTTON, label='Delete',
       
   430               name='DeleteBusButton', parent=self.LeftPanel, pos=wx.Point(0, 0),
       
   431               size=wx.Size(64, 30), style=0)
       
   432         self.DeleteButton.Bind(wx.EVT_BUTTON, self.OnDeleteButton,
       
   433               id=ID_BEREMIZDELETEBUTTON)
       
   434         
       
   435         self.SecondSplitter = wx.SplitterWindow(id=ID_BEREMIZSECONDSPLITTER,
       
   436               name='SecondSplitter', parent=self.MainSplitter, point=wx.Point(0, 0),
       
   437               size=wx.Size(0, 0), style=wx.SP_3D)
       
   438         self.SecondSplitter.SetNeedUpdating(True)
       
   439         self.SecondSplitter.SetMinimumPaneSize(1)
       
   440         
       
   441         self.MainSplitter.SplitVertically(self.LeftPanel, self.SecondSplitter,
       
   442               300)
       
   443         
       
   444         self.ParamsPanel = wx.Panel(id=ID_BEREMIZPARAMSPANEL, 
       
   445               name='ParamsPanel', parent=self.SecondSplitter, pos=wx.Point(0, 0),
       
   446               size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
       
   447         
       
   448         self.ParamsStaticBox = wx.StaticBox(id=ID_BEREMIZPARAMSSTATICBOX,
       
   449               label='', name='staticBox1', parent=self.ParamsPanel,
       
   450               pos=wx.Point(0, 0), size=wx.Size(0, 0), style=0)
       
   451         
       
   452         self.ParamsEnable = wx.CheckBox(id=ID_BEREMIZPARAMSENABLE,
       
   453               label='Plugin enabled', name='ParamsEnable', parent=self.ParamsPanel,
       
   454               pos=wx.Point(0, 0), size=wx.Size(0, 24), style=0)
       
   455         self.Bind(wx.EVT_CHECKBOX, self.OnParamsEnableChanged, id=ID_BEREMIZPARAMSENABLE)
       
   456         
       
   457         self.ParamsStaticText1 = wx.StaticText(id=ID_BEREMIZPARAMSSTATICTEXT1,
       
   458               label='IEC Channel:', name='ParamsStaticText1', parent=self.ParamsPanel,
       
   459               pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0)
       
   460         
       
   461         self.ParamsIECChannel = wx.SpinCtrl(id=ID_BEREMIZPARAMSIECCHANNEL,
       
   462               name='ParamsIECChannel', parent=self.ParamsPanel, pos=wx.Point(0, 0),
       
   463               size=wx.Size(0, 24), style=wx.SP_ARROW_KEYS, min=0)
       
   464         self.Bind(wx.EVT_SPINCTRL, self.OnParamsIECChannelChanged, id=ID_BEREMIZPARAMSIECCHANNEL)
       
   465 
       
   466         self.ParamsStaticText2 = wx.StaticText(id=ID_BEREMIZPARAMSSTATICTEXT2,
       
   467               label='Target Type:', name='ParamsStaticText2', parent=self.ParamsPanel,
       
   468               pos=wx.Point(0, 0), size=wx.Size(0, 17), style=0)
       
   469 
       
   470         self.ParamsTargetType = wx.Choice(id=ID_BEREMIZPARAMSTARGETTYPE, 
       
   471               name='TargetType', choices=[""], parent=self.ParamsPanel, 
       
   472               pos=wx.Point(0, 0), size=wx.Size(0, 24), style=wx.LB_SINGLE)
       
   473         self.Bind(wx.EVT_CHOICE, self.OnParamsTargetTypeChanged, id=ID_BEREMIZPARAMSTARGETTYPE)
       
   474 
       
   475         self.AttributesGrid = wx.grid.Grid(id=ID_BEREMIZPARAMSATTRIBUTESGRID,
       
   476               name='AttributesGrid', parent=self.ParamsPanel, pos=wx.Point(0, 0), 
       
   477               size=wx.Size(0, 150), style=wx.VSCROLL)
       
   478         self.AttributesGrid.SetFont(wx.Font(12, 77, wx.NORMAL, wx.NORMAL, False,
       
   479               'Sans'))
       
   480         self.AttributesGrid.SetLabelFont(wx.Font(10, 77, wx.NORMAL, wx.NORMAL,
       
   481               False, 'Sans'))
       
   482         self.AttributesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnAttributesGridCellChange)
       
   483 
   249         self.LogConsole = wx.TextCtrl(id=ID_BEREMIZLOGCONSOLE, value='',
   484         self.LogConsole = wx.TextCtrl(id=ID_BEREMIZLOGCONSOLE, value='',
   250               name='LogConsole', parent=self, pos=wx.Point(0, 0),
   485               name='LogConsole', parent=self.SecondSplitter, pos=wx.Point(0, 0),
   251               size=wx.Size(0, 0), style=wx.TE_MULTILINE|wx.TE_RICH2)
   486               size=wx.Size(0, 0), style=wx.TE_MULTILINE|wx.TE_RICH2)
   252         
   487         
   253         self.EditPLCButton = wx.Button(id=ID_BEREMIZEDITPLCBUTTON, label='Edit\nPLC',
   488         self.SecondSplitter.SplitHorizontally(self.ParamsPanel, self.LogConsole,
   254               name='EditPLCButton', parent=self, pos=wx.Point(0, 0),
   489               -250)
   255               size=wx.Size(48, 48), style=0)
       
   256         self.EditPLCButton.Bind(wx.EVT_BUTTON, self.OnEditPLCButton,
       
   257               id=ID_BEREMIZEDITPLCBUTTON)
       
   258         
       
   259         self.BuildButton = wx.Button(id=ID_BEREMIZBUILDBUTTON, label='Build',
       
   260               name='BuildButton', parent=self, pos=wx.Point(0, 0),
       
   261               size=wx.Size(48, 48), style=0)
       
   262         self.BuildButton.Bind(wx.EVT_BUTTON, self.OnBuildButton,
       
   263               id=ID_BEREMIZBUILDBUTTON)
       
   264         
       
   265         self.SimulateButton = wx.Button(id=ID_BEREMIZSIMULATEBUTTON, label='Simul',
       
   266               name='SimulateButton', parent=self, pos=wx.Point(0, 0),
       
   267               size=wx.Size(48, 48), style=0)
       
   268         self.EditPLCButton.Bind(wx.EVT_BUTTON, self.OnSimulateButton,
       
   269               id=ID_BEREMIZSIMULATEBUTTON)
       
   270         
       
   271         self.RunButton = wx.Button(id=ID_BEREMIZRUNBUTTON, label='Run',
       
   272               name='RunButton', parent=self, pos=wx.Point(0, 0),
       
   273               size=wx.Size(48, 48), style=0)
       
   274         self.RunButton.Bind(wx.EVT_BUTTON, self.OnRunButton,
       
   275               id=ID_BEREMIZRUNBUTTON)
       
   276         
       
   277         self.BusList = wx.ListBox(choices=[], id=ID_BEREMIZBUSLIST,
       
   278               name='BusList', parent=self, pos=wx.Point(0, 0),
       
   279               size=wx.Size(-1, -1), style=wx.LB_SINGLE|wx.LB_NEEDED_SB)
       
   280         self.BusList.Bind(wx.EVT_LISTBOX_DCLICK, self.OnBusListDClick,
       
   281               id=ID_BEREMIZBUSLIST)
       
   282         
       
   283         self.AddBusButton = wx.Button(id=ID_BEREMIZADDBUSBUTTON, label='Add',
       
   284               name='AddBusButton', parent=self, pos=wx.Point(0, 0),
       
   285               size=wx.Size(48, 48), style=0)
       
   286         self.AddBusButton.Bind(wx.EVT_BUTTON, self.OnAddBusButton,
       
   287               id=ID_BEREMIZADDBUSBUTTON)
       
   288         
       
   289         self.DeleteBusButton = wx.Button(id=ID_BEREMIZDELETEBUSBUTTON, label='Delete',
       
   290               name='DeleteBusButton', parent=self, pos=wx.Point(0, 0),
       
   291               size=wx.Size(48, 48), style=0)
       
   292         self.DeleteBusButton.Bind(wx.EVT_BUTTON, self.OnDeleteBusButton,
       
   293               id=ID_BEREMIZDELETEBUSBUTTON)
       
   294         
   490         
   295         self._init_sizers()
   491         self._init_sizers()
   296 
   492 
   297     def __init__(self, parent, projectOpen):
   493     def __init__(self, parent, projectOpen):
   298         self._init_ctrls(parent)
   494         self._init_ctrls(parent)
   299         
   495         
   300         for name in plugins.__all__:
   496         self.Log = LogPseudoFile(self.LogConsole)
   301             module = getattr(plugins, name)
   497         
   302             
   498         self.PluginRoot = PluginsRoot()
   303 			#AddPlugin(module.GetBlockGenerationFunction(self))
   499         for value in self.PluginRoot.GetTargetTypes():
   304         
   500             self.ParamsTargetType.Append(value)
   305         self.CurrentProjectPath = ""
   501         
   306         
   502         self.Table = AttributesTable(self, [], ["Attribute", "Value"])
   307         self.PLCManager = None
   503         self.AttributesGrid.SetTable(self.Table)
       
   504         self.AttributesGrid.SetRowLabelSize(0)
       
   505         
       
   506         if projectOpen:
       
   507             self.PluginRoot.LoadProject(projectOpen)
       
   508             self.RefreshPluginTree()
       
   509         
   308         self.PLCEditor = None
   510         self.PLCEditor = None
   309         self.BusManagers = {}
   511         
   310         
   512         self.RefreshPluginParams()
   311         self.Log = LogPseudoFile(self.LogConsole)
       
   312         
       
   313         if projectOpen:
       
   314             self.OpenProject(projectOpen)
       
   315             
       
   316         self.RefreshButtons()
   513         self.RefreshButtons()
   317         self.RefreshMainMenu()
   514         self.RefreshMainMenu()
   318         
   515         
   319     def RefreshButtons(self):
   516     def RefreshButtons(self):
   320         if self.CurrentProjectPath == "":
   517         if self.PluginRoot.HasProjectOpened():
   321             self.LogConsole.Enable(False)
   518             self.PluginChilds.Enable(True)
   322             self.EditPLCButton.Enable(False)
   519             self.AddButton.Enable(True)
   323             self.BuildButton.Enable(False)
   520             self.DeleteButton.Enable(True)
   324             self.SimulateButton.Enable(False)
       
   325             self.RunButton.Enable(False)
       
   326             self.BusList.Enable(False)
       
   327             self.AddBusButton.Enable(False)
       
   328             self.DeleteBusButton.Enable(False)
       
   329         else:
   521         else:
   330             self.LogConsole.Enable(True)
   522             self.PluginChilds.Enable(False)
   331             self.EditPLCButton.Enable(True)
   523             self.AddButton.Enable(False)
   332             self.BuildButton.Enable(True)
   524             self.DeleteButton.Enable(False)
   333             self.SimulateButton.Enable(True)
   525         
   334             self.RunButton.Enable(True)
       
   335             self.BusList.Enable(True)
       
   336             self.AddBusButton.Enable(True)
       
   337             self.DeleteBusButton.Enable(True)
       
   338 
       
   339     def RefreshBusList(self):
       
   340         selected = self.BusList.GetStringSelection()
       
   341         self.BusList.Clear()
       
   342         busidlist = self.BusManagers.keys()
       
   343         busidlist.sort()
       
   344         for id in busidlist:
       
   345             bus_infos = self.BusManagers[id]
       
   346             self.BusList.Append("0x%2.2X\t%s\t%s"%(id, bus_infos["Type"], bus_infos["Name"]))
       
   347         if selected != "":
       
   348             self.BusList.SetStringSelection(selected)
       
   349 
       
   350     def RefreshMainMenu(self):
   526     def RefreshMainMenu(self):
   351         if self.menuBar1:
   527         if self.menuBar1:
   352             if self.CurrentProjectPath == "":
   528             if self.PluginRoot.HasProjectOpened():
       
   529                 self.menuBar1.EnableTop(1, True)
       
   530                 self.menuBar1.EnableTop(2, True)
       
   531                 self.FileMenu.Enable(ID_BEREMIZFILEMENUITEMS2, True)
       
   532                 self.FileMenu.Enable(ID_BEREMIZFILEMENUITEMS3, True)
       
   533                 self.FileMenu.Enable(ID_BEREMIZFILEMENUITEMS5, True)
       
   534             else:
   353                 self.menuBar1.EnableTop(1, False)
   535                 self.menuBar1.EnableTop(1, False)
   354                 self.menuBar1.EnableTop(2, False)
   536                 self.menuBar1.EnableTop(2, False)
   355                 self.FileMenu.Enable(ID_BEREMIZFILEMENUITEMS2, False)
   537                 self.FileMenu.Enable(ID_BEREMIZFILEMENUITEMS2, False)
   356                 self.FileMenu.Enable(ID_BEREMIZFILEMENUITEMS3, False)
   538                 self.FileMenu.Enable(ID_BEREMIZFILEMENUITEMS3, False)
   357                 self.FileMenu.Enable(ID_BEREMIZFILEMENUITEMS5, False)
   539                 self.FileMenu.Enable(ID_BEREMIZFILEMENUITEMS5, False)
       
   540 
       
   541     def RefreshPluginTree(self):
       
   542         infos = self.PluginRoot.GetPlugInfos()
       
   543         root = self.PluginTree.GetRootItem()
       
   544         self.GenerateTreeBranch(root, infos)
       
   545         self.PluginTree.Expand(self.PluginTree.GetRootItem())
       
   546         self.RefreshPluginParams()
       
   547 
       
   548     def GenerateTreeBranch(self, root, infos):
       
   549         to_delete = []
       
   550         if root.IsOk():
       
   551             self.PluginTree.SetItemText(root, infos["name"])
       
   552         else:
       
   553             root = self.PluginTree.AddRoot(infos["name"])
       
   554         self.PluginTree.SetPyData(root, infos["type"])
       
   555         item, root_cookie = self.PluginTree.GetFirstChild(root)
       
   556         if len(infos["values"]) > 0:
       
   557             for values in infos["values"]:
       
   558                 if not item.IsOk():
       
   559                     item = self.PluginTree.AppendItem(root, "")
       
   560                     item, root_cookie = self.PluginTree.GetNextChild(root, root_cookie)
       
   561                 self.GenerateTreeBranch(item, values)
       
   562                 item, root_cookie = self.PluginTree.GetNextChild(root, root_cookie)
       
   563         while item.IsOk():
       
   564             to_delete.append(item)
       
   565             item, root_cookie = self.PluginTree.GetNextChild(root, root_cookie)
       
   566         for item in to_delete:
       
   567             self.PluginTree.Delete(item)
       
   568 
       
   569     def GetSelectedPlugin(self):
       
   570         selected = self.PluginTree.GetSelection()
       
   571         if not selected.IsOk():
       
   572             return None
       
   573         if selected == self.PluginTree.GetRootItem():
       
   574             return self.PluginRoot
       
   575         else:
       
   576             name = self.PluginTree.GetItemText(selected)
       
   577             item = self.PluginTree.GetItemParent(selected)
       
   578             while item.IsOk() and item != self.PluginTree.GetRootItem():
       
   579                 name = "%s.%s"%(self.PluginTree.GetItemText(item), name)
       
   580                 item = self.PluginTree.GetItemParent(item)
       
   581             return self.PluginRoot.GetChildByName(name)
       
   582 
       
   583     def OnPluginTreeItemSelected(self, event):
       
   584         wx.CallAfter(self.RefreshPluginParams)
       
   585         event.Skip()
       
   586     
       
   587     def _GetAddPluginFunction(self, name):
       
   588         def OnPluginMenu(event):
       
   589             self.AddPlugin(name)
       
   590             event.Skip()
       
   591         return OnPluginMenu
       
   592     
       
   593     def OnPluginTreeRightUp(self, event):
       
   594         plugin = self.GetSelectedPlugin()
       
   595         if plugin:
       
   596             main_menu = wx.Menu(title='')
       
   597             if len(plugin.PlugChildsTypes) > 0:
       
   598                 plugin_menu = wx.Menu(title='')
       
   599                 for name, XSDClass in self.GetSelectedPlugin().PlugChildsTypes:
       
   600                     new_id = wx.NewId()
       
   601                     plugin_menu.Append(help='', id=new_id, kind=wx.ITEM_NORMAL, text=name)
       
   602                     self.Bind(wx.EVT_MENU, self._GetAddPluginFunction(name), id=new_id)
       
   603                 main_menu.AppendMenu(-1, "Add", plugin_menu, '')
       
   604             new_id = wx.NewId()
       
   605             main_menu.Append(help='', id=new_id, kind=wx.ITEM_NORMAL, text="Delete")
       
   606             self.Bind(wx.EVT_MENU, self.OnDeleteButton, id=new_id)
       
   607             rect = self.PluginTree.GetBoundingRect(self.PluginTree.GetSelection())
       
   608             self.PluginTree.PopupMenuXY(main_menu, rect.x + rect.width, rect.y)
       
   609         event.Skip()
       
   610     
       
   611     def RefreshPluginParams(self):
       
   612         plugin = self.GetSelectedPlugin()
       
   613         if not plugin:
       
   614             # Refresh ParamsPanel
       
   615             self.ParamsPanel.Hide()
       
   616             
       
   617             # Refresh PluginChilds
       
   618             self.PluginChilds.Clear()
       
   619             self.PluginChilds.Enable(False)
       
   620             self.AddButton.Enable(False)
       
   621             self.DeleteButton.Enable(False)
       
   622         else:
       
   623             # Refresh ParamsPanel
       
   624             self.ParamsPanel.Show()
       
   625             self.ParamsStaticBox.SetLabel(plugin.BaseParams.getName())
       
   626             if plugin == self.PluginRoot:
       
   627                 self.ParamsPanelMainSizer.Hide(self.ParamsPanelChildSizer)
       
   628                 self.ParamsPanelMainSizer.Show(self.ParamsPanelPluginSizer)
       
   629                 self.ParamsTargetType.SetStringSelection(self.PluginRoot.GetTargetType())
   358             else:
   630             else:
   359                 self.menuBar1.EnableTop(1, True)
   631                 self.ParamsPanelMainSizer.Show(self.ParamsPanelChildSizer)
   360                 self.menuBar1.EnableTop(2, True)
   632                 self.ParamsPanelMainSizer.Hide(self.ParamsPanelPluginSizer)
   361                 self.FileMenu.Enable(ID_BEREMIZFILEMENUITEMS2, True)
   633                 self.ParamsEnable.SetValue(plugin.BaseParams.getEnabled())
   362                 self.FileMenu.Enable(ID_BEREMIZFILEMENUITEMS3, True)
   634                 self.ParamsEnable.Enable(True)
   363                 self.FileMenu.Enable(ID_BEREMIZFILEMENUITEMS5, True)
   635                 self.ParamsStaticText1.Enable(True)
   364 
   636                 self.ParamsIECChannel.SetValue(plugin.BaseParams.getIEC_Channel())
       
   637                 self.ParamsIECChannel.Enable(True)
       
   638             self.ParamsPanelMainSizer.Layout()
       
   639             self.RefreshAttributesGrid()
       
   640             
       
   641             # Refresh PluginChilds
       
   642             self.PluginChilds.Clear()
       
   643             if len(plugin.PlugChildsTypes) > 0:
       
   644                 self.PluginChilds.Append("")
       
   645                 for name, XSDClass in plugin.PlugChildsTypes:
       
   646                     self.PluginChilds.Append(name)
       
   647                 self.PluginChilds.Enable(True)
       
   648                 self.AddButton.Enable(True)
       
   649             else:
       
   650                 self.PluginChilds.Enable(False)
       
   651                 self.AddButton.Enable(False)
       
   652             self.DeleteButton.Enable(True)
       
   653     
       
   654     def RefreshAttributesGrid(self):
       
   655         plugin = self.GetSelectedPlugin()
       
   656         if not plugin:
       
   657             self.Table.Empty()
       
   658         else:
       
   659             if plugin == self.PluginRoot:
       
   660                 attr_infos = self.PluginRoot.GetTargetAttributes()
       
   661             else:
       
   662                 attr_infos = plugin.GetPlugParamsAttributes()
       
   663             data = []
       
   664             for infos in attr_infos:
       
   665                 data.append({"Attribute" : infos["name"], "Value" : infos["value"],
       
   666                     "Type" : infos["type"]})
       
   667             self.Table.SetData(data)
       
   668         self.Table.ResetView(self.AttributesGrid)
       
   669     
       
   670     def OnParamsEnableChanged(self, event):
       
   671         plugin = self.GetSelectedPlugin()
       
   672         if plugin and plugin != self.PluginRoot:
       
   673             plugin.BaseParams.setEnabled(event.Checked())
       
   674         event.Skip()
       
   675     
       
   676     def OnParamsIECChannelChanged(self, event):
       
   677         plugin = self.GetSelectedPlugin()
       
   678         if plugin and plugin != self.PluginRoot:
       
   679             plugin.BaseParams.setIEC_Channel(self.ParamsIECChannel.GetValue())
       
   680         event.Skip()
       
   681     
       
   682     def OnParamsTargetTypeChanged(self, event):
       
   683         plugin = self.GetSelectedPlugin()
       
   684         if plugin and plugin == self.PluginRoot:
       
   685             self.PluginRoot.ChangeTargetType(self.ParamsTargetType.GetStringSelection())
       
   686             self.RefreshAttributesGrid()
       
   687         event.Skip()
       
   688     
       
   689     def OnAttributesGridCellChange(self, event):
       
   690         row = event.GetRow()
       
   691         plugin = self.GetSelectedPlugin()
       
   692         if plugin:
       
   693             name = self.Table.GetValueByName(row, "Attribute")
       
   694             value = self.Table.GetValueByName(row, "Value")
       
   695             if plugin == self.PluginRoot:
       
   696                 self.PluginRoot.SetTargetAttribute(name, value)
       
   697             else:
       
   698                 plugin.SetPlugParamsAttribute(name, value)
       
   699         event.Skip()
       
   700     
   365     def OnNewProjectMenu(self, event):
   701     def OnNewProjectMenu(self, event):
   366         if self.CurrentProjectPath != "":
   702         defaultpath = self.PluginRoot.GetProjectPath()
   367             defaultpath = self.CurrentProjectPath
   703         if defaultpath == "":
   368         else:
       
   369             defaultpath = os.getcwd()
   704             defaultpath = os.getcwd()
   370         dialog = wx.DirDialog(self , "Choose a project", defaultpath, wx.DD_NEW_DIR_BUTTON)
   705         dialog = wx.DirDialog(self , "Choose a project", defaultpath, wx.DD_NEW_DIR_BUTTON)
   371         if dialog.ShowModal() == wx.ID_OK:
   706         if dialog.ShowModal() == wx.ID_OK:
   372             projectpath = dialog.GetPath()
   707             projectpath = dialog.GetPath()
   373             dialog.Destroy()
   708             dialog.Destroy()
   374             if os.path.isdir(projectpath) and len(os.listdir(projectpath)) == 0:
   709             if os.path.isdir(projectpath) and len(os.listdir(projectpath)) == 0:
   375                 os.mkdir(os.path.join(projectpath, "eds"))
       
   376                 self.PLCManager = PLCControler()
       
   377                 plc_file = os.path.join(projectpath, "plc.xml")
       
   378                 dialog = ProjectDialog(self)
   710                 dialog = ProjectDialog(self)
   379                 if dialog.ShowModal() == wx.ID_OK:
   711                 if dialog.ShowModal() == wx.ID_OK:
   380                     values = dialog.GetValues()
   712                     values = dialog.GetValues()
   381                     values["creationDateTime"] = datetime(*localtime()[:6])
   713                     values["creationDateTime"] = datetime(*localtime()[:6])
   382                     self.PLCManager.CreateNewProject(values.pop("projectName"))
   714                     self.PluginRoot.NewProject(projectpath, values)
   383                     self.PLCManager.SetProjectProperties(properties=values)
   715                     self.RefreshPluginTree()
   384                     self.PLCManager.SaveXMLFile(plc_file)
   716                     self.RefreshButtons()
   385                     self.CurrentProjectPath = projectpath
   717                     self.RefreshMainMenu()
   386                 dialog.Destroy()
   718                 dialog.Destroy()
   387                 self.RefreshButtons()
       
   388                 self.RefreshMainMenu()
       
   389             else:
   719             else:
   390                 message = wx.MessageDialog(self, "Folder choosen isn't empty. You can't use it for a new project!", "ERROR", wx.OK|wx.ICON_ERROR)
   720                 message = wx.MessageDialog(self, "Folder choosen isn't empty. You can't use it for a new project!", "ERROR", wx.OK|wx.ICON_ERROR)
   391                 message.ShowModal()
   721                 message.ShowModal()
   392                 message.Destroy()
   722                 message.Destroy()
   393         event.Skip()
   723         event.Skip()
   394     
   724     
   395     def OpenProject(self, projectpath):
       
   396         try:
       
   397             if not os.path.isdir(projectpath):
       
   398                 raise Exception
       
   399             self.BusManagers = {}
       
   400             configpath = os.path.join(projectpath, ".project")
       
   401             if not os.path.isfile(configpath):
       
   402                 raise Exception
       
   403             file = open(configpath, "r")
       
   404             lines = [line.strip() for line in file.readlines() if line.strip() != ""]
       
   405             if lines[0] != "Beremiz":
       
   406                 file.close()
       
   407                 raise Exception
       
   408             for bus_id, bus_type, bus_name in [line.split(" ") for line in lines[1:]]:
       
   409                 id = int(bus_id, 16)
       
   410                 controller = getattr(plugins, bus_type).controller
       
   411                 if controller != None:
       
   412                     manager = controller()
       
   413                     result = manager.LoadProject(projectpath, bus_name)
       
   414                     if not result:
       
   415                         self.BusManagers[id] = {"Name" : bus_name, "Type" : bus_type, "Manager" : manager, "Editor" : None}
       
   416                     else:
       
   417                         message = wx.MessageDialog(self, result, "Error", wx.OK|wx.ICON_ERROR)
       
   418                         message.ShowModal()
       
   419                         message.Destroy()
       
   420                 else:
       
   421                     self.BusManagers[id] = {"Name" : bus_name, "Type" : bus_type, "Manager" : None, "Editor" : None}
       
   422             file.close()
       
   423             self.PLCManager = PLCControler()
       
   424             plc_file = os.path.join(projectpath, "plc.xml")
       
   425             if os.path.isfile(plc_file):
       
   426                 self.PLCManager.OpenXMLFile(plc_file)
       
   427                 self.CurrentProjectPath = projectpath
       
   428             else:
       
   429                 dialog = ProjectDialog(self)
       
   430                 if dialog.ShowModal() == wx.ID_OK:
       
   431                     values = dialog.GetValues()
       
   432                     projectname = values.pop("projectName")
       
   433                     values["creationDateTime"] = datetime(*localtime()[:6])
       
   434                     self.PLCManager.CreateNewProject(projectname)
       
   435                     self.PLCManager.SetProjectProperties(values)
       
   436                     self.PLCManager.SaveXMLFile(plc_file)
       
   437                     self.CurrentProjectPath = projectpath
       
   438                 dialog.Destroy()
       
   439             self.RefreshBusList()
       
   440             self.RefreshButtons()
       
   441             self.RefreshMainMenu()
       
   442         except Exception, message:
       
   443             message = wx.MessageDialog(self, "\"%s\" folder is not a valid Beremiz project\n%s"%(projectpath,message), "Error", wx.OK|wx.ICON_ERROR)
       
   444             message.ShowModal()
       
   445             message.Destroy()
       
   446     
       
   447     def OnOpenProjectMenu(self, event):
   725     def OnOpenProjectMenu(self, event):
   448         if self.CurrentProjectPath != "":
   726         defaultpath = self.PluginRoot.GetProjectPath()
   449             defaultpath = self.CurrentProjectPath
   727         if defaultpath == "":
   450         else:
       
   451             defaultpath = os.getcwd()
   728             defaultpath = os.getcwd()
   452         dialog = wx.DirDialog(self , "Choose a project", defaultpath, wx.DD_NEW_DIR_BUTTON)
   729         dialog = wx.DirDialog(self , "Choose a project", defaultpath, wx.DD_NEW_DIR_BUTTON)
   453         if dialog.ShowModal() == wx.ID_OK:
   730         if dialog.ShowModal() == wx.ID_OK:
   454             self.OpenProject(dialog.GetPath())
   731             projectpath = dialog.GetPath()
       
   732             if os.path.isdir(projectpath):
       
   733                 result = self.PluginRoot.LoadProject(projectpath)
       
   734                 if not result:
       
   735                     self.RefreshPluginTree()
       
   736                     self.RefreshButtons()
       
   737                     self.RefreshMainMenu()
       
   738                 else:
       
   739                     message = wx.MessageDialog(self, result, "Error", wx.OK|wx.ICON_ERROR)
       
   740                     message.ShowModal()
       
   741                     message.Destroy()
       
   742             else:
       
   743                 message = wx.MessageDialog(self, "\"%s\" folder is not a valid Beremiz project\n"%projectpath, "Error", wx.OK|wx.ICON_ERROR)
       
   744                 message.ShowModal()
       
   745                 message.Destroy()
   455             dialog.Destroy()
   746             dialog.Destroy()
   456         event.Skip()
   747         event.Skip()
   457     
   748     
   458     def OnCloseProjectMenu(self, event):
   749     def OnCloseProjectMenu(self, event):
   459         self.PLCManager = None
   750         self.PLCManager = None
   461         self.RefreshButtons()
   752         self.RefreshButtons()
   462         self.RefreshMainMenu()
   753         self.RefreshMainMenu()
   463         event.Skip()
   754         event.Skip()
   464     
   755     
   465     def OnSaveProjectMenu(self, event):
   756     def OnSaveProjectMenu(self, event):
   466         self.PLCManager.SaveXMLFile()
   757         if self.PluginRoot.HasProjectOpened():
   467         cpjfilepath = os.path.join(self.CurrentProjectPath, "nodelist.cpj")
   758             self.PluginRoot.SaveProject()
   468         file = open(cpjfilepath, "w")
       
   469         file.write("")
       
   470         file.close()
       
   471         configpath = os.path.join(self.CurrentProjectPath, ".project")
       
   472         file = open(configpath, "w")
       
   473         file.write("Beremiz\n")
       
   474         busidlist = self.BusManagers.keys()
       
   475         busidlist.sort()
       
   476         for id in busidlist:
       
   477             bus_infos = self.BusManagers[id]
       
   478             file.write("0x%2.2X %s %s\n"%(id, bus_infos["Type"], bus_infos["Name"]))
       
   479             bus_infos["Manager"].SaveProject(bus_infos["Name"])
       
   480         file.close()
       
   481         event.Skip()
   759         event.Skip()
   482     
   760     
   483     def OnPropertiesMenu(self, event):
   761     def OnPropertiesMenu(self, event):
   484         event.Skip()
   762         event.Skip()
   485     
   763     
   489     
   767     
   490     def OnEditPLCMenu(self, event):
   768     def OnEditPLCMenu(self, event):
   491         self.EditPLC()
   769         self.EditPLC()
   492         event.Skip()
   770         event.Skip()
   493     
   771     
   494     def OnAddBusMenu(self, event):
   772     def OnAddMenu(self, event):
   495         self.AddBus()
   773         self.AddPlugin()
   496         event.Skip()
   774         event.Skip()
   497     
   775     
   498     def OnDeleteBusMenu(self, event):
   776     def OnDeleteMenu(self, event):
   499         self.DeleteBus()
   777         self.DeletePlugin()
   500         event.Skip()
   778         event.Skip()
   501 
   779 
   502     def OnBuildMenu(self, event):
   780     def OnBuildMenu(self, event):
   503         self.BuildAutom()
   781         self.BuildAutom()
   504         event.Skip()
   782         event.Skip()
   515     def OnBeremizMenu(self, event):
   793     def OnBeremizMenu(self, event):
   516         event.Skip()
   794         event.Skip()
   517     
   795     
   518     def OnAboutMenu(self, event):
   796     def OnAboutMenu(self, event):
   519         event.Skip()
   797         event.Skip()
   520 
   798     
   521     def OnEditPLCButton(self, event):
   799     def OnAddButton(self, event):
   522         self.EditPLC()
   800         PluginType = self.PluginChilds.GetStringSelection()
   523         event.Skip()
   801         if PluginType != "":
   524     
   802             self.AddPlugin(PluginType)
   525     def OnBuildButton(self, event):
   803         event.Skip()
   526         self.BuildAutom()
   804     
   527         event.Skip()
   805     def OnDeleteButton(self, event):
   528     
   806         self.DeletePlugin()
   529     def OnSimulateButton(self, event):
       
   530         event.Skip()
       
   531         
       
   532     def OnRunButton(self, event):
       
   533         event.Skip()
       
   534     
       
   535     def OnAddBusButton(self, event):
       
   536         self.AddBus()
       
   537         event.Skip()
       
   538     
       
   539     def OnDeleteBusButton(self, event):
       
   540         self.DeleteBus()
       
   541         event.Skip()
       
   542     
       
   543     def OnBusListDClick(self, event):
       
   544         selected = event.GetSelection()
       
   545         busidlist = self.BusManagers.keys()
       
   546         busidlist.sort()
       
   547         bus_infos = self.BusManagers[busidlist[selected]]
       
   548         view = getattr(plugins, bus_infos["Type"]).view
       
   549         if view != None:
       
   550             if bus_infos["Editor"] == None:
       
   551                 editor = view(self, bus_infos["Manager"])
       
   552                 editor.SetBusId(busidlist[selected])
       
   553                 editor.Show()
       
   554                 bus_infos["Editor"] = editor
       
   555         event.Skip()
   807         event.Skip()
   556     
   808     
   557     def CloseEditor(self, bus_id):
   809     def CloseEditor(self, bus_id):
   558         if self.BusManagers.get(bus_id, None) != None:
   810         if self.BusManagers.get(bus_id, None) != None:
   559             self.BusManagers[bus_id]["Editor"] = None
   811             self.BusManagers[bus_id]["Editor"] = None
   560     
   812     
   561     def AddBus(self):
   813     def AddPlugin(self, PluginType):
   562         dialog = AddBusDialog(self)
   814         dialog = wx.TextEntryDialog(self, "Please enter a name for plugin:", "Add Plugin", "", wx.OK|wx.CANCEL)
   563         if dialog.ShowModal() == wx.ID_OK:
   815         if dialog.ShowModal() == wx.ID_OK:
   564             values = dialog.GetValues()
   816             PluginName = dialog.GetValue()
   565             if values["busID"].startswith("0x"):
   817             plugin = self.GetSelectedPlugin()
   566                 bus_id = int(values["busID"], 16)
   818             plugin.PlugAddChild(PluginName, PluginType)
   567             else:
   819             self.RefreshPluginTree()
   568                 bus_id = int(values["busID"])
       
   569             if self.BusManagers.get(bus_id, None) == None:
       
   570                 controller = getattr(plugins, values["busType"]).controller
       
   571                 if controller != None:
       
   572                     manager = controller()
       
   573                     result = manager.LoadProject(self.CurrentProjectPath, values["busName"])
       
   574                     if not result:
       
   575                         self.BusManagers[bus_id] = {"Name" : values["busName"], "Type" : values["busType"], "Manager" : manager, "Editor" : None}
       
   576                     else:
       
   577                         message = wx.MessageDialog(self, result, "Error", wx.OK|wx.ICON_ERROR)
       
   578                         message.ShowModal()
       
   579                         message.Destroy()
       
   580                 else:
       
   581                     self.BusManagers[bus_id] = {"Name" : values["busName"], "Type" : values["busType"], "Manager" : None, "Editor" : None}
       
   582             else:
       
   583                 message = wx.MessageDialog(self, "The bus ID \"0x%2.2X\" is already used!"%bus_id, "Error", wx.OK|wx.ICON_ERROR)
       
   584                 message.ShowModal()
       
   585                 message.Destroy()
       
   586             self.RefreshBusList()
       
   587         dialog.Destroy()
   820         dialog.Destroy()
   588     
   821     
   589     def DeleteBus(self):
   822     def DeletePlugin(self):
   590         busidlist = self.BusManagers.keys()
   823         pass
   591         busidlist.sort()
       
   592         list = ["0x%2.2X\t%s\t%s"%(id, self.BusManagers[id]["Type"], self.BusManagers[id]["Name"]) for id in busidlist]
       
   593         dialog = wx.SingleChoiceDialog(self, "Select Bus to delete:", "Bus Delete", list, wx.OK|wx.CANCEL)
       
   594         if dialog.ShowModal() == wx.ID_OK:
       
   595             selected = dialog.GetSelection()
       
   596             editor = self.BusManagers[busidlist[selected]]["Editor"]
       
   597             if editor:
       
   598                 editor.Close()
       
   599             self.BusManagers.pop(busidlist[selected])
       
   600             self.RefreshBusList()
       
   601         dialog.Destroy()
       
   602     
   824     
   603     def EditPLC(self):
   825     def EditPLC(self):
   604         if not self.PLCEditor:
   826         if not self.PLCEditor:
   605             self.PLCEditor = PLCOpenEditor(self, self.PLCManager)
   827             self.PLCEditor = PLCOpenEditor(self, self.PluginRoot.PLCManager)
   606             self.PLCEditor.RefreshProjectTree()
   828             self.PLCEditor.RefreshProjectTree()
   607             self.PLCEditor.RefreshFileMenu()
   829             self.PLCEditor.RefreshFileMenu()
   608             self.PLCEditor.RefreshEditMenu()
   830             self.PLCEditor.RefreshEditMenu()
   609             self.PLCEditor.RefreshToolBar()
   831             self.PLCEditor.RefreshToolBar()
   610             self.PLCEditor.Show()
   832             self.PLCEditor.Show()
   644         err = child.wait()
   866         err = child.wait()
   645         return (err, outdata, errdata)
   867         return (err, outdata, errdata)
   646 
   868 
   647     def BuildAutom(self):
   869     def BuildAutom(self):
   648         LOCATED_MODEL = re.compile("__LOCATED_VAR\(([A-Z]*),([_A-Za-z0-9]*)\)")
   870         LOCATED_MODEL = re.compile("__LOCATED_VAR\(([A-Z]*),([_A-Za-z0-9]*)\)")
   649 
   871         
   650         if self.PLCManager:
   872         if self.PLCManager:
   651             self.TargetDir = os.path.join(self.CurrentProjectPath, "build")
   873             self.TargetDir = os.path.join(self.CurrentProjectPath, "build")
   652             if not os.path.exists(self.TargetDir):
   874             if not os.path.exists(self.TargetDir):
   653                 os.mkdir(self.TargetDir)
   875                 os.mkdir(self.TargetDir)
   654             self.Log.flush()
   876             self.Log.flush()
   655             #sys.stdout = self.Log
       
   656             try:
   877             try:
   657                 self.Log.write("Generating IEC-61131 code...\n")
   878                 self.Log.write("Generating IEC-61131 code...\n")
   658                 plc_file = os.path.join(self.TargetDir, "plc.st")
   879                 plc_file = os.path.join(self.TargetDir, "plc.st")
   659                 result = self.PLCManager.GenerateProgram(plc_file)
   880                 result = self.PLCManager.GenerateProgram(plc_file)
   660                 if not result:
   881                 if not result:
   675                 self.Log.write("Extracting Located Variables...\n")
   896                 self.Log.write("Extracting Located Variables...\n")
   676                 location_file = open(os.path.join(self.TargetDir,"LOCATED_VARIABLES.h"))
   897                 location_file = open(os.path.join(self.TargetDir,"LOCATED_VARIABLES.h"))
   677                 locations = []
   898                 locations = []
   678                 lines = [line.strip() for line in location_file.readlines()]
   899                 lines = [line.strip() for line in location_file.readlines()]
   679                 for line in lines:
   900                 for line in lines:
   680                     result = self.LOCATED_MODEL.match(line)
   901                     result = LOCATED_MODEL.match(line)
   681                     if result:
   902                     if result:
   682                         locations.append(result.groups())
   903                         locations.append(result.groups())
   683                 self.Log.write("Generating Network Configurations...\n")
   904                 self.Log.write("Generating Network Configurations...\n")
   684                 for bus_id, bus_infos in self.BusManagers.items():
   905                 for bus_id, bus_infos in self.BusManagers.items():
   685                    if bus_infos["Manager"]:
   906                    if bus_infos["Manager"]:
   697                 self.Log.write("\nBuild Project completed\n")
   918                 self.Log.write("\nBuild Project completed\n")
   698             except Exception, message:
   919             except Exception, message:
   699                 self.Log.write_error("\nBuild Failed\n")
   920                 self.Log.write_error("\nBuild Failed\n")
   700                 self.Log.write(str(message))
   921                 self.Log.write(str(message))
   701                 pass
   922                 pass
   702             #sys.stdout = sys.__stdout__
       
   703                 
   923                 
   704 #-------------------------------------------------------------------------------
   924 #-------------------------------------------------------------------------------
   705 #                             Add Bus Dialog
   925 #                             Add Bus Dialog
   706 #-------------------------------------------------------------------------------
   926 #-------------------------------------------------------------------------------
   707 
   927