Bug with AUINotebook double click
authorlbessard
Thu, 09 Apr 2009 15:34:35 +0200
changeset 341 88030497e29e
parent 340 5a305b7c6735
child 342 25e093542b40
Bug with AUINotebook double click
PLCOpenEditor.py
--- a/PLCOpenEditor.py	Thu Apr 09 15:31:56 2009 +0200
+++ b/PLCOpenEditor.py	Thu Apr 09 15:34:35 2009 +0200
@@ -447,10 +447,22 @@
                         self.OnPouSelectedChanged)
                 self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CLOSE,
                         self.OnPageClose)
+                self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_END_DRAG,
+                        self.OnPageDragged)
                 self.AUIManager.AddPane(self.TabsOpened, wx.aui.AuiPaneInfo().CentrePane())
+                
+                self.DebugVariablePanel = DebugVariablePanel(self, self.Controler)
+                self.AUIManager.AddPane(self.DebugVariablePanel, wx.aui.AuiPaneInfo().Caption("Variables").Right().Layer(0).BestSize(wx.Size(250, 600)).CloseButton(False))
             else:
+                self.SecondSplitter = wx.SplitterWindow(id=ID_PLCOPENEDITORSECONDSPLITTER,
+                      name='SecondSplitter', parent=self.MainSplitter, point=wx.Point(0, 0),
+                      size=wx.Size(0, 0), style=wx.SP_3D)
+                self.SecondSplitter.SetMinimumPaneSize(1)
+                
+                self.MainSplitter.SplitVertically(self.TreeNoteBook, self.SecondSplitter, 200)
+                
                 self.TabsOpened = wx.Notebook(id=ID_PLCOPENEDITORTABSOPENED,
-                      name='TabsOpened', parent=self.MainSplitter, pos=wx.Point(0,
+                      name='TabsOpened', parent=self.SecondSplitter, pos=wx.Point(0,
                       0), size=wx.Size(0, 0), style=0)
                 if wx.VERSION >= (2, 6, 0):
                     self.TabsOpened.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED,
@@ -458,8 +470,10 @@
                 else:
                     wx.EVT_NOTEBOOK_PAGE_CHANGED(self.TabsOpened, ID_PLCOPENEDITORTABSOPENED,
                         self.OnPouSelectedChanged)
-            
-                self.MainSplitter.SplitVertically(self.TreeNoteBook, self.TabsOpened, 200)
+                
+                self.DebugVariablePanel = DebugVariablePanel(self.SecondSplitter, self.Controler)
+                
+                self.SecondSplitter.SplitVertically(self.TabsOpened, self.DebugVariablePanel, -250)
         else:
             self.TreeNoteBook.AddPage(self.TypesTree, "Types")
             self.TreeNoteBook.AddPage(self.InstancesTree, "Instances")
@@ -496,6 +510,8 @@
                         self.OnPouSelectedChanged)
                 self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_PAGE_CLOSE,
                         self.OnPageClose)
