27 from types import * |
27 from types import * |
28 |
28 |
29 import re |
29 import re |
30 |
30 |
31 from graphics.GraphicCommons import ERROR_HIGHLIGHT, SEARCH_RESULT_HIGHLIGHT, REFRESH_HIGHLIGHT_PERIOD |
31 from graphics.GraphicCommons import ERROR_HIGHLIGHT, SEARCH_RESULT_HIGHLIGHT, REFRESH_HIGHLIGHT_PERIOD |
|
32 from plcopen.structures import ST_BLOCK_START_KEYWORDS, ST_BLOCK_END_KEYWORDS |
32 |
33 |
33 #------------------------------------------------------------------------------- |
34 #------------------------------------------------------------------------------- |
34 # Textual programs Viewer class |
35 # Textual programs Viewer class |
35 #------------------------------------------------------------------------------- |
36 #------------------------------------------------------------------------------- |
36 |
37 |
96 else: |
97 else: |
97 return i + 1 |
98 return i + 1 |
98 else: |
99 else: |
99 return None |
100 return None |
100 |
101 |
|
102 def LineStartswith(line, symbols): |
|
103 return reduce(lambda x, y: x or y, map(lambda x: line.startswith(x), symbols), False) |
101 |
104 |
102 class TextViewer(wx.stc.StyledTextCtrl): |
105 class TextViewer(wx.stc.StyledTextCtrl): |
103 |
106 |
104 if wx.VERSION < (2, 6, 0): |
107 if wx.VERSION < (2, 6, 0): |
105 def Bind(self, event, function, id = None): |
108 def Bind(self, event, function, id = None): |
145 self.IndicatorSetForeground(0, wx.WHITE) |
148 self.IndicatorSetForeground(0, wx.WHITE) |
146 |
149 |
147 # Line numbers in the margin |
150 # Line numbers in the margin |
148 self.SetMarginType(1, wx.stc.STC_MARGIN_NUMBER) |
151 self.SetMarginType(1, wx.stc.STC_MARGIN_NUMBER) |
149 self.SetMarginWidth(1, 50) |
152 self.SetMarginWidth(1, 50) |
|
153 |
|
154 # Folding |
|
155 self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDEROPEN, wx.stc.STC_MARK_BOXMINUS, "white", "#808080") |
|
156 self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDER, wx.stc.STC_MARK_BOXPLUS, "white", "#808080") |
|
157 self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDERSUB, wx.stc.STC_MARK_VLINE, "white", "#808080") |
|
158 self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDERTAIL, wx.stc.STC_MARK_LCORNER, "white", "#808080") |
|
159 self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDEREND, wx.stc.STC_MARK_BOXPLUSCONNECTED, "white", "#808080") |
|
160 self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDEROPENMID, wx.stc.STC_MARK_BOXMINUSCONNECTED, "white", "#808080") |
|
161 self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDERMIDTAIL, wx.stc.STC_MARK_TCORNER, "white", "#808080") |
150 |
162 |
151 # Indentation size |
163 # Indentation size |
152 self.SetTabWidth(2) |
164 self.SetTabWidth(2) |
153 self.SetUseTabs(0) |
165 self.SetUseTabs(0) |
154 |
166 |
177 self.SetModEventMask(wx.stc.STC_MOD_BEFOREINSERT| |
189 self.SetModEventMask(wx.stc.STC_MOD_BEFOREINSERT| |
178 wx.stc.STC_MOD_BEFOREDELETE| |
190 wx.stc.STC_MOD_BEFOREDELETE| |
179 wx.stc.STC_PERFORMED_USER) |
191 wx.stc.STC_PERFORMED_USER) |
180 |
192 |
181 self.Bind(wx.stc.EVT_STC_STYLENEEDED, self.OnStyleNeeded, id=ID_TEXTVIEWER) |
193 self.Bind(wx.stc.EVT_STC_STYLENEEDED, self.OnStyleNeeded, id=ID_TEXTVIEWER) |
|
194 self.Bind(wx.stc.EVT_STC_MARGINCLICK, self.OnMarginClick) |
182 if controler: |
195 if controler: |
183 self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) |
196 self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) |
184 self.Bind(wx.stc.EVT_STC_DO_DROP, self.OnDoDrop, id=ID_TEXTVIEWER) |
197 self.Bind(wx.stc.EVT_STC_DO_DROP, self.OnDoDrop, id=ID_TEXTVIEWER) |
185 self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus) |
198 self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus) |
186 self.Bind(wx.stc.EVT_STC_MODIFIED, self.OnModification, id=ID_TEXTVIEWER) |
199 self.Bind(wx.stc.EVT_STC_MODIFIED, self.OnModification, id=ID_TEXTVIEWER) |
298 event.SetDragText("") |
311 event.SetDragText("") |
299 event.Skip() |
312 event.Skip() |
300 |
313 |
301 def SetTextSyntax(self, syntax): |
314 def SetTextSyntax(self, syntax): |
302 self.TextSyntax = syntax |
315 self.TextSyntax = syntax |
|
316 if syntax == "ST": |
|
317 self.SetMarginType(2, wx.stc.STC_MARGIN_SYMBOL) |
|
318 self.SetMarginMask(2, wx.stc.STC_MASK_FOLDERS) |
|
319 self.SetMarginSensitive(2, 1) |
|
320 self.SetMarginWidth(2, 12) |
303 |
321 |
304 def SetKeywords(self, keywords): |
322 def SetKeywords(self, keywords): |
305 self.Keywords = [keyword.upper() for keyword in keywords] |
323 self.Keywords = [keyword.upper() for keyword in keywords] |
306 self.Colourise(0, -1) |
324 self.Colourise(0, -1) |
307 |
325 |
366 self.Functions[blockname]["extensible"] |= blocktype["extensible"] |
384 self.Functions[blockname]["extensible"] |= blocktype["extensible"] |
367 else: |
385 else: |
368 self.Functions[blockname] = {"interface": interface, |
386 self.Functions[blockname] = {"interface": interface, |
369 "extensible": blocktype["extensible"]} |
387 "extensible": blocktype["extensible"]} |
370 self.Colourise(0, -1) |
388 self.Colourise(0, -1) |
371 |
389 |
372 def RefreshVariableTree(self): |
390 def RefreshVariableTree(self): |
373 words = self.TagName.split("::") |
391 words = self.TagName.split("::") |
374 self.Variables = self.GenerateVariableTree([(variable["Name"], variable["Type"], variable["Tree"]) for variable in self.Controler.GetEditedElementInterfaceVars(self.TagName, self.Debug)]) |
392 self.Variables = self.GenerateVariableTree([(variable["Name"], variable["Type"], variable["Tree"]) for variable in self.Controler.GetEditedElementInterfaceVars(self.TagName, self.Debug)]) |
375 if self.Controler.GetEditedElementType(self.TagName, self.Debug)[1] == "function" or words[0] == "T" and self.TextSyntax == "IL": |
393 if self.Controler.GetEditedElementType(self.TagName, self.Debug)[1] == "function" or words[0] == "T" and self.TextSyntax == "IL": |
376 return_type = self.Controler.GetEditedElementInterfaceReturnType(self.TagName, self.Debug) |
394 return_type = self.Controler.GetEditedElementInterfaceReturnType(self.TagName, self.Debug) |
395 def IsCallParameter(self, name, call): |
413 def IsCallParameter(self, name, call): |
396 if call is not None: |
414 if call is not None: |
397 return (call["interface"].get(name.upper(), None) is not None or |
415 return (call["interface"].get(name.upper(), None) is not None or |
398 call["extensible"] and EXTENSIBLE_PARAMETER.match(name.upper()) is not None) |
416 call["extensible"] and EXTENSIBLE_PARAMETER.match(name.upper()) is not None) |
399 return False |
417 return False |
400 |
418 |
|
419 def RefreshLineFolding(self, line_number): |
|
420 if self.TextSyntax == "ST": |
|
421 level = wx.stc.STC_FOLDLEVELBASE + self.GetLineIndentation(line_number) |
|
422 line = self.GetLine(line_number).strip() |
|
423 if line == "": |
|
424 if line_number > 0: |
|
425 if LineStartswith(self.GetLine(line_number - 1).strip(), ST_BLOCK_END_KEYWORDS): |
|
426 level = self.GetFoldLevel(self.GetFoldParent(line_number - 1)) & wx.stc.STC_FOLDLEVELNUMBERMASK |
|
427 else: |
|
428 level = self.GetFoldLevel(line_number - 1) & wx.stc.STC_FOLDLEVELNUMBERMASK |
|
429 if level != wx.stc.STC_FOLDLEVELBASE: |
|
430 level |= wx.stc.STC_FOLDLEVELWHITEFLAG |
|
431 elif LineStartswith(line, ST_BLOCK_START_KEYWORDS): |
|
432 level |= wx.stc.STC_FOLDLEVELHEADERFLAG |
|
433 elif LineStartswith(line, ST_BLOCK_END_KEYWORDS): |
|
434 if LineStartswith(self.GetLine(line_number - 1).strip(), ST_BLOCK_END_KEYWORDS): |
|
435 level = self.GetFoldLevel(self.GetFoldParent(line_number - 1)) & wx.stc.STC_FOLDLEVELNUMBERMASK |
|
436 else: |
|
437 level = self.GetFoldLevel(line_number - 1) & wx.stc.STC_FOLDLEVELNUMBERMASK |
|
438 self.SetFoldLevel(line_number, level) |
|
439 |
401 def OnStyleNeeded(self, event): |
440 def OnStyleNeeded(self, event): |
402 self.TextChanged = True |
441 self.TextChanged = True |
403 line = self.LineFromPosition(self.GetEndStyled()) |
442 line_number = self.LineFromPosition(self.GetEndStyled()) |
404 if line == 0: |
443 if line_number == 0: |
405 start_pos = last_styled_pos = 0 |
444 start_pos = last_styled_pos = 0 |
406 else: |
445 else: |
407 start_pos = last_styled_pos = self.GetLineEndPosition(line - 1) + 1 |
446 start_pos = last_styled_pos = self.GetLineEndPosition(line_number - 1) + 1 |
|
447 self.RefreshLineFolding(line_number) |
408 end_pos = event.GetPosition() |
448 end_pos = event.GetPosition() |
409 self.StartStyling(start_pos, 0xff) |
449 self.StartStyling(start_pos, 0xff) |
410 |
450 |
411 current_context = self.Variables |
451 current_context = self.Variables |
412 current_call = None |
452 current_call = None |
447 else: |
487 else: |
448 self.SetStyling(current_pos - last_styled_pos, 31) |
488 self.SetStyling(current_pos - last_styled_pos, 31) |
449 last_styled_pos = current_pos |
489 last_styled_pos = current_pos |
450 state = SPACE |
490 state = SPACE |
451 line = "" |
491 line = "" |
|
492 line_number += 1 |
|
493 self.RefreshLineFolding(line_number) |
452 elif line.endswith("(*") and state != COMMENT: |
494 elif line.endswith("(*") and state != COMMENT: |
453 self.SetStyling(current_pos - last_styled_pos - 1, 31) |
495 self.SetStyling(current_pos - last_styled_pos - 1, 31) |
454 last_styled_pos = current_pos |
496 last_styled_pos = current_pos |
455 if state == WORD: |
497 if state == WORD: |
456 current_context = self.Variables |
498 current_context = self.Variables |
583 else: |
625 else: |
584 self.SetStyling(current_pos - start_pos, 31) |
626 self.SetStyling(current_pos - start_pos, 31) |
585 self.ShowHighlights(start_pos, end_pos) |
627 self.ShowHighlights(start_pos, end_pos) |
586 event.Skip() |
628 event.Skip() |
587 |
629 |
|
630 def OnMarginClick(self, event): |
|
631 if event.GetMargin() == 2: |
|
632 self.ToggleFold(self.LineFromPosition(event.GetPosition())) |
|
633 event.Skip() |
|
634 |
588 def Cut(self): |
635 def Cut(self): |
589 self.ResetBuffer() |
636 self.ResetBuffer() |
590 self.CmdKeyExecute(wx.stc.STC_CMD_CUT) |
637 self.CmdKeyExecute(wx.stc.STC_CMD_CUT) |
591 self.RefreshModel() |
638 self.RefreshModel() |
592 self.RefreshBuffer() |
639 self.RefreshBuffer() |
606 |
653 |
607 def OnKeyDown(self, event): |
654 def OnKeyDown(self, event): |
608 if self.CallTipActive(): |
655 if self.CallTipActive(): |
609 self.CallTipCancel() |
656 self.CallTipCancel() |
610 key = event.GetKeyCode() |
657 key = event.GetKeyCode() |
611 |
658 key_handled = False |
|
659 |
612 # Code completion |
660 # Code completion |
613 if key == wx.WXK_SPACE and event.ControlDown(): |
661 if key == wx.WXK_SPACE and event.ControlDown(): |
614 |
662 |
615 line = self.GetCurrentLine() |
663 line = self.GetCurrentLine() |
616 if line == 0: |
664 if line == 0: |
641 if len(words[-1]) > 0: |
689 if len(words[-1]) > 0: |
642 kw = [keyword for keyword in kw if keyword.startswith(words[-1])] |
690 kw = [keyword for keyword in kw if keyword.startswith(words[-1])] |
643 kw.sort() |
691 kw.sort() |
644 self.AutoCompSetIgnoreCase(True) |
692 self.AutoCompSetIgnoreCase(True) |
645 self.AutoCompShow(len(words[-1]), " ".join(kw)) |
693 self.AutoCompShow(len(words[-1]), " ".join(kw)) |
646 else: |
694 key_handled = True |
|
695 elif key == wx.WXK_RETURN or key == wx.WXK_NUMPAD_ENTER: |
|
696 if self.TextSyntax == "ST": |
|
697 line = self.GetCurrentLine() |
|
698 indent = self.GetLineIndentation(line) |
|
699 if LineStartswith(self.GetLine(line).strip(), ST_BLOCK_START_KEYWORDS): |
|
700 indent += 2 |
|
701 self.AddText("\n" + " " * indent) |
|
702 key_handled = True |
|
703 elif key == wx.WXK_BACK: |
|
704 if self.TextSyntax == "ST": |
|
705 line = self.GetCurrentLine() |
|
706 indent = self.GetLineIndentation(line) |
|
707 if self.GetLine(line).strip() == "" and indent > 0: |
|
708 self.DelLineLeft() |
|
709 self.AddText(" " * max(0, indent - 2)) |
|
710 key_handled = True |
|
711 if not key_handled: |
647 event.Skip() |
712 event.Skip() |
648 |
713 |
649 def OnKillFocus(self, event): |
714 def OnKillFocus(self, event): |
650 self.AutoCompCancel() |
715 self.AutoCompCancel() |
651 event.Skip() |
716 event.Skip() |