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] |