Merged search in CTN branch
authorEdouard Tisserant
Fri, 22 Mar 2019 11:10:37 +0100
changeset 2530 02d09fc6eb90
parent 2521 48ebcbe7f19b (current diff)
parent 2529 efb532295607 (diff)
child 2550 f2af2a655868
Merged search in CTN branch
--- a/BeremizIDE.py	Mon Mar 11 13:51:07 2019 +0100
+++ b/BeremizIDE.py	Fri Mar 22 11:10:37 2019 +0100
@@ -1033,6 +1033,14 @@
             else:
                 IDEFrame.ProjectTreeItemSelect(self, select_item)
 
+    def GetProjectElementWindow(self, element, tagname):
+        is_a_CTN_tagname = len(tagname.split("::"))==1
+        if is_a_CTN_tagname:
+            confnode = self.CTR.GetChildByName(tagname)
+            return confnode.GetView() 
+        else :
+            return IDEFrame.GetProjectElementWindow(self, element, tagname)
+
     def SelectProjectTreeItem(self, tagname):
         if self.ProjectTree is not None:
             root = self.ProjectTree.GetRootItem()
--- a/CodeFileTreeNode.py	Mon Mar 11 13:51:07 2019 +0100
+++ b/CodeFileTreeNode.py	Fri Mar 22 11:10:37 2019 +0100
@@ -36,6 +36,9 @@
 from PLCControler import UndoBuffer
 from ConfigTreeNode import XSDSchemaErrorMessage
 
