Beremiz.py
changeset 109 f27ca37b6e7a
parent 106 9810689febb0
child 110 a05e8b30c024
equal deleted inserted replaced
108:280b458e42e5 109:f27ca37b6e7a
    57               'size' : 18,
    57               'size' : 18,
    58              }
    58              }
    59 
    59 
    60 CWD = os.path.split(os.path.realpath(__file__))[0]
    60 CWD = os.path.split(os.path.realpath(__file__))[0]
    61 
    61 
       
    62 # Some helpers to tweak GenBitmapTextButtons
       
    63 # TODO: declare customized classes instead.
    62 gen_mini_GetBackgroundBrush = lambda obj:lambda dc: wx.Brush(obj.GetParent().GetBackgroundColour(), wx.SOLID)
    64 gen_mini_GetBackgroundBrush = lambda obj:lambda dc: wx.Brush(obj.GetParent().GetBackgroundColour(), wx.SOLID)
    63 gen_mini_GetLabelSize = lambda obj:lambda:(wx.lib.buttons.GenBitmapTextButton._GetLabelSize(obj)[:-1] + (False,))
       
    64 gen_textbutton_GetLabelSize = lambda obj:lambda:(wx.lib.buttons.GenButton._GetLabelSize(obj)[:-1] + (False,))
    65 gen_textbutton_GetLabelSize = lambda obj:lambda:(wx.lib.buttons.GenButton._GetLabelSize(obj)[:-1] + (False,))
    65 
    66 
    66 def make_genbitmaptogglebutton_flat(button):
    67 def make_genbitmaptogglebutton_flat(button):
    67     button.GetBackgroundBrush = gen_mini_GetBackgroundBrush(button)
    68     button.GetBackgroundBrush = gen_mini_GetBackgroundBrush(button)
    68     button.labelDelta = 0
    69     button.labelDelta = 0
    69     button.SetBezelWidth(0)
    70     button.SetBezelWidth(0)
    70     button.SetUseFocusIndicator(False)
    71     button.SetUseFocusIndicator(False)
    71 
    72 
    72 def GenerateEmptyBitmap(width, height, color):
    73 # Patch wx.lib.imageutils so that gray is supported on alpha images
    73 #    bitmap = wx.EmptyBitmap(width, height)
    74 import wx.lib.imageutils
    74 #    dc = wx.MemoryDC(bitmap)
    75 def grayOut(anImage):
    75 #    dc.SetPen(wx.Pen(color))
    76     """
    76 #    dc.SetBrush(wx.Brush(color))
    77     Convert the given image (in place) to a grayed-out
    77 #    dc.DrawRectangle(0, 0, width, height)
    78     version, appropriate for a 'disabled' appearance.
    78 #    return bitmap
    79     """
    79     return wx.Bitmap(os.path.join(CWD, "images", "empty.png"))
    80     factor = 0.7        # 0 < f < 1.  Higher is grayer.
       
    81     if anImage.HasMask():
       
    82         maskColor = (anImage.GetMaskRed(), anImage.GetMaskGreen(), anImage.GetMaskBlue())
       
    83     else:
       
    84         maskColor = None
       
    85 
       
    86     if anImage.HasAlpha():
       
    87         AlphaData = anImage.GetAlphaData()
       
    88     else :
       
    89         AlphaData = None
       
    90 
       
    91     data = map(ord, list(anImage.GetData()))
       
    92          
       
    93     for i in range(0, len(data), 3):
       
    94         pixel = (data[i], data[i+1], data[i+2])
       
    95         pixel = wx.lib.imageutils.makeGray(pixel, factor, maskColor)
       
    96         for x in range(3):
       
    97             data[i+x] = pixel[x]
       
    98     anImage.SetData(''.join(map(chr, data)))
       
    99 
       
   100     if AlphaData is not None:
       
   101         anImage.SetAlphaData(AlphaData)
       
   102 
       
   103 wx.lib.imageutils.grayOut = grayOut
       
   104 
       
   105 class GenBitmapTextButton(wx.lib.buttons.GenBitmapTextButton):
       
   106     def _GetLabelSize(self):
       
   107         return wx.lib.buttons.GenBitmapTextButton._GetLabelSize(self)[:-1] + (False,)
    80 
   108 
    81 class GenStaticBitmap(wx.lib.statbmp.GenStaticBitmap):
   109 class GenStaticBitmap(wx.lib.statbmp.GenStaticBitmap):
       
   110     """ Customized GenStaticBitmap, fix transparency redraw bug on wx2.8/win32, 
       
   111     and accept image name as __init__ parameter, fail silently if file do not exist"""
    82     def __init__(self, parent, ID, bitmapname,
   112     def __init__(self, parent, ID, bitmapname,
    83                  pos = wx.DefaultPosition, size = wx.DefaultSize,
   113                  pos = wx.DefaultPosition, size = wx.DefaultSize,
    84                  style = 0,
   114                  style = 0,
    85                  name = "genstatbmp"):
   115                  name = "genstatbmp"):
    86         
   116         
   405             maxx, maxy = sizer.GetMinSize()
   435             maxx, maxy = sizer.GetMinSize()
   406             self.PLCConfig.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT, 
   436             self.PLCConfig.SetScrollbars(SCROLLBAR_UNIT, SCROLLBAR_UNIT, 
   407                 maxx / SCROLLBAR_UNIT, maxy / SCROLLBAR_UNIT, xstart, ystart)
   437                 maxx / SCROLLBAR_UNIT, maxy / SCROLLBAR_UNIT, xstart, ystart)
   408 
   438 
   409     def RefreshPLCParams(self):
   439     def RefreshPLCParams(self):
       
   440         self.Freeze()
   410         self.ClearSizer(self.PLCParamsSizer)
   441         self.ClearSizer(self.PLCParamsSizer)
   411         
   442         
   412         if self.PluginRoot.HasProjectOpened():
   443         if self.PluginRoot.HasProjectOpened():
   413             plcwindow = wx.Panel(self.PLCConfig, -1, size=wx.Size(-1, -1))
   444             plcwindow = wx.Panel(self.PLCConfig, -1, size=wx.Size(-1, -1))
   414             plcwindow.SetBackgroundColour(TITLE_COLOUR)
   445             plcwindow.SetBackgroundColour(TITLE_COLOUR)
   481                 event.Skip()
   512                 event.Skip()
   482             minimizebutton.Bind(wx.EVT_BUTTON, togglewindow, id=minimizebutton_id)
   513             minimizebutton.Bind(wx.EVT_BUTTON, togglewindow, id=minimizebutton_id)
   483         
   514         
   484         self.PLCConfigMainSizer.Layout()
   515         self.PLCConfigMainSizer.Layout()
   485         self.RefreshScrollBars()
   516         self.RefreshScrollBars()
       
   517         self.Thaw()
   486 
   518 
   487 #    def GenerateAddButtonSizer(self, plugin, parent, horizontal = True):
   519 #    def GenerateAddButtonSizer(self, plugin, parent, horizontal = True):
   488 #        if horizontal:
   520 #        if horizontal:
   489 #            addsizer = wx.FlexGridSizer(cols=len(plugin.PluginMethods))
   521 #            addsizer = wx.FlexGridSizer(cols=len(plugin.PluginMethods))
   490 #        else:
   522 #        else:
   510         else:
   542         else:
   511             msizer = wx.FlexGridSizer(cols=1)
   543             msizer = wx.FlexGridSizer(cols=1)
   512         for plugin_method in plugin.PluginMethods:
   544         for plugin_method in plugin.PluginMethods:
   513             if "method" in plugin_method:
   545             if "method" in plugin_method:
   514                 id = wx.NewId()
   546                 id = wx.NewId()
   515                 button = wx.lib.buttons.GenBitmapTextButton(id=id, parent=parent,
   547                 button = GenBitmapTextButton(id=id, parent=parent,
   516                     bitmap=wx.Bitmap(os.path.join(CWD, "%s24x24.png"%plugin_method.get("bitmap", os.path.join("images", "Unknown")))), label=plugin_method["name"], 
   548                     bitmap=wx.Bitmap(os.path.join(CWD, "%s24x24.png"%plugin_method.get("bitmap", os.path.join("images", "Unknown")))), label=plugin_method["name"], 
   517                     name=plugin_method["name"], pos=wx.DefaultPosition, style=wx.NO_BORDER)
   549                     name=plugin_method["name"], pos=wx.DefaultPosition, style=wx.NO_BORDER)
   518                 button.SetToolTipString(plugin_method["tooltip"])
   550                 button.SetToolTipString(plugin_method["tooltip"])
   519                 button.Bind(wx.EVT_BUTTON, self.GetButtonCallBackFunction(plugin, plugin_method["method"]), id=id)
   551                 button.Bind(wx.EVT_BUTTON, self.GetButtonCallBackFunction(plugin, plugin_method["method"]), id=id)
   520                 #hack to force size to mini
   552                 #hack to force size to mini
   521                 button._GetLabelSize = gen_mini_GetLabelSize(button)
   553                 if not plugin_method.get("enabled",True):
   522                 #button._GetLabelSize = lambda :(-1,-1,False)
   554                     button.Disable()
   523                 msizer.AddWindow(button, 0, border=0, flag=0)
   555                 msizer.AddWindow(button, 0, border=0, flag=0)
   524         return msizer
   556         return msizer
   525 
   557 
   526     def RefreshPluginTree(self):
   558     def RefreshPluginTree(self):
       
   559         self.Freeze()
   527         self.ClearSizer(self.PluginTreeSizer)
   560         self.ClearSizer(self.PluginTreeSizer)
   528         if self.PluginRoot.HasProjectOpened():
   561         if self.PluginRoot.HasProjectOpened():
   529             index = [0]
   562             index = [0]
   530             for child in self.PluginRoot.IECSortedChilds():
   563             for child in self.PluginRoot.IECSortedChilds():
   531                 self.GenerateTreeBranch(child, index)
   564                 self.GenerateTreeBranch(child, index)
   532                 if not self.PluginInfos[child]["expanded"]:
   565                 if not self.PluginInfos[child]["expanded"]:
   533                     self.CollapsePlugin(child)
   566                     self.CollapsePlugin(child)
   534         self.PLCConfigMainSizer.Layout()
   567         self.PLCConfigMainSizer.Layout()
   535         self.RefreshScrollBars()
   568         self.RefreshScrollBars()
       
   569         self.Thaw()
   536 
   570 
   537     def ExpandPlugin(self, plugin, force = False):
   571     def ExpandPlugin(self, plugin, force = False):
   538         for child in self.PluginInfos[plugin]["children"]:
   572         for child in self.PluginInfos[plugin]["children"]:
   539             self.PluginTreeSizer.Show(self.PluginInfos[child]["left"])
   573             self.PluginTreeSizer.Show(self.PluginInfos[child]["left"])
   540             self.PluginTreeSizer.Show(self.PluginInfos[child]["middle"])
   574             self.PluginTreeSizer.Show(self.PluginInfos[child]["middle"])
   580         leftsizer = wx.BoxSizer(wx.VERTICAL)
   614         leftsizer = wx.BoxSizer(wx.VERTICAL)
   581         leftbuttonsizer.AddSizer(leftsizer, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
   615         leftbuttonsizer.AddSizer(leftsizer, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
   582 
   616 
   583         rolesizer = wx.BoxSizer(wx.HORIZONTAL)
   617         rolesizer = wx.BoxSizer(wx.HORIZONTAL)
   584         leftsizer.AddSizer(rolesizer, 0, border=0, flag=wx.GROW|wx.RIGHT)
   618         leftsizer.AddSizer(rolesizer, 0, border=0, flag=wx.GROW|wx.RIGHT)
   585 
       
   586         roletext = wx.StaticText(leftwindow, -1)
       
   587         roletext.SetLabel(plugin.PlugHelp)
       
   588         rolesizer.AddWindow(roletext, 0, border=5, flag=wx.RIGHT|wx.ALIGN_LEFT)
       
   589 
   619 
   590         enablebutton_id = wx.NewId()
   620         enablebutton_id = wx.NewId()
   591         enablebutton = wx.lib.buttons.GenBitmapToggleButton(id=enablebutton_id, bitmap=wx.Bitmap(os.path.join(CWD, 'images', 'Disabled.png')),
   621         enablebutton = wx.lib.buttons.GenBitmapToggleButton(id=enablebutton_id, bitmap=wx.Bitmap(os.path.join(CWD, 'images', 'Disabled.png')),
   592               name='EnableButton', parent=leftwindow, size=wx.Size(16, 16), pos=wx.Point(0, 0), style=0)#wx.NO_BORDER)
   622               name='EnableButton', parent=leftwindow, size=wx.Size(16, 16), pos=wx.Point(0, 0), style=0)#wx.NO_BORDER)
   593         enablebutton.SetToolTipString("Enable/Disable this plugin")
   623         enablebutton.SetToolTipString("Enable/Disable this plugin")
   600             enablebutton.SetToggle(res)
   630             enablebutton.SetToggle(res)
   601             event.Skip()
   631             event.Skip()
   602         enablebutton.Bind(wx.EVT_BUTTON, toggleenablebutton, id=enablebutton_id)
   632         enablebutton.Bind(wx.EVT_BUTTON, toggleenablebutton, id=enablebutton_id)
   603         rolesizer.AddWindow(enablebutton, 0, border=0, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
   633         rolesizer.AddWindow(enablebutton, 0, border=0, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
   604 
   634 
       
   635         roletext = wx.StaticText(leftwindow, -1)
       
   636         roletext.SetLabel(plugin.PlugHelp)
       
   637         rolesizer.AddWindow(roletext, 0, border=5, flag=wx.RIGHT|wx.ALIGN_LEFT)
   605         
   638         
   606         plugin_IECChannel = plugin.BaseParams.getIEC_Channel()
   639         plugin_IECChannel = plugin.BaseParams.getIEC_Channel()
   607         
   640         
   608         iecsizer = wx.BoxSizer(wx.HORIZONTAL)
   641         iecsizer = wx.BoxSizer(wx.HORIZONTAL)
   609         leftsizer.AddSizer(iecsizer, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
   642         leftsizer.AddSizer(iecsizer, 0, border=5, flag=wx.RIGHT|wx.ALIGN_CENTER_VERTICAL)
   803             infos["variable_list"].Clear()
   836             infos["variable_list"].Clear()
   804             for location in locations:
   837             for location in locations:
   805                 infos["variable_list"].Append(location["NAME"].replace("__", "%").replace("_", "."))
   838                 infos["variable_list"].Append(location["NAME"].replace("__", "%").replace("_", "."))
   806         self.PLCConfigMainSizer.Layout()
   839         self.PLCConfigMainSizer.Layout()
   807         self.RefreshScrollBars()
   840         self.RefreshScrollBars()
   808 
   841         
       
   842     def RefreshAll(self):
       
   843         self.RefreshPLCParams()
       
   844         self.RefreshPluginTree()
       
   845         
   809     def GetItemChannelChangedFunction(self, plugin, value):
   846     def GetItemChannelChangedFunction(self, plugin, value):
   810         def OnPluginTreeItemChannelChanged(event):
   847         def OnPluginTreeItemChannelChanged(event):
   811             res, StructChanged = plugin.SetParamsAttribute("BaseParams.IEC_Channel", value, self.Log)
   848             res, StructChanged = plugin.SetParamsAttribute("BaseParams.IEC_Channel", value, self.Log)
   812             wx.CallAfter(self.RefreshPluginTree)
   849             wx.CallAfter(self.RefreshPluginTree)
   813             event.Skip()
   850             event.Skip()
   832         return AddPluginMenu
   869         return AddPluginMenu
   833     
   870     
   834     def GetButtonCallBackFunction(self, plugin, method):
   871     def GetButtonCallBackFunction(self, plugin, method):
   835         def OnButtonClick(event):
   872         def OnButtonClick(event):
   836             getattr(plugin,method)(self.Log)
   873             getattr(plugin,method)(self.Log)
   837             self.RefreshVariableLists()
   874             #self.RefreshVariableLists()
       
   875             wx.CallAfter(self.RefreshAll)
   838             event.Skip()
   876             event.Skip()
   839         return OnButtonClick
   877         return OnButtonClick
   840     
   878     
   841     def GetChoiceCallBackFunction(self, choicectrl, plugin, path):
   879     def GetChoiceCallBackFunction(self, choicectrl, plugin, path):
   842         def OnChoiceChanged(event):
   880         def OnChoiceChanged(event):
  1164 #                               Exception Handler
  1202 #                               Exception Handler
  1165 #-------------------------------------------------------------------------------
  1203 #-------------------------------------------------------------------------------
  1166 
  1204 
  1167 Max_Traceback_List_Size = 20
  1205 Max_Traceback_List_Size = 20
  1168 
  1206 
  1169 def Display_Exception_Dialog(e_type,e_value,e_tb):
  1207 def Display_Exception_Dialog(e_type, e_value, e_tb, bug_report_path):
  1170     trcbck_lst = []
  1208     trcbck_lst = []
  1171     for i,line in enumerate(traceback.extract_tb(e_tb)):
  1209     for i,line in enumerate(traceback.extract_tb(e_tb)):
  1172         trcbck = " " + str(i+1) + ". "
  1210         trcbck = " " + str(i+1) + ". "
  1173         if line[0].find(os.getcwd()) == -1:
  1211         if line[0].find(os.getcwd()) == -1:
  1174             trcbck += "file : " + str(line[0]) + ",   "
  1212             trcbck += "file : " + str(line[0]) + ",   "
  1182     if cap:
  1220     if cap:
  1183         cap.ReleaseMouse()
  1221         cap.ReleaseMouse()
  1184 
  1222 
  1185     dlg = wx.SingleChoiceDialog(None, 
  1223     dlg = wx.SingleChoiceDialog(None, 
  1186         """
  1224         """
  1187 An error happens.
  1225 An unhandled exception (bug) occured. Bug report saved at :
  1188 
  1226 (%s)
  1189 Click on OK for saving an error report.
  1227 
  1190 
  1228 Please be kind enough to send this file to:
  1191 Please contact LOLITech at:
  1229 bugs_beremiz@lolitech.fr
  1192 +33 (0)3 29 52 95 67
  1230 
  1193 bugs_Beremiz@lolitech.fr
  1231 You should now restart Beremiz.
  1194 
  1232 
  1195 
  1233 Traceback:
  1196 Error:
  1234 """ % bug_report_path +
  1197 """ +
       
  1198         str(e_type) + " : " + str(e_value), 
  1235         str(e_type) + " : " + str(e_value), 
  1199         "Error",
  1236         "Error",
  1200         trcbck_lst)
  1237         trcbck_lst)
  1201     try:
  1238     try:
  1202         res = (dlg.ShowModal() == wx.ID_OK)
  1239         res = (dlg.ShowModal() == wx.ID_OK)
  1229         last_tb = get_last_traceback(e_traceback)
  1266         last_tb = get_last_traceback(e_traceback)
  1230         ex = (last_tb.tb_frame.f_code.co_filename, last_tb.tb_frame.f_lineno)
  1267         ex = (last_tb.tb_frame.f_code.co_filename, last_tb.tb_frame.f_lineno)
  1231         if str(e_value).startswith("!!!"):
  1268         if str(e_value).startswith("!!!"):
  1232             Display_Error_Dialog(e_value)
  1269             Display_Error_Dialog(e_value)
  1233         elif ex not in ignored_exceptions:
  1270         elif ex not in ignored_exceptions:
  1234             result = Display_Exception_Dialog(e_type,e_value,e_traceback)
  1271             date = time.ctime()
       
  1272             bug_report_path = path+os.sep+"bug_report_"+date.replace(':','-').replace(' ','_')+".txt"
       
  1273             result = Display_Exception_Dialog(e_type,e_value,e_traceback,bug_report_path)
  1235             if result:
  1274             if result:
  1236                 ignored_exceptions.append(ex)
  1275                 ignored_exceptions.append(ex)
  1237                 info = {
  1276                 info = {
  1238                     'app-title' : wx.GetApp().GetAppName(), # app_title
  1277                     'app-title' : wx.GetApp().GetAppName(), # app_title
  1239                     'app-version' : app_version,
  1278                     'app-version' : app_version,
  1241                     'wx-platform' : wx.Platform,
  1280                     'wx-platform' : wx.Platform,
  1242                     'python-version' : platform.python_version(), #sys.version.split()[0],
  1281                     'python-version' : platform.python_version(), #sys.version.split()[0],
  1243                     'platform' : platform.platform(),
  1282                     'platform' : platform.platform(),
  1244                     'e-type' : e_type,
  1283                     'e-type' : e_type,
  1245                     'e-value' : e_value,
  1284                     'e-value' : e_value,
  1246                     'date' : time.ctime(),
  1285                     'date' : date,
  1247                     'cwd' : os.getcwd(),
  1286                     'cwd' : os.getcwd(),
  1248                     }
  1287                     }
  1249                 if e_traceback:
  1288                 if e_traceback:
  1250                     info['traceback'] = ''.join(traceback.format_tb(e_traceback)) + '%s: %s' % (e_type, e_value)
  1289                     info['traceback'] = ''.join(traceback.format_tb(e_traceback)) + '%s: %s' % (e_type, e_value)
  1251                     last_tb = get_last_traceback(e_traceback)
  1290                     last_tb = get_last_traceback(e_traceback)
  1252                     exception_locals = last_tb.tb_frame.f_locals # the locals at the level of the stack trace where the exception actually occurred
  1291                     exception_locals = last_tb.tb_frame.f_locals # the locals at the level of the stack trace where the exception actually occurred
  1253                     info['locals'] = format_namespace(exception_locals)
  1292                     info['locals'] = format_namespace(exception_locals)
  1254                     if 'self' in exception_locals:
  1293                     if 'self' in exception_locals:
  1255                         info['self'] = format_namespace(exception_locals['self'].__dict__)
  1294                         info['self'] = format_namespace(exception_locals['self'].__dict__)
  1256                 
  1295                 
  1257                 output = open(path+os.sep+"bug_report_"+info['date'].replace(':','-').replace(' ','_')+".txt",'w')
  1296                 output = open(bug_report_path,'w')
  1258                 lst = info.keys()
  1297                 lst = info.keys()
  1259                 lst.sort()
  1298                 lst.sort()
  1260                 for a in lst:
  1299                 for a in lst:
  1261                     output.write(a+":\n"+str(info[a])+"\n\n")
  1300                     output.write(a+":\n"+str(info[a])+"\n\n")
  1262 
  1301