# HG changeset patch # User Laurent Bessard # Date 1366817866 -7200 # Node ID fd7c9a7cf882a62b6ff6cfabc717bff89dab0bf7 # Parent b0ac30ba7eaf20d30e4497a0f97c309a07ac2c7b# Parent 02f371f3e06387890efb18857a5e3b240e969bef Merged diff -r b0ac30ba7eaf -r fd7c9a7cf882 Beremiz.py --- a/Beremiz.py Wed Apr 24 18:34:00 2013 +0900 +++ b/Beremiz.py Wed Apr 24 17:37:46 2013 +0200 @@ -980,7 +980,6 @@ self.CTR.SaveProjectAs() self.RefreshAll() self._Refresh(TITLE, FILEMENU, EDITMENU, PAGETITLES) - event.Skip() def OnQuitMenu(self, event): self.Close() diff -r b0ac30ba7eaf -r fd7c9a7cf882 ConfigTreeNode.py --- a/ConfigTreeNode.py Wed Apr 24 18:34:00 2013 +0900 +++ b/ConfigTreeNode.py Wed Apr 24 17:37:46 2013 +0200 @@ -73,10 +73,12 @@ def ConfNodePath(self): return os.path.join(self.CTNParent.ConfNodePath(), self.CTNType) - def CTNPath(self,CTNName=None): + def CTNPath(self,CTNName=None,project_path=None): if not CTNName: CTNName = self.CTNName() - return os.path.join(self.CTNParent.CTNPath(), + if not project_path: + project_path = self.CTNParent.CTNPath() + return os.path.join(project_path, CTNName + NameTypeSeparator + self.CTNType) def CTNName(self): @@ -113,7 +115,7 @@ def RemoteExec(self, script, **kwargs): return self.CTNParent.RemoteExec(script, **kwargs) - def OnCTNSave(self): + def OnCTNSave(self, from_project_path=None): #Default, do nothing and return success return True @@ -155,7 +157,7 @@ def CTNMakeDir(self): os.mkdir(self.CTNPath()) - def CTNRequestSave(self): + def CTNRequestSave(self, from_project_path=None): if self.GetCTRoot().CheckProjectPathPerm(False): # If confnode do not have corresponding directory ctnpath = self.CTNPath() @@ -178,7 +180,7 @@ XMLFile.close() # Call the confnode specific OnCTNSave method - result = self.OnCTNSave() + result = self.OnCTNSave(from_project_path) if not result: return _("Error while saving \"%s\"\n")%self.CTNPath() @@ -186,7 +188,8 @@ self.ChangesToSave = False # go through all children and do the same for CTNChild in self.IterChildren(): - result = CTNChild.CTNRequestSave() + result = CTNChild.CTNRequestSave( + CTNChild.CTNPath(project_path=from_project_path)) if result: return result return None diff -r b0ac30ba7eaf -r fd7c9a7cf882 ProjectController.py --- a/ProjectController.py Wed Apr 24 18:34:00 2013 +0900 +++ b/ProjectController.py Wed Apr 24 17:37:46 2013 +0200 @@ -234,7 +234,9 @@ return True return False - def _getProjectFilesPath(self): + def _getProjectFilesPath(self, project_path=None): + if project_path is not None: + return os.path.join(project_path, "project_files") projectfiles_path = os.path.join(self.GetProjectPath(), "project_files") if not os.path.exists(projectfiles_path): os.mkdir(projectfiles_path) @@ -348,14 +350,19 @@ self.ClearChildren() self.ResetAppFrame(None) - def SaveProject(self): + def SaveProject(self, from_project_path=None): if self.CheckProjectPathPerm(False): + if from_project_path is not None: + old_projectfiles_path = self._getProjectFilesPath(from_project_path) + if os.path.isdir(old_projectfiles_path): + shutil.copytree(old_projectfiles_path, + self._getProjectFilesPath(self.ProjectPath)) self.SaveXMLFile(os.path.join(self.ProjectPath, 'plc.xml')) - result = self.CTNRequestSave() + result = self.CTNRequestSave(from_project_path) if result: self.logger.write_error(result) - def SaveProjectAs(self, dosave=True): + def SaveProjectAs(self): # Ask user to choose a path with write permissions if wx.Platform == '__WXMSW__': path = os.getenv("USERPROFILE") @@ -367,9 +374,8 @@ if answer == wx.ID_OK: newprojectpath = dirdialog.GetPath() if os.path.isdir(newprojectpath): - self.ProjectPath = newprojectpath - if dosave: - self.SaveProject() + self.ProjectPath, old_project_path = newprojectpath, self.ProjectPath + self.SaveProject(old_project_path) self._setBuildPath(self.BuildPath) return True return False diff -r b0ac30ba7eaf -r fd7c9a7cf882 c_ext/CFileEditor.py --- a/c_ext/CFileEditor.py Wed Apr 24 18:34:00 2013 +0900 +++ b/c_ext/CFileEditor.py Wed Apr 24 17:37:46 2013 +0200 @@ -8,24 +8,7 @@ from controls import CustomGrid, CustomTable from editors.ConfTreeNodeEditor import ConfTreeNodeEditor, SCROLLBAR_UNIT from util.BitmapLibrary import GetBitmap - -if wx.Platform == '__WXMSW__': - faces = { 'times': 'Times New Roman', - 'mono' : 'Courier New', - 'helv' : 'Arial', - 'other': 'Comic Sans MS', - 'size' : 10, - 'size2': 8, - } -else: - faces = { 'times': 'Times', - 'mono' : 'Courier', - 'helv' : 'Helvetica', - 'other': 'new century schoolbook', - 'size' : 12, - 'size2': 10, - } - +from editors.TextViewer import GetCursorPos, faces def AppendMenu(parent, help, id, kind, text): if wx.VERSION >= (2, 6, 0): @@ -47,27 +30,6 @@ "typedef", "typeid", "typename", "union", "unsigned", "using", "virtual", "void", "volatile", "wchar_t", "while"] -def GetCursorPos(old, new): - old_length = len(old) - new_length = len(new) - common_length = min(old_length, new_length) - i = 0 - for i in xrange(common_length): - if old[i] != new[i]: - break - if old_length < new_length: - if common_length > 0 and old[i] != new[i]: - return i + new_length - old_length - else: - return i + new_length - old_length + 1 - elif old_length > new_length or i < min(old_length, new_length) - 1: - if common_length > 0 and old[i] != new[i]: - return i - else: - return i + 1 - else: - return None - class CppEditor(stc.StyledTextCtrl): fold_symbols = 3 @@ -165,15 +127,15 @@ self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, "fore:#FFFFFF,back:#0000FF,bold") self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, "fore:#000000,back:#FF0000,bold") - self.StyleSetSpec(stc.STC_C_COMMENT, 'fore:#408060') - self.StyleSetSpec(stc.STC_C_COMMENTLINE, 'fore:#408060') - self.StyleSetSpec(stc.STC_C_COMMENTDOC, 'fore:#408060') - self.StyleSetSpec(stc.STC_C_NUMBER, 'fore:#0076AE') - self.StyleSetSpec(stc.STC_C_WORD, 'bold,fore:#800056') - self.StyleSetSpec(stc.STC_C_STRING, 'fore:#2a00ff') - self.StyleSetSpec(stc.STC_C_PREPROCESSOR, 'bold,fore:#800056') - self.StyleSetSpec(stc.STC_C_OPERATOR, 'bold') - self.StyleSetSpec(stc.STC_C_STRINGEOL, 'back:#FFD5FF') + self.StyleSetSpec(stc.STC_C_COMMENT, 'fore:#408060,size:%(size)d' % faces) + self.StyleSetSpec(stc.STC_C_COMMENTLINE, 'fore:#408060,size:%(size)d' % faces) + self.StyleSetSpec(stc.STC_C_COMMENTDOC, 'fore:#408060,size:%(size)d' % faces) + self.StyleSetSpec(stc.STC_C_NUMBER, 'fore:#0076AE,size:%(size)d' % faces) + self.StyleSetSpec(stc.STC_C_WORD, 'bold,fore:#800056,size:%(size)d' % faces) + self.StyleSetSpec(stc.STC_C_STRING, 'fore:#2a00ff,size:%(size)d' % faces) + self.StyleSetSpec(stc.STC_C_PREPROCESSOR, 'bold,fore:#800056,size:%(size)d' % faces) + self.StyleSetSpec(stc.STC_C_OPERATOR, 'bold,size:%(size)d' % faces) + self.StyleSetSpec(stc.STC_C_STRINGEOL, 'back:#FFD5FF,size:%(size)d' % faces) # register some images for use in the AutoComplete box. #self.RegisterImage(1, images.getSmilesBitmap()) @@ -254,16 +216,19 @@ self.ResetBuffer() self.DisableEvents = True old_cursor_pos = self.GetCurrentPos() + line = self.GetFirstVisibleLine() + column = self.GetXOffset() old_text = self.GetText() new_text = self.Controler.GetPartText(self.Name) self.SetText(new_text) - new_cursor_pos = GetCursorPos(old_text, new_text) - if new_cursor_pos != None: - self.GotoPos(new_cursor_pos) - else: - self.GotoPos(old_cursor_pos) - self.ScrollToColumn(0) - self.EmptyUndoBuffer() + if old_text != new_text: + new_cursor_pos = GetCursorPos(old_text, new_text) + self.LineScroll(column, line) + if new_cursor_pos != None: + self.GotoPos(new_cursor_pos) + else: + self.GotoPos(old_cursor_pos) + self.EmptyUndoBuffer() self.DisableEvents = False self.Colourise(0, -1) diff -r b0ac30ba7eaf -r fd7c9a7cf882 c_ext/c_ext.py --- a/c_ext/c_ext.py Wed Apr 24 18:34:00 2013 +0900 +++ b/c_ext/c_ext.py Wed Apr 24 17:37:46 2013 +0200 @@ -144,7 +144,7 @@ def CTNTestModified(self): return self.ChangesToSave or not self.CFileIsSaved() - def OnCTNSave(self): + def OnCTNSave(self, from_project_path=None): filepath = self.CFileName() text = "\n" diff -r b0ac30ba7eaf -r fd7c9a7cf882 canfestival/canfestival.py --- a/canfestival/canfestival.py Wed Apr 24 18:34:00 2013 +0900 +++ b/canfestival/canfestival.py Wed Apr 24 17:37:46 2013 +0200 @@ -1,4 +1,4 @@ -import os, sys +import os, sys, shutil base_folder = os.path.split(sys.path[0])[0] CanFestivalPath = os.path.join(base_folder, "CanFestival-3") @@ -154,7 +154,7 @@ def CTNTestModified(self): return self.ChangesToSave or self.OneFileHasChanged() - def OnCTNSave(self): + def OnCTNSave(self, from_project_path=None): return self.SaveCurrentInFile(self.GetSlaveODPath()) def SetParamsAttribute(self, path, value): @@ -378,8 +378,10 @@ def CTNTestModified(self): return self.ChangesToSave or self.HasChanged() - def OnCTNSave(self): + def OnCTNSave(self, from_project_path=None): self.SetRoot(self.CTNPath()) + shutil.copytree(self.GetEDSFolder(from_project_path), + self.GetEDSFolder()) return self.SaveProject() is None def CTNGenerate_C(self, buildpath, locations): diff -r b0ac30ba7eaf -r fd7c9a7cf882 dialogs/FindInPouDialog.py --- a/dialogs/FindInPouDialog.py Wed Apr 24 18:34:00 2013 +0900 +++ b/dialogs/FindInPouDialog.py Wed Apr 24 17:37:46 2013 +0200 @@ -109,7 +109,8 @@ self.ParentWindow = parent self.Bind(wx.EVT_CLOSE, self.OnCloseFrame) - + + self.FindPattern.SetFocus() self.RefreshButtonsState() def RefreshButtonsState(self): diff -r b0ac30ba7eaf -r fd7c9a7cf882 editors/ConfTreeNodeEditor.py --- a/editors/ConfTreeNodeEditor.py Wed Apr 24 18:34:00 2013 +0900 +++ b/editors/ConfTreeNodeEditor.py Wed Apr 24 17:37:46 2013 +0200 @@ -147,57 +147,22 @@ def _init_Editor(self, parent): tabs_num = len(self.CONFNODEEDITOR_TABS) - if self.SHOW_PARAMS: + if self.SHOW_PARAMS and len(self.Controler.GetParamsAttributes()) > 0: tabs_num += 1 - if tabs_num > 1: + if tabs_num > 1 or self.SHOW_BASE_PARAMS: self.Editor = wx.Panel(parent, style=wx.SUNKEN_BORDER|wx.SP_3D) - - main_sizer = wx.BoxSizer(wx.VERTICAL) - - self.ConfNodeNoteBook = wx.Notebook(self.Editor) - parent = self.ConfNodeNoteBook - main_sizer.AddWindow(self.ConfNodeNoteBook, 1, flag=wx.GROW) - - self.Editor.SetSizer(main_sizer) - else: - self.ConfNodeNoteBook = None - self.Editor = None - - for title, create_func_name in self.CONFNODEEDITOR_TABS: - editor = getattr(self, create_func_name)(parent) - if self.ConfNodeNoteBook is not None: - self.ConfNodeNoteBook.AddPage(editor, title) - else: - self.Editor = editor - - if self.SHOW_PARAMS: - - panel_style = wx.TAB_TRAVERSAL|wx.HSCROLL|wx.VSCROLL - if self.ConfNodeNoteBook is None: - panel_style |= wx.SUNKEN_BORDER - self.ParamsEditor = wx.ScrolledWindow(parent, - style=panel_style) - self.ParamsEditor.SetBackgroundColour(WINDOW_COLOUR) - self.ParamsEditor.Bind(wx.EVT_SIZE, self.OnWindowResize) - self.ParamsEditor.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheel) - - # Variable allowing disabling of ParamsEditor scroll when Popup shown - self.ScrollingEnabled = True + self.Editor.SetBackgroundColour(WINDOW_COLOUR) + + self.MainSizer = wx.BoxSizer(wx.VERTICAL) if self.SHOW_BASE_PARAMS: - self.ParamsEditorSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=2, vgap=5) - self.ParamsEditorSizer.AddGrowableCol(0) - self.ParamsEditorSizer.AddGrowableRow(1) - - self.ParamsEditor.SetSizer(self.ParamsEditorSizer) - baseparamseditor_sizer = wx.BoxSizer(wx.HORIZONTAL) - self.ParamsEditorSizer.AddSizer(baseparamseditor_sizer, border=5, - flag=wx.GROW|wx.LEFT|wx.RIGHT|wx.TOP) - - self.FullIECChannel = wx.StaticText(self.ParamsEditor, -1) + self.MainSizer.AddSizer(baseparamseditor_sizer, border=5, + flag=wx.GROW|wx.ALL) + + self.FullIECChannel = wx.StaticText(self.Editor, -1) self.FullIECChannel.SetFont( wx.Font(faces["size"], wx.DEFAULT, wx.NORMAL, wx.BOLD, faceName = faces["helv"])) @@ -208,19 +173,19 @@ baseparamseditor_sizer.AddSizer(updownsizer, border=5, flag=wx.LEFT|wx.ALIGN_CENTER_VERTICAL) - self.IECCUpButton = wx.lib.buttons.GenBitmapTextButton(self.ParamsEditor, + self.IECCUpButton = wx.lib.buttons.GenBitmapTextButton(self.Editor, bitmap=GetBitmap('IECCDown'), size=wx.Size(16, 16), style=wx.NO_BORDER) self.IECCUpButton.Bind(wx.EVT_BUTTON, self.GetItemChannelChangedFunction(1), self.IECCUpButton) updownsizer.AddWindow(self.IECCUpButton, flag=wx.ALIGN_LEFT) - self.IECCDownButton = wx.lib.buttons.GenBitmapButton(self.ParamsEditor, + self.IECCDownButton = wx.lib.buttons.GenBitmapButton(self.Editor, bitmap=GetBitmap('IECCUp'), size=wx.Size(16, 16), style=wx.NO_BORDER) self.IECCDownButton.Bind(wx.EVT_BUTTON, self.GetItemChannelChangedFunction(-1), self.IECCDownButton) updownsizer.AddWindow(self.IECCDownButton, flag=wx.ALIGN_LEFT) - self.ConfNodeName = wx.TextCtrl(self.ParamsEditor, + self.ConfNodeName = wx.TextCtrl(self.Editor, size=wx.Size(150, 25), style=wx.NO_BORDER) self.ConfNodeName.SetFont( wx.Font(faces["size"] * 0.75, wx.DEFAULT, wx.NORMAL, @@ -234,10 +199,46 @@ buttons_sizer = self.GenerateMethodButtonSizer() baseparamseditor_sizer.AddSizer(buttons_sizer, flag=wx.ALIGN_CENTER) + if tabs_num > 1: + self.ConfNodeNoteBook = wx.Notebook(self.Editor) + parent = self.ConfNodeNoteBook + self.MainSizer.AddWindow(self.ConfNodeNoteBook, 1, flag=wx.GROW) else: - self.ParamsEditorSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=1, vgap=5) - self.ParamsEditorSizer.AddGrowableCol(0) - self.ParamsEditorSizer.AddGrowableRow(0) + parent = self.Editor + self.ConfNodeNoteBook = None + + self.Editor.SetSizer(self.MainSizer) + else: + self.ConfNodeNoteBook = None + self.Editor = None + + for title, create_func_name in self.CONFNODEEDITOR_TABS: + editor = getattr(self, create_func_name)(parent) + if self.ConfNodeNoteBook is not None: + self.ConfNodeNoteBook.AddPage(editor, title) + elif self.SHOW_BASE_PARAMS: + self.MainSizer.AddWindow(editor, 1, flag=wx.GROW) + else: + self.Editor = editor + + if self.SHOW_PARAMS and len(self.Controler.GetParamsAttributes()) > 0: + + panel_style = wx.TAB_TRAVERSAL|wx.HSCROLL|wx.VSCROLL + if self.ConfNodeNoteBook is None and parent != self.Editor: + panel_style |= wx.SUNKEN_BORDER + self.ParamsEditor = wx.ScrolledWindow(parent, + style=panel_style) + self.ParamsEditor.SetBackgroundColour(WINDOW_COLOUR) + self.ParamsEditor.Bind(wx.EVT_SIZE, self.OnWindowResize) + self.ParamsEditor.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheel) + + # Variable allowing disabling of ParamsEditor scroll when Popup shown + self.ScrollingEnabled = True + + self.ParamsEditorSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=1, vgap=5) + self.ParamsEditorSizer.AddGrowableCol(0) + self.ParamsEditorSizer.AddGrowableRow(0) + self.ParamsEditor.SetSizer(self.ParamsEditorSizer) self.ConfNodeParamsSizer = wx.BoxSizer(wx.VERTICAL) self.ParamsEditorSizer.AddSizer(self.ConfNodeParamsSizer, border=5, @@ -247,6 +248,8 @@ if self.ConfNodeNoteBook is not None: self.ConfNodeNoteBook.AddPage(self.ParamsEditor, _("Config")) + elif self.SHOW_BASE_PARAMS: + self.MainSizer.AddWindow(self.ParamsEditor, 1, flag=wx.GROW) else: self.Editor = self.ParamsEditor else: @@ -287,10 +290,10 @@ def RefreshView(self): EditorPanel.RefreshView(self) + if self.SHOW_BASE_PARAMS: + self.ConfNodeName.ChangeValue(self.Controler.MandatoryParams[1].getName()) + self.RefreshIECChannelControlsState() if self.ParamsEditor is not None: - if self.SHOW_BASE_PARAMS: - self.ConfNodeName.ChangeValue(self.Controler.MandatoryParams[1].getName()) - self.RefreshIECChannelControlsState() self.RefreshConfNodeParamsSizer() self.RefreshScrollbars() @@ -300,6 +303,7 @@ def RefreshIECChannelControlsState(self): self.FullIECChannel.SetLabel(self.Controler.GetFullIEC_Channel()) self.IECCDownButton.Enable(self.Controler.BaseParams.getIEC_Channel() > 0) + self.MainSizer.Layout() def RefreshConfNodeParamsSizer(self): self.Freeze() @@ -320,7 +324,7 @@ for confnode_method in self.Controler.ConfNodeMethods: if "method" in confnode_method and confnode_method.get("shown",True): - button = GenBitmapTextButton(self.ParamsEditor, + button = GenBitmapTextButton(self.Editor, bitmap=GetBitmap(confnode_method.get("bitmap", "Unknown")), label=confnode_method["name"], style=wx.NO_BORDER) button.SetFont(normal_bt_font) diff -r b0ac30ba7eaf -r fd7c9a7cf882 editors/IECCodeViewer.py --- a/editors/IECCodeViewer.py Wed Apr 24 18:34:00 2013 +0900 +++ b/editors/IECCodeViewer.py Wed Apr 24 17:37:46 2013 +0200 @@ -1,9 +1,13 @@ from editors.TextViewer import TextViewer +from plcopen.plcopen import TestTextElement class IECCodeViewer(TextViewer): def __del__(self): TextViewer.__del__(self) if getattr(self, "_OnClose"): - self._OnClose(self) \ No newline at end of file + self._OnClose(self) + + def Search(self, criteria): + return [((self.TagName, "body", 0),) + result for result in TestTextElement(self.Editor.GetText(), criteria)] \ No newline at end of file diff -r b0ac30ba7eaf -r fd7c9a7cf882 editors/ProjectNodeEditor.py --- a/editors/ProjectNodeEditor.py Wed Apr 24 18:34:00 2013 +0900 +++ b/editors/ProjectNodeEditor.py Wed Apr 24 17:37:46 2013 +0200 @@ -33,12 +33,10 @@ ConfTreeNodeEditor.__init__(self, parent, controler, window, tagname) - if self.SHOW_BASE_PARAMS: - buttons_sizer = self.GenerateMethodButtonSizer() - self.ParamsEditorSizer.InsertSizer(0, buttons_sizer, 0, border=5, - flag=wx.LEFT|wx.RIGHT|wx.TOP) - self.ParamsEditorSizer.Layout() - + buttons_sizer = self.GenerateMethodButtonSizer() + self.MainSizer.InsertSizer(0, buttons_sizer, 0, border=5, flag=wx.ALL) + self.MainSizer.Layout() + self.VariableEditor = self.VariableEditorPanel def GetTagName(self): diff -r b0ac30ba7eaf -r fd7c9a7cf882 editors/TextViewer.py --- a/editors/TextViewer.py Wed Apr 24 18:34:00 2013 +0900 +++ b/editors/TextViewer.py Wed Apr 24 17:37:46 2013 +0200 @@ -80,6 +80,8 @@ } def GetCursorPos(old, new): + if old == "": + return 0 old_length = len(old) new_length = len(new) common_length = min(old_length, new_length) @@ -445,17 +447,20 @@ self.ResetBuffer() self.DisableEvents = True old_cursor_pos = self.GetCurrentPos() + line = self.Editor.GetFirstVisibleLine() + column = self.Editor.GetXOffset() old_text = self.GetText() new_text = self.Controler.GetEditedElementText(self.TagName, self.Debug) - self.SetText(new_text) - new_cursor_pos = GetCursorPos(old_text, new_text) - if new_cursor_pos != None: - self.Editor.GotoPos(new_cursor_pos) - else: - self.Editor.GotoPos(old_cursor_pos) - self.Editor.ScrollToColumn(0) - self.RefreshJumpList() - self.Editor.EmptyUndoBuffer() + if old_text != new_text: + self.SetText(new_text) + new_cursor_pos = GetCursorPos(old_text, new_text) + self.Editor.LineScroll(column, line) + if new_cursor_pos != None: + self.Editor.GotoPos(new_cursor_pos) + else: + self.Editor.GotoPos(old_cursor_pos) + self.RefreshJumpList() + self.Editor.EmptyUndoBuffer() self.DisableEvents = False self.RefreshVariableTree() @@ -764,6 +769,9 @@ self.RefreshModel() self.RefreshBuffer() + def Search(self, criteria): + return self.Controler.SearchInPou(self.TagName, criteria, self.Debug) + def Find(self, direction, search_params): if self.SearchParams != search_params: self.ClearHighlights(SEARCH_RESULT_HIGHLIGHT) @@ -779,7 +787,8 @@ self.SearchResults = [ (infos[1:], start, end, SEARCH_RESULT_HIGHLIGHT) for infos, start, end, text in - self.Controler.SearchInPou(self.TagName, criteria, self.Debug)] + self.Search(criteria)] + self.CurrentFindHighlight = None if len(self.SearchResults) > 0: if self.CurrentFindHighlight is not None: @@ -801,6 +810,8 @@ self.RemoveHighlight(*self.CurrentFindHighlight) self.CurrentFindHighlight = None + print self.CurrentFindHighlight + def RefreshModel(self): self.RefreshJumpList() self.Controler.SetEditedElementText(self.TagName, self.GetText()) diff -r b0ac30ba7eaf -r fd7c9a7cf882 editors/Viewer.py --- a/editors/Viewer.py Wed Apr 24 18:34:00 2013 +0900 +++ b/editors/Viewer.py Wed Apr 24 17:37:46 2013 +0200 @@ -3167,6 +3167,7 @@ blocks.append((block, (infos[1:], start, end, SEARCH_RESULT_HIGHLIGHT))) blocks.sort(sort_blocks) self.SearchResults.extend([infos for block, infos in blocks]) + self.CurrentFindHighlight = None if len(self.SearchResults) > 0: if self.CurrentFindHighlight is not None: diff -r b0ac30ba7eaf -r fd7c9a7cf882 graphics/FBD_Objects.py --- a/graphics/FBD_Objects.py Wed Apr 24 18:34:00 2013 +0900 +++ b/graphics/FBD_Objects.py Wed Apr 24 17:37:46 2013 +0200 @@ -263,43 +263,49 @@ self.Pen = MiterPen(self.Colour) # Extract the inputs properties and create or modify the corresponding connector - idx = 0 - for idx, (input_name, input_type, input_modifier) in enumerate(inputs): - if idx < len(self.Inputs): - connector = self.Inputs[idx] - connector.SetName(input_name) - connector.SetType(input_type) - else: - connector = Connector(self, input_name, input_type, wx.Point(0, 0), WEST, onlyone = True) - self.Inputs.append(connector) + input_connectors = [] + for input_name, input_type, input_modifier in inputs: + connector = Connector(self, input_name, input_type, wx.Point(0, 0), WEST, onlyone = True) if input_modifier == "negated": connector.SetNegated(True) elif input_modifier != "none": connector.SetEdge(input_modifier) - for i in xrange(idx + 1, len(self.Inputs)): - self.Inputs[i].UnConnect(delete = True) - self.Inputs = self.Inputs[:idx + 1] + for input in self.Inputs: + if input.GetName() == input_name: + wires = input.GetWires()[:] + input.UnConnect() + for wire in wires: + connector.Connect(wire) + break + input_connectors.append(connector) + for input in self.Inputs: + input.UnConnect(delete = True) + self.Inputs = input_connectors # Extract the outputs properties and create or modify the corresponding connector - idx = 0 - for idx, (output_name, output_type, output_modifier) in enumerate(outputs): - if idx < len(self.Outputs): - connector = self.Outputs[idx] - connector.SetName(output_name) - connector.SetType(output_type) - else: - connector = Connector(self, output_name, output_type, wx.Point(0, 0), EAST) - self.Outputs.append(connector) + output_connectors = [] + for output_name, output_type, output_modifier in outputs: + connector = Connector(self, output_name, output_type, wx.Point(0, 0), EAST) if output_modifier == "negated": connector.SetNegated(True) elif output_modifier != "none": connector.SetEdge(output_modifier) - for i in xrange(idx + 1, len(self.Outputs)): - self.Outputs[i].UnConnect(delete = True) - self.Outputs = self.Outputs[:idx + 1] + for output in self.Outputs: + if output.GetName() == output_name: + wires = output.GetWires()[:] + output.UnConnect() + for wire in wires: + connector.Connect(wire) + break + output_connectors.append(connector) + for output in self.Outputs: + output.UnConnect(delete = True) + self.Outputs = output_connectors self.RefreshMinSize() self.RefreshConnectors() + for output in self.Outputs: + output.RefreshWires() self.RefreshBoundingBox() # Returns the block type diff -r b0ac30ba7eaf -r fd7c9a7cf882 graphics/GraphicCommons.py --- a/graphics/GraphicCommons.py Wed Apr 24 18:34:00 2013 +0900 +++ b/graphics/GraphicCommons.py Wed Apr 24 17:37:46 2013 +0200 @@ -1695,6 +1695,10 @@ def InsertConnect(self, idx, wire, refresh = True): if wire not in self.Wires: self.Wires.insert(idx, wire) + if wire[1] == 0: + wire[0].ConnectStartPoint(None, self) + else: + wire[0].ConnectEndPoint(None, self) if refresh: self.ParentBlock.RefreshModel(False) diff -r b0ac30ba7eaf -r fd7c9a7cf882 py_ext/PythonEditor.py --- a/py_ext/PythonEditor.py Wed Apr 24 18:34:00 2013 +0900 +++ b/py_ext/PythonEditor.py Wed Apr 24 17:37:46 2013 +0200 @@ -1,59 +1,25 @@ +import re +import keyword + import wx import wx.grid -import wx.stc as stc -import keyword - +import wx.stc as stc + +from plcopen.plcopen import TestTextElement +from graphics.GraphicCommons import ERROR_HIGHLIGHT, SEARCH_RESULT_HIGHLIGHT, REFRESH_HIGHLIGHT_PERIOD from editors.ConfTreeNodeEditor import ConfTreeNodeEditor - -if wx.Platform == '__WXMSW__': - faces = { 'times': 'Times New Roman', - 'mono' : 'Courier New', - 'helv' : 'Arial', - 'other': 'Comic Sans MS', - 'size' : 10, - 'size2': 8, - } -elif wx.Platform == '__WXMAC__': - faces = { 'times': 'Times New Roman', - 'mono' : 'Monaco', - 'helv' : 'Arial', - 'other': 'Comic Sans MS', - 'size' : 12, - 'size2': 10, - } -else: - faces = { 'times': 'Times', - 'mono' : 'Courier', - 'helv' : 'Helvetica', - 'other': 'new century schoolbook', - 'size' : 12, - 'size2': 10, - } +from editors.TextViewer import GetCursorPos, faces + +[STC_PYTHON_ERROR, STC_PYTHON_SEARCH_RESULT] = range(15, 17) + +HIGHLIGHT_TYPES = { + ERROR_HIGHLIGHT: STC_PYTHON_ERROR, + SEARCH_RESULT_HIGHLIGHT: STC_PYTHON_SEARCH_RESULT, +} [ID_PYTHONEDITOR, ] = [wx.NewId() for _init_ctrls in range(1)] -def GetCursorPos(old, new): - old_length = len(old) - new_length = len(new) - common_length = min(old_length, new_length) - i = 0 - for i in xrange(common_length): - if old[i] != new[i]: - break - if old_length < new_length: - if common_length > 0 and old[i] != new[i]: - return i + new_length - old_length - else: - return i + new_length - old_length + 1 - elif old_length > new_length or i < min(old_length, new_length) - 1: - if common_length > 0 and old[i] != new[i]: - return i - else: - return i + 1 - else: - return None - class PythonEditor(ConfTreeNodeEditor): fold_symbols = 3 @@ -136,7 +102,7 @@ self.PythonCodeEditor.Bind(stc.EVT_STC_UPDATEUI, self.OnUpdateUI) self.PythonCodeEditor.Bind(stc.EVT_STC_MARGINCLICK, self.OnMarginClick) self.PythonCodeEditor.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressed) - + # Global default style if wx.Platform == '__WXMSW__': self.PythonCodeEditor.StyleSetSpec(stc.STC_STYLE_DEFAULT, 'fore:#000000,back:#FFFFFF,face:Courier New') @@ -155,39 +121,43 @@ # The rest remains unchanged. # Line numbers in margin - self.PythonCodeEditor.StyleSetSpec(wx.stc.STC_STYLE_LINENUMBER,'fore:#000000,back:#99A9C2') + self.PythonCodeEditor.StyleSetSpec(stc.STC_STYLE_LINENUMBER,'fore:#000000,back:#99A9C2,size:%(size)d' % faces) # Highlighted brace - self.PythonCodeEditor.StyleSetSpec(wx.stc.STC_STYLE_BRACELIGHT,'fore:#00009D,back:#FFFF00') + self.PythonCodeEditor.StyleSetSpec(stc.STC_STYLE_BRACELIGHT,'fore:#00009D,back:#FFFF00,size:%(size)d' % faces) # Unmatched brace - self.PythonCodeEditor.StyleSetSpec(wx.stc.STC_STYLE_BRACEBAD,'fore:#00009D,back:#FF0000') + self.PythonCodeEditor.StyleSetSpec(stc.STC_STYLE_BRACEBAD,'fore:#00009D,back:#FF0000,size:%(size)d' % faces) # Indentation guide - self.PythonCodeEditor.StyleSetSpec(wx.stc.STC_STYLE_INDENTGUIDE, "fore:#CDCDCD") + self.PythonCodeEditor.StyleSetSpec(stc.STC_STYLE_INDENTGUIDE, 'fore:#CDCDCD,size:%(size)d' % faces) # Python styles - self.PythonCodeEditor.StyleSetSpec(wx.stc.STC_P_DEFAULT, 'fore:#000000') + self.PythonCodeEditor.StyleSetSpec(stc.STC_P_DEFAULT, 'fore:#000000,size:%(size)d' % faces) # Comments - self.PythonCodeEditor.StyleSetSpec(wx.stc.STC_P_COMMENTLINE, 'fore:#008000,back:#F0FFF0') - self.PythonCodeEditor.StyleSetSpec(wx.stc.STC_P_COMMENTBLOCK, 'fore:#008000,back:#F0FFF0') + self.PythonCodeEditor.StyleSetSpec(stc.STC_P_COMMENTLINE, 'fore:#008000,back:#F0FFF0,size:%(size)d' % faces) + self.PythonCodeEditor.StyleSetSpec(stc.STC_P_COMMENTBLOCK, 'fore:#008000,back:#F0FFF0,size:%(size)d' % faces) # Numbers - self.PythonCodeEditor.StyleSetSpec(wx.stc.STC_P_NUMBER, 'fore:#008080') + self.PythonCodeEditor.StyleSetSpec(stc.STC_P_NUMBER, 'fore:#008080,size:%(size)d' % faces) # Strings and characters - self.PythonCodeEditor.StyleSetSpec(wx.stc.STC_P_STRING, 'fore:#800080') - self.PythonCodeEditor.StyleSetSpec(wx.stc.STC_P_CHARACTER, 'fore:#800080') + self.PythonCodeEditor.StyleSetSpec(stc.STC_P_STRING, 'fore:#800080,size:%(size)d' % faces) + self.PythonCodeEditor.StyleSetSpec(stc.STC_P_CHARACTER, 'fore:#800080,size:%(size)d' % faces) # Keywords - self.PythonCodeEditor.StyleSetSpec(wx.stc.STC_P_WORD, 'fore:#000080,bold') + self.PythonCodeEditor.StyleSetSpec(stc.STC_P_WORD, 'fore:#000080,bold,size:%(size)d' % faces) # Triple quotes - self.PythonCodeEditor.StyleSetSpec(wx.stc.STC_P_TRIPLE, 'fore:#800080,back:#FFFFEA') - self.PythonCodeEditor.StyleSetSpec(wx.stc.STC_P_TRIPLEDOUBLE, 'fore:#800080,back:#FFFFEA') + self.PythonCodeEditor.StyleSetSpec(stc.STC_P_TRIPLE, 'fore:#800080,back:#FFFFEA,size:%(size)d' % faces) + self.PythonCodeEditor.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, 'fore:#800080,back:#FFFFEA,size:%(size)d' % faces) # Class names - self.PythonCodeEditor.StyleSetSpec(wx.stc.STC_P_CLASSNAME, 'fore:#0000FF,bold') + self.PythonCodeEditor.StyleSetSpec(stc.STC_P_CLASSNAME, 'fore:#0000FF,bold,size:%(size)d' % faces) # Function names - self.PythonCodeEditor.StyleSetSpec(wx.stc.STC_P_DEFNAME, 'fore:#008080,bold') + self.PythonCodeEditor.StyleSetSpec(stc.STC_P_DEFNAME, 'fore:#008080,bold,size:%(size)d' % faces) # Operators - self.PythonCodeEditor.StyleSetSpec(wx.stc.STC_P_OPERATOR, 'fore:#800000,bold') + self.PythonCodeEditor.StyleSetSpec(stc.STC_P_OPERATOR, 'fore:#800000,bold,size:%(size)d' % faces) # Identifiers. I leave this as not bold because everything seems # to be an identifier if it doesn't match the above criterae - self.PythonCodeEditor.StyleSetSpec(wx.stc.STC_P_IDENTIFIER, 'fore:#000000') - + self.PythonCodeEditor.StyleSetSpec(stc.STC_P_IDENTIFIER, 'fore:#000000,size:%(size)d' % faces) + + # Highlighting styles + self.PythonCodeEditor.StyleSetSpec(STC_PYTHON_ERROR, 'fore:#FF0000,back:#FFFF00,size:%(size)d' % faces) + self.PythonCodeEditor.StyleSetSpec(STC_PYTHON_SEARCH_RESULT, 'fore:#FFFFFF,back:#FFA500,size:%(size)d' % faces) + # Caret color self.PythonCodeEditor.SetCaretForeground("BLUE") # Selection background @@ -219,13 +189,13 @@ # EOL: Since we are loading/saving ourselves, and the # strings will always have \n's in them, set the STC to # edit them that way. - self.PythonCodeEditor.SetEOLMode(wx.stc.STC_EOL_LF) + self.PythonCodeEditor.SetEOLMode(stc.STC_EOL_LF) self.PythonCodeEditor.SetViewEOL(False) # No right-edge mode indicator self.PythonCodeEditor.SetEdgeMode(stc.STC_EDGE_NONE) - self.PythonCodeEditor.SetModEventMask(wx.stc.STC_MOD_BEFOREINSERT|wx.stc.STC_MOD_BEFOREDELETE) + self.PythonCodeEditor.SetModEventMask(stc.STC_MOD_BEFOREINSERT|stc.STC_MOD_BEFOREDELETE) self.PythonCodeEditor.Bind(wx.stc.EVT_STC_DO_DROP, self.OnDoDrop, id=ID_PYTHONEDITOR) self.PythonCodeEditor.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus) @@ -239,6 +209,14 @@ self.DisableEvents = False self.CurrentAction = None + self.Highlights = [] + self.SearchParams = None + self.SearchResults = None + self.CurrentFindHighlight = None + + self.RefreshHighlightsTimer = wx.Timer(self, -1) + self.Bind(wx.EVT_TIMER, self.OnRefreshHighlightsTimer, self.RefreshHighlightsTimer) + def GetBufferState(self): return self.Controler.GetBufferState() @@ -305,19 +283,24 @@ self.ResetBuffer() self.DisableEvents = True old_cursor_pos = self.PythonCodeEditor.GetCurrentPos() + line = self.PythonCodeEditor.GetFirstVisibleLine() + column = self.PythonCodeEditor.GetXOffset() old_text = self.PythonCodeEditor.GetText() new_text = self.Controler.GetPythonCode() - self.PythonCodeEditor.SetText(new_text) - new_cursor_pos = GetCursorPos(old_text, new_text) - if new_cursor_pos != None: - self.PythonCodeEditor.GotoPos(new_cursor_pos) - else: - self.PythonCodeEditor.GotoPos(old_cursor_pos) - self.PythonCodeEditor.ScrollToColumn(0) - self.PythonCodeEditor.EmptyUndoBuffer() + if old_text != new_text: + self.PythonCodeEditor.SetText(new_text) + new_cursor_pos = GetCursorPos(old_text, new_text) + self.PythonCodeEditor.LineScroll(column, line) + if new_cursor_pos != None: + self.PythonCodeEditor.GotoPos(new_cursor_pos) + else: + self.PythonCodeEditor.GotoPos(old_cursor_pos) + self.PythonCodeEditor.EmptyUndoBuffer() self.DisableEvents = False self.PythonCodeEditor.Colourise(0, -1) + + self.ShowHighlights() def RefreshModel(self): self.Controler.SetPythonCode(self.PythonCodeEditor.GetText()) @@ -338,7 +321,7 @@ self.PythonCodeEditor.AutoCompShow(0, " ".join([word + "?1" for word in keyword.kwlist])) else: event.Skip() - + def OnKillFocus(self, event): self.PythonCodeEditor.AutoCompCancel() event.Skip() @@ -483,3 +466,89 @@ self.DisableEvents = False self.RefreshModel() self.RefreshBuffer() + + def Find(self, direction, search_params): + if self.SearchParams != search_params: + self.ClearHighlights(SEARCH_RESULT_HIGHLIGHT) + + self.SearchParams = search_params + criteria = { + "raw_pattern": search_params["find_pattern"], + "pattern": re.compile(search_params["find_pattern"]), + "case_sensitive": search_params["case_sensitive"], + "regular_expression": search_params["regular_expression"], + "filter": "all"} + + self.SearchResults = [ + (start, end, SEARCH_RESULT_HIGHLIGHT) + for start, end, text in + TestTextElement(self.PythonCodeEditor.GetText(), criteria)] + self.CurrentFindHighlight = None + + if len(self.SearchResults) > 0: + if self.CurrentFindHighlight is not None: + old_idx = self.SearchResults.index(self.CurrentFindHighlight) + if self.SearchParams["wrap"]: + idx = (old_idx + direction) % len(self.SearchResults) + else: + idx = max(0, min(old_idx + direction, len(self.SearchResults) - 1)) + if idx != old_idx: + self.RemoveHighlight(*self.CurrentFindHighlight) + self.CurrentFindHighlight = self.SearchResults[idx] + self.AddHighlight(*self.CurrentFindHighlight) + else: + self.CurrentFindHighlight = self.SearchResults[0] + self.AddHighlight(*self.CurrentFindHighlight) + + else: + if self.CurrentFindHighlight is not None: + self.RemoveHighlight(*self.CurrentFindHighlight) + self.CurrentFindHighlight = None + +#------------------------------------------------------------------------------- +# Highlights showing functions +#------------------------------------------------------------------------------- + + def OnRefreshHighlightsTimer(self, event): + self.RefreshView() + event.Skip() + + def ClearHighlights(self, highlight_type=None): + if highlight_type is None: + self.Highlights = [] + else: + highlight_type = HIGHLIGHT_TYPES.get(highlight_type, None) + if highlight_type is not None: + self.Highlights = [(start, end, highlight) for (start, end, highlight) in self.Highlights if highlight != highlight_type] + self.RefreshView() + + def AddHighlight(self, start, end, highlight_type): + highlight_type = HIGHLIGHT_TYPES.get(highlight_type, None) + if highlight_type is not None: + self.Highlights.append((start, end, highlight_type)) + self.PythonCodeEditor.GotoPos(self.PythonCodeEditor.PositionFromLine(start[0]) + start[1]) + self.RefreshHighlightsTimer.Start(int(REFRESH_HIGHLIGHT_PERIOD * 1000), oneShot=True) + self.RefreshView() + + def RemoveHighlight(self, start, end, highlight_type): + highlight_type = HIGHLIGHT_TYPES.get(highlight_type, None) + if (highlight_type is not None and + (start, end, highlight_type) in self.Highlights): + self.Highlights.remove((start, end, highlight_type)) + self.RefreshHighlightsTimer.Start(int(REFRESH_HIGHLIGHT_PERIOD * 1000), oneShot=True) + + def ShowHighlights(self): + for start, end, highlight_type in self.Highlights: + if start[0] == 0: + highlight_start_pos = start[1] + else: + highlight_start_pos = self.PythonCodeEditor.GetLineEndPosition(start[0] - 1) + start[1] + 1 + if end[0] == 0: + highlight_end_pos = end[1] - indent + 1 + else: + highlight_end_pos = self.PythonCodeEditor.GetLineEndPosition(end[0] - 1) + end[1] + 2 + self.PythonCodeEditor.StartStyling(highlight_start_pos, 0xff) + self.PythonCodeEditor.SetStyling(highlight_end_pos - highlight_start_pos, highlight_type) + self.PythonCodeEditor.StartStyling(highlight_start_pos, 0x00) + self.PythonCodeEditor.SetStyling(len(self.PythonCodeEditor.GetText()) - highlight_end_pos, stc.STC_STYLE_DEFAULT) + diff -r b0ac30ba7eaf -r fd7c9a7cf882 py_ext/PythonFileCTNMixin.py --- a/py_ext/PythonFileCTNMixin.py Wed Apr 24 18:34:00 2013 +0900 +++ b/py_ext/PythonFileCTNMixin.py Wed Apr 24 17:37:46 2013 +0200 @@ -48,7 +48,7 @@ def CTNTestModified(self): return self.ChangesToSave or not self.PythonIsSaved() - def OnCTNSave(self): + def OnCTNSave(self, from_project_path=None): filepath = self.PythonFileName() text = "\n" diff -r b0ac30ba7eaf -r fd7c9a7cf882 svgui/svgui.py --- a/svgui/svgui.py Wed Apr 24 18:34:00 2013 +0900 +++ b/svgui/svgui.py Wed Apr 24 17:37:46 2013 +0200 @@ -5,12 +5,13 @@ from POULibrary import POULibrary from docutil import open_svg +from py_ext import PythonFileCTNMixin class SVGUILibrary(POULibrary): def GetLibraryPath(self): return os.path.join(os.path.split(__file__)[0], "pous.xml") -class SVGUI: +class SVGUI(PythonFileCTNMixin): ConfNodeMethods = [ {"bitmap" : "ImportSVG", @@ -26,13 +27,21 @@ def ConfNodePath(self): return os.path.join(os.path.dirname(__file__)) - def _getSVGpath(self): - # define name for IEC raw code file - return os.path.join(self.CTNPath(), "gui.svg") + def _getSVGpath(self, project_path=None): + if project_path is None: + project_path = self.CTNPath() + # define name for SVG file containing gui layout + return os.path.join(project_path, "gui.svg") def _getSVGUIserverpath(self): return os.path.join(os.path.dirname(__file__), "svgui_server.py") + def OnCTNSave(self, from_project_path=None): + if from_project_path is not None: + shutil.copyfile(self._getSVGpath(from_project_path), + self._getSVGpath()) + return PythonFileCTNMixin.OnCTNSave(self, from_project_path) + def CTNGenerate_C(self, buildpath, locations): """ Return C code generated by iec2c compiler diff -r b0ac30ba7eaf -r fd7c9a7cf882 wxglade_hmi/wxglade_hmi.py --- a/wxglade_hmi/wxglade_hmi.py Wed Apr 24 18:34:00 2013 +0900 +++ b/wxglade_hmi/wxglade_hmi.py Wed Apr 24 17:37:46 2013 +0200 @@ -1,5 +1,5 @@ import wx -import os, sys +import os, sys, shutil from xml.dom import minidom from py_ext import PythonFileCTNMixin @@ -16,9 +16,11 @@ def ConfNodePath(self): return os.path.join(os.path.dirname(__file__)) - def _getWXGLADEpath(self): - # define name for IEC raw code file - return os.path.join(self.CTNPath(), "hmi.wxg") + def _getWXGLADEpath(self, project_path=None): + if project_path is None: + project_path = self.CTNPath() + # define name for wxGlade gui file + return os.path.join(project_path, "hmi.wxg") def launch_wxglade(self, options, wait=False): from wxglade import __file__ as fileName @@ -29,6 +31,11 @@ mode = {False:os.P_NOWAIT, True:os.P_WAIT}[wait] os.spawnv(mode, sys.executable, ["\"%s\""%sys.executable] + [glade] + options) + def OnCTNSave(self, from_project_path=None): + if from_project_path is not None: + shutil.copyfile(self._getWXGLADEpath(from_project_path), + self._getWXGLADEpath()) + return PythonFileCTNMixin.OnCTNSave(self, from_project_path) def CTNGenerate_C(self, buildpath, locations): """ @@ -128,3 +135,4 @@ if wx.Platform == '__WXMSW__': wxg_filename = "\"%s\""%wxg_filename self.launch_wxglade([wxg_filename]) +