laurent@738: import wx laurent@738: import wx.grid laurent@738: import wx.stc as stc laurent@366: import keyword laurent@366: Laurent@814: from editors.ConfTreeNodeEditor import ConfTreeNodeEditor laurent@657: laurent@366: if wx.Platform == '__WXMSW__': laurent@366: faces = { 'times': 'Times New Roman', laurent@366: 'mono' : 'Courier New', laurent@366: 'helv' : 'Arial', laurent@366: 'other': 'Comic Sans MS', laurent@366: 'size' : 10, laurent@366: 'size2': 8, laurent@366: } laurent@366: elif wx.Platform == '__WXMAC__': laurent@366: faces = { 'times': 'Times New Roman', laurent@366: 'mono' : 'Monaco', laurent@366: 'helv' : 'Arial', laurent@366: 'other': 'Comic Sans MS', laurent@366: 'size' : 12, laurent@366: 'size2': 10, laurent@366: } laurent@366: else: laurent@366: faces = { 'times': 'Times', laurent@366: 'mono' : 'Courier', laurent@366: 'helv' : 'Helvetica', laurent@366: 'other': 'new century schoolbook', laurent@366: 'size' : 12, laurent@366: 'size2': 10, laurent@366: } laurent@366: laurent@366: [ID_PYTHONEDITOR, laurent@366: ] = [wx.NewId() for _init_ctrls in range(1)] laurent@366: laurent@366: def GetCursorPos(old, new): laurent@366: old_length = len(old) laurent@366: new_length = len(new) laurent@366: common_length = min(old_length, new_length) laurent@366: i = 0 laurent@366: for i in xrange(common_length): laurent@366: if old[i] != new[i]: laurent@366: break laurent@366: if old_length < new_length: laurent@366: if common_length > 0 and old[i] != new[i]: laurent@366: return i + new_length - old_length laurent@366: else: laurent@366: return i + new_length - old_length + 1 laurent@366: elif old_length > new_length or i < min(old_length, new_length) - 1: laurent@366: if common_length > 0 and old[i] != new[i]: laurent@366: return i laurent@366: else: laurent@366: return i + 1 laurent@366: else: laurent@366: return None laurent@366: laurent@738: class PythonEditor(ConfTreeNodeEditor): laurent@366: laurent@366: fold_symbols = 3 laurent@366: laurent@738: def _init_ConfNodeEditor(self, prnt): laurent@738: self.ConfNodeEditor = stc.StyledTextCtrl(id=ID_PYTHONEDITOR, parent=prnt, laurent@657: name="TextViewer", pos=wx.DefaultPosition, laurent@657: size=wx.DefaultSize, style=0) laurent@753: self.ConfNodeEditor.ParentWindow = self laurent@753: laurent@738: self.ConfNodeEditor.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN) laurent@738: self.ConfNodeEditor.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT) laurent@738: laurent@738: self.ConfNodeEditor.SetLexer(stc.STC_LEX_PYTHON) laurent@738: self.ConfNodeEditor.SetKeyWords(0, " ".join(keyword.kwlist)) laurent@738: laurent@738: self.ConfNodeEditor.SetProperty("fold", "1") laurent@738: self.ConfNodeEditor.SetProperty("tab.timmy.whinge.level", "1") laurent@738: self.ConfNodeEditor.SetMargins(0,0) laurent@738: laurent@738: self.ConfNodeEditor.SetViewWhiteSpace(False) laurent@738: laurent@738: self.ConfNodeEditor.SetEdgeMode(stc.STC_EDGE_BACKGROUND) laurent@738: self.ConfNodeEditor.SetEdgeColumn(78) laurent@366: laurent@366: # Set up the numbers in the margin for margin #1 laurent@738: self.ConfNodeEditor.SetMarginType(1, wx.stc.STC_MARGIN_NUMBER) laurent@366: # Reasonable value for, say, 4-5 digits using a mono font (40 pix) laurent@738: self.ConfNodeEditor.SetMarginWidth(1, 40) laurent@366: laurent@366: # Setup a margin to hold fold markers laurent@738: self.ConfNodeEditor.SetMarginType(2, stc.STC_MARGIN_SYMBOL) laurent@738: self.ConfNodeEditor.SetMarginMask(2, stc.STC_MASK_FOLDERS) laurent@738: self.ConfNodeEditor.SetMarginSensitive(2, True) laurent@738: self.ConfNodeEditor.SetMarginWidth(2, 12) laurent@366: laurent@366: if self.fold_symbols == 0: laurent@366: # Arrow pointing right for contracted folders, arrow pointing down for expanded laurent@738: self.ConfNodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_ARROWDOWN, "black", "black") laurent@738: self.ConfNodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_ARROW, "black", "black") laurent@738: self.ConfNodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_EMPTY, "black", "black") laurent@738: self.ConfNodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_EMPTY, "black", "black") laurent@738: self.ConfNodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_EMPTY, "white", "black") laurent@738: self.ConfNodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_EMPTY, "white", "black") laurent@738: self.ConfNodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_EMPTY, "white", "black") laurent@366: laurent@366: elif self.fold_symbols == 1: laurent@366: # Plus for contracted folders, minus for expanded laurent@738: self.ConfNodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_MINUS, "white", "black") laurent@738: self.ConfNodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_PLUS, "white", "black") laurent@738: self.ConfNodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_EMPTY, "white", "black") laurent@738: self.ConfNodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_EMPTY, "white", "black") laurent@738: self.ConfNodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_EMPTY, "white", "black") laurent@738: self.ConfNodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_EMPTY, "white", "black") laurent@738: self.ConfNodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_EMPTY, "white", "black") laurent@366: laurent@366: elif self.fold_symbols == 2: laurent@366: # Like a flattened tree control using circular headers and curved joins laurent@738: self.ConfNodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_CIRCLEMINUS, "white", "#404040") laurent@738: self.ConfNodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_CIRCLEPLUS, "white", "#404040") laurent@738: self.ConfNodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_VLINE, "white", "#404040") laurent@738: self.ConfNodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_LCORNERCURVE, "white", "#404040") laurent@738: self.ConfNodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_CIRCLEPLUSCONNECTED, "white", "#404040") laurent@738: self.ConfNodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_CIRCLEMINUSCONNECTED, "white", "#404040") laurent@738: self.ConfNodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNERCURVE, "white", "#404040") laurent@366: laurent@366: elif self.fold_symbols == 3: laurent@366: # Like a flattened tree control using square headers laurent@738: self.ConfNodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_BOXMINUS, "white", "#808080") laurent@738: self.ConfNodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_BOXPLUS, "white", "#808080") laurent@738: self.ConfNodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_VLINE, "white", "#808080") laurent@738: self.ConfNodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_LCORNER, "white", "#808080") laurent@738: self.ConfNodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_BOXPLUSCONNECTED, "white", "#808080") laurent@738: self.ConfNodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_BOXMINUSCONNECTED, "white", "#808080") laurent@738: self.ConfNodeEditor.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNER, "white", "#808080") laurent@738: laurent@738: laurent@738: self.ConfNodeEditor.Bind(stc.EVT_STC_UPDATEUI, self.OnUpdateUI) laurent@738: self.ConfNodeEditor.Bind(stc.EVT_STC_MARGINCLICK, self.OnMarginClick) laurent@738: self.ConfNodeEditor.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressed) laurent@366: laurent@366: # Global default style laurent@366: if wx.Platform == '__WXMSW__': laurent@738: self.ConfNodeEditor.StyleSetSpec(stc.STC_STYLE_DEFAULT, 'fore:#000000,back:#FFFFFF,face:Courier New') laurent@366: elif wx.Platform == '__WXMAC__': laurent@366: # TODO: if this looks fine on Linux too, remove the Mac-specific case laurent@366: # and use this whenever OS != MSW. laurent@738: self.ConfNodeEditor.StyleSetSpec(stc.STC_STYLE_DEFAULT, 'fore:#000000,back:#FFFFFF,face:Monaco') laurent@366: else: laurent@366: defsize = wx.SystemSettings.GetFont(wx.SYS_ANSI_FIXED_FONT).GetPointSize() laurent@738: self.ConfNodeEditor.StyleSetSpec(stc.STC_STYLE_DEFAULT, 'fore:#000000,back:#FFFFFF,face:Courier,size:%d'%defsize) laurent@366: laurent@366: # Clear styles and revert to default. laurent@738: self.ConfNodeEditor.StyleClearAll() laurent@366: laurent@366: # Following style specs only indicate differences from default. laurent@366: # The rest remains unchanged. laurent@366: laurent@366: # Line numbers in margin laurent@738: self.ConfNodeEditor.StyleSetSpec(wx.stc.STC_STYLE_LINENUMBER,'fore:#000000,back:#99A9C2') laurent@366: # Highlighted brace laurent@738: self.ConfNodeEditor.StyleSetSpec(wx.stc.STC_STYLE_BRACELIGHT,'fore:#00009D,back:#FFFF00') laurent@366: # Unmatched brace laurent@738: self.ConfNodeEditor.StyleSetSpec(wx.stc.STC_STYLE_BRACEBAD,'fore:#00009D,back:#FF0000') laurent@366: # Indentation guide laurent@738: self.ConfNodeEditor.StyleSetSpec(wx.stc.STC_STYLE_INDENTGUIDE, "fore:#CDCDCD") laurent@366: laurent@366: # Python styles laurent@738: self.ConfNodeEditor.StyleSetSpec(wx.stc.STC_P_DEFAULT, 'fore:#000000') laurent@366: # Comments laurent@738: self.ConfNodeEditor.StyleSetSpec(wx.stc.STC_P_COMMENTLINE, 'fore:#008000,back:#F0FFF0') laurent@738: self.ConfNodeEditor.StyleSetSpec(wx.stc.STC_P_COMMENTBLOCK, 'fore:#008000,back:#F0FFF0') laurent@366: # Numbers laurent@738: self.ConfNodeEditor.StyleSetSpec(wx.stc.STC_P_NUMBER, 'fore:#008080') laurent@366: # Strings and characters laurent@738: self.ConfNodeEditor.StyleSetSpec(wx.stc.STC_P_STRING, 'fore:#800080') laurent@738: self.ConfNodeEditor.StyleSetSpec(wx.stc.STC_P_CHARACTER, 'fore:#800080') laurent@366: # Keywords laurent@738: self.ConfNodeEditor.StyleSetSpec(wx.stc.STC_P_WORD, 'fore:#000080,bold') laurent@366: # Triple quotes laurent@738: self.ConfNodeEditor.StyleSetSpec(wx.stc.STC_P_TRIPLE, 'fore:#800080,back:#FFFFEA') laurent@738: self.ConfNodeEditor.StyleSetSpec(wx.stc.STC_P_TRIPLEDOUBLE, 'fore:#800080,back:#FFFFEA') laurent@366: # Class names laurent@738: self.ConfNodeEditor.StyleSetSpec(wx.stc.STC_P_CLASSNAME, 'fore:#0000FF,bold') laurent@366: # Function names laurent@738: self.ConfNodeEditor.StyleSetSpec(wx.stc.STC_P_DEFNAME, 'fore:#008080,bold') laurent@366: # Operators laurent@738: self.ConfNodeEditor.StyleSetSpec(wx.stc.STC_P_OPERATOR, 'fore:#800000,bold') laurent@366: # Identifiers. I leave this as not bold because everything seems laurent@366: # to be an identifier if it doesn't match the above criterae laurent@738: self.ConfNodeEditor.StyleSetSpec(wx.stc.STC_P_IDENTIFIER, 'fore:#000000') laurent@366: laurent@366: # Caret color laurent@738: self.ConfNodeEditor.SetCaretForeground("BLUE") laurent@366: # Selection background laurent@738: self.ConfNodeEditor.SetSelBackground(1, '#66CCFF') laurent@738: laurent@738: self.ConfNodeEditor.SetSelBackground(True, wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT)) laurent@738: self.ConfNodeEditor.SetSelForeground(True, wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT)) laurent@366: laurent@366: # register some images for use in the AutoComplete box. laurent@366: #self.RegisterImage(1, images.getSmilesBitmap()) laurent@738: self.ConfNodeEditor.RegisterImage(1, laurent@366: wx.ArtProvider.GetBitmap(wx.ART_DELETE, size=(16,16))) laurent@738: self.ConfNodeEditor.RegisterImage(2, laurent@366: wx.ArtProvider.GetBitmap(wx.ART_NEW, size=(16,16))) laurent@738: self.ConfNodeEditor.RegisterImage(3, laurent@366: wx.ArtProvider.GetBitmap(wx.ART_COPY, size=(16,16))) laurent@366: laurent@366: # Indentation and tab stuff laurent@738: self.ConfNodeEditor.SetIndent(4) # Proscribed indent size for wx laurent@738: self.ConfNodeEditor.SetIndentationGuides(True) # Show indent guides laurent@738: self.ConfNodeEditor.SetBackSpaceUnIndents(True)# Backspace unindents rather than delete 1 space laurent@738: self.ConfNodeEditor.SetTabIndents(True) # Tab key indents laurent@738: self.ConfNodeEditor.SetTabWidth(4) # Proscribed tab size for wx laurent@738: self.ConfNodeEditor.SetUseTabs(False) # Use spaces rather than tabs, or laurent@366: # TabTimmy will complain! laurent@366: # White space laurent@738: self.ConfNodeEditor.SetViewWhiteSpace(False) # Don't view white space laurent@366: laurent@366: # EOL: Since we are loading/saving ourselves, and the laurent@366: # strings will always have \n's in them, set the STC to laurent@366: # edit them that way. laurent@738: self.ConfNodeEditor.SetEOLMode(wx.stc.STC_EOL_LF) laurent@738: self.ConfNodeEditor.SetViewEOL(False) laurent@366: laurent@366: # No right-edge mode indicator laurent@738: self.ConfNodeEditor.SetEdgeMode(stc.STC_EDGE_NONE) laurent@738: laurent@738: self.ConfNodeEditor.SetModEventMask(wx.stc.STC_MOD_BEFOREINSERT|wx.stc.STC_MOD_BEFOREDELETE) laurent@738: laurent@738: self.ConfNodeEditor.Bind(wx.stc.EVT_STC_DO_DROP, self.OnDoDrop, id=ID_PYTHONEDITOR) laurent@738: self.ConfNodeEditor.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus) laurent@738: self.ConfNodeEditor.Bind(wx.stc.EVT_STC_MODIFIED, self.OnModification, id=ID_PYTHONEDITOR) laurent@657: laurent@657: laurent@657: def __init__(self, parent, controler, window): laurent@743: ConfTreeNodeEditor.__init__(self, parent, controler, window) laurent@657: laurent@657: self.DisableEvents = False laurent@366: self.CurrentAction = None laurent@657: laurent@657: def GetBufferState(self): laurent@657: return self.Controler.GetBufferState() laurent@657: laurent@657: def Undo(self): laurent@657: self.Controler.LoadPrevious() laurent@657: self.RefreshView() laurent@657: laurent@657: def Redo(self): laurent@657: self.Controler.LoadNext() laurent@657: self.RefreshView() laurent@657: laurent@366: def OnModification(self, event): laurent@366: if not self.DisableEvents: laurent@366: mod_type = event.GetModificationType() laurent@366: if not (mod_type&wx.stc.STC_PERFORMED_UNDO or mod_type&wx.stc.STC_PERFORMED_REDO): laurent@366: if mod_type&wx.stc.STC_MOD_BEFOREINSERT: laurent@657: if self.CurrentAction is None: laurent@366: self.StartBuffering() laurent@366: elif self.CurrentAction[0] != "Add" or self.CurrentAction[1] != event.GetPosition() - 1: laurent@366: self.Controler.EndBuffering() laurent@366: self.StartBuffering() laurent@366: self.CurrentAction = ("Add", event.GetPosition()) laurent@657: wx.CallAfter(self.RefreshModel) laurent@366: elif mod_type&wx.stc.STC_MOD_BEFOREDELETE: laurent@366: if self.CurrentAction == None: laurent@366: self.StartBuffering() laurent@366: elif self.CurrentAction[0] != "Delete" or self.CurrentAction[1] != event.GetPosition() + 1: laurent@366: self.Controler.EndBuffering() laurent@366: self.StartBuffering() laurent@366: self.CurrentAction = ("Delete", event.GetPosition()) laurent@657: wx.CallAfter(self.RefreshModel) laurent@366: event.Skip() laurent@366: laurent@366: def OnDoDrop(self, event): laurent@366: self.ResetBuffer() laurent@366: wx.CallAfter(self.RefreshModel) laurent@366: event.Skip() laurent@366: laurent@366: # Buffer the last model state laurent@366: def RefreshBuffer(self): laurent@366: self.Controler.BufferPython() laurent@657: if self.ParentWindow is not None: laurent@366: self.ParentWindow.RefreshTitle() laurent@534: self.ParentWindow.RefreshFileMenu() laurent@366: self.ParentWindow.RefreshEditMenu() laurent@657: self.ParentWindow.RefreshPageTitles() laurent@366: laurent@366: def StartBuffering(self): laurent@366: self.Controler.StartBuffering() laurent@657: if self.ParentWindow is not None: laurent@366: self.ParentWindow.RefreshTitle() laurent@534: self.ParentWindow.RefreshFileMenu() laurent@366: self.ParentWindow.RefreshEditMenu() laurent@657: self.ParentWindow.RefreshPageTitles() laurent@366: laurent@366: def ResetBuffer(self): laurent@366: if self.CurrentAction != None: laurent@366: self.Controler.EndBuffering() laurent@366: self.CurrentAction = None laurent@366: laurent@366: def RefreshView(self): laurent@751: ConfTreeNodeEditor.RefreshView(self) laurent@751: laurent@366: self.ResetBuffer() laurent@366: self.DisableEvents = True laurent@738: old_cursor_pos = self.ConfNodeEditor.GetCurrentPos() laurent@738: old_text = self.ConfNodeEditor.GetText() laurent@366: new_text = self.Controler.GetPythonCode() laurent@738: self.ConfNodeEditor.SetText(new_text) laurent@366: new_cursor_pos = GetCursorPos(old_text, new_text) laurent@366: if new_cursor_pos != None: laurent@738: self.ConfNodeEditor.GotoPos(new_cursor_pos) laurent@738: else: laurent@738: self.ConfNodeEditor.GotoPos(old_cursor_pos) laurent@738: self.ConfNodeEditor.ScrollToColumn(0) laurent@738: self.ConfNodeEditor.EmptyUndoBuffer() laurent@366: self.DisableEvents = False laurent@366: laurent@738: self.ConfNodeEditor.Colourise(0, -1) laurent@366: laurent@366: def RefreshModel(self): laurent@738: self.Controler.SetPythonCode(self.ConfNodeEditor.GetText()) laurent@366: laurent@366: def OnKeyPressed(self, event): laurent@738: if self.ConfNodeEditor.CallTipActive(): laurent@738: self.ConfNodeEditor.CallTipCancel() laurent@366: key = event.GetKeyCode() laurent@366: laurent@366: if key == 32 and event.ControlDown(): laurent@738: pos = self.ConfNodeEditor.GetCurrentPos() laurent@738: laurent@366: # Code completion laurent@738: if not event.ShiftDown(): laurent@738: self.ConfNodeEditor.AutoCompSetIgnoreCase(False) # so this needs to match laurent@366: laurent@366: # Images are specified with a appended "?type" laurent@738: self.ConfNodeEditor.AutoCompShow(0, " ".join([word + "?1" for word in keyword.kwlist])) laurent@366: else: laurent@366: event.Skip() laurent@366: laurent@366: def OnKillFocus(self, event): laurent@738: self.ConfNodeEditor.AutoCompCancel() laurent@366: event.Skip() laurent@366: laurent@366: def OnUpdateUI(self, evt): laurent@366: # check for matching braces laurent@366: braceAtCaret = -1 laurent@366: braceOpposite = -1 laurent@366: charBefore = None laurent@738: caretPos = self.ConfNodeEditor.GetCurrentPos() laurent@366: laurent@366: if caretPos > 0: laurent@738: charBefore = self.ConfNodeEditor.GetCharAt(caretPos - 1) laurent@738: styleBefore = self.ConfNodeEditor.GetStyleAt(caretPos - 1) laurent@366: laurent@366: # check before laurent@366: if charBefore and chr(charBefore) in "[]{}()" and styleBefore == stc.STC_P_OPERATOR: laurent@366: braceAtCaret = caretPos - 1 laurent@366: laurent@366: # check after laurent@366: if braceAtCaret < 0: laurent@738: charAfter = self.ConfNodeEditor.GetCharAt(caretPos) laurent@738: styleAfter = self.ConfNodeEditor.GetStyleAt(caretPos) laurent@366: laurent@366: if charAfter and chr(charAfter) in "[]{}()" and styleAfter == stc.STC_P_OPERATOR: laurent@366: braceAtCaret = caretPos laurent@366: laurent@366: if braceAtCaret >= 0: laurent@738: braceOpposite = self.ConfNodeEditor.BraceMatch(braceAtCaret) laurent@366: laurent@366: if braceAtCaret != -1 and braceOpposite == -1: laurent@738: self.ConfNodeEditor.BraceBadLight(braceAtCaret) laurent@738: else: laurent@738: self.ConfNodeEditor.BraceHighlight(braceAtCaret, braceOpposite) laurent@366: laurent@366: def OnMarginClick(self, evt): laurent@366: # fold and unfold as needed laurent@366: if evt.GetMargin() == 2: laurent@366: if evt.GetShift() and evt.GetControl(): laurent@366: self.FoldAll() laurent@366: else: laurent@738: lineClicked = self.ConfNodeEditor.LineFromPosition(evt.GetPosition()) laurent@738: laurent@738: if self.ConfNodeEditor.GetFoldLevel(lineClicked) & stc.STC_FOLDLEVELHEADERFLAG: laurent@366: if evt.GetShift(): laurent@738: self.ConfNodeEditor.SetFoldExpanded(lineClicked, True) laurent@366: self.Expand(lineClicked, True, True, 1) laurent@366: elif evt.GetControl(): laurent@738: if self.ConfNodeEditor.GetFoldExpanded(lineClicked): laurent@738: self.ConfNodeEditor.SetFoldExpanded(lineClicked, False) laurent@366: self.Expand(lineClicked, False, True, 0) laurent@366: else: laurent@738: self.ConfNodeEditor.SetFoldExpanded(lineClicked, True) laurent@366: self.Expand(lineClicked, True, True, 100) laurent@366: else: laurent@738: self.ConfNodeEditor.ToggleFold(lineClicked) laurent@366: laurent@366: laurent@366: def FoldAll(self): laurent@738: lineCount = self.ConfNodeEditor.GetLineCount() laurent@366: expanding = True laurent@366: laurent@366: # find out if we are folding or unfolding laurent@366: for lineNum in range(lineCount): laurent@738: if self.ConfNodeEditor.GetFoldLevel(lineNum) & stc.STC_FOLDLEVELHEADERFLAG: laurent@738: expanding = not self.ConfNodeEditor.GetFoldExpanded(lineNum) laurent@366: break laurent@366: laurent@366: lineNum = 0 laurent@366: laurent@366: while lineNum < lineCount: laurent@738: level = self.ConfNodeEditor.GetFoldLevel(lineNum) laurent@366: if level & stc.STC_FOLDLEVELHEADERFLAG and \ laurent@366: (level & stc.STC_FOLDLEVELNUMBERMASK) == stc.STC_FOLDLEVELBASE: laurent@366: laurent@366: if expanding: laurent@738: self.ConfNodeEditor.SetFoldExpanded(lineNum, True) laurent@366: lineNum = self.Expand(lineNum, True) laurent@366: lineNum = lineNum - 1 laurent@366: else: laurent@738: lastChild = self.ConfNodeEditor.GetLastChild(lineNum, -1) laurent@738: self.ConfNodeEditor.SetFoldExpanded(lineNum, False) laurent@366: laurent@366: if lastChild > lineNum: laurent@738: self.ConfNodeEditor.HideLines(lineNum+1, lastChild) laurent@366: laurent@366: lineNum = lineNum + 1 laurent@366: laurent@366: laurent@366: laurent@366: def Expand(self, line, doExpand, force=False, visLevels=0, level=-1): laurent@738: lastChild = self.ConfNodeEditor.GetLastChild(line, level) laurent@366: line = line + 1 laurent@366: laurent@366: while line <= lastChild: laurent@366: if force: laurent@366: if visLevels > 0: laurent@738: self.ConfNodeEditor.ShowLines(line, line) laurent@366: else: laurent@738: self.ConfNodeEditor.HideLines(line, line) laurent@366: else: laurent@366: if doExpand: laurent@738: self.ConfNodeEditor.ShowLines(line, line) laurent@366: laurent@366: if level == -1: laurent@738: level = self.ConfNodeEditor.GetFoldLevel(line) laurent@366: laurent@366: if level & stc.STC_FOLDLEVELHEADERFLAG: laurent@366: if force: laurent@366: if visLevels > 1: laurent@738: self.ConfNodeEditor.SetFoldExpanded(line, True) laurent@366: else: laurent@738: self.ConfNodeEditor.SetFoldExpanded(line, False) laurent@366: laurent@366: line = self.Expand(line, doExpand, force, visLevels-1) laurent@366: laurent@366: else: laurent@738: if doExpand and self.ConfNodeEditor.GetFoldExpanded(line): laurent@366: line = self.Expand(line, True, force, visLevels-1) laurent@366: else: laurent@366: line = self.Expand(line, False, force, visLevels-1) laurent@366: else: laurent@366: line = line + 1 laurent@366: laurent@366: return line laurent@657: laurent@657: def Cut(self): laurent@657: self.ResetBuffer() laurent@657: self.DisableEvents = True laurent@738: self.ConfNodeEditor.CmdKeyExecute(wx.stc.STC_CMD_CUT) laurent@657: self.DisableEvents = False laurent@657: self.RefreshModel() laurent@657: self.RefreshBuffer() laurent@657: laurent@657: def Copy(self): laurent@738: self.ConfNodeEditor.CmdKeyExecute(wx.stc.STC_CMD_COPY) laurent@657: laurent@657: def Paste(self): laurent@657: self.ResetBuffer() laurent@657: self.DisableEvents = True laurent@738: self.ConfNodeEditor.CmdKeyExecute(wx.stc.STC_CMD_PASTE) laurent@657: self.DisableEvents = False laurent@657: self.RefreshModel() laurent@657: self.RefreshBuffer()