+from plcopen.plcopen import TestTextElement
+from editors.CodeFileEditor import GetSectionsText
+
 CODEFILE_XSD = """<?xml version="1.0" encoding="ISO-8859-1" ?>
 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
             xmlns:xhtml="http://www.w3.org/1999/xhtml">
@@ -209,6 +212,19 @@
                     if variable.getonchange()])
         return ret
 
+    def CTNSearch(self, criteria):
+        variables = self.GetVariables()
+        results = []
+        tagname = self.CTNFullName()
+        for index, var in enumerate(variables):
+            varname = var["Name"]
+            results.extend([((tagname, "var_inout", index, "name"),) + result
+                            for result in TestTextElement(varname, criteria)])
+        results.extend([((tagname, "body"),) + result
+                        for result in TestTextElement(
+                            GetSectionsText(self, lambda x:""), criteria)])
+        return results
+
 # -------------------------------------------------------------------------------
 #                      Current Buffering Management Functions
 # -------------------------------------------------------------------------------
--- a/ConfigTreeNode.py	Mon Mar 11 13:51:07 2019 +0100
+++ b/ConfigTreeNode.py	Fri Mar 22 11:10:37 2019 +0100
@@ -36,6 +36,7 @@
 import traceback
 import types
 import shutil
+from operator import add
 from builtins import str as text
 from past.builtins import execfile
 
@@ -121,6 +122,12 @@
             return parent + "." + self.CTNName()
         return self.BaseParams.getName()
 
+    def CTNSearch(self, criteria):
+        # TODO match config's fields name and fields contents
+        return reduce(add, [
+            CTNChild.CTNSearch(criteria)
+            for CTNChild in self.IterChildren()])
+
     def GetIconName(self):
         return None
 
@@ -464,20 +471,23 @@
     def GetContextualMenuItems(self):
         return None
 
+    def GetView(self):
+        if self._View is None and self.EditorType is not None:
+            app_frame = self.GetCTRoot().AppFrame
+            self._View = self.EditorType(app_frame.TabsOpened, self, app_frame)
+
+        return self._View
+
     def _OpenView(self, name=None, onlyopened=False):
-        if self.EditorType is not None:
+        view = self.GetView()
+
+        if view is not None:
+            if name is None:
+                name = self.CTNFullName()
             app_frame = self.GetCTRoot().AppFrame
-            if self._View is None and not onlyopened:
-
-                self._View = self.EditorType(app_frame.TabsOpened, self, app_frame)
-
-            if self._View is not None:
-                if name is None:
-                    name = self.CTNFullName()
-                app_frame.EditProjectElement(self._View, name)
-
-            return self._View
-        return None
+            app_frame.EditProjectElement(view, name)
+
+        return view
 
     def _CloseView(self, view):
         app_frame = self.GetCTRoot().AppFrame
--- a/IDEFrame.py	Mon Mar 11 13:51:07 2019 +0100
+++ b/IDEFrame.py	Fri Mar 22 11:10:37 2019 +0100
@@ -1819,6 +1819,47 @@
         else:
             event.Skip()
 
+    def GetProjectElementWindow(self, element, tagname):
+        new_window = None
+        if self.Controler.GetEditedElement(tagname) is not None:
+            new_window = None
+            if element == ITEM_CONFIGURATION:
+                new_window = ConfigurationEditor(self.TabsOpened, tagname, self, self.Controler)
+                new_window.SetIcon(GetBitmap("CONFIGURATION"))
+            elif element == ITEM_RESOURCE:
+                new_window = ResourceEditor(self.TabsOpened, tagname, self, self.Controler)
+                new_window.SetIcon(GetBitmap("RESOURCE"))
+            elif element in [ITEM_POU, ITEM_TRANSITION, ITEM_ACTION]:
+                bodytype = self.Controler.GetEditedElementBodyType(tagname)
+                if bodytype == "FBD":
+                    new_window = Viewer(self.TabsOpened, tagname, self, self.Controler)
+                    new_window.RefreshScaling(False)
+                elif bodytype == "LD":
+                    new_window = LD_Viewer(self.TabsOpened, tagname, self, self.Controler)
+                    new_window.RefreshScaling(False)
+                elif bodytype == "SFC":
+                    new_window = SFC_Viewer(self.TabsOpened, tagname, self, self.Controler)
+                    new_window.RefreshScaling(False)
+                else:
+                    new_window = TextViewer(self.TabsOpened, tagname, self, self.Controler)
+                    new_window.SetTextSyntax(bodytype)
+                    if bodytype == "IL":
+                        new_window.SetKeywords(IL_KEYWORDS)
+                    else:
+                        new_window.SetKeywords(ST_KEYWORDS)
+                if element == ITEM_POU:
+                    pou_type = self.Controler.GetEditedElementType(tagname)[1].upper()
+                    icon = GetBitmap(pou_type, bodytype)
+                elif element == ITEM_TRANSITION:
+                    icon = GetBitmap("TRANSITION", bodytype)
+                elif element == ITEM_ACTION:
+                    icon = GetBitmap("ACTION", bodytype)
+                new_window.SetIcon(icon)
+            elif element == ITEM_DATATYPE:
+                new_window = DataTypeEditor(self.TabsOpened, tagname, self, self.Controler)
+                new_window.SetIcon(GetBitmap("DATATYPE"))
+        return new_window
+
     def EditProjectElement(self, element, tagname, onlyopened=False):
         openedidx = self.IsOpened(tagname)
         if openedidx is not None:
@@ -1831,49 +1872,11 @@
         elif not onlyopened:
             if isinstance(element, EditorPanel):
                 new_window = element
-                self.AddPage(element, "")
-            elif self.Controler.GetEditedElement(tagname) is not None:
-                new_window = None
-                if element == ITEM_CONFIGURATION:
-                    new_window = ConfigurationEditor(self.TabsOpened, tagname, self, self.Controler)
-                    new_window.SetIcon(GetBitmap("CONFIGURATION"))
-                    self.AddPage(new_window, "")
-                elif element == ITEM_RESOURCE:
-                    new_window = ResourceEditor(self.TabsOpened, tagname, self, self.Controler)
-                    new_window.SetIcon(GetBitmap("RESOURCE"))
-                    self.AddPage(new_window, "")
-                elif element in [ITEM_POU, ITEM_TRANSITION, ITEM_ACTION]:
-                    bodytype = self.Controler.GetEditedElementBodyType(tagname)
-                    if bodytype == "FBD":
-                        new_window = Viewer(self.TabsOpened, tagname, self, self.Controler)
-                        new_window.RefreshScaling(False)
-                    elif bodytype == "LD":
-                        new_window = LD_Viewer(self.TabsOpened, tagname, self, self.Controler)
-                        new_window.RefreshScaling(False)
-                    elif bodytype == "SFC":
-                        new_window = SFC_Viewer(self.TabsOpened, tagname, self, self.Controler)
-                        new_window.RefreshScaling(False)
-                    else:
-                        new_window = TextViewer(self.TabsOpened, tagname, self, self.Controler)
-                        new_window.SetTextSyntax(bodytype)
-                        if bodytype == "IL":
-                            new_window.SetKeywords(IL_KEYWORDS)
-                        else:
-                            new_window.SetKeywords(ST_KEYWORDS)
-                    if element == ITEM_POU:
-                        pou_type = self.Controler.GetEditedElementType(tagname)[1].upper()
-                        icon = GetBitmap(pou_type, bodytype)
-                    elif element == ITEM_TRANSITION:
-                        icon = GetBitmap("TRANSITION", bodytype)
-                    elif element == ITEM_ACTION:
-                        icon = GetBitmap("ACTION", bodytype)
-                    new_window.SetIcon(icon)
-                    self.AddPage(new_window, "")
-                elif element == ITEM_DATATYPE:
-                    new_window = DataTypeEditor(self.TabsOpened, tagname, self, self.Controler)
-                    new_window.SetIcon(GetBitmap("DATATYPE"))
-                    self.AddPage(new_window, "")
+            else:
+                new_window = self.GetProjectElementWindow(element, tagname)
+
             if new_window is not None:
+                self.AddPage(new_window, "")
                 openedidx = self.IsOpened(tagname)
                 old_selected = self.TabsOpened.GetSelection()
                 if old_selected != openedidx:
--- a/PLCControler.py	Mon Mar 11 13:51:07 2019 +0100
+++ b/PLCControler.py	Fri Mar 22 11:10:37 2019 +0100
@@ -2749,7 +2749,9 @@
     # -------------------------------------------------------------------------------
 
     def SearchInProject(self, criteria):
-        return self.Project.Search(criteria)
+        project_matches =  self.Project.Search(criteria)
+        ctn_matches =  self.CTNSearch(criteria)
+        return project_matches + ctn_matches
 
     def SearchInPou(self, tagname, criteria, debug=False):
         pou = self.GetEditedElement(tagname, debug)
--- a/controls/SearchResultPanel.py	Mon Mar 11 13:51:07 2019 +0100
+++ b/controls/SearchResultPanel.py	Fri Mar 22 11:10:37 2019 +0100
@@ -130,7 +130,9 @@
                 ("DATATYPE",       ITEM_DATATYPE),
                 ("ACTION",         "action_block"),
                 ("IL",             "IL"),
-                ("ST",             "ST")]:
+                ("ST",             "ST"),
+                ("FILE",           ITEM_CONFNODE),
+                ]:
             self.TreeImageDict[itemtype] = self.TreeImageList.Add(GetBitmap(imgname))
 
         for itemtype in ["function", "functionBlock", "program",
@@ -202,7 +204,12 @@
 
                 children = element_infos.setdefault("children", [])
                 for infos, start, end, text in results:
-                    if infos[1] == "name" or element_type == ITEM_DATATYPE:
+                    if len(words) == 1:  # CTN match
+                        child_name = {"body":str(start[0])+":",
+                                      "var_inout":_("Variable:")}[infos[1]]
+                        child_type = {"body":ITEM_CONFNODE,
+                                      "var_inout":"var_inout"}[infos[1]]
+                    elif infos[1] == "name" or element_type == ITEM_DATATYPE:
                         child_name = GenerateName(infos[1:])
                         child_type = element_type
                     else:
@@ -232,6 +239,7 @@
                     }
                     children.append(child_infos)
 
+                # not Project node
                 if len(words) > 2:
                     for _element_infos in search_results_tree_children:
                         if _element_infos["name"] == words[1]:
@@ -240,7 +248,7 @@
                             break
                     if element_type == ITEM_RESOURCE:
                         search_results_tree_children.append(element_infos)
-                else:
+                else:  # Project node or CTN
                     search_results_tree_children.append(element_infos)
 
             if matches_number < 2:
@@ -302,7 +310,7 @@
         if text is not None:
             text_ctrl_style = wx.BORDER_NONE | wx.TE_READONLY | wx.TE_RICH2
             if wx.Platform != '__WXMSW__' or len(text.splitlines()) > 1:
-                text_ctrl_style |= wx.TE_MULTILINE
+                text_ctrl_style |= wx.TE_MULTILINE | wx.TE_NO_VSCROLL
             text_ctrl = wx.TextCtrl(id=-1, parent=self.SearchResultsTree, pos=wx.Point(0, 0),
                                     value=text, style=text_ctrl_style)
             width, height = text_ctrl.GetTextExtent(text)
--- a/editors/CodeFileEditor.py	Mon Mar 11 13:51:07 2019 +0100
+++ b/editors/CodeFileEditor.py	Fri Mar 22 11:10:37 2019 +0100
@@ -56,6 +56,21 @@
 EDGE_COLUMN = 80
 
 
+def GetSectionsText(controler, sections_headers):
+    parts = controler.GetTextParts()
+    text = ""
+    for section in controler.SECTIONS_NAMES:
+        text += sections_headers(section)
+        if parts[section] == "":
+            text += "\n"
+        else:
+            if not parts[section].startswith("\n"):
+                text += "\n"
+            text += parts[section]
+            if not parts[section].endswith("\n"):
+                text += "\n"
+    return text
+
 class CodeEditor(CustomStyledTextCtrl):
 
     KEYWORDS = []
@@ -239,20 +254,9 @@
             self.CurrentAction = None
 
     def GetCodeText(self):
-        parts = self.Controler.GetTextParts()
-        text = ""
-        for section in self.Controler.SECTIONS_NAMES:
-            section_comments = self.SectionsComments[section]
-            text += section_comments["comment"]
-            if parts[section] == "":
-                text += "\n"
-            else:
-                if not parts[section].startswith("\n"):
-                    text += "\n"
-                text += parts[section]
-                if not parts[section].endswith("\n"):
-                    text += "\n"
-        return text
+        return GetSectionsText(
+            self.Controler, 
+            lambda section : self.SectionsComments[section]["comment"])
 
     def RefreshView(self, scroll_to_highlight=False):
         self.ResetBuffer()
@@ -644,6 +648,7 @@
         """
 
         for row in range(self.GetNumberRows()):