+                self.TabsOpened.Bind(wx.aui.EVT_AUINOTEBOOK_END_DRAG,
+                        self.OnPageDragged)
                 self.AUIManager.AddPane(self.TabsOpened, wx.aui.AuiPaneInfo().CentrePane().MinSize(wx.Size(0, 0)))
             
                 self.LibraryPanel = wx.Panel(id=ID_PLCOPENEDITORLIBRARYPANEL,
@@ -621,6 +637,8 @@
         self.Errors = []
         self.DrawingMode = FREEDRAWING_MODE
         #self.DrawingMode = DRIVENDRAWING_MODE
+        if USE_AUI:
+            self.AuiTabCtrl = []
         
         self.PrintData = wx.PrintData()
         self.PrintData.SetPaperId(wx.PAPER_A4)
@@ -660,6 +678,11 @@
             self.RefreshEditMenu()
             self.RefreshDisplayMenu()
             self.RefreshToolBar()
+        wx.CallAfter(self.RefreshTabCtrlEvent)
+        event.Skip()
+
+    def OnPageDragged(self, event):
+        wx.CallAfter(self.RefreshTabCtrlEvent)
         event.Skip()
 
     def GetCopyBuffer(self):
@@ -755,11 +778,22 @@
     
     def AddPage(self, window, text):
         self.TabsOpened.AddPage(window, text)
+        self.RefreshTabCtrlEvent()
+    
+    def RefreshTabCtrlEvent(self):
         if USE_AUI:
-            children = self.TabsOpened.GetChildren()
-            last_element = children[len(children) - 1]
-            if isinstance(last_element, wx.aui.AuiTabCtrl):
-                last_element.Bind(wx.EVT_LEFT_DCLICK, self.GetTabsOpenedDClickFunction(last_element))
+            auitabctrl = []
+            for child in self.TabsOpened.GetChildren():
+                if isinstance(child, wx.aui.AuiTabCtrl):
+                    auitabctrl.append(child)
+                    if child not in self.AuiTabCtrl:
+                        child.Bind(wx.EVT_LEFT_DCLICK, self.GetTabsOpenedDClickFunction(child))
+            self.AuiTabCtrl = auitabctrl
+            if self.TabsOpened.GetPageCount() == 0:
+                pane = self.AUIManager.GetPane(self.TabsOpened)
+                if pane.IsMaximized():
+                    self.AUIManager.RestorePane(pane)
+                self.AUIManager.Update()
     
     def DeleteAllPages(self):
         if USE_AUI:
@@ -1121,10 +1155,13 @@
         event.Skip()
     
     def OnSelectAllMenu(self, event):
-        selected = self.TabsOpened.GetSelection()        
-        if selected != -1:
-            window = self.TabsOpened.GetPage(selected)
-            window.SelectAll()
+        control = self.FindFocus()
+        if isinstance(control, (Viewer, TextViewer)):
+            control.SelectAll()
+        elif isinstance(control, wx.TextCtrl):
+            control.SetSelection(0, control.GetLastPosition())
+        elif isinstance(control, wx.ComboBox):
+            control.SetMark(0, control.GetLastPosition() + 1)
         event.Skip()
     
     def OnDeleteMenu(self, event):
@@ -1938,11 +1975,14 @@
                     var_path = "%s.%s"%(parent_name, var_path)
                     parent_item = self.InstancesTree.GetItemParent(parent_item)
                 
-                new_window = GraphicViewer(self.TabsOpened, self, self.Controler, var_path)
-                self.AddPage(new_window, "")
-                new_window.SetFocus()
-                self.RefreshPageTitles()
-        event.Skip()
+                self.OpenGraphicViewer(var_path)
+        event.Skip()
+
+    def OpenGraphicViewer(self, var_path):
+        new_window = GraphicViewer(self.TabsOpened, self, self.Controler, var_path)
+        self.AddPage(new_window, "")
+        new_window.SetFocus()
+        self.RefreshPageTitles()
 
     def OnInstancesTreeRightUp(self, event):
         if wx.Platform == '__WXMSW__':
@@ -1973,10 +2013,7 @@
 
     def AddVariableGraphicFunction(self, iec_path):
         def AddVariableGraphic(event):
-            new_window = GraphicViewer(self.TabsOpened, self, self.Controler, iec_path)
-            self.AddPage(new_window, "")
-            new_window.SetFocus()
-            self.RefreshPageTitles()
+            self.OpenGraphicViewer(iec_path)
             event.Skip()
         return AddVariableGraphic
 
@@ -4078,23 +4115,25 @@
 
         self.VariablesGrid = wx.grid.Grid(id=ID_VARIABLEEDITORPANELVARIABLESGRID,
               name='VariablesGrid', parent=self, pos=wx.Point(0, 0), 
-              size=wx.Size(0, 150), style=wx.VSCROLL)
+              size=wx.Size(0, 0), style=wx.VSCROLL)
         self.VariablesGrid.SetFont(wx.Font(12, 77, wx.NORMAL, wx.NORMAL, False,
               'Sans'))
         self.VariablesGrid.SetLabelFont(wx.Font(10, 77, wx.NORMAL, wx.NORMAL,
               False, 'Sans'))
         self.VariablesGrid.SetSelectionBackground(wx.WHITE)
