controls/DebugVariablePanel/DebugVariableViewer.py
changeset 1730 64d8f52bc8c8
parent 1571 486f94a8032c
child 1736 7e61baa047f0
equal deleted inserted replaced
1726:d51af006fa6b 1730:64d8f52bc8c8
    54 Class that implements a generic viewer that display a list of variable values
    54 Class that implements a generic viewer that display a list of variable values
    55 This class has to be inherited to effectively display variable values
    55 This class has to be inherited to effectively display variable values
    56 """
    56 """
    57 
    57 
    58 class DebugVariableViewer:
    58 class DebugVariableViewer:
    59     
    59 
    60     def __init__(self, window, items=[]):
    60     def __init__(self, window, items=[]):
    61         """
    61         """
    62         Constructor
    62         Constructor
    63         @param window: Reference to the Debug Variable Panel
    63         @param window: Reference to the Debug Variable Panel
    64         @param items: List of DebugVariableItem displayed by Viewer
    64         @param items: List of DebugVariableItem displayed by Viewer
    65         """
    65         """
    66         self.ParentWindow = window
    66         self.ParentWindow = window
    67         self.ItemsDict = OrderedDict([(item.GetVariable(), item)
    67         self.ItemsDict = OrderedDict([(item.GetVariable(), item)
    68                                       for item in items])
    68                                       for item in items])
    69         self.Items = self.ItemsDict.viewvalues()
    69         self.Items = self.ItemsDict.viewvalues()
    70         
    70 
    71         # Variable storing current highlight displayed in Viewer
    71         # Variable storing current highlight displayed in Viewer
    72         self.Highlight = HIGHLIGHT_NONE
    72         self.Highlight = HIGHLIGHT_NONE
    73         # List of buttons
    73         # List of buttons
    74         self.Buttons = []
    74         self.Buttons = []
    75     
    75 
    76     def __del__(self):
    76     def __del__(self):
    77         """
    77         """
    78         Destructor
    78         Destructor
    79         """
    79         """
    80         # Remove reference to Debug Variable Panel
    80         # Remove reference to Debug Variable Panel
    81         self.ParentWindow = None
    81         self.ParentWindow = None
    82     
    82 
    83     def GetIndex(self):
    83     def GetIndex(self):
    84         """
    84         """
    85         Return position of Viewer in Debug Variable Panel
    85         Return position of Viewer in Debug Variable Panel
    86         @return: Position of Viewer
    86         @return: Position of Viewer
    87         """
    87         """
    88         return self.ParentWindow.GetViewerIndex(self)
    88         return self.ParentWindow.GetViewerIndex(self)
    89     
    89 
    90     def GetItem(self, variable):
    90     def GetItem(self, variable):
    91         """
    91         """
    92         Return item storing values of a variable
    92         Return item storing values of a variable
    93         @param variable: Variable path
    93         @param variable: Variable path
    94         @return: Item storing values of this variable
    94         @return: Item storing values of this variable
    95         """
    95         """
    96         return self.ItemsDict.get(variable, None)
    96         return self.ItemsDict.get(variable, None)
    97     
    97 
    98     def GetItems(self):
    98     def GetItems(self):
    99         """
    99         """
   100         Return items displayed by Viewer
   100         Return items displayed by Viewer
   101         @return: List of items displayed in Viewer
   101         @return: List of items displayed in Viewer
   102         """
   102         """
   103         return self.ItemsDict.values()
   103         return self.ItemsDict.values()
   104     
   104 
   105     def AddItem(self, item):
   105     def AddItem(self, item):
   106         """
   106         """
   107         Add an item to the list of items displayed by Viewer
   107         Add an item to the list of items displayed by Viewer
   108         @param item: Item to add to the list
   108         @param item: Item to add to the list
   109         """
   109         """
   110         self.ItemsDict[item.GetVariable()] = item
   110         self.ItemsDict[item.GetVariable()] = item
   111         
   111 
   112     def RemoveItem(self, item):
   112     def RemoveItem(self, item):
   113         """
   113         """
   114         Remove an item from the list of items displayed by Viewer
   114         Remove an item from the list of items displayed by Viewer
   115         @param item: Item to remove from the list
   115         @param item: Item to remove from the list
   116         """
   116         """
   117         self.ItemsDict.pop(item.GetVariable(), None)
   117         self.ItemsDict.pop(item.GetVariable(), None)
   118     
   118 
   119     def ClearItems(self):
   119     def ClearItems(self):
   120         """
   120         """
   121         Clear list of items displayed by Viewer
   121         Clear list of items displayed by Viewer
   122         """
   122         """
   123         # Unsubscribe every items of the list
   123         # Unsubscribe every items of the list
   124         for item in self.Items:
   124         for item in self.Items:
   125             self.ParentWindow.RemoveDataConsumer(item)
   125             self.ParentWindow.RemoveDataConsumer(item)
   126         
   126 
   127         # Clear list
   127         # Clear list
   128         self.ItemsDict.clear()
   128         self.ItemsDict.clear()
   129         
   129 
   130     def ItemsIsEmpty(self):
   130     def ItemsIsEmpty(self):
   131         """
   131         """
   132         Return if list of items displayed by Viewer is empty
   132         Return if list of items displayed by Viewer is empty
   133         @return: True if list is empty
   133         @return: True if list is empty
   134         """
   134         """
   135         return len(self.Items) == 0
   135         return len(self.Items) == 0
   136     
   136 
   137     def SubscribeAllDataConsumers(self):
   137     def SubscribeAllDataConsumers(self):
   138         """
   138         """
   139         Function that unsubscribe and remove every item that store values of
   139         Function that unsubscribe and remove every item that store values of
   140         a variable that doesn't exist in PLC anymore
   140         a variable that doesn't exist in PLC anymore
   141         """
   141         """
   142         for item in self.ItemsDict.values()[:]:
   142         for item in self.ItemsDict.values()[:]:
   143             iec_path = item.GetVariable()
   143             iec_path = item.GetVariable()
   144             
   144 
   145             # Check that variablepath exist in PLC
   145             # Check that variablepath exist in PLC
   146             if self.ParentWindow.GetDataType(iec_path) is None:
   146             if self.ParentWindow.GetDataType(iec_path) is None:
   147                 # If not, unsubscribe and remove it
   147                 # If not, unsubscribe and remove it
   148                 self.ParentWindow.RemoveDataConsumer(item)
   148                 self.ParentWindow.RemoveDataConsumer(item)
   149                 self.RemoveItem(item)
   149                 self.RemoveItem(item)
   150             else:
   150             else:
   151                 # If it exist, resubscribe and refresh data type
   151                 # If it exist, resubscribe and refresh data type
   152                 self.ParentWindow.AddDataConsumer(iec_path.upper(), item, True)
   152                 self.ParentWindow.AddDataConsumer(iec_path.upper(), item, True)
   153                 item.RefreshVariableType()
   153                 item.RefreshVariableType()
   154     
   154 
   155     def ResetItemsData(self):
   155     def ResetItemsData(self):
   156         """
   156         """
   157         Reset data stored in every items displayed in Viewer
   157         Reset data stored in every items displayed in Viewer
   158         """
   158         """
   159         for item in self.Items:
   159         for item in self.Items:
   160             item.ResetData()
   160             item.ResetData()
   161     
   161 
   162     def GetItemsMinCommonTick(self):
   162     def GetItemsMinCommonTick(self):
   163         """
   163         """
   164         Return the minimum tick common to all iems displayed in Viewer
   164         Return the minimum tick common to all iems displayed in Viewer
   165         @return: Minimum common tick between items
   165         @return: Minimum common tick between items
   166         """
   166         """
   167         return reduce(max, [item.GetData()[0, 0] 
   167         return reduce(max, [item.GetData()[0, 0]
   168                             for item in self.Items
   168                             for item in self.Items
   169                             if len(item.GetData()) > 0], 0)
   169                             if len(item.GetData()) > 0], 0)
   170     
   170 
   171     def RefreshViewer(self):
   171     def RefreshViewer(self):
   172         """
   172         """
   173         Method that refresh the content displayed by Viewer
   173         Method that refresh the content displayed by Viewer
   174         Need to be overridden by inherited classes
   174         Need to be overridden by inherited classes
   175         """
   175         """
   176         pass
   176         pass
   177     
   177 
   178     def SetHighlight(self, highlight):
   178     def SetHighlight(self, highlight):
   179         """
   179         """
   180         Set Highlight type displayed in Viewer
   180         Set Highlight type displayed in Viewer
   181         @return: True if highlight has changed
   181         @return: True if highlight has changed
   182         """
   182         """
   183         # Return immediately if highlight don't change
   183         # Return immediately if highlight don't change
   184         if self.Highlight == highlight:
   184         if self.Highlight == highlight:
   185             return False
   185             return False
   186         
   186 
   187         self.Highlight = highlight
   187         self.Highlight = highlight
   188         return True
   188         return True
   189     
   189 
   190     def GetButtons(self):
   190     def GetButtons(self):
   191         """
   191         """
   192         Return list of buttons defined in Viewer
   192         Return list of buttons defined in Viewer
   193         @return: List of buttons
   193         @return: List of buttons
   194         """
   194         """
   195         return self.Buttons
   195         return self.Buttons
   196     
   196 
   197     def IsOverButton(self, x, y):
   197     def IsOverButton(self, x, y):
   198         """
   198         """
   199         Return if point is over one button of Viewer
   199         Return if point is over one button of Viewer
   200         @param x: X coordinate of point
   200         @param x: X coordinate of point
   201         @param y: Y coordinate of point
   201         @param y: Y coordinate of point
   203         """
   203         """
   204         for button in self.GetButtons():
   204         for button in self.GetButtons():
   205             if button.HitTest(x, y):
   205             if button.HitTest(x, y):
   206                 return button
   206                 return button
   207         return None
   207         return None
   208     
   208 
   209     def HandleButton(self, x, y):
   209     def HandleButton(self, x, y):
   210         """
   210         """
   211         Search for the button under point and if found execute associated
   211         Search for the button under point and if found execute associated
   212         callback
   212         callback
   213         @param x: X coordinate of point
   213         @param x: X coordinate of point
   215         @return: True if a button was found and callback executed
   215         @return: True if a button was found and callback executed
   216         """
   216         """
   217         button = self.IsOverButton(x, y)
   217         button = self.IsOverButton(x, y)
   218         if button is None:
   218         if button is None:
   219             return False
   219             return False
   220         
   220 
   221         button.ProcessCallback()
   221         button.ProcessCallback()
   222         return True
   222         return True
   223     
   223 
   224     def ShowButtons(self, show):
   224     def ShowButtons(self, show):
   225         """
   225         """
   226         Set display state of buttons in Viewer
   226         Set display state of buttons in Viewer
   227         @param show: Display state (True if buttons must be displayed)
   227         @param show: Display state (True if buttons must be displayed)
   228         """
   228         """
   229         # Change display of every buttons
   229         # Change display of every buttons
   230         for button in self.Buttons:
   230         for button in self.Buttons:
   231             button.Show(show)
   231             button.Show(show)
   232         
   232 
   233         # Refresh button positions
   233         # Refresh button positions
   234         self.RefreshButtonsPosition()
   234         self.RefreshButtonsPosition()
   235         self.RefreshViewer()
   235         self.RefreshViewer()
   236     
   236 
   237     def RefreshButtonsPosition(self):
   237     def RefreshButtonsPosition(self):
   238         """
   238         """
   239         Function that refresh buttons position in Viewer
   239         Function that refresh buttons position in Viewer
   240         """
   240         """
   241         # Get Viewer size
   241         # Get Viewer size
   242         width, height = self.GetSize()
   242         width, height = self.GetSize()
   243         
   243 
   244         # Buttons are align right so we calculate buttons positions in
   244         # Buttons are align right so we calculate buttons positions in
   245         # reverse order
   245         # reverse order
   246         buttons = self.Buttons[:]
   246         buttons = self.Buttons[:]
   247         buttons.reverse()
   247         buttons.reverse()
   248         
   248 
   249         # Position offset on x coordinate
   249         # Position offset on x coordinate
   250         x_offset = 0
   250         x_offset = 0
   251         for button in buttons:
   251         for button in buttons:
   252             # Buttons are stacked right, removing those that are not active 
   252             # Buttons are stacked right, removing those that are not active
   253             if button.IsEnabled():
   253             if button.IsEnabled():
   254                 # Update button position according to button width and offset
   254                 # Update button position according to button width and offset
   255                 # on x coordinate
   255                 # on x coordinate
   256                 w, h = button.GetSize()
   256                 w, h = button.GetSize()
   257                 button.SetPosition(width - 5 - w - x_offset, 5)
   257                 button.SetPosition(width - 5 - w - x_offset, 5)
   258                 # Update offset on x coordinate
   258                 # Update offset on x coordinate
   259                 x_offset += w + 2
   259                 x_offset += w + 2
   260     
   260 
   261     def DrawCommonElements(self, dc, buttons=None):
   261     def DrawCommonElements(self, dc, buttons=None):
   262         """
   262         """
   263         Function that draw common graphics for every Viewers
   263         Function that draw common graphics for every Viewers
   264         @param dc: wx.DC object corresponding to Device context where drawing
   264         @param dc: wx.DC object corresponding to Device context where drawing
   265         common graphics
   265         common graphics
   266         @param buttons: List of buttons to draw if different from default
   266         @param buttons: List of buttons to draw if different from default
   267         (default None)
   267         (default None)
   268         """
   268         """
   269         # Get Viewer size
   269         # Get Viewer size
   270         width, height = self.GetSize()
   270         width, height = self.GetSize()
   271         
   271 
   272         # Set dc styling for drop before or drop after highlight
   272         # Set dc styling for drop before or drop after highlight
   273         dc.SetPen(HIGHLIGHT_DROP_PEN)
   273         dc.SetPen(HIGHLIGHT_DROP_PEN)
   274         dc.SetBrush(HIGHLIGHT_DROP_BRUSH)
   274         dc.SetBrush(HIGHLIGHT_DROP_BRUSH)
   275         
   275 
   276         # Draw line at upper side of Viewer if highlight is drop before
   276         # Draw line at upper side of Viewer if highlight is drop before
   277         if self.Highlight == HIGHLIGHT_BEFORE:
   277         if self.Highlight == HIGHLIGHT_BEFORE:
   278             dc.DrawLine(0, 1, width - 1, 1)
   278             dc.DrawLine(0, 1, width - 1, 1)
   279         
   279 
   280         # Draw line at lower side of Viewer if highlight is drop before
   280         # Draw line at lower side of Viewer if highlight is drop before
   281         elif self.Highlight == HIGHLIGHT_AFTER:
   281         elif self.Highlight == HIGHLIGHT_AFTER:
   282             dc.DrawLine(0, height - 1, width - 1, height - 1)
   282             dc.DrawLine(0, height - 1, width - 1, height - 1)
   283         
   283 
   284         # If no specific buttons are defined, get default buttons
   284         # If no specific buttons are defined, get default buttons
   285         if buttons is None:
   285         if buttons is None:
   286             buttons = self.Buttons
   286             buttons = self.Buttons
   287         # Draw buttons
   287         # Draw buttons
   288         for button in buttons:
   288         for button in buttons:
   289             button.Draw(dc)
   289             button.Draw(dc)
   290         
   290 
   291         # If graph dragging is processing
   291         # If graph dragging is processing
   292         if self.ParentWindow.IsDragging():
   292         if self.ParentWindow.IsDragging():
   293             destBBox = self.ParentWindow.GetDraggingAxesClippingRegion(self)
   293             destBBox = self.ParentWindow.GetDraggingAxesClippingRegion(self)
   294             srcPos = self.ParentWindow.GetDraggingAxesPosition(self)
   294             srcPos = self.ParentWindow.GetDraggingAxesPosition(self)
   295             if destBBox.width > 0 and destBBox.height > 0:
   295             if destBBox.width > 0 and destBBox.height > 0:
   296                 srcPanel = self.ParentWindow.DraggingAxesPanel
   296                 srcPanel = self.ParentWindow.DraggingAxesPanel
   297                 srcBBox = srcPanel.GetAxesBoundingBox()
   297                 srcBBox = srcPanel.GetAxesBoundingBox()
   298                 
   298 
   299                 srcX = srcBBox.x - (srcPos.x if destBBox.x == 0 else 0)
   299                 srcX = srcBBox.x - (srcPos.x if destBBox.x == 0 else 0)
   300                 srcY = srcBBox.y - (srcPos.y if destBBox.y == 0 else 0)
   300                 srcY = srcBBox.y - (srcPos.y if destBBox.y == 0 else 0)
   301                 
   301 
   302                 srcBmp = _convert_agg_to_wx_bitmap(
   302                 srcBmp = _convert_agg_to_wx_bitmap(
   303                             srcPanel.get_renderer(), None)
   303                             srcPanel.get_renderer(), None)
   304                 srcDC = wx.MemoryDC()
   304                 srcDC = wx.MemoryDC()
   305                 srcDC.SelectObject(srcBmp)
   305                 srcDC.SelectObject(srcBmp)
   306                 
   306 
   307                 dc.Blit(destBBox.x, destBBox.y, 
   307                 dc.Blit(destBBox.x, destBBox.y,
   308                         int(destBBox.width), int(destBBox.height), 
   308                         int(destBBox.width), int(destBBox.height),
   309                         srcDC, srcX, srcY)
   309                         srcDC, srcX, srcY)
   310     
   310 
   311     def OnEnter(self, event):
   311     def OnEnter(self, event):
   312         """
   312         """
   313         Function called when entering Viewer
   313         Function called when entering Viewer
   314         @param event: wx.MouseEvent 
   314         @param event: wx.MouseEvent
   315         """
   315         """
   316         # Display buttons
   316         # Display buttons
   317         self.ShowButtons(True)
   317         self.ShowButtons(True)
   318         event.Skip()
   318         event.Skip()
   319         
   319 
   320     def OnLeave(self, event):
   320     def OnLeave(self, event):
   321         """
   321         """
   322         Function called when leaving Viewer
   322         Function called when leaving Viewer
   323         @param event: wx.MouseEvent 
   323         @param event: wx.MouseEvent
   324         """
   324         """
   325         # Hide buttons
   325         # Hide buttons
   326         self.ShowButtons(False)
   326         self.ShowButtons(False)
   327         event.Skip()
   327         event.Skip()
   328     
   328 
   329     def OnCloseButton(self):
   329     def OnCloseButton(self):
   330         """
   330         """
   331         Function called when Close button is pressed
   331         Function called when Close button is pressed
   332         """
   332         """
   333         wx.CallAfter(self.ParentWindow.DeleteValue, self)
   333         wx.CallAfter(self.ParentWindow.DeleteValue, self)
   334     
   334 
   335     def OnForceButton(self):
   335     def OnForceButton(self):
   336         """
   336         """
   337         Function called when Force button is pressed
   337         Function called when Force button is pressed
   338         """
   338         """
   339         self.ForceValue(self.ItemsDict.values()[0])
   339         self.ForceValue(self.ItemsDict.values()[0])
   340         
   340 
   341     def OnReleaseButton(self):
   341     def OnReleaseButton(self):
   342         """
   342         """
   343         Function called when Release button is pressed
   343         Function called when Release button is pressed
   344         """
   344         """
   345         self.ReleaseValue(self.ItemsDict.values()[0])
   345         self.ReleaseValue(self.ItemsDict.values()[0])
   346     
   346 
   347     def OnMouseDragging(self, x, y):
   347     def OnMouseDragging(self, x, y):
   348         """
   348         """
   349         Function called when mouse is dragged over Viewer
   349         Function called when mouse is dragged over Viewer
   350         @param x: X coordinate of mouse pointer
   350         @param x: X coordinate of mouse pointer
   351         @param y: Y coordinate of mouse pointer
   351         @param y: Y coordinate of mouse pointer
   352         """
   352         """
   353         xw, yw = self.GetPosition()
   353         xw, yw = self.GetPosition()
   354         # Refresh highlight in Debug Variable Panel (highlight can be displayed
   354         # Refresh highlight in Debug Variable Panel (highlight can be displayed
   355         # in another Viewer
   355         # in another Viewer
   356         self.ParentWindow.RefreshHighlight(x + xw, y + yw)
   356         self.ParentWindow.RefreshHighlight(x + xw, y + yw)
   357     
   357 
   358     def RefreshHighlight(self, x, y):
   358     def RefreshHighlight(self, x, y):
   359         """
   359         """
   360         Function called by Debug Variable Panel asking Viewer to refresh
   360         Function called by Debug Variable Panel asking Viewer to refresh
   361         highlight according to mouse position
   361         highlight according to mouse position
   362         @param x: X coordinate of mouse pointer
   362         @param x: X coordinate of mouse pointer
   363         @param y: Y coordinate of mouse pointer
   363         @param y: Y coordinate of mouse pointer
   364         """
   364         """
   365         # Get Viewer size
   365         # Get Viewer size
   366         width, height = self.GetSize()
   366         width, height = self.GetSize()
   367         
   367 
   368         # Mouse is in the first half of Viewer
   368         # Mouse is in the first half of Viewer
   369         if y < height / 2:
   369         if y < height / 2:
   370             # If Viewer is the upper one, draw drop before highlight
   370             # If Viewer is the upper one, draw drop before highlight
   371             if self.ParentWindow.IsViewerFirst(self):
   371             if self.ParentWindow.IsViewerFirst(self):
   372                 self.SetHighlight(HIGHLIGHT_BEFORE)
   372                 self.SetHighlight(HIGHLIGHT_BEFORE)
   373             
   373 
   374             # Else draw drop after highlight in previous Viewer
   374             # Else draw drop after highlight in previous Viewer
   375             else:
   375             else:
   376                 self.SetHighlight(HIGHLIGHT_NONE)
   376                 self.SetHighlight(HIGHLIGHT_NONE)
   377                 self.ParentWindow.HighlightPreviousViewer(self)
   377                 self.ParentWindow.HighlightPreviousViewer(self)
   378         
   378 
   379         # Mouse is in the second half of Viewer, draw drop after highlight 
   379         # Mouse is in the second half of Viewer, draw drop after highlight
   380         else:
   380         else:
   381             self.SetHighlight(HIGHLIGHT_AFTER)
   381             self.SetHighlight(HIGHLIGHT_AFTER)
   382     
   382 
   383     def OnEraseBackground(self, event):
   383     def OnEraseBackground(self, event):
   384         """
   384         """
   385         Function called when Viewer background is going to be erase
   385         Function called when Viewer background is going to be erase
   386         @param event: wx.EraseEvent
   386         @param event: wx.EraseEvent
   387         """
   387         """
   388         # Prevent flicker on Windows
   388         # Prevent flicker on Windows
   389         pass
   389         pass
   390     
   390 
   391     def OnResize(self, event):
   391     def OnResize(self, event):
   392         """
   392         """
   393         Function called when Viewer size changed
   393         Function called when Viewer size changed
   394         @param event: wx.ResizeEvent
   394         @param event: wx.ResizeEvent
   395         """
   395         """
   396         # Refresh button positions
   396         # Refresh button positions
   397         self.RefreshButtonsPosition()
   397         self.RefreshButtonsPosition()
   398         self.ParentWindow.ForceRefresh()
   398         self.ParentWindow.ForceRefresh()
   399         event.Skip()
   399         event.Skip()
   400     
   400 
   401     def ForceValue(self, item):
   401     def ForceValue(self, item):
   402         """
   402         """
   403         Force value of item given
   403         Force value of item given
   404         @param item: Item to force value
   404         @param item: Item to force value
   405         """
   405         """
   407         iec_path = item.GetVariable()
   407         iec_path = item.GetVariable()
   408         iec_type = self.ParentWindow.GetDataType(iec_path)
   408         iec_type = self.ParentWindow.GetDataType(iec_path)
   409         # Return immediately if not found
   409         # Return immediately if not found
   410         if iec_type is None:
   410         if iec_type is None:
   411             return
   411             return
   412         
   412 
   413         # Open a dialog to enter varaible forced value
   413         # Open a dialog to enter varaible forced value
   414         dialog = ForceVariableDialog(self, iec_type, str(item.GetValue()))
   414         dialog = ForceVariableDialog(self, iec_type, str(item.GetValue()))
   415         if dialog.ShowModal() == wx.ID_OK:
   415         if dialog.ShowModal() == wx.ID_OK:
   416             self.ParentWindow.ForceDataValue(iec_path.upper(),
   416             self.ParentWindow.ForceDataValue(iec_path.upper(),
   417                                              dialog.GetValue())
   417                                              dialog.GetValue())
   418     
   418 
   419     def ReleaseValue(self, item):
   419     def ReleaseValue(self, item):
   420         """
   420         """
   421         Release value of item given
   421         Release value of item given
   422         @param item: Item to release value
   422         @param item: Item to release value
   423         """
   423         """