1 #!/usr/bin/env python |
1 #!/usr/bin/env python |
2 # -*- coding: utf-8 -*- |
2 # -*- coding: utf-8 -*- |
3 |
3 |
4 #This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor |
4 # This file is part of Beremiz, a Integrated Development Environment for |
5 #based on the plcopen standard. |
5 # programming IEC 61131-3 automates supporting plcopen standard and CanFestival. |
6 # |
6 # |
7 #Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD |
7 # Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD |
8 # |
8 # |
9 #See COPYING file for copyrights details. |
9 # See COPYING file for copyrights details. |
10 # |
10 # |
11 #This library is free software; you can redistribute it and/or |
11 # This program is free software; you can redistribute it and/or |
12 #modify it under the terms of the GNU General Public |
12 # modify it under the terms of the GNU General Public License |
13 #License as published by the Free Software Foundation; either |
13 # as published by the Free Software Foundation; either version 2 |
14 #version 2.1 of the License, or (at your option) any later version. |
14 # of the License, or (at your option) any later version. |
15 # |
15 # |
16 #This library is distributed in the hope that it will be useful, |
16 # This program is distributed in the hope that it will be useful, |
17 #but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 # but WITHOUT ANY WARRANTY; without even the implied warranty of |
18 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
18 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
19 #General Public License for more details. |
19 # GNU General Public License for more details. |
20 # |
20 # |
21 #You should have received a copy of the GNU General Public |
21 # You should have received a copy of the GNU General Public License |
22 #License along with this library; if not, write to the Free Software |
22 # along with this program; if not, write to the Free Software |
23 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
23 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. |
24 |
24 |
25 import re |
25 import re |
26 from types import * |
26 from types import * |
27 |
27 |
28 import wx |
28 import wx |
45 LETTERS.append(chr(ord('a') + i)) |
45 LETTERS.append(chr(ord('a') + i)) |
46 LETTERS.append(chr(ord('A') + i)) |
46 LETTERS.append(chr(ord('A') + i)) |
47 |
47 |
48 [STC_PLC_WORD, STC_PLC_COMMENT, STC_PLC_NUMBER, STC_PLC_STRING, |
48 [STC_PLC_WORD, STC_PLC_COMMENT, STC_PLC_NUMBER, STC_PLC_STRING, |
49 STC_PLC_VARIABLE, STC_PLC_PARAMETER, STC_PLC_FUNCTION, STC_PLC_JUMP, |
49 STC_PLC_VARIABLE, STC_PLC_PARAMETER, STC_PLC_FUNCTION, STC_PLC_JUMP, |
50 STC_PLC_ERROR, STC_PLC_SEARCH_RESULT] = range(10) |
50 STC_PLC_ERROR, STC_PLC_SEARCH_RESULT, |
|
51 STC_PLC_EMPTY] = range(11) |
51 [SPACE, WORD, NUMBER, STRING, WSTRING, COMMENT, PRAGMA, DPRAGMA] = range(8) |
52 [SPACE, WORD, NUMBER, STRING, WSTRING, COMMENT, PRAGMA, DPRAGMA] = range(8) |
52 |
53 |
53 [ID_TEXTVIEWER, ID_TEXTVIEWERTEXTCTRL, |
54 [ID_TEXTVIEWER, ID_TEXTVIEWERTEXTCTRL, |
54 ] = [wx.NewId() for _init_ctrls in range(2)] |
55 ] = [wx.NewId() for _init_ctrls in range(2)] |
55 |
56 |
256 blockinputs = values[3] |
257 blockinputs = values[3] |
257 else: |
258 else: |
258 blockinputs = None |
259 blockinputs = None |
259 if values[1] != "function": |
260 if values[1] != "function": |
260 if blockname == "": |
261 if blockname == "": |
261 dialog = wx.TextEntryDialog(self.ParentWindow, "Block name", "Please enter a block name", "", wx.OK|wx.CANCEL|wx.CENTRE) |
262 dialog = wx.TextEntryDialog(self.ParentWindow, _("Block name"), _("Please enter a block name"), "", wx.OK|wx.CANCEL|wx.CENTRE) |
262 if dialog.ShowModal() == wx.ID_OK: |
263 if dialog.ShowModal() == wx.ID_OK: |
263 blockname = dialog.GetValue() |
264 blockname = dialog.GetValue() |
264 else: |
265 else: |
|
266 event.SetDragText("") |
265 return |
267 return |
266 dialog.Destroy() |
268 dialog.Destroy() |
267 if blockname.upper() in [name.upper() for name in self.Controler.GetProjectPouNames(self.Debug)]: |
269 if blockname.upper() in [name.upper() for name in self.Controler.GetProjectPouNames(self.Debug)]: |
268 message = _("\"%s\" pou already exists!")%blockname |
270 message = _("\"%s\" pou already exists!")%blockname |
269 elif blockname.upper() in [name.upper() for name in self.Controler.GetEditedElementVariables(self.TagName, self.Debug)]: |
271 elif blockname.upper() in [name.upper() for name in self.Controler.GetEditedElementVariables(self.TagName, self.Debug)]: |
410 def SetKeywords(self, keywords): |
412 def SetKeywords(self, keywords): |
411 self.Keywords = [keyword.upper() for keyword in keywords] |
413 self.Keywords = [keyword.upper() for keyword in keywords] |
412 self.Colourise(0, -1) |
414 self.Colourise(0, -1) |
413 |
415 |
414 def RefreshJumpList(self): |
416 def RefreshJumpList(self): |
415 if self.TextSyntax != "IL": |
417 if self.TextSyntax == "IL": |
416 self.Jumps = [jump.upper() for jump in LABEL_MODEL.findall(self.GetText())] |
418 self.Jumps = [jump.upper() for jump in LABEL_MODEL.findall(self.GetText())] |
417 self.Colourise(0, -1) |
419 self.Colourise(0, -1) |
418 |
420 |
419 # Buffer the last model state |
421 # Buffer the last model state |
420 def RefreshBuffer(self): |
422 def RefreshBuffer(self): |
591 elif self.TextSyntax == "IL" and word in self.Jumps: |
593 elif self.TextSyntax == "IL" and word in self.Jumps: |
592 self.SetStyling(current_pos - last_styled_pos, STC_PLC_JUMP) |
594 self.SetStyling(current_pos - last_styled_pos, STC_PLC_JUMP) |
593 elif word in self.EnumeratedValues: |
595 elif word in self.EnumeratedValues: |
594 self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER) |
596 self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER) |
595 else: |
597 else: |
596 self.SetStyling(current_pos - last_styled_pos, 31) |
598 self.SetStyling(current_pos - last_styled_pos, STC_PLC_EMPTY) |
597 if word not in ["]", ")"] and (self.GetCurrentPos() < last_styled_pos or self.GetCurrentPos() > current_pos): |
599 if word not in ["]", ")"] and (self.GetCurrentPos() < last_styled_pos or self.GetCurrentPos() > current_pos): |
598 self.StartStyling(last_styled_pos, wx.stc.STC_INDICS_MASK) |
600 self.StartStyling(last_styled_pos, wx.stc.STC_INDICS_MASK) |
599 self.SetStyling(current_pos - last_styled_pos, wx.stc.STC_INDIC0_MASK) |
601 self.SetStyling(current_pos - last_styled_pos, wx.stc.STC_INDIC0_MASK) |
600 self.StartStyling(current_pos, 0xff) |
602 self.StartStyling(current_pos, 0xff) |
601 else: |
603 else: |
602 self.SetStyling(current_pos - last_styled_pos, 31) |
604 self.SetStyling(current_pos - last_styled_pos, STC_PLC_EMPTY) |
603 last_styled_pos = current_pos |
605 last_styled_pos = current_pos |
604 if state != DPRAGMA: |
606 if (state != DPRAGMA) and (state != COMMENT): |
605 state = SPACE |
607 state = SPACE |
606 line = "" |
608 line = "" |
607 line_number += 1 |
609 line_number += 1 |
608 self.RefreshLineFolding(line_number) |
610 self.RefreshLineFolding(line_number) |
609 elif line.endswith("(*") and state != COMMENT: |
611 elif line.endswith("(*") and state != COMMENT: |
610 self.SetStyling(current_pos - last_styled_pos - 1, 31) |
612 self.SetStyling(current_pos - last_styled_pos - 1, STC_PLC_EMPTY) |
611 last_styled_pos = current_pos |
613 last_styled_pos = current_pos |
612 if state == WORD: |
614 if state == WORD: |
613 current_context = self.Variables |
615 current_context = self.Variables |
614 state = COMMENT |
616 state = COMMENT |
615 elif line.endswith("{") and state not in [PRAGMA, DPRAGMA]: |
617 elif line.endswith("{") and state not in [PRAGMA, DPRAGMA]: |
616 self.SetStyling(current_pos - last_styled_pos, 31) |
618 self.SetStyling(current_pos - last_styled_pos, STC_PLC_EMPTY) |
617 last_styled_pos = current_pos |
619 last_styled_pos = current_pos |
618 if state == WORD: |
620 if state == WORD: |
619 current_context = self.Variables |
621 current_context = self.Variables |
620 state = PRAGMA |
622 state = PRAGMA |
621 elif line.endswith("{{") and state == PRAGMA: |
623 elif line.endswith("{{") and state == PRAGMA: |
622 self.SetStyling(current_pos - last_styled_pos, 31) |
624 self.SetStyling(current_pos - last_styled_pos, STC_PLC_EMPTY) |
623 last_styled_pos = current_pos |
625 last_styled_pos = current_pos |
624 state = DPRAGMA |
626 state = DPRAGMA |
625 elif state == COMMENT: |
627 elif state == COMMENT: |
626 if line.endswith("*)"): |
628 if line.endswith("*)"): |
627 self.SetStyling(current_pos - last_styled_pos + 2, STC_PLC_COMMENT) |
629 self.SetStyling(current_pos - last_styled_pos + 2, STC_PLC_COMMENT) |
628 last_styled_pos = current_pos + 1 |
630 last_styled_pos = current_pos + 1 |
629 state = SPACE |
631 state = SPACE |
|
632 if len(self.CallStack) > 0: |
|
633 current_call = self.CallStack.pop() |
|
634 else: |
|
635 current_call = None |
630 elif state == PRAGMA: |
636 elif state == PRAGMA: |
631 if line.endswith("}"): |
637 if line.endswith("}"): |
632 self.SetStyling(current_pos - last_styled_pos, 31) |
638 self.SetStyling(current_pos - last_styled_pos, STC_PLC_EMPTY) |
633 last_styled_pos = current_pos |
639 last_styled_pos = current_pos |
634 state = SPACE |
640 state = SPACE |
635 elif state == DPRAGMA: |
641 elif state == DPRAGMA: |
636 if line.endswith("}}"): |
642 if line.endswith("}}"): |
637 self.SetStyling(current_pos - last_styled_pos + 1, 31) |
643 self.SetStyling(current_pos - last_styled_pos + 1, STC_PLC_EMPTY) |
638 last_styled_pos = current_pos + 1 |
644 last_styled_pos = current_pos + 1 |
639 state = SPACE |
645 state = SPACE |
640 elif (line.endswith("'") or line.endswith('"')) and state not in [STRING, WSTRING]: |
646 elif (line.endswith("'") or line.endswith('"')) and state not in [STRING, WSTRING]: |
641 self.SetStyling(current_pos - last_styled_pos, 31) |
647 self.SetStyling(current_pos - last_styled_pos, STC_PLC_EMPTY) |
642 last_styled_pos = current_pos |
648 last_styled_pos = current_pos |
643 if state == WORD: |
649 if state == WORD: |
644 current_context = self.Variables |
650 current_context = self.Variables |
645 if line.endswith("'"): |
651 if line.endswith("'"): |
646 state = STRING |
652 state = STRING |
690 elif self.TextSyntax == "IL" and word in self.Jumps: |
696 elif self.TextSyntax == "IL" and word in self.Jumps: |
691 self.SetStyling(current_pos - last_styled_pos, STC_PLC_JUMP) |
697 self.SetStyling(current_pos - last_styled_pos, STC_PLC_JUMP) |
692 elif word in self.EnumeratedValues: |
698 elif word in self.EnumeratedValues: |
693 self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER) |
699 self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER) |
694 else: |
700 else: |
695 self.SetStyling(current_pos - last_styled_pos, 31) |
701 self.SetStyling(current_pos - last_styled_pos, STC_PLC_EMPTY) |
696 if word not in ["]", ")"] and (self.GetCurrentPos() < last_styled_pos or self.GetCurrentPos() > current_pos): |
702 if word not in ["]", ")"] and (self.GetCurrentPos() < last_styled_pos or self.GetCurrentPos() > current_pos): |
697 self.StartStyling(last_styled_pos, wx.stc.STC_INDICS_MASK) |
703 self.StartStyling(last_styled_pos, wx.stc.STC_INDICS_MASK) |
698 self.SetStyling(current_pos - last_styled_pos, wx.stc.STC_INDIC0_MASK) |
704 self.SetStyling(current_pos - last_styled_pos, wx.stc.STC_INDIC0_MASK) |
699 self.StartStyling(current_pos, 0xff) |
705 self.StartStyling(current_pos, 0xff) |
700 if char == '.': |
706 if char == '.': |
754 elif word in self.Jumps: |
760 elif word in self.Jumps: |
755 self.SetStyling(current_pos - last_styled_pos, STC_PLC_JUMP) |
761 self.SetStyling(current_pos - last_styled_pos, STC_PLC_JUMP) |
756 elif word in self.EnumeratedValues: |
762 elif word in self.EnumeratedValues: |
757 self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER) |
763 self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER) |
758 else: |
764 else: |
759 self.SetStyling(current_pos - last_styled_pos, 31) |
765 self.SetStyling(current_pos - last_styled_pos, STC_PLC_EMPTY) |
760 else: |
766 else: |
761 self.SetStyling(current_pos - start_pos, 31) |
767 self.SetStyling(current_pos - start_pos, STC_PLC_EMPTY) |
762 self.ShowHighlights(start_pos, end_pos) |
768 self.ShowHighlights(start_pos, end_pos) |
763 event.Skip() |
769 event.Skip() |
764 |
770 |
765 def OnMarginClick(self, event): |
771 def OnMarginClick(self, event): |
766 if event.GetMargin() == 2: |
772 if event.GetMargin() == 2: |
802 def Find(self, direction, search_params): |
808 def Find(self, direction, search_params): |
803 if self.SearchParams != search_params: |
809 if self.SearchParams != search_params: |
804 self.ClearHighlights(SEARCH_RESULT_HIGHLIGHT) |
810 self.ClearHighlights(SEARCH_RESULT_HIGHLIGHT) |
805 |
811 |
806 self.SearchParams = search_params |
812 self.SearchParams = search_params |
807 criteria = { |
|
808 "raw_pattern": search_params["find_pattern"], |
|
809 "pattern": re.compile(search_params["find_pattern"]), |
|
810 "case_sensitive": search_params["case_sensitive"], |
|
811 "regular_expression": search_params["regular_expression"], |
|
812 "filter": "all"} |
|
813 |
|
814 self.SearchResults = [ |
813 self.SearchResults = [ |
815 (infos[1:], start, end, SEARCH_RESULT_HIGHLIGHT) |
814 (infos[1:], start, end, SEARCH_RESULT_HIGHLIGHT) |
816 for infos, start, end, text in |
815 for infos, start, end, text in |
817 self.Search(criteria)] |
816 self.Search(search_params)] |
818 self.CurrentFindHighlight = None |
817 self.CurrentFindHighlight = None |
819 |
818 |
820 if len(self.SearchResults) > 0: |
819 if len(self.SearchResults) > 0: |
821 if self.CurrentFindHighlight is not None: |
820 if self.CurrentFindHighlight is not None: |
822 old_idx = self.SearchResults.index(self.CurrentFindHighlight) |
821 old_idx = self.SearchResults.index(self.CurrentFindHighlight) |
893 indent = (indent / 2 + 1) * 2 |
892 indent = (indent / 2 + 1) * 2 |
894 self.Editor.AddText("\n" + " " * indent) |
893 self.Editor.AddText("\n" + " " * indent) |
895 key_handled = True |
894 key_handled = True |
896 elif key == wx.WXK_BACK: |
895 elif key == wx.WXK_BACK: |
897 if self.TextSyntax in ["ST", "ALL"]: |
896 if self.TextSyntax in ["ST", "ALL"]: |
898 indent = self.Editor.GetLineIndentation(line) |
897 if not self.Editor.GetSelectedText(): |
899 if lineText.strip() == "" and indent > 0: |
898 indent = self.Editor.GetColumn(self.Editor.GetCurrentPos()) |
900 self.Editor.DelLineLeft() |
899 if lineText.strip() == "" and len(lineText) > 0 and indent > 0: |
901 self.Editor.AddText(" " * ((max(0, indent - 1) / 2) * 2)) |
900 self.Editor.DelLineLeft() |
902 key_handled = True |
901 self.Editor.AddText(" " * ((max(0, indent - 1) / 2) * 2)) |
|
902 key_handled = True |
903 if not key_handled: |
903 if not key_handled: |
904 event.Skip() |
904 event.Skip() |
905 elif key in NAVIGATION_KEYS: |
905 else: |
906 event.Skip() |
906 event.Skip() |
907 |
907 |
908 def OnKillFocus(self, event): |
908 def OnKillFocus(self, event): |
909 self.Editor.AutoCompCancel() |
909 self.Editor.AutoCompCancel() |
910 event.Skip() |
910 event.Skip() |