PLCOpenEditor.py
changeset 711 5f6a743dcde5
parent 709 2507f2736a3e
child 712 c11b54730a7b
equal deleted inserted replaced
710:365bb7496697 711:5f6a743dcde5
   106 from GraphicViewer import *
   106 from GraphicViewer import *
   107 from RessourceEditor import *
   107 from RessourceEditor import *
   108 from DataTypeEditor import *
   108 from DataTypeEditor import *
   109 from PLCControler import *
   109 from PLCControler import *
   110 from SearchResultPanel import SearchResultPanel
   110 from SearchResultPanel import SearchResultPanel
   111 from controls import CustomGrid, CustomTable, CustomTree, LibraryPanel, PouInstanceVariablesPanel
   111 from controls import CustomTree, LibraryPanel, PouInstanceVariablesPanel, DebugVariablePanel
   112 from dialogs import ProjectDialog, PouTransitionDialog, PouActionDialog
   112 from dialogs import ProjectDialog, PouTransitionDialog, PouActionDialog
   113 
   113 
   114 # Define PLCOpenEditor controls id
   114 # Define PLCOpenEditor controls id
   115 [ID_PLCOPENEDITOR, ID_PLCOPENEDITORLEFTNOTEBOOK, 
   115 [ID_PLCOPENEDITOR, ID_PLCOPENEDITORLEFTNOTEBOOK, 
   116  ID_PLCOPENEDITORBOTTOMNOTEBOOK, ID_PLCOPENEDITORRIGHTNOTEBOOK, 
   116  ID_PLCOPENEDITORBOTTOMNOTEBOOK, ID_PLCOPENEDITORRIGHTNOTEBOOK, 
   560               BestSize(wx.Size(250, 400)).CloseButton(False))
   560               BestSize(wx.Size(250, 400)).CloseButton(False))
   561         
   561         
   562         self.TabsOpened = wx.aui.AuiNotebook(self, ID_PLCOPENEDITORTABSOPENED, 
   562         self.TabsOpened = wx.aui.AuiNotebook(self, ID_PLCOPENEDITORTABSOPENED, 
   563               style=wx.aui.AUI_NB_DEFAULT_STYLE|wx.aui.AUI_NB_WINDOWLIST_BUTTON)
   563               style=wx.aui.AUI_NB_DEFAULT_STYLE|wx.aui.AUI_NB_WINDOWLIST_BUTTON)
   564         self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGING,
   564         self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGING,
   565                 self.OnPouSelectedChanging)
   565               self.OnPouSelectedChanging)
   566         self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGED,
   566         self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGED,
   567                 self.OnPouSelectedChanged)
   567               self.OnPouSelectedChanged)
   568         self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CLOSE,
   568         self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CLOSE,
   569                 self.OnPageClose)
   569               self.OnPageClose)
   570         self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_END_DRAG,
   570         self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_END_DRAG,
   571                 self.OnPageDragged)
   571               self.OnPageDragged)
   572         self.AUIManager.AddPane(self.TabsOpened, 
   572         self.AUIManager.AddPane(self.TabsOpened, 
   573               wx.aui.AuiPaneInfo().CentrePane().Name("TabsPane"))
   573               wx.aui.AuiPaneInfo().CentrePane().Name("TabsPane"))
   574         
   574         
   575         #-----------------------------------------------------------------------
   575         #-----------------------------------------------------------------------
   576         #                    Creating PLCopen Project Types Tree
   576         #                    Creating PLCopen Project Types Tree
   668                 
   668                 
   669         self._init_utils()
   669         self._init_utils()
   670         self.SetMenuBar(self.MenuBar)
   670         self.SetMenuBar(self.MenuBar)
   671                 
   671                 
   672         if self.EnableDebug:
   672         if self.EnableDebug:
   673             self.DebugVariablePanel = DebugVariablePanel(self.RightNoteBook, self.Controler)
   673             self.DebugVariablePanel = DebugVariablePanel(self.RightNoteBook, self, self.Controler)
   674             self.MainTabs["DebugVariablePanel"] = (self.DebugVariablePanel, _("Debugger"))
   674             self.MainTabs["DebugVariablePanel"] = (self.DebugVariablePanel, _("Debugger"))
   675             self.RightNoteBook.AddPage(*self.MainTabs["DebugVariablePanel"])
   675             self.RightNoteBook.AddPage(*self.MainTabs["DebugVariablePanel"])
   676         
   676         
   677         self.AUIManager.Update()
   677         self.AUIManager.Update()
   678     
   678     
  2886 
  2886 
  2887 #-------------------------------------------------------------------------------
  2887 #-------------------------------------------------------------------------------
  2888 #                            Debug Variables Panel
  2888 #                            Debug Variables Panel
  2889 #-------------------------------------------------------------------------------
  2889 #-------------------------------------------------------------------------------
  2890 
  2890 
  2891 def GetDebugVariablesTableColnames():
       
  2892     _ = lambda x : x
       
  2893     return [_("Variable"), _("Value")]
       
  2894 
       
  2895 class VariableTableItem(DebugDataConsumer):
       
  2896     
       
  2897     def __init__(self, parent, variable, value):
       
  2898         DebugDataConsumer.__init__(self)
       
  2899         self.Parent = parent
       
  2900         self.Variable = variable
       
  2901         self.Value = value
       
  2902     
       
  2903     def __del__(self):
       
  2904         self.Parent = None
       
  2905     
       
  2906     def SetVariable(self, variable):
       
  2907         if self.Parent and self.Variable != variable:
       
  2908             self.Variable = variable
       
  2909             self.Parent.RefreshGrid()
       
  2910     
       
  2911     def GetVariable(self):
       
  2912         return self.Variable
       
  2913     
       
  2914     def SetForced(self, forced):
       
  2915         if self.Forced != forced:
       
  2916             self.Forced = forced
       
  2917             self.Parent.HasNewData = True
       
  2918     
       
  2919     def SetValue(self, value):
       
  2920         if self.Value != value:
       
  2921             self.Value = value
       
  2922             self.Parent.HasNewData = True
       
  2923             
       
  2924     def GetValue(self):
       
  2925         return self.Value
       
  2926 
       
  2927 class DebugVariableTable(CustomTable):
       
  2928     
       
  2929     def GetValue(self, row, col):
       
  2930         if row < self.GetNumberRows():
       
  2931             return self.GetValueByName(row, self.GetColLabelValue(col, False))
       
  2932         return ""
       
  2933     
       
  2934     def SetValue(self, row, col, value):
       
  2935         if col < len(self.colnames):
       
  2936             self.SetValueByName(row, self.GetColLabelValue(col, False), value)
       
  2937             
       
  2938     def GetValueByName(self, row, colname):
       
  2939         if row < self.GetNumberRows():
       
  2940             if colname == "Variable":
       
  2941                 return self.data[row].GetVariable()
       
  2942             elif colname == "Value":
       
  2943                 return self.data[row].GetValue()
       
  2944         return ""
       
  2945 
       
  2946     def SetValueByName(self, row, colname, value):
       
  2947         if row < self.GetNumberRows():
       
  2948             if colname == "Variable":
       
  2949                 self.data[row].SetVariable(value)
       
  2950             elif colname == "Value":
       
  2951                 self.data[row].SetValue(value)
       
  2952     
       
  2953     def IsForced(self, row):
       
  2954         if row < self.GetNumberRows():
       
  2955             return self.data[row].IsForced()
       
  2956         return False
       
  2957     
       
  2958     def _updateColAttrs(self, grid):
       
  2959         """
       
  2960         wx.grid.Grid -> update the column attributes to add the
       
  2961         appropriate renderer given the column name.
       
  2962 
       
  2963         Otherwise default to the default renderer.
       
  2964         """
       
  2965         
       
  2966         for row in range(self.GetNumberRows()):
       
  2967             for col in range(self.GetNumberCols()):
       
  2968                 if self.GetColLabelValue(col, False) == "Value":
       
  2969                     if self.IsForced(row):
       
  2970                         grid.SetCellTextColour(row, col, wx.BLUE)
       
  2971                     else:
       
  2972                         grid.SetCellTextColour(row, col, wx.BLACK)
       
  2973                 grid.SetReadOnly(row, col, True)
       
  2974             self.ResizeRow(grid, row)
       
  2975                 
       
  2976     def AppendItem(self, data):
       
  2977         self.data.append(data)
       
  2978     
       
  2979     def InsertItem(self, idx, data):
       
  2980         self.data.insert(idx, data)
       
  2981     
       
  2982     def RemoveItem(self, idx):
       
  2983         self.data.pop(idx)
       
  2984     
       
  2985     def MoveItem(self, idx, new_idx):
       
  2986         self.data.insert(new_idx, self.data.pop(idx))
       
  2987         
       
  2988     def GetItem(self, idx):
       
  2989         return self.data[idx]
       
  2990 
       
  2991 
       
  2992 class DebugVariableDropTarget(wx.TextDropTarget):
       
  2993     
       
  2994     def __init__(self, parent):
       
  2995         wx.TextDropTarget.__init__(self)
       
  2996         self.ParentWindow = parent
       
  2997     
       
  2998     def OnDropText(self, x, y, data):
       
  2999         x, y = self.ParentWindow.VariablesGrid.CalcUnscrolledPosition(x, y)
       
  3000         row = self.ParentWindow.VariablesGrid.YToRow(y - self.ParentWindow.VariablesGrid.GetColLabelSize())
       
  3001         if row == wx.NOT_FOUND:
       
  3002             row = self.ParentWindow.Table.GetNumberRows()
       
  3003         message = None
       
  3004         try:
       
  3005             values = eval(data)
       
  3006         except:
       
  3007             message = _("Invalid value \"%s\" for debug variable")%data
       
  3008             values = None
       
  3009         if not isinstance(values, TupleType):
       
  3010             message = _("Invalid value \"%s\" for debug variable")%data
       
  3011             values = None
       
  3012         if values is not None and values[1] == "debug":
       
  3013             self.ParentWindow.InsertValue(values[0], row)
       
  3014         if message is not None:
       
  3015             wx.CallAfter(self.ShowMessage, message)
       
  3016             
       
  3017     def ShowMessage(self, message):
       
  3018         message = wx.MessageDialog(self.ParentWindow, message, _("Error"), wx.OK|wx.ICON_ERROR)
       
  3019         message.ShowModal()
       
  3020         message.Destroy()
       
  3021 
       
  3022 [ID_DEBUGVARIABLEPANEL, ID_DEBUGVARIABLEPANELVARIABLESGRID, 
       
  3023  ID_DEBUGVARIABLEPANELUPBUTTON, ID_DEBUGVARIABLEPANELDOWNBUTTON, 
       
  3024  ID_DEBUGVARIABLEPANELDELETEBUTTON,
       
  3025 ] = [wx.NewId() for _init_ctrls in range(5)]
       
  3026 
       
  3027 class DebugVariablePanel(wx.Panel, DebugViewer):
       
  3028     
       
  3029     if wx.VERSION < (2, 6, 0):
       
  3030         def Bind(self, event, function, id = None):
       
  3031             if id is not None:
       
  3032                 event(self, id, function)
       
  3033             else:
       
  3034                 event(self, function)
       
  3035     
       
  3036     def _init_coll_MainSizer_Items(self, parent):
       
  3037         parent.AddSizer(self.ButtonPanelSizer, 0, border=5, flag=wx.ALIGN_RIGHT|wx.ALL)
       
  3038         parent.AddWindow(self.VariablesGrid, 0, border=0, flag=wx.GROW)
       
  3039     
       
  3040     def _init_coll_MainSizer_Growables(self, parent):
       
  3041         parent.AddGrowableCol(0)
       
  3042         parent.AddGrowableRow(1)
       
  3043     
       
  3044     def _init_coll_ButtonPanelSizer_Items(self, parent):
       
  3045         parent.AddWindow(self.UpButton, 0, border=5, flag=wx.RIGHT)
       
  3046         parent.AddWindow(self.DownButton, 0, border=5, flag=wx.RIGHT)
       
  3047         parent.AddWindow(self.DeleteButton, 0, border=0, flag=0)
       
  3048         
       
  3049     def _init_sizers(self):
       
  3050         self.MainSizer = wx.FlexGridSizer(cols=1, hgap=10, rows=2, vgap=0)
       
  3051         self.ButtonPanelSizer = wx.BoxSizer(wx.HORIZONTAL)
       
  3052         
       
  3053         self._init_coll_MainSizer_Items(self.MainSizer)
       
  3054         self._init_coll_MainSizer_Growables(self.MainSizer)
       
  3055         self._init_coll_ButtonPanelSizer_Items(self.ButtonPanelSizer)
       
  3056         
       
  3057         self.SetSizer(self.MainSizer)
       
  3058         
       
  3059     def _init_ctrls(self, prnt):
       
  3060         wx.Panel.__init__(self, id=ID_DEBUGVARIABLEPANEL,
       
  3061               name='DebugVariablePanel', parent=prnt, pos=wx.Point(0, 0),
       
  3062               size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
       
  3063 
       
  3064         self.VariablesGrid = CustomGrid(id=ID_DEBUGVARIABLEPANELVARIABLESGRID,
       
  3065               name='VariablesGrid', parent=self, pos=wx.Point(0, 0), 
       
  3066               size=wx.Size(0, 150), style=wx.VSCROLL)
       
  3067         self.VariablesGrid.SetDropTarget(DebugVariableDropTarget(self))
       
  3068         if wx.VERSION >= (2, 6, 0):
       
  3069             self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_RIGHT_CLICK, self.OnVariablesGridCellRightClick)
       
  3070         else:
       
  3071             wx.grid.EVT_GRID_CELL_RIGHT_CLICK(self.VariablesGrid, self.OnVariablesGridCellRightClick)
       
  3072         
       
  3073         self.UpButton = wx.Button(id=ID_DEBUGVARIABLEPANELUPBUTTON, label='^',
       
  3074               name='UpButton', parent=self, pos=wx.Point(0, 0),
       
  3075               size=wx.Size(32, 32), style=0)
       
  3076         
       
  3077         self.DownButton = wx.Button(id=ID_DEBUGVARIABLEPANELDOWNBUTTON, label='v',
       
  3078               name='DownButton', parent=self, pos=wx.Point(0, 0),
       
  3079               size=wx.Size(32, 32), style=0)
       
  3080         
       
  3081         self.DeleteButton = wx.Button(id=ID_DEBUGVARIABLEPANELDELETEBUTTON, label=_('Delete'),
       
  3082               name='DeleteButton', parent=self, pos=wx.Point(0, 0),
       
  3083               size=wx.DefaultSize, style=0)
       
  3084         
       
  3085         self._init_sizers()
       
  3086     
       
  3087     def __init__(self, parent, producer):
       
  3088         self._init_ctrls(parent)
       
  3089         DebugViewer.__init__(self, producer, True)
       
  3090         self.HasNewData = False
       
  3091         
       
  3092         self.Table = DebugVariableTable(self, [], GetDebugVariablesTableColnames())
       
  3093         self.VariablesGrid.SetTable(self.Table)
       
  3094         self.VariablesGrid.SetButtons({"Delete": self.DeleteButton,
       
  3095                                        "Up": self.UpButton,
       
  3096                                        "Down": self.DownButton})
       
  3097         
       
  3098         def _AddVariable(new_row):
       
  3099             return self.VariablesGrid.GetGridCursorRow()
       
  3100         setattr(self.VariablesGrid, "_AddRow", _AddVariable)
       
  3101         
       
  3102         def _DeleteVariable(row):
       
  3103             item = self.Table.GetItem(row)
       
  3104             self.RemoveDataConsumer(item)
       
  3105             self.Table.RemoveItem(row)
       
  3106             self.RefreshGrid()
       
  3107         setattr(self.VariablesGrid, "_DeleteRow", _DeleteVariable)
       
  3108         
       
  3109         def _MoveVariable(row, move):
       
  3110             new_row = max(0, min(row + move, self.Table.GetNumberRows() - 1))
       
  3111             if new_row != row:
       
  3112                 self.Table.MoveItem(row, new_row)
       
  3113                 self.RefreshGrid()
       
  3114             return new_row
       
  3115         setattr(self.VariablesGrid, "_MoveRow", _MoveVariable)
       
  3116         
       
  3117         self.VariablesGrid.SetRowLabelSize(0)
       
  3118         
       
  3119         for col in range(self.Table.GetNumberCols()):
       
  3120             attr = wx.grid.GridCellAttr()
       
  3121             attr.SetAlignment(wx.ALIGN_RIGHT, wx.ALIGN_CENTER)
       
  3122             self.VariablesGrid.SetColAttr(col, attr)
       
  3123             self.VariablesGrid.SetColSize(col, 100)
       
  3124         
       
  3125         self.Table.ResetView(self.VariablesGrid)
       
  3126         self.VariablesGrid.RefreshButtons()
       
  3127     
       
  3128     def RefreshNewData(self):
       
  3129         if self.HasNewData:
       
  3130             self.HasNewData = False
       
  3131             self.RefreshGrid()
       
  3132         DebugViewer.RefreshNewData(self)
       
  3133     
       
  3134     def RefreshGrid(self):
       
  3135         self.Freeze()
       
  3136         self.Table.ResetView(self.VariablesGrid)
       
  3137         self.VariablesGrid.RefreshButtons()
       
  3138         self.Thaw()
       
  3139     
       
  3140     def UnregisterObsoleteData(self):
       
  3141         items = [(idx, item) for idx, item in enumerate(self.Table.GetData())]
       
  3142         items.reverse()
       
  3143         for idx, item in items:
       
  3144             iec_path = item.GetVariable().upper()
       
  3145             if self.GetDataType(iec_path) is None:
       
  3146                 self.RemoveDataConsumer(item)
       
  3147                 self.Table.RemoveItem(idx)
       
  3148             else:
       
  3149                 self.AddDataConsumer(iec_path, item)
       
  3150         self.Freeze()
       
  3151         self.Table.ResetView(self.VariablesGrid)
       
  3152         self.VariablesGrid.RefreshButtons()
       
  3153         self.Thaw()
       
  3154     
       
  3155     def ResetGrid(self):
       
  3156         self.DeleteDataConsumers()
       
  3157         self.Table.Empty()
       
  3158         self.Freeze()
       
  3159         self.Table.ResetView(self.VariablesGrid)
       
  3160         self.VariablesGrid.RefreshButtons()
       
  3161         self.Thaw()
       
  3162     
       
  3163     def GetForceVariableMenuFunction(self, iec_path, item):
       
  3164         iec_type = self.GetDataType(iec_path)
       
  3165         def ForceVariableFunction(event):
       
  3166             if iec_type is not None:
       
  3167                 dialog = ForceVariableDialog(self, iec_type, str(item.GetValue()))
       
  3168                 if dialog.ShowModal() == wx.ID_OK:
       
  3169                     self.ForceDataValue(iec_path, dialog.GetValue())
       
  3170         return ForceVariableFunction
       
  3171 
       
  3172     def GetReleaseVariableMenuFunction(self, iec_path):
       
  3173         def ReleaseVariableFunction(event):
       
  3174             self.ReleaseDataValue(iec_path)
       
  3175         return ReleaseVariableFunction
       
  3176     
       
  3177     def OnVariablesGridCellRightClick(self, event):
       
  3178         row, col = event.GetRow(), event.GetCol()
       
  3179         if self.Table.GetColLabelValue(col, False) == "Value":
       
  3180             iec_path = self.Table.GetValueByName(row, "Variable").upper()
       
  3181 
       
  3182             menu = wx.Menu(title='')
       
  3183             new_id = wx.NewId()
       
  3184             AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Force value"))
       
  3185             self.Bind(wx.EVT_MENU, self.GetForceVariableMenuFunction(iec_path.upper(), self.Table.GetItem(row)), id=new_id)
       
  3186             new_id = wx.NewId()
       
  3187             AppendMenu(menu, help='', id=new_id, kind=wx.ITEM_NORMAL, text=_("Release value"))
       
  3188             self.Bind(wx.EVT_MENU, self.GetReleaseVariableMenuFunction(iec_path.upper()), id=new_id)
       
  3189             if self.Table.IsForced(row):
       
  3190                 menu.Enable(new_id, True)
       
  3191             else:
       
  3192                 menu.Enable(new_id, False)
       
  3193             self.PopupMenu(menu)
       
  3194             menu.Destroy()
       
  3195         event.Skip()
       
  3196     
       
  3197     def InsertValue(self, iec_path, idx = None, force=False):
       
  3198         if idx is None:
       
  3199             idx = self.Table.GetNumberRows()
       
  3200         for item in self.Table.GetData():
       
  3201             if iec_path == item.GetVariable():
       
  3202                 return
       
  3203         item = VariableTableItem(self, iec_path, "")
       
  3204         result = self.AddDataConsumer(iec_path.upper(), item)
       
  3205         if result is not None or force:
       
  3206             self.Table.InsertItem(idx, item)
       
  3207             self.RefreshGrid()
       
  3208         
       
  3209     def GetDebugVariables(self):
       
  3210         return [item.GetVariable() for item in self.Table.GetData()]
       
  3211         
       
  3212 #-------------------------------------------------------------------------------
  2891 #-------------------------------------------------------------------------------
  3213 #                               Viewer Printout
  2892 #                               Viewer Printout
  3214 #-------------------------------------------------------------------------------
  2893 #-------------------------------------------------------------------------------
  3215 
  2894 
  3216 UPPER_DIV = lambda x, y: (x / y) + {True : 0, False : 1}[(x % y) == 0]
  2895 UPPER_DIV = lambda x, y: (x / y) + {True : 0, False : 1}[(x % y) == 0]