+            row_highlights = self.Highlights.get(row, {})
             for col in range(self.GetNumberCols()):
                 editor = None
                 renderer = None
@@ -656,7 +661,9 @@
                 grid.SetCellEditor(row, col, editor)
                 grid.SetCellRenderer(row, col, renderer)
 
-                grid.SetCellBackgroundColour(row, col, wx.WHITE)
+                highlight_colours = row_highlights.get(colname.lower(), [(wx.WHITE, wx.BLACK)])[-1]
+                grid.SetCellBackgroundColour(row, col, highlight_colours[0])
+                grid.SetCellTextColour(row, col, highlight_colours[1])
             self.ResizeRow(grid, row)
 
 
@@ -859,6 +866,20 @@
             return
         event.Skip()
 
+    def AddVariableHighlight(self, infos, highlight_type):
+        self.Table.AddHighlight(infos, highlight_type)
+        cell_visible = infos[0]
+        colnames = [colname.lower() for colname in self.Table.colnames]
+        self.VariablesGrid.MakeCellVisible(cell_visible, colnames.index(infos[1]))
+        self.Table.ResetView(self.VariablesGrid)
+
+    def RemoveVariableHighlight(self, infos, highlight_type):
+        self.Table.RemoveHighlight(infos, highlight_type)
+        self.Table.ResetView(self.VariablesGrid)
+
+    def ClearHighlights(self, highlight_type=None):
+        self.Table.ClearHighlights(highlight_type)
+        self.Table.ResetView(self.VariablesGrid)
 
 # -------------------------------------------------------------------------------
 #                          CodeFileEditor Main Frame Class