-        self.VariablesGrid.SetSelectionForeground(wx.BLACK)
+        self.VariablesGrid.SetSelectionBackground(wx.BLACK)
         if wx.VERSION >= (2, 6, 0):
             self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnVariablesGridCellChange)
             self.VariablesGrid.Bind(wx.grid.EVT_GRID_SELECT_CELL, self.OnVariablesGridSelectCell)
             self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.OnVariablesGridCellLeftClick)
             self.VariablesGrid.Bind(wx.grid.EVT_GRID_EDITOR_SHOWN, self.OnVariablesGridEditorShown)
+            #self.VariablesGrid.Bind(wx.EVT_KEY_DOWN, self.OnChar)
         else:
             wx.grid.EVT_GRID_CELL_CHANGE(self.VariablesGrid, self.OnVariablesGridCellChange)
             wx.grid.EVT_GRID_SELECT_CELL(self.VariablesGrid, self.OnVariablesGridSelectCell)
             wx.grid.EVT_GRID_CELL_LEFT_CLICK(self.VariablesGrid, self.OnVariablesGridCellLeftClick)
             wx.grid.EVT_GRID_EDITOR_SHOWN(self.VariablesGrid, self.OnVariablesGridEditorShown)
+            #wx.EVT_KEY_DOWN(self.VariablesGrid, self.OnChar)
         self.VariablesGrid.SetDropTarget(VariableDropTarget(self))
         
         self.ControlPanel = wx.ScrolledWindow(id=ID_VARIABLEEDITORCONTROLPANEL,
@@ -4420,6 +4459,16 @@
         wx.CallAfter(self.RefreshButtons)
         event.Skip()
 
+    def OnChar(self, event):
+        keycode = event.GetKeyCode()
+        if keycode == wx.WXK_DELETE:
+            row = self.Table.GetRow(self.VariablesGrid.GetGridCursorRow())
+            self.Values.remove(row)
+            self.SaveValues()
+            self.RefreshValues()
+            self.RefreshButtons()
+        event.Skip()
+
     def MoveValue(self, value_index, move):
         new_index = max(0, min(value_index + move, len(self.Values) - 1))
         if new_index != value_index:
@@ -4473,6 +4522,320 @@
         self.Table.ClearErrors()
         self.Table.ResetView(self.VariablesGrid)
 
+#-------------------------------------------------------------------------------
+#                            Variables Editor Panel
+#-------------------------------------------------------------------------------
+
+class VariableTableItem:
+    
+    def __init__(self, parent, variable, value):
+        self.Parent = parent
+        self.Variable = variable
+        self.Value = value
+    
+    def __del__(self):
+        self.Parent = None
+    
+    def SetVariable(self, variable):
+        if self.Parent and self.Variable != variable:
+            self.Variable = variable
+            self.Parent.RefreshGrid()
+    
+    def GetVariable(self):
+        return self.Variable
+    
+    def SetValue(self, value):
+        if self.Parent and self.Value != value:
+            self.Value = value
+            self.Parent.RefreshGrid()
+    
+    def GetValue(self):
+        return self.Value    
+
+class DebugVariableTable(wx.grid.PyGridTableBase):
+    
+    """
+    A custom wx.grid.Grid Table using user supplied data
+    """
+    def __init__(self, parent, data, colnames):
+        # The base class must be initialized *first*
+        wx.grid.PyGridTableBase.__init__(self)
+        self.data = data
+        self.colnames = colnames
+        self.Parent = parent
+        # XXX
+        # we need to store the row length and collength to
+        # see if the table has changed size
+        self._rows = self.GetNumberRows()
+        self._cols = self.GetNumberCols()
+    
+    def GetNumberCols(self):
+        return len(self.colnames)
+        
+    def GetNumberRows(self):
+        return len(self.data)
+
+    def GetColLabelValue(self, col):
+        if col < len(self.colnames):
+            return self.colnames[col]
+
+    def GetRowLabelValues(self, row):
+        return row
+
+    def GetValue(self, row, col):
+        if row < self.GetNumberRows():
+            return self.GetValueByName(row, self.GetColLabelValue(col))
+        return ""
+    
+    def SetValue(self, row, col, value):
+        if col < len(self.colnames):
+            self.SetValueByName(row, self.GetColLabelValue(col), value)
+            
+    def GetValueByName(self, row, colname):
+        if row < self.GetNumberRows():
+            if colname == "Variable":
+                return self.data[row].GetVariable()
+            elif colname == "Value":
+                return self.data[row].GetValue()
+        return ""
+
+    def SetValueByName(self, row, colname, value):
+        if row < self.GetNumberRows():
+            if colname == "Variable":
+                self.data[row].SetVariable(value)
+            elif colname == "Value":
+                self.data[row].SetValue(value)
+    
+    def ResetView(self, grid):
+        """
+        (wx.grid.Grid) -> Reset the grid view.   Call this to
+        update the grid if rows and columns have been added or deleted
+        """
+        grid.BeginBatch()
+        for current, new, delmsg, addmsg in [
+            (self._rows, self.GetNumberRows(), wx.grid.GRIDTABLE_NOTIFY_ROWS_DELETED, wx.grid.GRIDTABLE_NOTIFY_ROWS_APPENDED),
+            (self._cols, self.GetNumberCols(), wx.grid.GRIDTABLE_NOTIFY_COLS_DELETED, wx.grid.GRIDTABLE_NOTIFY_COLS_APPENDED),
+        ]:
+            if new < current:
+                msg = wx.grid.GridTableMessage(self,delmsg,new,current-new)
+                grid.ProcessTableMessage(msg)
+            elif new > current:
+                msg = wx.grid.GridTableMessage(self,addmsg,new-current)
+                grid.ProcessTableMessage(msg)
+                self.UpdateValues(grid)
+        grid.EndBatch()
+
+        self._rows = self.GetNumberRows()
+        self._cols = self.GetNumberCols()
+        # update the column rendering scheme
+        self._updateColAttrs(grid)
+
+        # update the scrollbars and the displayed part of the grid
+        grid.AdjustScrollbars()
+        grid.ForceRefresh()
+
+    def UpdateValues(self, grid):
+        """Update all displayed values"""
+        # This sends an event to the grid table to update all of the values
+        msg = wx.grid.GridTableMessage(self, wx.grid.GRIDTABLE_REQUEST_VIEW_GET_VALUES)
+        grid.ProcessTableMessage(msg)
+
+    def _updateColAttrs(self, grid):
+        """
+        wx.grid.Grid -> update the column attributes to add the
+        appropriate renderer given the column name.
+
+        Otherwise default to the default renderer.
+        """
+        
+        for row in range(self.GetNumberRows()):
+            for col in range(self.GetNumberCols()):
+                grid.SetReadOnly(row, col, True)
+                
+    def SetData(self, data):
+        self.data = data
+    
+    def GetData(self):
+        return self.data
+    
+    def AppendItem(self, data):
+        self.data.append(data)
+    
+    def InsertItem(self, idx, data):
+        self.data.insert(idx, data)
+    
+    def RemoveItem(self, idx):
+        self.data.pop(idx)
+    
+    def MoveItem(self, idx, new_idx):
+        self.data.insert(new_idx, self.data.pop(idx))
+        
+    def GetItem(self, idx):
+        return self.data[idx]
+
+    def Empty(self):
+        self.data = []
+    
+class DebugVariableDropTarget(wx.TextDropTarget):
+    
+    def __init__(self, parent):
+        wx.TextDropTarget.__init__(self)
+        self.ParentWindow = parent
+    
+    def OnDropText(self, x, y, data):
+        x, y = self.ParentWindow.VariablesGrid.CalcUnscrolledPosition(x, y)
+        row = self.ParentWindow.VariablesGrid.YToRow(y - self.ParentWindow.VariablesGrid.GetColLabelSize())
+        if row == wx.NOT_FOUND:
+            row = self.ParentWindow.Table.GetNumberRows()
+        message = None
+        try:
+            values = eval(data)
+        except:
+            message = "Invalid value \"%s\" for debug variable"%data
+            values = None
+        if not isinstance(values, TupleType):
+            message = "Invalid value \"%s\" for debug variable"%data
+            values = None
+        if values is not None and values[1] == "debug":
+            self.ParentWindow.InsertValue(row, values[0])
+        if message is not None:
+            wx.CallAfter(self.ShowMessage, message)
+            
+    def ShowMessage(self, message):
+        message = wx.MessageDialog(self.ParentWindow, message, "Error", wx.OK|wx.ICON_ERROR)
+        message.ShowModal()
+        message.Destroy()
+
+[ID_DEBUGVARIABLEPANEL, ID_DEBUGVARIABLEPANELVARIABLESGRID, 
+ ID_DEBUGVARIABLEPANELUPBUTTON, ID_DEBUGVARIABLEPANELDOWNBUTTON, 
+ ID_DEBUGVARIABLEPANELDELETEBUTTON, 
+] = [wx.NewId() for _init_ctrls in range(5)]
+
+class DebugVariablePanel(wx.Panel):
+    
+    if wx.VERSION < (2, 6, 0):
+        def Bind(self, event, function, id = None):
+            if id is not None:
+                event(self, id, function)
+            else:
+                event(self, function)
+    
+    def _init_coll_MainSizer_Items(self, parent):
+        parent.AddSizer(self.ButtonPanelSizer, 0, border=5, flag=wx.ALIGN_RIGHT|wx.ALL)
+        parent.AddWindow(self.VariablesGrid, 0, border=0, flag=wx.GROW)
+    
+    def _init_coll_MainSizer_Growables(self, parent):
+        parent.AddGrowableCol(0)
+        parent.AddGrowableRow(1)
+    
+    def _init_coll_ButtonPanelSizer_Items(self, parent):
+        parent.AddWindow(self.UpButton, 0, border=5, flag=wx.RIGHT)
+        parent.AddWindow(self.DownButton, 0, border=5, flag=wx.RIGHT)
+        parent.AddWindow(self.DeleteButton, 0, border=0, flag=0)
+        
+    def _init_sizers(self):
+        self.MainSizer = wx.FlexGridSizer(cols=1, hgap=10, rows=2, vgap=0)
+        self.ButtonPanelSizer = wx.BoxSizer(wx.HORIZONTAL)
+        
+        self._init_coll_MainSizer_Items(self.MainSizer)
+        self._init_coll_MainSizer_Growables(self.MainSizer)
+        self._init_coll_ButtonPanelSizer_Items(self.ButtonPanelSizer)
+        
+        self.SetSizer(self.MainSizer)
+        
+    def _init_ctrls(self, prnt):
+        wx.Panel.__init__(self, id=ID_DEBUGVARIABLEPANEL,
+              name='DebugVariablePanel', parent=prnt, pos=wx.Point(0, 0),
+              size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
+
+        self.VariablesGrid = wx.grid.Grid(id=ID_DEBUGVARIABLEPANELVARIABLESGRID,
+              name='VariablesGrid', parent=self, pos=wx.Point(0, 0), 
+              size=wx.Size(0, 150), style=wx.VSCROLL)
+        self.VariablesGrid.SetFont(wx.Font(12, 77, wx.NORMAL, wx.NORMAL, False,
+              'Sans'))
+        self.VariablesGrid.SetLabelFont(wx.Font(10, 77, wx.NORMAL, wx.NORMAL,
+              False, 'Sans'))
+        self.VariablesGrid.SetSelectionBackground(wx.WHITE)
+        self.VariablesGrid.SetSelectionForeground(wx.BLACK)
+        self.VariablesGrid.SetDropTarget(DebugVariableDropTarget(self))
+        
+        self.UpButton = wx.Button(id=ID_DEBUGVARIABLEPANELUPBUTTON, label='^',
+              name='UpButton', parent=self, pos=wx.Point(0, 0),
+              size=wx.Size(32, 32), style=0)
+        self.Bind(wx.EVT_BUTTON, self.OnUpButton, id=ID_DEBUGVARIABLEPANELUPBUTTON)
+        
+        self.DownButton = wx.Button(id=ID_DEBUGVARIABLEPANELDOWNBUTTON, label='v',
+              name='DownButton', parent=self, pos=wx.Point(0, 0),
+              size=wx.Size(32, 32), style=0)
+        self.Bind(wx.EVT_BUTTON, self.OnDownButton, id=ID_DEBUGVARIABLEPANELDOWNBUTTON)
+        
+        self.DeleteButton = wx.Button(id=ID_DEBUGVARIABLEPANELDELETEBUTTON, label='Delete',
+              name='DeleteButton', parent=self, pos=wx.Point(0, 0),
+              size=wx.Size(72, 32), style=0)
+        self.Bind(wx.EVT_BUTTON, self.OnDeleteButton, id=ID_DEBUGVARIABLEPANELDELETEBUTTON)
+        
+        self._init_sizers()
+    
+    def __init__(self, parent, controler):
+        self._init_ctrls(parent)
+        self.Controler = controler
+        
+        self.Table = DebugVariableTable(self, [], ["Variable", "Value"])    
+        self.VariablesGrid.SetTable(self.Table)
+        self.VariablesGrid.SetRowLabelSize(0)
+        
+        for col in range(self.Table.GetNumberCols()):
+            attr = wx.grid.GridCellAttr()
+            attr.SetAlignment(wx.ALIGN_RIGHT, wx.ALIGN_CENTER)
+            self.VariablesGrid.SetColAttr(col, attr)
+            self.VariablesGrid.SetColSize(col, 100)
+    
+        self.Table.ResetView(self.VariablesGrid)
+    
+    def __del__(self):
+        for item in self.Table.GetData():
+            self.Controler.UnsubscribeDebugIECVariable(item.GetVariable().upper(), item)
+    
+    def RefreshGrid(self):
+        self.Table.ResetView(self.VariablesGrid)
+    
+    def OnDeleteButton(self, event):
+        idx = self.VariablesGrid.GetGridCursorRow()
+        item = self.Table.GetItem(idx)
+        self.Controler.UnsubscribeDebugIECVariable(item.GetVariable().upper(), item)
+        self.Table.RemoveItem(idx)
+        self.RefreshGrid()
+        event.Skip()
+
+    def OnUpButton(self, event):
+        self.MoveValue(self.VariablesGrid.GetGridCursorRow(), -1)
+        event.Skip()
+
+    def OnDownButton(self, event):
+        self.MoveValue(self.VariablesGrid.GetGridCursorRow(), 1)
+        event.Skip()
+
+    def InsertValue(self, idx, iec_path):
+        for item in self.Table.GetData():
+            if iec_path == item.GetVariable():
+                return
+        item = VariableTableItem(self, iec_path, "")
+        result = self.Controler.SubscribeDebugIECVariable(iec_path.upper(), item)
+        if result is not None:
+            self.Table.InsertItem(idx, item)
+            self.RefreshGrid()
+
+    def MoveValue(self, idx, move):
+        new_idx = max(0, min(idx + move, self.Table.GetNumberRows() - 1))
+        if new_idx != idx:
+            self.Table.MoveItem(idx, new_idx)
+            self.RefreshGrid()
+            self.VariablesGrid.SetGridCursor(new_idx, self.VariablesGrid.GetGridCursorCol())
+    
+#-------------------------------------------------------------------------------
+#                               Viewer Printout
+#-------------------------------------------------------------------------------
+
 UPPER_DIV = lambda x, y: (x / y) + {True : 0, False : 1}[(x % y) == 0]
 
 class GraphicPrintout(wx.Printout):