dialogs/BlockPreviewDialog.py
changeset 1730 64d8f52bc8c8
parent 1696 8043f32de7b8
child 1736 7e61baa047f0
equal deleted inserted replaced
1726:d51af006fa6b 1730:64d8f52bc8c8
    36 Class that implements a generic dialog containing a preview panel for displaying
    36 Class that implements a generic dialog containing a preview panel for displaying
    37 graphic created by dialog
    37 graphic created by dialog
    38 """
    38 """
    39 
    39 
    40 class BlockPreviewDialog(wx.Dialog):
    40 class BlockPreviewDialog(wx.Dialog):
    41     
    41 
    42     def __init__(self, parent, controller, tagname, title):
    42     def __init__(self, parent, controller, tagname, title):
    43         """
    43         """
    44         Constructor
    44         Constructor
    45         @param parent: Parent wx.Window of dialog for modal
    45         @param parent: Parent wx.Window of dialog for modal
    46         @param controller: Reference to project controller
    46         @param controller: Reference to project controller
    47         @param tagname: Tagname of project POU edited
    47         @param tagname: Tagname of project POU edited
    48         @param title: Title of dialog frame
    48         @param title: Title of dialog frame
    49         """
    49         """
    50         wx.Dialog.__init__(self, parent, title=title)
    50         wx.Dialog.__init__(self, parent, title=title)
    51         
    51 
    52         # Save reference to
    52         # Save reference to
    53         self.Controller = controller
    53         self.Controller = controller
    54         self.TagName = tagname
    54         self.TagName = tagname
    55         
    55 
    56         # Label for preview
    56         # Label for preview
    57         self.PreviewLabel = wx.StaticText(self, label=_('Preview:'))
    57         self.PreviewLabel = wx.StaticText(self, label=_('Preview:'))
    58         
    58 
    59         # Create Preview panel
    59         # Create Preview panel
    60         self.Preview = wx.Panel(self, style=wx.SIMPLE_BORDER)
    60         self.Preview = wx.Panel(self, style=wx.SIMPLE_BORDER)
    61         self.Preview.SetBackgroundColour(wx.WHITE)
    61         self.Preview.SetBackgroundColour(wx.WHITE)
    62         
    62 
    63         # Add function to preview panel so that it answers to graphic elements
    63         # Add function to preview panel so that it answers to graphic elements
    64         # like Viewer
    64         # like Viewer
    65         setattr(self.Preview, "GetDrawingMode", lambda:FREEDRAWING_MODE)
    65         setattr(self.Preview, "GetDrawingMode", lambda:FREEDRAWING_MODE)
    66         setattr(self.Preview, "GetScaling", lambda:None)
    66         setattr(self.Preview, "GetScaling", lambda:None)
    67         setattr(self.Preview, "GetBlockType", controller.GetBlockType)
    67         setattr(self.Preview, "GetBlockType", controller.GetBlockType)
    68         setattr(self.Preview, "IsOfType", controller.IsOfType)
    68         setattr(self.Preview, "IsOfType", controller.IsOfType)
    69         
    69 
    70         # Bind paint event on Preview panel
    70         # Bind paint event on Preview panel
    71         self.Preview.Bind(wx.EVT_PAINT, self.OnPaint)
    71         self.Preview.Bind(wx.EVT_PAINT, self.OnPaint)
    72         
    72 
    73         # Add default dialog buttons sizer
    73         # Add default dialog buttons sizer
    74         self.ButtonSizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE)
    74         self.ButtonSizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE)
    75         self.Bind(wx.EVT_BUTTON, self.OnOK, 
    75         self.Bind(wx.EVT_BUTTON, self.OnOK,
    76                   self.ButtonSizer.GetAffirmativeButton())
    76                   self.ButtonSizer.GetAffirmativeButton())
    77         
    77 
    78         self.Element = None            # Graphic element to display in preview
    78         self.Element = None            # Graphic element to display in preview
    79         self.MinElementSize = None     # Graphic element minimal size
    79         self.MinElementSize = None     # Graphic element minimal size
    80         
    80 
    81         # Variable containing the graphic element name when dialog is opened
    81         # Variable containing the graphic element name when dialog is opened
    82         self.DefaultElementName = None
    82         self.DefaultElementName = None
    83         self.Fit()
    83         self.Fit()
    84         
    84 
    85         # List of variables defined in POU {var_name: (var_class, var_type),...}
    85         # List of variables defined in POU {var_name: (var_class, var_type),...}
    86         self.VariableList = {}
    86         self.VariableList = {}
    87         
    87 
    88     def __del__(self):
    88     def __del__(self):
    89         """
    89         """
    90         Destructor
    90         Destructor
    91         """
    91         """
    92         # Remove reference to project controller
    92         # Remove reference to project controller
    93         self.Controller = None
    93         self.Controller = None
    94     
    94 
    95     def _init_sizers(self, main_rows, main_growable_row,
    95     def _init_sizers(self, main_rows, main_growable_row,
    96                             left_rows, left_growable_row,
    96                             left_rows, left_growable_row,
    97                             right_rows, right_growable_row):
    97                             right_rows, right_growable_row):
    98         """
    98         """
    99         Initialize common sizers
    99         Initialize common sizers
   106         @param right_rows: Number of rows in right grid sizer
   106         @param right_rows: Number of rows in right grid sizer
   107         @param right_growable_row: Row that is growable in right grid sizer,
   107         @param right_growable_row: Row that is growable in right grid sizer,
   108         None if no row is growable
   108         None if no row is growable
   109         """
   109         """
   110         # Create dialog main sizer
   110         # Create dialog main sizer
   111         self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, 
   111         self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0,
   112                                           rows=main_rows, vgap=10)
   112                                           rows=main_rows, vgap=10)
   113         self.MainSizer.AddGrowableCol(0)
   113         self.MainSizer.AddGrowableCol(0)
   114         if main_growable_row is not None:
   114         if main_growable_row is not None:
   115             self.MainSizer.AddGrowableRow(main_growable_row)
   115             self.MainSizer.AddGrowableRow(main_growable_row)
   116         
   116 
   117         # Create a sizer for dividing parameters in two columns
   117         # Create a sizer for dividing parameters in two columns
   118         self.ColumnSizer = wx.BoxSizer(wx.HORIZONTAL)
   118         self.ColumnSizer = wx.BoxSizer(wx.HORIZONTAL)
   119         self.MainSizer.AddSizer(self.ColumnSizer, border=20, 
   119         self.MainSizer.AddSizer(self.ColumnSizer, border=20,
   120               flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT)
   120               flag=wx.GROW|wx.TOP|wx.LEFT|wx.RIGHT)
   121         
   121 
   122         # Create a sizer for left column
   122         # Create a sizer for left column
   123         self.LeftGridSizer = wx.FlexGridSizer(cols=1, hgap=0, 
   123         self.LeftGridSizer = wx.FlexGridSizer(cols=1, hgap=0,
   124                                               rows=left_rows, vgap=5)
   124                                               rows=left_rows, vgap=5)
   125         self.LeftGridSizer.AddGrowableCol(0)
   125         self.LeftGridSizer.AddGrowableCol(0)
   126         if left_growable_row is not None:
   126         if left_growable_row is not None:
   127             self.LeftGridSizer.AddGrowableRow(left_growable_row)
   127             self.LeftGridSizer.AddGrowableRow(left_growable_row)
   128         self.ColumnSizer.AddSizer(self.LeftGridSizer, 1, border=5, 
   128         self.ColumnSizer.AddSizer(self.LeftGridSizer, 1, border=5,
   129               flag=wx.GROW|wx.RIGHT|wx.EXPAND)
   129               flag=wx.GROW|wx.RIGHT|wx.EXPAND)
   130         
   130 
   131         # Create a sizer for right column
   131         # Create a sizer for right column
   132         self.RightGridSizer = wx.FlexGridSizer(cols=1, hgap=0, 
   132         self.RightGridSizer = wx.FlexGridSizer(cols=1, hgap=0,
   133                                                rows=right_rows, vgap=0)
   133                                                rows=right_rows, vgap=0)
   134         self.RightGridSizer.AddGrowableCol(0)
   134         self.RightGridSizer.AddGrowableCol(0)
   135         if right_growable_row is not None:
   135         if right_growable_row is not None:
   136             self.RightGridSizer.AddGrowableRow(right_growable_row)
   136             self.RightGridSizer.AddGrowableRow(right_growable_row)
   137         self.ColumnSizer.AddSizer(self.RightGridSizer, 1, border=5, 
   137         self.ColumnSizer.AddSizer(self.RightGridSizer, 1, border=5,
   138               flag=wx.GROW|wx.LEFT)
   138               flag=wx.GROW|wx.LEFT)
   139         
   139 
   140         self.SetSizer(self.MainSizer)
   140         self.SetSizer(self.MainSizer)
   141     
   141 
   142     def SetMinElementSize(self, size):
   142     def SetMinElementSize(self, size):
   143         """
   143         """
   144         Define minimal graphic element size
   144         Define minimal graphic element size
   145         @param size: Tuple containing minimal size (width, height)
   145         @param size: Tuple containing minimal size (width, height)
   146         """
   146         """
   147         self.MinElementSize = size
   147         self.MinElementSize = size
   148     
   148 
   149     def GetMinElementSize(self):
   149     def GetMinElementSize(self):
   150         """
   150         """
   151         Get minimal graphic element size
   151         Get minimal graphic element size
   152         @return: Tuple containing minimal size (width, height) or None if no
   152         @return: Tuple containing minimal size (width, height) or None if no
   153         element defined
   153         element defined
   154         May be overridden by inherited classes
   154         May be overridden by inherited classes
   155         """
   155         """
   156         if self.Element is None:
   156         if self.Element is None:
   157             return None
   157             return None
   158         
   158 
   159         return self.Element.GetMinSize()
   159         return self.Element.GetMinSize()
   160     
   160 
   161     def SetPreviewFont(self, font):
   161     def SetPreviewFont(self, font):
   162         """
   162         """
   163         Set font of Preview panel
   163         Set font of Preview panel
   164         @param font: wx.Font object containing font style
   164         @param font: wx.Font object containing font style
   165         """
   165         """
   166         self.Preview.SetFont(font)
   166         self.Preview.SetFont(font)
   167     
   167 
   168     def RefreshVariableList(self):
   168     def RefreshVariableList(self):
   169         """
   169         """
   170         Extract list of variables defined in POU
   170         Extract list of variables defined in POU
   171         """
   171         """
   172         # Get list of variables defined in POU
   172         # Get list of variables defined in POU
   173         self.VariableList = {
   173         self.VariableList = {
   174             var.Name: (var.Class, var.Type)
   174             var.Name: (var.Class, var.Type)
   175             for var in self.Controller.GetEditedElementInterfaceVars(
   175             for var in self.Controller.GetEditedElementInterfaceVars(
   176                                                         self.TagName)
   176                                                         self.TagName)
   177             if var.Edit}
   177             if var.Edit}
   178         
   178 
   179         # Add POU name to variable list if POU is a function 
   179         # Add POU name to variable list if POU is a function
   180         returntype = self.Controller.GetEditedElementInterfaceReturnType(
   180         returntype = self.Controller.GetEditedElementInterfaceReturnType(
   181                                                             self.TagName)
   181                                                             self.TagName)
   182         if returntype is not None:
   182         if returntype is not None:
   183             self.VariableList[
   183             self.VariableList[
   184                 self.Controller.GetEditedElementName(self.TagName)] = \
   184                 self.Controller.GetEditedElementName(self.TagName)] = \
   185                  ("Output", returntype)
   185                  ("Output", returntype)
   186         
   186 
   187         # Add POU name if POU is a transition
   187         # Add POU name if POU is a transition
   188         words = self.TagName.split("::")
   188         words = self.TagName.split("::")
   189         if words[0] == "T":
   189         if words[0] == "T":
   190             self.VariableList[words[2]] = ("Output", "BOOL")
   190             self.VariableList[words[2]] = ("Output", "BOOL")
   191     
   191 
   192     def TestElementName(self, element_name):
   192     def TestElementName(self, element_name):
   193         """
   193         """
   194         Test displayed graphic element name
   194         Test displayed graphic element name
   195         @param element_name: Graphic element name
   195         @param element_name: Graphic element name
   196         """
   196         """
   197         # Variable containing error message format
   197         # Variable containing error message format
   198         message_format = None
   198         message_format = None
   199         # Get graphic element name in upper case
   199         # Get graphic element name in upper case
   200         uppercase_element_name = element_name.upper()
   200         uppercase_element_name = element_name.upper()
   201         
   201 
   202         # Test if graphic element name is a valid identifier
   202         # Test if graphic element name is a valid identifier
   203         if not TestIdentifier(element_name):
   203         if not TestIdentifier(element_name):
   204             message_format = _("\"%s\" is not a valid identifier!")
   204             message_format = _("\"%s\" is not a valid identifier!")
   205         
   205 
   206         # Test that graphic element name isn't a keyword
   206         # Test that graphic element name isn't a keyword
   207         elif uppercase_element_name in IEC_KEYWORDS:
   207         elif uppercase_element_name in IEC_KEYWORDS:
   208             message_format = _("\"%s\" is a keyword. It can't be used!")
   208             message_format = _("\"%s\" is a keyword. It can't be used!")
   209         
   209 
   210         # Test that graphic element name isn't a POU name
   210         # Test that graphic element name isn't a POU name
   211         elif uppercase_element_name in self.Controller.GetProjectPouNames():
   211         elif uppercase_element_name in self.Controller.GetProjectPouNames():
   212             message_format = _("\"%s\" pou already exists!")
   212             message_format = _("\"%s\" pou already exists!")
   213         
   213 
   214         # Test that graphic element name isn't already used in POU by a variable
   214         # Test that graphic element name isn't already used in POU by a variable
   215         # or another graphic element
   215         # or another graphic element
   216         elif ((self.DefaultElementName is None or 
   216         elif ((self.DefaultElementName is None or
   217                self.DefaultElementName.upper() != uppercase_element_name) and 
   217                self.DefaultElementName.upper() != uppercase_element_name) and
   218               uppercase_element_name in self.Controller.\
   218               uppercase_element_name in self.Controller.\
   219                     GetEditedElementVariables(self.TagName)):
   219                     GetEditedElementVariables(self.TagName)):
   220             message_format = _("\"%s\" element for this pou already exists!")
   220             message_format = _("\"%s\" element for this pou already exists!")
   221         
   221 
   222         # If an error have been identify, show error message dialog
   222         # If an error have been identify, show error message dialog
   223         if message_format is not None:
   223         if message_format is not None:
   224             self.ShowErrorMessage(message_format % element_name)
   224             self.ShowErrorMessage(message_format % element_name)
   225             # Test failed
   225             # Test failed
   226             return False
   226             return False
   227         
   227 
   228         # Test succeed
   228         # Test succeed
   229         return True
   229         return True
   230     
   230 
   231     def ShowErrorMessage(self, message):
   231     def ShowErrorMessage(self, message):
   232         """
   232         """
   233         Show an error message dialog over this dialog
   233         Show an error message dialog over this dialog
   234         @param message: Error message to display
   234         @param message: Error message to display
   235         """
   235         """
   236         dialog = wx.MessageDialog(self, message, 
   236         dialog = wx.MessageDialog(self, message,
   237                                   _("Error"), 
   237                                   _("Error"),
   238                                   wx.OK|wx.ICON_ERROR)
   238                                   wx.OK|wx.ICON_ERROR)
   239         dialog.ShowModal()
   239         dialog.ShowModal()
   240         dialog.Destroy()
   240         dialog.Destroy()
   241     
   241 
   242     def OnOK(self, event):
   242     def OnOK(self, event):
   243         """
   243         """
   244         Called when dialog OK button is pressed
   244         Called when dialog OK button is pressed
   245         Need to be overridden by inherited classes to check that dialog values
   245         Need to be overridden by inherited classes to check that dialog values
   246         are valid
   246         are valid
   247         @param event: wx.Event from OK button
   247         @param event: wx.Event from OK button
   248         """
   248         """
   249         # Close dialog
   249         # Close dialog
   250         self.EndModal(wx.ID_OK)
   250         self.EndModal(wx.ID_OK)
   251     
   251 
   252     def RefreshPreview(self):
   252     def RefreshPreview(self):
   253         """
   253         """
   254         Refresh preview panel of graphic element
   254         Refresh preview panel of graphic element
   255         May be overridden by inherited classes
   255         May be overridden by inherited classes
   256         """
   256         """
   257         # Init preview panel paint device context
   257         # Init preview panel paint device context
   258         dc = wx.ClientDC(self.Preview)
   258         dc = wx.ClientDC(self.Preview)
   259         dc.SetFont(self.Preview.GetFont())
   259         dc.SetFont(self.Preview.GetFont())
   260         dc.Clear()
   260         dc.Clear()
   261         
   261 
   262         # Return immediately if no graphic element defined
   262         # Return immediately if no graphic element defined
   263         if self.Element is None:
   263         if self.Element is None:
   264             return
   264             return
   265         
   265 
   266         # Calculate block size according to graphic element min size due to its
   266         # Calculate block size according to graphic element min size due to its
   267         # parameters and graphic element min size defined
   267         # parameters and graphic element min size defined
   268         min_width, min_height = self.GetMinElementSize()
   268         min_width, min_height = self.GetMinElementSize()
   269         width = max(self.MinElementSize[0], min_width)
   269         width = max(self.MinElementSize[0], min_width)
   270         height = max(self.MinElementSize[1], min_height)
   270         height = max(self.MinElementSize[1], min_height)
   271         self.Element.SetSize(width, height)
   271         self.Element.SetSize(width, height)
   272         
   272 
   273         # Get element position and bounding box to center in preview
   273         # Get element position and bounding box to center in preview
   274         posx, posy = self.Element.GetPosition()
   274         posx, posy = self.Element.GetPosition()
   275         bbox = self.Element.GetBoundingBox()
   275         bbox = self.Element.GetBoundingBox()
   276         
   276 
   277         # Get Preview panel size
   277         # Get Preview panel size
   278         client_size = self.Preview.GetClientSize()
   278         client_size = self.Preview.GetClientSize()
   279         
   279 
   280         # If graphic element is too big to be displayed in preview panel,
   280         # If graphic element is too big to be displayed in preview panel,
   281         # calculate preview panel scale so that graphic element fit inside
   281         # calculate preview panel scale so that graphic element fit inside
   282         scale = (max(float(bbox.width) / client_size.width, 
   282         scale = (max(float(bbox.width) / client_size.width,
   283                      float(bbox.height) / client_size.height) * 1.1
   283                      float(bbox.height) / client_size.height) * 1.1
   284                  if bbox.width * 1.1 > client_size.width or 
   284                  if bbox.width * 1.1 > client_size.width or
   285                     bbox.height * 1.1 > client_size.height
   285                     bbox.height * 1.1 > client_size.height
   286                  else 1.0)
   286                  else 1.0)
   287         dc.SetUserScale(1.0 / scale, 1.0 / scale)
   287         dc.SetUserScale(1.0 / scale, 1.0 / scale)
   288         
   288 
   289         # Center graphic element in preview panel
   289         # Center graphic element in preview panel
   290         x = int(client_size.width * scale - bbox.width) / 2 + posx - bbox.x
   290         x = int(client_size.width * scale - bbox.width) / 2 + posx - bbox.x
   291         y = int(client_size.height * scale - bbox.height) / 2 + posy - bbox.y
   291         y = int(client_size.height * scale - bbox.height) / 2 + posy - bbox.y
   292         self.Element.SetPosition(x, y)
   292         self.Element.SetPosition(x, y)
   293         
   293 
   294         # Draw graphic element
   294         # Draw graphic element
   295         self.Element.Draw(dc)
   295         self.Element.Draw(dc)
   296     
   296 
   297     def OnPaint(self, event):
   297     def OnPaint(self, event):
   298         """
   298         """
   299         Called when Preview panel need to be redraw
   299         Called when Preview panel need to be redraw
   300         @param event: wx.PaintEvent
   300         @param event: wx.PaintEvent
   301         """
   301         """
   302         self.RefreshPreview()
   302         self.RefreshPreview()
   303         event.Skip()
   303         event.Skip()
   304