@@ -914,3 +935,21 @@
 
     def Find(self, direction, search_params):
         self.CodeEditor.Find(direction, search_params)
+
+    def AddHighlight(self, infos, start, end, highlight_type):
+        if self.VariablesPanel is not None and infos[0] == "var_inout":
+            self.VariablesPanel.AddVariableHighlight(infos[1:], highlight_type)
+        else:
+            self.CodeEditor.AddHighlight(start, end, highlight_type)
+
+    def RemoveHighlight(self, infos, start, end, highlight_type):
+        if self.VariablesPanel is not None and infos[0] == "var_inout":
+            self.VariablesPanel.RemoveVariableHighlight(infos[1:], highlight_type)
+        else:
+            self.CodeEditor.RemoveHighlight(start, end, highlight_type)
+
+    def ClearHighlights(self, highlight_type=None):
+        if self.VariablesPanel is not None:
+            self.VariablesPanel.ClearHighlights(highlight_type)
+        else:
+            self.CodeEditor.ClearHighlights(highlight_type)
--- a/plcopen/plcopen.py	Mon Mar 11 13:51:07 2019 +0100
+++ b/plcopen/plcopen.py	Fri Mar 22 11:10:37 2019 +0100
@@ -856,6 +856,7 @@
     setattr(cls, "removeVariableByFilter", _removeConfigurationResourceVariableByFilter)
 
     def Search(self, criteria, parent_infos=None):
+        # FIXME  : two next lines are incompatible [][-1] raises exception !
         parent_infos = [] if parent_infos is None else parent_infos
         parent_infos = parent_infos[:-1] + ["R::%s::%s" % (parent_infos[-1].split("::")[1], self.getname())]
         search_result = _SearchInConfigurationResource(self, criteria, parent_infos)
--- a/plcopen/types_enums.py	Mon Mar 11 13:51:07 2019 +0100
+++ b/plcopen/types_enums.py	Fri Mar 22 11:10:37 2019 +0100
@@ -117,6 +117,8 @@
 
 def GetElementType(tagname):
     words = tagname.split("::")
+    if len(words) == 1:
+        return ITEM_CONFNODE
     return {
         "D": ITEM_DATATYPE,
         "P": ITEM_POU,