4 import wx.grid |
4 import wx.grid |
5 import wx.stc as stc |
5 import wx.stc as stc |
6 import wx.lib.buttons |
6 import wx.lib.buttons |
7 |
7 |
8 from plcopen.plcopen import TestTextElement |
8 from plcopen.plcopen import TestTextElement |
9 from plcopen.structures import TestIdentifier, IEC_KEYWORDS |
9 from plcopen.structures import TestIdentifier, IEC_KEYWORDS, DefaultType |
10 from controls import CustomGrid, CustomTable |
10 from controls import CustomGrid, CustomTable |
11 from editors.ConfTreeNodeEditor import ConfTreeNodeEditor |
11 from editors.ConfTreeNodeEditor import ConfTreeNodeEditor |
12 from util.BitmapLibrary import GetBitmap |
12 from util.BitmapLibrary import GetBitmap |
13 from controls.CustomStyledTextCtrl import CustomStyledTextCtrl, faces, GetCursorPos, NAVIGATION_KEYS |
13 from controls.CustomStyledTextCtrl import CustomStyledTextCtrl, faces, GetCursorPos, NAVIGATION_KEYS |
14 from controls.VariablePanel import VARIABLE_NAME_SUFFIX_MODEL |
14 from controls.VariablePanel import VARIABLE_NAME_SUFFIX_MODEL |
15 from graphics.GraphicCommons import ERROR_HIGHLIGHT, SEARCH_RESULT_HIGHLIGHT, REFRESH_HIGHLIGHT_PERIOD |
15 from graphics.GraphicCommons import ERROR_HIGHLIGHT, SEARCH_RESULT_HIGHLIGHT, REFRESH_HIGHLIGHT_PERIOD |
16 |
16 |
17 [STC_CODE_ERROR, STC_CODE_SEARCH_RESULT, |
17 [STC_CODE_ERROR, STC_CODE_SEARCH_RESULT, |
18 STC_CODE_SECTION] = range(15, 18) |
18 STC_CODE_SECTION] = range(15, 18) |
19 |
19 |
20 HIGHLIGHT_TYPES = { |
20 HIGHLIGHT_TYPES = { |
21 ERROR_HIGHLIGHT: STC_CODE_ERROR, |
21 ERROR_HIGHLIGHT: STC_CODE_ERROR, |
22 SEARCH_RESULT_HIGHLIGHT: STC_CODE_SEARCH_RESULT, |
22 SEARCH_RESULT_HIGHLIGHT: STC_CODE_SEARCH_RESULT, |
23 } |
23 } |
24 |
24 |
25 EDGE_COLUMN = 80 |
25 EDGE_COLUMN = 80 |
26 |
26 |
27 class CodeEditor(CustomStyledTextCtrl): |
27 class CodeEditor(CustomStyledTextCtrl): |
28 |
28 |
29 KEYWORDS = [] |
29 KEYWORDS = [] |
30 COMMENT_HEADER = "" |
30 COMMENT_HEADER = "" |
31 |
31 |
32 def __init__(self, parent, window, controler): |
32 def __init__(self, parent, window, controler): |
33 CustomStyledTextCtrl.__init__(self, parent, -1, wx.DefaultPosition, |
33 CustomStyledTextCtrl.__init__(self, parent, -1, wx.DefaultPosition, |
34 wx.Size(-1, 300), 0) |
34 wx.Size(-1, 300), 0) |
35 |
35 |
36 self.SetMarginType(1, stc.STC_MARGIN_NUMBER) |
36 self.SetMarginType(1, stc.STC_MARGIN_NUMBER) |
37 self.SetMarginWidth(1, 25) |
37 self.SetMarginWidth(1, 25) |
38 |
38 |
39 self.SetProperty("fold", "1") |
39 self.SetProperty("fold", "1") |
40 self.SetProperty("tab.timmy.whinge.level", "1") |
40 self.SetProperty("tab.timmy.whinge.level", "1") |
41 self.SetMargins(0,0) |
41 self.SetMargins(0,0) |
42 |
42 |
43 self.SetViewWhiteSpace(False) |
43 self.SetViewWhiteSpace(False) |
44 |
44 |
45 self.SetEdgeMode(stc.STC_EDGE_BACKGROUND) |
45 self.SetEdgeMode(stc.STC_EDGE_BACKGROUND) |
46 self.SetEdgeColumn(EDGE_COLUMN) |
46 self.SetEdgeColumn(EDGE_COLUMN) |
47 |
47 |
48 # Setup a margin to hold fold markers |
48 # Setup a margin to hold fold markers |
49 self.SetMarginType(2, stc.STC_MARGIN_SYMBOL) |
49 self.SetMarginType(2, stc.STC_MARGIN_SYMBOL) |
57 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_VLINE, "white", "#808080") |
57 self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_VLINE, "white", "#808080") |
58 self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_LCORNER, "white", "#808080") |
58 self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_LCORNER, "white", "#808080") |
59 self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_BOXPLUSCONNECTED, "white", "#808080") |
59 self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_BOXPLUSCONNECTED, "white", "#808080") |
60 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_BOXMINUSCONNECTED, "white", "#808080") |
60 self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_BOXMINUSCONNECTED, "white", "#808080") |
61 self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNER, "white", "#808080") |
61 self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNER, "white", "#808080") |
62 |
62 |
63 self.Bind(stc.EVT_STC_UPDATEUI, self.OnUpdateUI) |
63 self.Bind(stc.EVT_STC_UPDATEUI, self.OnUpdateUI) |
64 self.Bind(stc.EVT_STC_MARGINCLICK, self.OnMarginClick) |
64 self.Bind(stc.EVT_STC_MARGINCLICK, self.OnMarginClick) |
65 self.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressed) |
65 self.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressed) |
66 |
66 |
67 # Make some styles, The lexer defines what each style is used for, we |
67 # Make some styles, The lexer defines what each style is used for, we |
76 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % faces) |
76 self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % faces) |
77 self.StyleSetSpec(stc.STC_STYLE_LINENUMBER, "back:#C0C0C0,face:%(helv)s,size:%(size)d" % faces) |
77 self.StyleSetSpec(stc.STC_STYLE_LINENUMBER, "back:#C0C0C0,face:%(helv)s,size:%(size)d" % faces) |
78 self.StyleSetSpec(stc.STC_STYLE_CONTROLCHAR, "face:%(mono)s" % faces) |
78 self.StyleSetSpec(stc.STC_STYLE_CONTROLCHAR, "face:%(mono)s" % faces) |
79 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, "fore:#FFFFFF,back:#0000FF,bold") |
79 self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, "fore:#FFFFFF,back:#0000FF,bold") |
80 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, "fore:#000000,back:#FF0000,bold") |
80 self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, "fore:#000000,back:#FF0000,bold") |
81 |
81 |
82 # Highlighting styles |
82 # Highlighting styles |
83 self.StyleSetSpec(STC_CODE_ERROR, 'fore:#FF0000,back:#FFFF00,size:%(size)d' % faces) |
83 self.StyleSetSpec(STC_CODE_ERROR, 'fore:#FF0000,back:#FFFF00,size:%(size)d' % faces) |
84 self.StyleSetSpec(STC_CODE_SEARCH_RESULT, 'fore:#FFFFFF,back:#FFA500,size:%(size)d' % faces) |
84 self.StyleSetSpec(STC_CODE_SEARCH_RESULT, 'fore:#FFFFFF,back:#FFA500,size:%(size)d' % faces) |
85 |
85 |
86 # Section style |
86 # Section style |
87 self.StyleSetSpec(STC_CODE_SECTION, 'fore:#808080,size:%(size)d') |
87 self.StyleSetSpec(STC_CODE_SECTION, 'fore:#808080,size:%(size)d') |
88 self.StyleSetChangeable(STC_CODE_SECTION, False) |
88 self.StyleSetChangeable(STC_CODE_SECTION, False) |
89 |
89 |
90 # Indentation size |
90 # Indentation size |
91 self.SetTabWidth(4) |
91 self.SetTabWidth(4) |
92 self.SetUseTabs(0) |
92 self.SetUseTabs(0) |
93 |
93 |
94 self.SetCodeLexer() |
94 self.SetCodeLexer() |
95 self.SetKeyWords(0, " ".join(self.KEYWORDS)) |
95 self.SetKeyWords(0, " ".join(self.KEYWORDS)) |
96 |
96 |
97 self.Controler = controler |
97 self.Controler = controler |
98 self.ParentWindow = window |
98 self.ParentWindow = window |
99 |
99 |
100 self.DisableEvents = True |
100 self.DisableEvents = True |
101 self.CurrentAction = None |
101 self.CurrentAction = None |
102 |
102 |
103 self.ResetSearchResults() |
103 self.ResetSearchResults() |
104 |
104 |
105 self.RefreshHighlightsTimer = wx.Timer(self, -1) |
105 self.RefreshHighlightsTimer = wx.Timer(self, -1) |
106 self.Bind(wx.EVT_TIMER, self.OnRefreshHighlightsTimer, self.RefreshHighlightsTimer) |
106 self.Bind(wx.EVT_TIMER, self.OnRefreshHighlightsTimer, self.RefreshHighlightsTimer) |
107 |
107 |
108 self.SectionsComments = {} |
108 self.SectionsComments = {} |
109 for section in self.Controler.SECTIONS_NAMES: |
109 for section in self.Controler.SECTIONS_NAMES: |
110 section_comment = " %s section " % (section) |
110 section_comment = " %s section " % (section) |
111 len_headers = EDGE_COLUMN - len(section_comment) |
111 len_headers = EDGE_COLUMN - len(section_comment) |
112 section_comment = self.COMMENT_HEADER * (len_headers / 2) + \ |
112 section_comment = self.COMMENT_HEADER * (len_headers / 2) + \ |
113 section_comment + \ |
113 section_comment + \ |
114 self.COMMENT_HEADER * (len_headers - len_headers / 2) |
114 self.COMMENT_HEADER * (len_headers - len_headers / 2) |
115 |
115 |
116 self.SectionsComments[section] = { |
116 self.SectionsComments[section] = { |
117 "comment": section_comment, |
117 "comment": section_comment, |
118 } |
118 } |
119 |
119 |
120 for i, section in enumerate(self.Controler.SECTIONS_NAMES): |
120 for i, section in enumerate(self.Controler.SECTIONS_NAMES): |
121 section_infos = self.SectionsComments[section] |
121 section_infos = self.SectionsComments[section] |
122 if i + 1 < len(self.Controler.SECTIONS_NAMES): |
122 if i + 1 < len(self.Controler.SECTIONS_NAMES): |
123 section_end = self.SectionsComments[ |
123 section_end = self.SectionsComments[ |
124 self.Controler.SECTIONS_NAMES[i + 1]]["comment"] |
124 self.Controler.SECTIONS_NAMES[i + 1]]["comment"] |
125 else: |
125 else: |
126 section_end = "$" |
126 section_end = "$" |
127 section_infos["pattern"] = re.compile( |
127 section_infos["pattern"] = re.compile( |
128 section_infos["comment"] + "(.*)" + |
128 section_infos["comment"] + "(.*)" + |
129 section_end, re.DOTALL) |
129 section_end, re.DOTALL) |
130 |
130 |
131 self.SetModEventMask(wx.stc.STC_MOD_BEFOREINSERT|wx.stc.STC_MOD_BEFOREDELETE) |
131 self.SetModEventMask(wx.stc.STC_MOD_BEFOREINSERT|wx.stc.STC_MOD_BEFOREDELETE) |
132 |
132 |
133 self.Bind(wx.stc.EVT_STC_DO_DROP, self.OnDoDrop) |
133 self.Bind(wx.stc.EVT_STC_DO_DROP, self.OnDoDrop) |
134 self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus) |
134 self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus) |
135 self.Bind(wx.stc.EVT_STC_MODIFIED, self.OnModification) |
135 self.Bind(wx.stc.EVT_STC_MODIFIED, self.OnModification) |
136 |
136 |
137 def SetCodeLexer(self): |
137 def SetCodeLexer(self): |
138 pass |
138 pass |
139 |
139 |
140 def ResetSearchResults(self): |
140 def ResetSearchResults(self): |
141 self.Highlights = [] |
141 self.Highlights = [] |
142 self.SearchParams = None |
142 self.SearchParams = None |
143 self.SearchResults = None |
143 self.SearchResults = None |
144 self.CurrentFindHighlight = None |
144 self.CurrentFindHighlight = None |
145 |
145 |
146 def OnModification(self, event): |
146 def OnModification(self, event): |
147 if not self.DisableEvents: |
147 if not self.DisableEvents: |
148 mod_type = event.GetModificationType() |
148 mod_type = event.GetModificationType() |
149 if not (mod_type&wx.stc.STC_PERFORMED_UNDO or mod_type&wx.stc.STC_PERFORMED_REDO): |
149 if not (mod_type&wx.stc.STC_PERFORMED_UNDO or mod_type&wx.stc.STC_PERFORMED_REDO): |
150 if mod_type&wx.stc.STC_MOD_BEFOREINSERT: |
150 if mod_type&wx.stc.STC_MOD_BEFOREINSERT: |
238 self.GotoPos(new_cursor_pos) |
238 self.GotoPos(new_cursor_pos) |
239 else: |
239 else: |
240 self.GotoPos(old_cursor_pos) |
240 self.GotoPos(old_cursor_pos) |
241 self.EmptyUndoBuffer() |
241 self.EmptyUndoBuffer() |
242 self.DisableEvents = False |
242 self.DisableEvents = False |
243 |
243 |
244 self.RefreshSectionStyling() |
244 self.RefreshSectionStyling() |
245 |
245 |
246 self.ShowHighlights() |
246 self.ShowHighlights() |
247 |
247 |
248 def RefreshSectionStyling(self): |
248 def RefreshSectionStyling(self): |
249 self.Colourise(0, -1) |
249 self.Colourise(0, -1) |
250 |
250 |
251 text = self.GetText() |
251 text = self.GetText() |
252 for line in xrange(self.GetLineCount()): |
252 for line in xrange(self.GetLineCount()): |
253 self.SetLineState(line, 0) |
253 self.SetLineState(line, 0) |
254 |
254 |
255 for section in self.Controler.SECTIONS_NAMES: |
255 for section in self.Controler.SECTIONS_NAMES: |
256 section_comments = self.SectionsComments[section] |
256 section_comments = self.SectionsComments[section] |
257 start_pos = text.find(section_comments["comment"]) |
257 start_pos = text.find(section_comments["comment"]) |
258 end_pos = start_pos + len(section_comments["comment"]) |
258 end_pos = start_pos + len(section_comments["comment"]) |
259 self.StartStyling(start_pos, 0xff) |
259 self.StartStyling(start_pos, 0xff) |
260 self.SetStyling(end_pos - start_pos, STC_CODE_SECTION) |
260 self.SetStyling(end_pos - start_pos, STC_CODE_SECTION) |
261 self.SetLineState(self.LineFromPosition(start_pos), 1) |
261 self.SetLineState(self.LineFromPosition(start_pos), 1) |
262 |
262 |
263 self.StartStyling(end_pos, 0x00) |
263 self.StartStyling(end_pos, 0x00) |
264 self.SetStyling(len(self.GetText()) - end_pos, stc.STC_STYLE_DEFAULT) |
264 self.SetStyling(len(self.GetText()) - end_pos, stc.STC_STYLE_DEFAULT) |
265 |
265 |
266 def DoGetBestSize(self): |
266 def DoGetBestSize(self): |
267 return self.ParentWindow.GetPanelBestSize() |
267 return self.ParentWindow.GetPanelBestSize() |
276 parts[section] = result.group(1) |
276 parts[section] = result.group(1) |
277 else: |
277 else: |
278 parts[section] = "" |
278 parts[section] = "" |
279 self.Controler.SetTextParts(parts) |
279 self.Controler.SetTextParts(parts) |
280 self.ResetSearchResults() |
280 self.ResetSearchResults() |
281 |
281 |
282 def OnKeyPressed(self, event): |
282 def OnKeyPressed(self, event): |
283 if self.CallTipActive(): |
283 if self.CallTipActive(): |
284 self.CallTipCancel() |
284 self.CallTipCancel() |
285 key = event.GetKeyCode() |
285 key = event.GetKeyCode() |
286 current_pos = self.GetCurrentPos() |
286 current_pos = self.GetCurrentPos() |
287 selected = self.GetSelection() |
287 selected = self.GetSelection() |
288 text_selected = selected[0] != selected[1] |
288 text_selected = selected[0] != selected[1] |
289 |
289 |
290 # Test if caret is before Windows like new line |
290 # Test if caret is before Windows like new line |
291 text = self.GetText() |
291 text = self.GetText() |
292 if current_pos < len(text) and ord(text[current_pos]) == 13: |
292 if current_pos < len(text) and ord(text[current_pos]) == 13: |
293 newline_size = 2 |
293 newline_size = 2 |
294 else: |
294 else: |
295 newline_size = 1 |
295 newline_size = 1 |
296 |
296 |
297 # Disable to type any character in section header lines |
297 # Disable to type any character in section header lines |
298 if (self.GetLineState(self.LineFromPosition(current_pos)) and |
298 if (self.GetLineState(self.LineFromPosition(current_pos)) and |
299 not text_selected and |
299 not text_selected and |
300 key not in NAVIGATION_KEYS + [ |
300 key not in NAVIGATION_KEYS + [ |
301 wx.WXK_RETURN, |
301 wx.WXK_RETURN, |
302 wx.WXK_NUMPAD_ENTER]): |
302 wx.WXK_NUMPAD_ENTER]): |
303 return |
303 return |
304 |
304 |
305 # Disable to delete line between code and header lines |
305 # Disable to delete line between code and header lines |
306 elif (self.GetCurLine()[0].strip() != "" and not text_selected and |
306 elif (self.GetCurLine()[0].strip() != "" and not text_selected and |
307 (key == wx.WXK_BACK and |
307 (key == wx.WXK_BACK and |
308 self.GetLineState(self.LineFromPosition(max(0, current_pos - 1))) or |
308 self.GetLineState(self.LineFromPosition(max(0, current_pos - 1))) or |
309 key in [wx.WXK_DELETE, wx.WXK_NUMPAD_DELETE] and |
309 key in [wx.WXK_DELETE, wx.WXK_NUMPAD_DELETE] and |
310 self.GetLineState(self.LineFromPosition(min(len(text), current_pos + newline_size))))): |
310 self.GetLineState(self.LineFromPosition(min(len(text), current_pos + newline_size))))): |
311 return |
311 return |
312 |
312 |
313 elif key == 32 and event.ControlDown(): |
313 elif key == 32 and event.ControlDown(): |
314 pos = self.GetCurrentPos() |
314 pos = self.GetCurrentPos() |
315 |
315 |
316 # Tips |
316 # Tips |
317 if event.ShiftDown(): |
317 if event.ShiftDown(): |
318 pass |
318 pass |
319 # Code completion |
319 # Code completion |
320 else: |
320 else: |
321 self.AutoCompSetIgnoreCase(False) # so this needs to match |
321 self.AutoCompSetIgnoreCase(False) # so this needs to match |
322 |
322 |
323 keywords = self.KEYWORDS + [var["Name"] |
323 keywords = self.KEYWORDS + [var["Name"] |
324 for var in self.Controler.GetVariables()] |
324 for var in self.Controler.GetVariables()] |
325 keywords.sort() |
325 keywords.sort() |
326 self.AutoCompShow(0, " ".join(keywords)) |
326 self.AutoCompShow(0, " ".join(keywords)) |
327 else: |
327 else: |
478 self.RefreshBuffer() |
478 self.RefreshBuffer() |
479 |
479 |
480 def Find(self, direction, search_params): |
480 def Find(self, direction, search_params): |
481 if self.SearchParams != search_params: |
481 if self.SearchParams != search_params: |
482 self.ClearHighlights(SEARCH_RESULT_HIGHLIGHT) |
482 self.ClearHighlights(SEARCH_RESULT_HIGHLIGHT) |
483 |
483 |
484 self.SearchParams = search_params |
484 self.SearchParams = search_params |
485 criteria = { |
485 criteria = { |
486 "raw_pattern": search_params["find_pattern"], |
486 "raw_pattern": search_params["find_pattern"], |
487 "pattern": re.compile(search_params["find_pattern"]), |
487 "pattern": re.compile(search_params["find_pattern"]), |
488 "case_sensitive": search_params["case_sensitive"], |
488 "case_sensitive": search_params["case_sensitive"], |
489 "regular_expression": search_params["regular_expression"], |
489 "regular_expression": search_params["regular_expression"], |
490 "filter": "all"} |
490 "filter": "all"} |
491 |
491 |
492 self.SearchResults = [ |
492 self.SearchResults = [ |
493 (start, end, SEARCH_RESULT_HIGHLIGHT) |
493 (start, end, SEARCH_RESULT_HIGHLIGHT) |
494 for start, end, text in |
494 for start, end, text in |
495 TestTextElement(self.GetText(), criteria)] |
495 TestTextElement(self.GetText(), criteria)] |
496 self.CurrentFindHighlight = None |
496 self.CurrentFindHighlight = None |
497 |
497 |
498 if len(self.SearchResults) > 0: |
498 if len(self.SearchResults) > 0: |
499 if self.CurrentFindHighlight is not None: |
499 if self.CurrentFindHighlight is not None: |
500 old_idx = self.SearchResults.index(self.CurrentFindHighlight) |
500 old_idx = self.SearchResults.index(self.CurrentFindHighlight) |
501 if self.SearchParams["wrap"]: |
501 if self.SearchParams["wrap"]: |
502 idx = (old_idx + direction) % len(self.SearchResults) |
502 idx = (old_idx + direction) % len(self.SearchResults) |
581 #------------------------------------------------------------------------------- |
581 #------------------------------------------------------------------------------- |
582 # Helper for VariablesGrid values |
582 # Helper for VariablesGrid values |
583 #------------------------------------------------------------------------------- |
583 #------------------------------------------------------------------------------- |
584 |
584 |
585 class VariablesTable(CustomTable): |
585 class VariablesTable(CustomTable): |
586 |
586 |
587 def GetValue(self, row, col): |
587 def GetValue(self, row, col): |
588 if row < self.GetNumberRows(): |
588 if row < self.GetNumberRows(): |
589 if col == 0: |
589 if col == 0: |
590 return row + 1 |
590 return row + 1 |
591 else: |
591 else: |
592 return str(self.data[row].get(self.GetColLabelValue(col, False), "")) |
592 return str(self.data[row].get(self.GetColLabelValue(col, False), "")) |
593 |
593 |
594 def _updateColAttrs(self, grid): |
594 def _updateColAttrs(self, grid): |
595 """ |
595 """ |
596 wxGrid -> update the column attributes to add the |
596 wxGrid -> update the column attributes to add the |
597 appropriate renderer given the column name. |
597 appropriate renderer given the column name. |
598 |
598 |
599 Otherwise default to the default renderer. |
599 Otherwise default to the default renderer. |
600 """ |
600 """ |
601 |
601 |
602 typelist = None |
602 typelist = None |
603 accesslist = None |
603 accesslist = None |
604 for row in range(self.GetNumberRows()): |
604 for row in range(self.GetNumberRows()): |
605 for col in range(self.GetNumberCols()): |
605 for col in range(self.GetNumberCols()): |
606 editor = None |
606 editor = None |
607 renderer = None |
607 renderer = None |
608 colname = self.GetColLabelValue(col, False) |
608 colname = self.GetColLabelValue(col, False) |
609 |
609 |
610 if colname in ["Name", "Initial"]: |
610 if colname in ["Name", "Initial"]: |
611 editor = wx.grid.GridCellTextEditor() |
611 editor = wx.grid.GridCellTextEditor() |
612 elif colname == "Class": |
612 elif colname == "Class": |
613 editor = wx.grid.GridCellChoiceEditor() |
613 editor = wx.grid.GridCellChoiceEditor() |
614 editor.SetParameters("input,memory,output") |
614 editor.SetParameters("input,memory,output") |
615 elif colname == "Type": |
615 elif colname == "Type": |
616 pass |
616 pass |
617 else: |
617 else: |
618 grid.SetReadOnly(row, col, True) |
618 grid.SetReadOnly(row, col, True) |
619 |
619 |
620 grid.SetCellEditor(row, col, editor) |
620 grid.SetCellEditor(row, col, editor) |
621 grid.SetCellRenderer(row, col, renderer) |
621 grid.SetCellRenderer(row, col, renderer) |
622 |
622 |
623 grid.SetCellBackgroundColour(row, col, wx.WHITE) |
623 grid.SetCellBackgroundColour(row, col, wx.WHITE) |
624 self.ResizeRow(grid, row) |
624 self.ResizeRow(grid, row) |
625 |
625 |
626 |
626 |
627 class VariablesEditor(wx.Panel): |
627 class VariablesEditor(wx.Panel): |
628 |
628 |
629 def __init__(self, parent, window, controler): |
629 def __init__(self, parent, window, controler): |
630 wx.Panel.__init__(self, parent, style=wx.TAB_TRAVERSAL) |
630 wx.Panel.__init__(self, parent, style=wx.TAB_TRAVERSAL) |
631 |
631 |
632 main_sizer = wx.FlexGridSizer(cols=2, hgap=0, rows=1, vgap=4) |
632 main_sizer = wx.FlexGridSizer(cols=2, hgap=0, rows=1, vgap=4) |
633 main_sizer.AddGrowableCol(1) |
633 main_sizer.AddGrowableCol(1) |
634 main_sizer.AddGrowableRow(0) |
634 main_sizer.AddGrowableRow(0) |
635 |
635 |
636 controls_sizer = wx.BoxSizer(wx.VERTICAL) |
636 controls_sizer = wx.BoxSizer(wx.VERTICAL) |
637 main_sizer.AddSizer(controls_sizer, border=5, flag=wx.ALL) |
637 main_sizer.AddSizer(controls_sizer, border=5, flag=wx.ALL) |
638 |
638 |
639 for name, bitmap, help in [ |
639 for name, bitmap, help in [ |
640 ("AddVariableButton", "add_element", _("Add variable")), |
640 ("AddVariableButton", "add_element", _("Add variable")), |
641 ("DeleteVariableButton", "remove_element", _("Remove variable")), |
641 ("DeleteVariableButton", "remove_element", _("Remove variable")), |
642 ("UpVariableButton", "up", _("Move variable up")), |
642 ("UpVariableButton", "up", _("Move variable up")), |
643 ("DownVariableButton", "down", _("Move variable down"))]: |
643 ("DownVariableButton", "down", _("Move variable down"))]: |
644 button = wx.lib.buttons.GenBitmapButton(self, bitmap=GetBitmap(bitmap), |
644 button = wx.lib.buttons.GenBitmapButton(self, bitmap=GetBitmap(bitmap), |
645 size=wx.Size(28, 28), style=wx.NO_BORDER) |
645 size=wx.Size(28, 28), style=wx.NO_BORDER) |
646 button.SetToolTipString(help) |
646 button.SetToolTipString(help) |
647 setattr(self, name, button) |
647 setattr(self, name, button) |
648 controls_sizer.AddWindow(button, border=5, flag=wx.BOTTOM) |
648 controls_sizer.AddWindow(button, border=5, flag=wx.BOTTOM) |
649 |
649 |
650 self.VariablesGrid = CustomGrid(self, style=wx.VSCROLL) |
650 self.VariablesGrid = CustomGrid(self, style=wx.VSCROLL) |
651 self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnVariablesGridCellChange) |
651 self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_CHANGE, self.OnVariablesGridCellChange) |
652 self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.OnVariablesGridCellLeftClick) |
652 self.VariablesGrid.Bind(wx.grid.EVT_GRID_CELL_LEFT_CLICK, self.OnVariablesGridCellLeftClick) |
653 self.VariablesGrid.Bind(wx.grid.EVT_GRID_EDITOR_SHOWN, self.OnVariablesGridEditorShown) |
653 self.VariablesGrid.Bind(wx.grid.EVT_GRID_EDITOR_SHOWN, self.OnVariablesGridEditorShown) |
654 main_sizer.AddWindow(self.VariablesGrid, flag=wx.GROW) |
654 main_sizer.AddWindow(self.VariablesGrid, flag=wx.GROW) |
655 |
655 |
656 self.SetSizer(main_sizer) |
656 self.SetSizer(main_sizer) |
657 |
657 |
658 self.ParentWindow = window |
658 self.ParentWindow = window |
659 self.Controler = controler |
659 self.Controler = controler |
660 |
660 |
661 self.VariablesDefaultValue = {"Name" : "", "Type" : "INT", "Initial": ""} |
661 self.VariablesDefaultValue = {"Name" : "", "Type" : DefaultType, "Initial": ""} |
662 self.Table = VariablesTable(self, [], ["#", "Name", "Type", "Initial"]) |
662 self.Table = VariablesTable(self, [], ["#", "Name", "Type", "Initial"]) |
663 self.ColAlignements = [wx.ALIGN_RIGHT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT] |
663 self.ColAlignements = [wx.ALIGN_RIGHT, wx.ALIGN_LEFT, wx.ALIGN_LEFT, wx.ALIGN_LEFT] |
664 self.ColSizes = [40, 200, 150, 150] |
664 self.ColSizes = [40, 200, 150, 150] |
665 self.VariablesGrid.SetTable(self.Table) |
665 self.VariablesGrid.SetTable(self.Table) |
666 self.VariablesGrid.SetButtons({"Add": self.AddVariableButton, |
666 self.VariablesGrid.SetButtons({"Add": self.AddVariableButton, |
667 "Delete": self.DeleteVariableButton, |
667 "Delete": self.DeleteVariableButton, |
668 "Up": self.UpVariableButton, |
668 "Up": self.UpVariableButton, |
669 "Down": self.DownVariableButton}) |
669 "Down": self.DownVariableButton}) |
670 |
670 |
671 def _AddVariable(new_row): |
671 def _AddVariable(new_row): |
672 if new_row > 0: |
672 if new_row > 0: |
673 row_content = self.Table.data[new_row - 1].copy() |
673 row_content = self.Table.data[new_row - 1].copy() |
674 result = VARIABLE_NAME_SUFFIX_MODEL.search(row_content["Name"]) |
674 result = VARIABLE_NAME_SUFFIX_MODEL.search(row_content["Name"]) |
675 if result is not None: |
675 if result is not None: |
728 |
728 |
729 def RefreshView(self): |
729 def RefreshView(self): |
730 self.Table.SetData(self.Controler.GetVariables()) |
730 self.Table.SetData(self.Controler.GetVariables()) |
731 self.Table.ResetView(self.VariablesGrid) |
731 self.Table.ResetView(self.VariablesGrid) |
732 self.VariablesGrid.RefreshButtons() |
732 self.VariablesGrid.RefreshButtons() |
733 |
733 |
734 def DoGetBestSize(self): |
734 def DoGetBestSize(self): |
735 return self.ParentWindow.GetPanelBestSize() |
735 return self.ParentWindow.GetPanelBestSize() |
736 |
736 |
737 def OnVariablesGridCellChange(self, event): |
737 def OnVariablesGridCellChange(self, event): |
738 row, col = event.GetRow(), event.GetCol() |
738 row, col = event.GetRow(), event.GetCol() |
739 colname = self.Table.GetColLabelValue(col, False) |
739 colname = self.Table.GetColLabelValue(col, False) |
740 value = self.Table.GetValue(row, col) |
740 value = self.Table.GetValue(row, col) |
741 message = None |
741 message = None |
742 |
742 |
743 if colname == "Name" and value != "": |
743 if colname == "Name" and value != "": |
744 if not TestIdentifier(value): |
744 if not TestIdentifier(value): |
745 message = _("\"%s\" is not a valid identifier!") % value |
745 message = _("\"%s\" is not a valid identifier!") % value |
746 elif value.upper() in IEC_KEYWORDS: |
746 elif value.upper() in IEC_KEYWORDS: |
747 message = _("\"%s\" is a keyword. It can't be used!") % value |
747 message = _("\"%s\" is a keyword. It can't be used!") % value |
748 elif value.upper() in [var["Name"].upper() |
748 elif value.upper() in [var["Name"].upper() |
749 for var_row, var in enumerate(self.Table.data) |
749 for var_row, var in enumerate(self.Table.data) |
750 if var_row != row]: |
750 if var_row != row]: |
751 message = _("A variable with \"%s\" as name already exists!") % value |
751 message = _("A variable with \"%s\" as name already exists!") % value |
752 else: |
752 else: |
753 self.RefreshModel() |
753 self.RefreshModel() |
754 wx.CallAfter(self.RefreshView) |
754 wx.CallAfter(self.RefreshView) |
755 else: |
755 else: |
756 self.RefreshModel() |
756 self.RefreshModel() |
757 wx.CallAfter(self.RefreshView) |
757 wx.CallAfter(self.RefreshView) |
758 |
758 |
759 if message is not None: |
759 if message is not None: |
760 dialog = wx.MessageDialog(self, message, _("Error"), wx.OK|wx.ICON_ERROR) |
760 dialog = wx.MessageDialog(self, message, _("Error"), wx.OK|wx.ICON_ERROR) |
761 dialog.ShowModal() |
761 dialog.ShowModal() |
762 dialog.Destroy() |
762 dialog.Destroy() |
763 event.Veto() |
763 event.Veto() |
764 else: |
764 else: |
765 event.Skip() |
765 event.Skip() |
766 |
766 |
767 def OnVariablesGridEditorShown(self, event): |
767 def OnVariablesGridEditorShown(self, event): |
768 row, col = event.GetRow(), event.GetCol() |
768 row, col = event.GetRow(), event.GetCol() |
769 if self.Table.GetColLabelValue(col, False) == "Type": |
769 if self.Table.GetColLabelValue(col, False) == "Type": |
770 type_menu = wx.Menu(title='') |
770 type_menu = wx.Menu(title='') |
771 base_menu = wx.Menu(title='') |
771 base_menu = wx.Menu(title='') |
772 for base_type in self.Controler.GetBaseTypes(): |
772 for base_type in self.Controler.GetBaseTypes(): |
773 new_id = wx.NewId() |
773 new_id = wx.NewId() |
801 def OnVariablesGridCellLeftClick(self, event): |
801 def OnVariablesGridCellLeftClick(self, event): |
802 if event.GetCol() == 0: |
802 if event.GetCol() == 0: |
803 row = event.GetRow() |
803 row = event.GetRow() |
804 data_type = self.Table.GetValueByName(row, "Type") |
804 data_type = self.Table.GetValueByName(row, "Type") |
805 var_name = self.Table.GetValueByName(row, "Name") |
805 var_name = self.Table.GetValueByName(row, "Name") |
806 data = wx.TextDataObject(str((var_name, "Global", data_type, |
806 data = wx.TextDataObject(str((var_name, "Global", data_type, |
807 self.Controler.GetCurrentLocation()))) |
807 self.Controler.GetCurrentLocation()))) |
808 dragSource = wx.DropSource(self.VariablesGrid) |
808 dragSource = wx.DropSource(self.VariablesGrid) |
809 dragSource.SetData(data) |
809 dragSource.SetData(data) |
810 dragSource.DoDragDrop() |
810 dragSource.DoDragDrop() |
811 return |
811 return |
812 event.Skip() |
812 event.Skip() |
813 |
813 |
814 |
814 |
815 #------------------------------------------------------------------------------- |
815 #------------------------------------------------------------------------------- |
816 # CodeFileEditor Main Frame Class |
816 # CodeFileEditor Main Frame Class |
817 #------------------------------------------------------------------------------- |
817 #------------------------------------------------------------------------------- |
818 |
818 |
819 class CodeFileEditor(ConfTreeNodeEditor): |
819 class CodeFileEditor(ConfTreeNodeEditor): |
820 |
820 |
821 CONFNODEEDITOR_TABS = [] |
821 CONFNODEEDITOR_TABS = [] |
822 CODE_EDITOR = None |
822 CODE_EDITOR = None |
823 |
823 |
824 def _create_CodePanel(self, prnt): |
824 def _create_CodePanel(self, prnt): |
825 self.CodeEditorPanel = wx.SplitterWindow(prnt) |
825 self.CodeEditorPanel = wx.SplitterWindow(prnt) |
826 self.CodeEditorPanel.SetMinimumPaneSize(1) |
826 self.CodeEditorPanel.SetMinimumPaneSize(1) |
827 |
827 |
828 self.VariablesPanel = VariablesEditor(self.CodeEditorPanel, |
828 self.VariablesPanel = VariablesEditor(self.CodeEditorPanel, |
829 self.ParentWindow, self.Controler) |
829 self.ParentWindow, self.Controler) |
830 |
830 |
831 if self.CODE_EDITOR is not None: |
831 if self.CODE_EDITOR is not None: |
832 self.CodeEditor = self.CODE_EDITOR(self.CodeEditorPanel, |
832 self.CodeEditor = self.CODE_EDITOR(self.CodeEditorPanel, |
833 self.ParentWindow, self.Controler) |
833 self.ParentWindow, self.Controler) |
834 |
834 |
835 self.CodeEditorPanel.SplitHorizontally(self.VariablesPanel, |
835 self.CodeEditorPanel.SplitHorizontally(self.VariablesPanel, |
836 self.CodeEditor, 150) |
836 self.CodeEditor, 150) |
837 else: |
837 else: |
838 self.CodeEditorPanel.Initialize(self.VariablesPanel) |
838 self.CodeEditorPanel.Initialize(self.VariablesPanel) |
839 |
839 |
840 return self.CodeEditorPanel |
840 return self.CodeEditorPanel |
841 |
841 |
842 def __init__(self, parent, controler, window): |
842 def __init__(self, parent, controler, window): |
843 ConfTreeNodeEditor.__init__(self, parent, controler, window) |
843 ConfTreeNodeEditor.__init__(self, parent, controler, window) |
844 |
844 |
845 wx.CallAfter(self.CodeEditorPanel.SetSashPosition, 150) |
845 wx.CallAfter(self.CodeEditorPanel.SetSashPosition, 150) |
846 |
846 |
847 def GetBufferState(self): |
847 def GetBufferState(self): |
848 return self.Controler.GetBufferState() |
848 return self.Controler.GetBufferState() |
849 |
849 |
850 def Undo(self): |
850 def Undo(self): |
851 self.Controler.LoadPrevious() |
851 self.Controler.LoadPrevious() |
852 self.RefreshView() |
852 self.RefreshView() |
853 |
853 |
854 def Redo(self): |
854 def Redo(self): |
855 self.Controler.LoadNext() |
855 self.Controler.LoadNext() |
856 self.RefreshView() |
856 self.RefreshView() |
857 |
857 |
858 def RefreshView(self): |
858 def RefreshView(self): |
859 ConfTreeNodeEditor.RefreshView(self) |
859 ConfTreeNodeEditor.RefreshView(self) |
860 |
860 |
861 self.VariablesPanel.RefreshView() |
861 self.VariablesPanel.RefreshView() |
862 self.CodeEditor.RefreshView() |
862 self.CodeEditor.RefreshView() |
863 |
863 |
864 def Find(self, direction, search_params): |
864 def Find(self, direction, search_params): |
865 self.CodeEditor.Find(direction, search_params) |
865 self.CodeEditor.Find(direction, search_params) |
866 |
866 |