]> git.saurik.com Git - wxWidgets.git/blame_incremental - wxPython/samples/ide/activegrid/tool/STCTextEditor.py
Disown the config object when calling wx.ConfigBase.Set
[wxWidgets.git] / wxPython / samples / ide / activegrid / tool / STCTextEditor.py
... / ...
CommitLineData
1#----------------------------------------------------------------------------
2# Name: STCTextEditor.py
3# Purpose: Text Editor for wx.lib.pydocview tbat uses the Styled Text Control
4#
5# Author: Peter Yared, Morgan Hua
6#
7# Created: 8/10/03
8# CVS-ID: $Id$
9# Copyright: (c) 2003-2005 ActiveGrid, Inc.
10# License: wxWindows License
11#----------------------------------------------------------------------------
12
13import wx
14import wx.stc
15import wx.lib.docview
16import wx.lib.multisash
17import wx.lib.pydocview
18import string
19import FindService
20import os
21import sys
22_ = wx.GetTranslation
23
24#----------------------------------------------------------------------------
25# Constants
26#----------------------------------------------------------------------------
27
28TEXT_ID = wx.NewId()
29VIEW_WHITESPACE_ID = wx.NewId()
30VIEW_EOL_ID = wx.NewId()
31VIEW_INDENTATION_GUIDES_ID = wx.NewId()
32VIEW_RIGHT_EDGE_ID = wx.NewId()
33VIEW_LINE_NUMBERS_ID = wx.NewId()
34ZOOM_ID = wx.NewId()
35ZOOM_NORMAL_ID = wx.NewId()
36ZOOM_IN_ID = wx.NewId()
37ZOOM_OUT_ID = wx.NewId()
38CHOOSE_FONT_ID = wx.NewId()
39WORD_WRAP_ID = wx.NewId()
40TEXT_STATUS_BAR_ID = wx.NewId()
41
42
43#----------------------------------------------------------------------------
44# Classes
45#----------------------------------------------------------------------------
46
47class TextDocument(wx.lib.docview.Document):
48
49
50 def OnSaveDocument(self, filename):
51 view = self.GetFirstView()
52 docFile = file(self._documentFile, "w")
53 docFile.write(view.GetValue())
54 docFile.close()
55 self.Modify(False)
56 self.SetDocumentModificationDate()
57 self.SetDocumentSaved(True)
58 return True
59
60
61 def OnOpenDocument(self, filename):
62 view = self.GetFirstView()
63 docFile = file(self._documentFile, 'r')
64 data = docFile.read()
65 view.SetValue(data)
66 self.SetFilename(filename, True)
67 self.Modify(False)
68 self.SetDocumentModificationDate()
69 self.UpdateAllViews()
70 self._savedYet = True
71 return True
72
73
74 def IsModified(self):
75 view = self.GetFirstView()
76 if view:
77 return wx.lib.docview.Document.IsModified(self) or view.IsModified()
78 else:
79 return wx.lib.docview.Document.IsModified(self)
80
81
82 def Modify(self, mod):
83 view = self.GetFirstView()
84 wx.lib.docview.Document.Modify(self, mod)
85 if not mod and view:
86 view.SetModifyFalse()
87
88
89 def OnCreateCommandProcessor(self):
90 # Don't create a command processor, it has its own
91 pass
92
93# Use this to override MultiClient.Select to prevent yellow background.
94def MultiClientSelectBGNotYellow(a):
95 a.GetParent().multiView.UnSelect()
96 a.selected = True
97 #a.SetBackgroundColour(wx.Colour(255,255,0)) # Yellow
98 a.Refresh()
99
100class TextView(wx.lib.docview.View):
101 MARKER_NUM = 0
102 MARKER_MASK = 0x1
103
104 #----------------------------------------------------------------------------
105 # Overridden methods
106 #----------------------------------------------------------------------------
107
108 def __init__(self):
109 wx.lib.docview.View.__init__(self)
110 self._textEditor = None
111 self._markerCount = 0
112 self._commandProcessor = None
113 self._multiSash = None
114
115
116 def GetCtrlClass(self):
117 return TextCtrl
118
119
120 def GetCtrl(self):
121 # look for active one first
122 self._textEditor = self._GetActiveCtrl(self._multiSash)
123 if self._textEditor == None: # it is possible none are active
124 # look for any existing one
125 self._textEditor = self._FindCtrl(self._multiSash)
126 return self._textEditor
127
128
129## def GetCtrls(self, parent = None):
130## """ Walk through the MultiSash windows and find all Ctrls """
131## controls = []
132## if isinstance(parent, self.GetCtrlClass()):
133## return [parent]
134## if hasattr(parent, "GetChildren"):
135## for child in parent.GetChildren():
136## controls = controls + self.GetCtrls(child)
137## return controls
138
139
140 def OnCreate(self, doc, flags):
141 frame = wx.GetApp().CreateDocumentFrame(self, doc, flags, style = wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE)
142 wx.lib.multisash.MultiClient.Select = MultiClientSelectBGNotYellow
143 self._multiSash = wx.lib.multisash.MultiSash(frame, -1)
144 self._multiSash.SetDefaultChildClass(self.GetCtrlClass()) # wxBug: MultiSash instantiates the first TextCtrl with this call
145 self._textEditor = self.GetCtrl() # wxBug: grab the TextCtrl from the MultiSash datastructure
146 self._CreateSizer(frame)
147 self.Activate()
148 frame.Show(True)
149 frame.Layout()
150 return True
151
152
153 def _GetActiveCtrl(self, parent):
154 """ Walk through the MultiSash windows and find the active Control """
155 if isinstance(parent, wx.lib.multisash.MultiClient) and parent.selected:
156 return parent.child
157 if hasattr(parent, "GetChildren"):
158 for child in parent.GetChildren():
159 found = self._GetActiveCtrl(child)
160 if found:
161 return found
162 return None
163
164
165 def _FindCtrl(self, parent):
166 """ Walk through the MultiSash windows and find the first TextCtrl """
167 if isinstance(parent, self.GetCtrlClass()):
168 return parent
169 if hasattr(parent, "GetChildren"):
170 for child in parent.GetChildren():
171 found = self._FindCtrl(child)
172 if found:
173 return found
174 return None
175
176
177 def _CreateSizer(self, frame):
178 sizer = wx.BoxSizer(wx.HORIZONTAL)
179 sizer.Add(self._multiSash, 1, wx.EXPAND)
180 frame.SetSizer(sizer)
181 frame.SetAutoLayout(True)
182
183
184 def OnUpdate(self, sender = None, hint = None):
185 if hint == "ViewStuff":
186 self.GetCtrl().SetViewDefaults()
187 elif hint == "Font":
188 font, color = self.GetFontAndColorFromConfig()
189 self.GetCtrl().SetFont(font)
190 self.GetCtrl().SetFontColor(color)
191
192
193 def OnActivateView(self, activate, activeView, deactiveView):
194 if activate and self.GetCtrl():
195 # In MDI mode just calling set focus doesn't work and in SDI mode using CallAfter causes an endless loop
196 if self.GetDocumentManager().GetFlags() & wx.lib.docview.DOC_SDI:
197 self.GetCtrl().SetFocus()
198 else:
199 wx.CallAfter(self.GetCtrl().SetFocus)
200
201
202 def OnClose(self, deleteWindow = True):
203 if not wx.lib.docview.View.OnClose(self, deleteWindow):
204 return False
205 self.Activate(False)
206 if deleteWindow and self.GetFrame():
207 self.GetFrame().Destroy()
208 return True
209
210
211 def ProcessEvent(self, event):
212 id = event.GetId()
213 if id == wx.ID_UNDO:
214 self.GetCtrl().Undo()
215 return True
216 elif id == wx.ID_REDO:
217 self.GetCtrl().Redo()
218 return True
219 elif id == wx.ID_CUT:
220 self.GetCtrl().Cut()
221 return True
222 elif id == wx.ID_COPY:
223 self.GetCtrl().Copy()
224 return True
225 elif id == wx.ID_PASTE:
226 self.GetCtrl().OnPaste()
227 return True
228 elif id == wx.ID_CLEAR:
229 self.GetCtrl().OnClear()
230 return True
231 elif id == wx.ID_SELECTALL:
232 self.GetCtrl().SetSelection(0, -1)
233 return True
234 elif id == VIEW_WHITESPACE_ID:
235 self.GetCtrl().SetViewWhiteSpace(not self.GetCtrl().GetViewWhiteSpace())
236 return True
237 elif id == VIEW_EOL_ID:
238 self.GetCtrl().SetViewEOL(not self.GetCtrl().GetViewEOL())
239 return True
240 elif id == VIEW_INDENTATION_GUIDES_ID:
241 self.GetCtrl().SetViewIndentationGuides(not self.GetCtrl().GetViewIndentationGuides())
242 return True
243 elif id == VIEW_RIGHT_EDGE_ID:
244 self.GetCtrl().SetViewRightEdge(not self.GetCtrl().GetViewRightEdge())
245 return True
246 elif id == VIEW_LINE_NUMBERS_ID:
247 self.GetCtrl().SetViewLineNumbers(not self.GetCtrl().GetViewLineNumbers())
248 return True
249 elif id == ZOOM_NORMAL_ID:
250 self.GetCtrl().SetZoom(0)
251 return True
252 elif id == ZOOM_IN_ID:
253 self.GetCtrl().CmdKeyExecute(wx.stc.STC_CMD_ZOOMIN)
254 return True
255 elif id == ZOOM_OUT_ID:
256 self.GetCtrl().CmdKeyExecute(wx.stc.STC_CMD_ZOOMOUT)
257 return True
258 elif id == CHOOSE_FONT_ID:
259 self.OnChooseFont()
260 return True
261 elif id == WORD_WRAP_ID:
262 self.GetCtrl().SetWordWrap(not self.GetCtrl().GetWordWrap())
263 return True
264 elif id == FindService.FindService.FIND_ID:
265 self.OnFind()
266 return True
267 elif id == FindService.FindService.FIND_PREVIOUS_ID:
268 self.DoFind(forceFindPrevious = True)
269 return True
270 elif id == FindService.FindService.FIND_NEXT_ID:
271 self.DoFind(forceFindNext = True)
272 return True
273 elif id == FindService.FindService.REPLACE_ID:
274 self.OnFind(replace = True)
275 return True
276 elif id == FindService.FindService.FINDONE_ID:
277 self.DoFind()
278 return True
279 elif id == FindService.FindService.REPLACEONE_ID:
280 self.DoFind(replace = True)
281 return True
282 elif id == FindService.FindService.REPLACEALL_ID:
283 self.DoFind(replaceAll = True)
284 return True
285 elif id == FindService.FindService.GOTO_LINE_ID:
286 self.OnGotoLine(event)
287 return True
288 else:
289 return wx.lib.docview.View.ProcessEvent(self, event)
290
291
292 def ProcessUpdateUIEvent(self, event):
293 if not self.GetCtrl():
294 return False
295
296 hasSelection = self.GetCtrl().GetSelectionStart() != self.GetCtrl().GetSelectionEnd()
297 hasText = self.GetCtrl().GetTextLength() > 0
298 notOnLastChar = self.GetCtrl().GetSelectionStart() != self.GetCtrl().GetTextLength()
299
300 id = event.GetId()
301 if id == wx.ID_UNDO:
302 event.Enable(self.GetCtrl().CanUndo())
303 event.SetText(_("Undo") + '\t' + _('Ctrl+Z'))
304 return True
305 elif id == wx.ID_REDO:
306 event.Enable(self.GetCtrl().CanRedo())
307 event.SetText(_("Redo") + '\t' + _('Ctrl+Y'))
308 return True
309 elif id == wx.ID_CUT:
310 event.Enable(hasSelection)
311 return True
312 elif id == wx.ID_COPY:
313 event.Enable(hasSelection)
314 return True
315 elif id == wx.ID_PASTE:
316 event.Enable(self.GetCtrl().CanPaste())
317 return True
318 elif id == wx.ID_CLEAR:
319 event.Enable(hasSelection)
320 return True
321 elif id == wx.ID_SELECTALL:
322 event.Enable(hasText)
323 return True
324 elif id == TEXT_ID:
325 event.Enable(True)
326 return True
327 elif id == VIEW_WHITESPACE_ID:
328 event.Enable(hasText)
329 event.Check(self.GetCtrl().GetViewWhiteSpace())
330 return True
331 elif id == VIEW_EOL_ID:
332 event.Enable(hasText)
333 event.Check(self.GetCtrl().GetViewEOL())
334 return True
335 elif id == VIEW_INDENTATION_GUIDES_ID:
336 event.Enable(hasText)
337 event.Check(self.GetCtrl().GetIndentationGuides())
338 return True
339 elif id == VIEW_RIGHT_EDGE_ID:
340 event.Enable(hasText)
341 event.Check(self.GetCtrl().GetViewRightEdge())
342 return True
343 elif id == VIEW_LINE_NUMBERS_ID:
344 event.Enable(hasText)
345 event.Check(self.GetCtrl().GetViewLineNumbers())
346 return True
347 elif id == ZOOM_ID:
348 event.Enable(True)
349 return True
350 elif id == ZOOM_NORMAL_ID:
351 event.Enable(self.GetCtrl().GetZoom() != 0)
352 return True
353 elif id == ZOOM_IN_ID:
354 event.Enable(self.GetCtrl().GetZoom() < 20)
355 return True
356 elif id == ZOOM_OUT_ID:
357 event.Enable(self.GetCtrl().GetZoom() > -10)
358 return True
359 elif id == CHOOSE_FONT_ID:
360 event.Enable(True)
361 return True
362 elif id == WORD_WRAP_ID:
363 event.Enable(self.GetCtrl().CanWordWrap())
364 event.Check(self.GetCtrl().CanWordWrap() and self.GetCtrl().GetWordWrap())
365 return True
366 elif id == FindService.FindService.FIND_ID:
367 event.Enable(hasText)
368 return True
369 elif id == FindService.FindService.FIND_PREVIOUS_ID:
370 event.Enable(hasText and
371 self._FindServiceHasString() and
372 self.GetCtrl().GetSelection()[0] > 0)
373 return True
374 elif id == FindService.FindService.FIND_NEXT_ID:
375 event.Enable(hasText and
376 self._FindServiceHasString() and
377 self.GetCtrl().GetSelection()[0] < self.GetCtrl().GetLength())
378 return True
379 elif id == FindService.FindService.REPLACE_ID:
380 event.Enable(hasText)
381 return True
382 elif id == FindService.FindService.GOTO_LINE_ID:
383 event.Enable(True)
384 return True
385 elif id == TEXT_STATUS_BAR_ID:
386 self.OnUpdateStatusBar(event)
387 return True
388 else:
389 return wx.lib.docview.View.ProcessUpdateUIEvent(self, event)
390
391
392 def _GetParentFrame(self):
393 return wx.GetTopLevelParent(self.GetFrame())
394
395
396 #----------------------------------------------------------------------------
397 # Methods for TextDocument to call
398 #----------------------------------------------------------------------------
399
400 def IsModified(self):
401 if not self.GetCtrl():
402 return False
403 return self.GetCtrl().GetModify()
404
405
406 def SetModifyFalse(self):
407 self.GetCtrl().SetSavePoint()
408
409
410 def GetValue(self):
411 if self.GetCtrl():
412 return self.GetCtrl().GetText()
413 else:
414 return None
415
416
417 def SetValue(self, value):
418 self.GetCtrl().SetText(value)
419 self.GetCtrl().UpdateLineNumberMarginWidth()
420 self.GetCtrl().EmptyUndoBuffer()
421
422
423 #----------------------------------------------------------------------------
424 # STC events
425 #----------------------------------------------------------------------------
426
427 def OnUpdateStatusBar(self, event):
428 statusBar = self._GetParentFrame().GetStatusBar()
429 statusBar.SetInsertMode(self.GetCtrl().GetOvertype() == 0)
430 statusBar.SetLineNumber(self.GetCtrl().GetCurrentLine() + 1)
431 statusBar.SetColumnNumber(self.GetCtrl().GetColumn(self.GetCtrl().GetCurrentPos()) + 1)
432
433
434 #----------------------------------------------------------------------------
435 # Format methods
436 #----------------------------------------------------------------------------
437
438 def OnChooseFont(self):
439 data = wx.FontData()
440 data.EnableEffects(True)
441 data.SetInitialFont(self.GetCtrl().GetFont())
442 data.SetColour(self.GetCtrl().GetFontColor())
443 fontDialog = wx.FontDialog(self.GetFrame(), data)
444 if fontDialog.ShowModal() == wx.ID_OK:
445 data = fontDialog.GetFontData()
446 self.GetCtrl().SetFont(data.GetChosenFont())
447 self.GetCtrl().SetFontColor(data.GetColour())
448 self.GetCtrl().UpdateStyles()
449 fontDialog.Destroy()
450
451
452 #----------------------------------------------------------------------------
453 # Find methods
454 #----------------------------------------------------------------------------
455
456 def OnFind(self, replace = False):
457 findService = wx.GetApp().GetService(FindService.FindService)
458 if findService:
459 findService.ShowFindReplaceDialog(findString = self.GetCtrl().GetSelectedText(), replace = replace)
460
461
462 def DoFind(self, forceFindNext = False, forceFindPrevious = False, replace = False, replaceAll = False):
463 findService = wx.GetApp().GetService(FindService.FindService)
464 if not findService:
465 return
466 findString = findService.GetFindString()
467 if len(findString) == 0:
468 return -1
469 replaceString = findService.GetReplaceString()
470 flags = findService.GetFlags()
471 startLoc, endLoc = self.GetCtrl().GetSelection()
472
473 wholeWord = flags & wx.FR_WHOLEWORD > 0
474 matchCase = flags & wx.FR_MATCHCASE > 0
475 regExp = flags & FindService.FindService.FR_REGEXP > 0
476 down = flags & wx.FR_DOWN > 0
477 wrap = flags & FindService.FindService.FR_WRAP > 0
478
479 if forceFindPrevious: # this is from function keys, not dialog box
480 down = False
481 wrap = False # user would want to know they're at the end of file
482 elif forceFindNext:
483 down = True
484 wrap = False # user would want to know they're at the end of file
485
486 badSyntax = False
487
488 # On replace dialog operations, user is allowed to replace the currently highlighted text to determine if it should be replaced or not.
489 # Typically, it is the text from a previous find operation, but we must check to see if it isn't, user may have moved the cursor or selected some other text accidentally.
490 # If the text is a match, then replace it.
491 if replace:
492 result, start, end, replText = findService.DoFind(findString, replaceString, self.GetCtrl().GetSelectedText(), 0, 0, True, matchCase, wholeWord, regExp, replace)
493 if result > 0:
494 self.GetCtrl().ReplaceSelection(replText)
495 self.GetDocument().Modify(True)
496 wx.GetApp().GetTopWindow().PushStatusText(_("1 occurrence of \"%s\" replaced") % findString)
497 if down:
498 startLoc += len(replText) # advance start location past replacement string to new text
499 endLoc = startLoc
500 elif result == FindService.FIND_SYNTAXERROR:
501 badSyntax = True
502 wx.GetApp().GetTopWindow().PushStatusText(_("Invalid regular expression \"%s\"") % findString)
503
504 if not badSyntax:
505 text = self.GetCtrl().GetText()
506
507 # Find the next matching text occurance or if it is a ReplaceAll, replace all occurances
508 # Even if the user is Replacing, we should replace here, but only select the text and let the user replace it with the next Replace operation
509 result, start, end, text = findService.DoFind(findString, replaceString, text, startLoc, endLoc, down, matchCase, wholeWord, regExp, False, replaceAll, wrap)
510 if result > 0:
511 self.GetCtrl().SetTargetStart(0)
512 self.GetCtrl().SetTargetEnd(self.GetCtrl().GetLength())
513 self.GetCtrl().ReplaceTarget(text) # Doing a SetText causes a clear document to be shown when undoing, so using replacetarget instead
514 self.GetDocument().Modify(True)
515 if result == 1:
516 wx.GetApp().GetTopWindow().PushStatusText(_("1 occurrence of \"%s\" replaced") % findString)
517 else:
518 wx.GetApp().GetTopWindow().PushStatusText(_("%i occurrences of \"%s\" replaced") % (result, findString))
519 elif result == 0:
520 self.GetCtrl().SetSelection(start, end)
521 self.GetCtrl().EnsureVisible(self.GetCtrl().LineFromPosition(end)) # show bottom then scroll up to top
522 self.GetCtrl().EnsureVisible(self.GetCtrl().LineFromPosition(start)) # do this after ensuring bottom is visible
523 wx.GetApp().GetTopWindow().PushStatusText(_("Found \"%s\".") % findString)
524 elif result == FindService.FIND_SYNTAXERROR:
525 # Dialog for this case gets popped up by the FindService.
526 wx.GetApp().GetTopWindow().PushStatusText(_("Invalid regular expression \"%s\"") % findString)
527 else:
528 wx.MessageBox(_("Can't find \"%s\".") % findString, "Find",
529 wx.OK | wx.ICON_INFORMATION)
530
531
532 def _FindServiceHasString(self):
533 findService = wx.GetApp().GetService(FindService.FindService)
534 if not findService or not findService.GetFindString():
535 return False
536 return True
537
538
539 def OnGotoLine(self, event):
540 findService = wx.GetApp().GetService(FindService.FindService)
541 if findService:
542 line = findService.GetLineNumber(self.GetDocumentManager().FindSuitableParent())
543 if line > -1:
544 line = line - 1
545 self.GetCtrl().EnsureVisible(line)
546 self.GetCtrl().GotoLine(line)
547
548
549 def GotoLine(self, lineNum):
550 if lineNum > -1:
551 lineNum = lineNum - 1 # line numbering for editor is 0 based, we are 1 based.
552 self.GetCtrl().EnsureVisibleEnforcePolicy(lineNum)
553 self.GetCtrl().GotoLine(lineNum)
554
555
556 def SetSelection(self, start, end):
557 self.GetCtrl().SetSelection(start, end)
558
559
560 def EnsureVisible(self, line):
561 self.GetCtrl().EnsureVisible(line-1) # line numbering for editor is 0 based, we are 1 based.
562
563 def EnsureVisibleEnforcePolicy(self, line):
564 self.GetCtrl().EnsureVisibleEnforcePolicy(line-1) # line numbering for editor is 0 based, we are 1 based.
565
566 def LineFromPosition(self, pos):
567 return self.GetCtrl().LineFromPosition(pos)+1 # line numbering for editor is 0 based, we are 1 based.
568
569
570 def PositionFromLine(self, line):
571 return self.GetCtrl().PositionFromLine(line-1) # line numbering for editor is 0 based, we are 1 based.
572
573
574 def GetLineEndPosition(self, line):
575 return self.GetCtrl().GetLineEndPosition(line-1) # line numbering for editor is 0 based, we are 1 based.
576
577
578 def GetLine(self, lineNum):
579 return self.GetCtrl().GetLine(lineNum-1) # line numbering for editor is 0 based, we are 1 based.
580
581 def MarkerDefine(self):
582 """ This must be called after the texteditor is instantiated """
583 self.GetCtrl().MarkerDefine(TextView.MARKER_NUM, wx.stc.STC_MARK_CIRCLE, wx.BLACK, wx.BLUE)
584
585
586 def MarkerToggle(self, lineNum = -1, marker_index=MARKER_NUM, mask=MARKER_MASK):
587 if lineNum == -1:
588 lineNum = self.GetCtrl().GetCurrentLine()
589 if self.GetCtrl().MarkerGet(lineNum) & mask:
590 self.GetCtrl().MarkerDelete(lineNum, marker_index)
591 self._markerCount -= 1
592 else:
593 self.GetCtrl().MarkerAdd(lineNum, marker_index)
594 self._markerCount += 1
595
596 def MarkerAdd(self, lineNum = -1, marker_index=MARKER_NUM, mask=MARKER_MASK):
597 if lineNum == -1:
598 lineNum = self.GetCtrl().GetCurrentLine()
599 self.GetCtrl().MarkerAdd(lineNum, marker_index)
600 self._markerCount += 1
601
602
603 def MarkerDelete(self, lineNum = -1, marker_index=MARKER_NUM, mask=MARKER_MASK):
604 if lineNum == -1:
605 lineNum = self.GetCtrl().GetCurrentLine()
606 if self.GetCtrl().MarkerGet(lineNum) & mask:
607 self.GetCtrl().MarkerDelete(lineNum, marker_index)
608 self._markerCount -= 1
609
610 def MarkerDeleteAll(self, marker_num=MARKER_NUM):
611 self.GetCtrl().MarkerDeleteAll(marker_num)
612 if marker_num == self.MARKER_NUM:
613 self._markerCount = 0
614
615
616 def MarkerNext(self, lineNum = -1):
617 if lineNum == -1:
618 lineNum = self.GetCtrl().GetCurrentLine() + 1 # start search below current line
619 foundLine = self.GetCtrl().MarkerNext(lineNum, self.MARKER_MASK)
620 if foundLine == -1:
621 # wrap to top of file
622 foundLine = self.GetCtrl().MarkerNext(0, self.MARKER_MASK)
623 if foundLine == -1:
624 wx.GetApp().GetTopWindow().PushStatusText(_("No markers"))
625 return
626
627 self.GotoLine(foundLine + 1)
628
629
630 def MarkerPrevious(self, lineNum = -1):
631 if lineNum == -1:
632 lineNum = self.GetCtrl().GetCurrentLine() - 1 # start search above current line
633 if lineNum == -1:
634 lineNum = self.GetCtrl().GetLineCount()
635
636 foundLine = self.GetCtrl().MarkerPrevious(lineNum, self.MARKER_MASK)
637 if foundLine == -1:
638 # wrap to bottom of file
639 foundLine = self.GetCtrl().MarkerPrevious(self.GetCtrl().GetLineCount(), self.MARKER_MASK)
640 if foundLine == -1:
641 wx.GetApp().GetTopWindow().PushStatusText(_("No markers"))
642 return
643
644 self.GotoLine(foundLine + 1)
645
646
647 def MarkerExists(self, lineNum = -1, mask=MARKER_MASK):
648 if lineNum == -1:
649 lineNum = self.GetCtrl().GetCurrentLine()
650 if self.GetCtrl().MarkerGet(lineNum) & mask:
651 return True
652 else:
653 return False
654
655
656 def GetMarkerCount(self):
657 return self._markerCount
658
659
660class TextService(wx.lib.pydocview.DocService):
661
662
663 def __init__(self):
664 wx.lib.pydocview.DocService.__init__(self)
665
666
667 def InstallControls(self, frame, menuBar = None, toolBar = None, statusBar = None, document = None):
668 if document and document.GetDocumentTemplate().GetDocumentType() != TextDocument:
669 return
670 if not document and wx.GetApp().GetDocumentManager().GetFlags() & wx.lib.docview.DOC_SDI:
671 return
672
673 statusBar = TextStatusBar(frame, TEXT_STATUS_BAR_ID)
674 frame.SetStatusBar(statusBar)
675 wx.EVT_UPDATE_UI(frame, TEXT_STATUS_BAR_ID, frame.ProcessUpdateUIEvent)
676
677 viewMenu = menuBar.GetMenu(menuBar.FindMenu(_("&View")))
678
679 viewMenu.AppendSeparator()
680 textMenu = wx.Menu()
681 textMenu.AppendCheckItem(VIEW_WHITESPACE_ID, _("&Whitespace"), _("Shows or hides whitespace"))
682 wx.EVT_MENU(frame, VIEW_WHITESPACE_ID, frame.ProcessEvent)
683 wx.EVT_UPDATE_UI(frame, VIEW_WHITESPACE_ID, frame.ProcessUpdateUIEvent)
684 textMenu.AppendCheckItem(VIEW_EOL_ID, _("&End of Line Markers"), _("Shows or hides indicators at the end of each line"))
685 wx.EVT_MENU(frame, VIEW_EOL_ID, frame.ProcessEvent)
686 wx.EVT_UPDATE_UI(frame, VIEW_EOL_ID, frame.ProcessUpdateUIEvent)
687 textMenu.AppendCheckItem(VIEW_INDENTATION_GUIDES_ID, _("&Indentation Guides"), _("Shows or hides indentations"))
688 wx.EVT_MENU(frame, VIEW_INDENTATION_GUIDES_ID, frame.ProcessEvent)
689 wx.EVT_UPDATE_UI(frame, VIEW_INDENTATION_GUIDES_ID, frame.ProcessUpdateUIEvent)
690 textMenu.AppendCheckItem(VIEW_RIGHT_EDGE_ID, _("&Right Edge"), _("Shows or hides the right edge marker"))
691 wx.EVT_MENU(frame, VIEW_RIGHT_EDGE_ID, frame.ProcessEvent)
692 wx.EVT_UPDATE_UI(frame, VIEW_RIGHT_EDGE_ID, frame.ProcessUpdateUIEvent)
693 textMenu.AppendCheckItem(VIEW_LINE_NUMBERS_ID, _("&Line Numbers"), _("Shows or hides the line numbers"))
694 wx.EVT_MENU(frame, VIEW_LINE_NUMBERS_ID, frame.ProcessEvent)
695 wx.EVT_UPDATE_UI(frame, VIEW_LINE_NUMBERS_ID, frame.ProcessUpdateUIEvent)
696
697 viewMenu.AppendMenu(TEXT_ID, _("&Text"), textMenu)
698 wx.EVT_UPDATE_UI(frame, TEXT_ID, frame.ProcessUpdateUIEvent)
699
700 isWindows = (wx.Platform == '__WXMSW__')
701
702 zoomMenu = wx.Menu()
703 zoomMenu.Append(ZOOM_NORMAL_ID, _("Normal Size"), _("Sets the document to its normal size"))
704 wx.EVT_MENU(frame, ZOOM_NORMAL_ID, frame.ProcessEvent)
705 wx.EVT_UPDATE_UI(frame, ZOOM_NORMAL_ID, frame.ProcessUpdateUIEvent)
706 if isWindows:
707 zoomMenu.Append(ZOOM_IN_ID, _("Zoom In\tCtrl+Page Up"), _("Zooms the document to a larger size"))
708 else:
709 zoomMenu.Append(ZOOM_IN_ID, _("Zoom In"), _("Zooms the document to a larger size"))
710 wx.EVT_MENU(frame, ZOOM_IN_ID, frame.ProcessEvent)
711 wx.EVT_UPDATE_UI(frame, ZOOM_IN_ID, frame.ProcessUpdateUIEvent)
712 if isWindows:
713 zoomMenu.Append(ZOOM_OUT_ID, _("Zoom Out\tCtrl+Page Down"), _("Zooms the document to a smaller size"))
714 else:
715 zoomMenu.Append(ZOOM_OUT_ID, _("Zoom Out"), _("Zooms the document to a smaller size"))
716 wx.EVT_MENU(frame, ZOOM_OUT_ID, frame.ProcessEvent)
717 wx.EVT_UPDATE_UI(frame, ZOOM_OUT_ID, frame.ProcessUpdateUIEvent)
718
719 viewMenu.AppendMenu(ZOOM_ID, _("&Zoom"), zoomMenu)
720 wx.EVT_UPDATE_UI(frame, ZOOM_ID, frame.ProcessUpdateUIEvent)
721
722 formatMenuIndex = menuBar.FindMenu(_("&Format"))
723 if formatMenuIndex > -1:
724 formatMenu = menuBar.GetMenu(formatMenuIndex)
725 else:
726 formatMenu = wx.Menu()
727 if not menuBar.FindItemById(CHOOSE_FONT_ID):
728 formatMenu.Append(CHOOSE_FONT_ID, _("&Font..."), _("Sets the font to use"))
729 wx.EVT_MENU(frame, CHOOSE_FONT_ID, frame.ProcessEvent)
730 wx.EVT_UPDATE_UI(frame, CHOOSE_FONT_ID, frame.ProcessUpdateUIEvent)
731 if not menuBar.FindItemById(WORD_WRAP_ID):
732 formatMenu.AppendCheckItem(WORD_WRAP_ID, _("Word Wrap"), _("Wraps text horizontally when checked"))
733 wx.EVT_MENU(frame, WORD_WRAP_ID, frame.ProcessEvent)
734 wx.EVT_UPDATE_UI(frame, WORD_WRAP_ID, frame.ProcessUpdateUIEvent)
735 if formatMenuIndex == -1:
736 viewMenuIndex = menuBar.FindMenu(_("&View"))
737 menuBar.Insert(viewMenuIndex + 1, formatMenu, _("&Format"))
738
739 # wxBug: wxToolBar::GetToolPos doesn't exist, need it to find cut tool and then insert find in front of it.
740 toolBar.AddSeparator()
741 toolBar.AddTool(ZOOM_IN_ID, getZoomInBitmap(), shortHelpString = _("Zoom In"), longHelpString = _("Zooms the document to a larger size"))
742 toolBar.AddTool(ZOOM_OUT_ID, getZoomOutBitmap(), shortHelpString = _("Zoom Out"), longHelpString = _("Zooms the document to a smaller size"))
743 toolBar.Realize()
744
745
746 def ProcessUpdateUIEvent(self, event):
747 id = event.GetId()
748 if id == TEXT_ID:
749 event.Enable(False)
750 return True
751 elif id == VIEW_WHITESPACE_ID:
752 event.Enable(False)
753 return True
754 elif id == VIEW_EOL_ID:
755 event.Enable(False)
756 return True
757 elif id == VIEW_INDENTATION_GUIDES_ID:
758 event.Enable(False)
759 return True
760 elif id == VIEW_RIGHT_EDGE_ID:
761 event.Enable(False)
762 return True
763 elif id == VIEW_LINE_NUMBERS_ID:
764 event.Enable(False)
765 return True
766 elif id == ZOOM_ID:
767 event.Enable(False)
768 return True
769 elif id == ZOOM_NORMAL_ID:
770 event.Enable(False)
771 return True
772 elif id == ZOOM_IN_ID:
773 event.Enable(False)
774 return True
775 elif id == ZOOM_OUT_ID:
776 event.Enable(False)
777 return True
778 elif id == CHOOSE_FONT_ID:
779 event.Enable(False)
780 return True
781 elif id == WORD_WRAP_ID:
782 event.Enable(False)
783 return True
784 else:
785 return False
786
787
788class TextStatusBar(wx.StatusBar):
789
790 # wxBug: Would be nice to show num key status in statusbar, but can't figure out how to detect if it is enabled or disabled
791
792 def __init__(self, parent, id, style = wx.ST_SIZEGRIP, name = "statusBar"):
793 wx.StatusBar.__init__(self, parent, id, style, name)
794 self.SetFieldsCount(4)
795 self.SetStatusWidths([-1, 50, 50, 55])
796
797 def SetInsertMode(self, insert = True):
798 if insert:
799 newText = _("Ins")
800 else:
801 newText = _("")
802 if self.GetStatusText(1) != newText: # wxBug: Need to check if the text has changed, otherwise it flickers under win32
803 self.SetStatusText(newText, 1)
804
805 def SetLineNumber(self, lineNumber):
806 newText = _("Ln %i") % lineNumber
807 if self.GetStatusText(2) != newText:
808 self.SetStatusText(newText, 2)
809
810 def SetColumnNumber(self, colNumber):
811 newText = _("Col %i") % colNumber
812 if self.GetStatusText(3) != newText:
813 self.SetStatusText(newText, 3)
814
815
816class TextOptionsPanel(wx.Panel):
817
818
819 def __init__(self, parent, id, configPrefix = "Text", label = "Text", hasWordWrap = True, hasTabs = False, addPage=True):
820 wx.Panel.__init__(self, parent, id)
821 self._configPrefix = configPrefix
822 self._hasWordWrap = hasWordWrap
823 self._hasTabs = hasTabs
824 SPACE = 10
825 HALF_SPACE = 5
826 config = wx.ConfigBase_Get()
827 self._textFont = wx.Font(10, wx.MODERN, wx.NORMAL, wx.NORMAL)
828 fontData = config.Read(self._configPrefix + "EditorFont", "")
829 if fontData:
830 nativeFont = wx.NativeFontInfo()
831 nativeFont.FromString(fontData)
832 self._textFont.SetNativeFontInfo(nativeFont)
833 self._originalTextFont = self._textFont
834 self._textColor = wx.BLACK
835 colorData = config.Read(self._configPrefix + "EditorColor", "")
836 if colorData:
837 red = int("0x" + colorData[0:2], 16)
838 green = int("0x" + colorData[2:4], 16)
839 blue = int("0x" + colorData[4:6], 16)
840 self._textColor = wx.Color(red, green, blue)
841 self._originalTextColor = self._textColor
842 fontLabel = wx.StaticText(self, -1, _("Font:"))
843 self._sampleTextCtrl = wx.TextCtrl(self, -1, "", size = (125, 21))
844 self._sampleTextCtrl.SetEditable(False)
845 chooseFontButton = wx.Button(self, -1, _("Choose Font..."))
846 wx.EVT_BUTTON(self, chooseFontButton.GetId(), self.OnChooseFont)
847 if self._hasWordWrap:
848 self._wordWrapCheckBox = wx.CheckBox(self, -1, _("Wrap words inside text area"))
849 self._wordWrapCheckBox.SetValue(wx.ConfigBase_Get().ReadInt(self._configPrefix + "EditorWordWrap", False))
850 self._viewWhitespaceCheckBox = wx.CheckBox(self, -1, _("Show whitespace"))
851 self._viewWhitespaceCheckBox.SetValue(config.ReadInt(self._configPrefix + "EditorViewWhitespace", False))
852 self._viewEOLCheckBox = wx.CheckBox(self, -1, _("Show end of line markers"))
853 self._viewEOLCheckBox.SetValue(config.ReadInt(self._configPrefix + "EditorViewEOL", False))
854 self._viewIndentationGuideCheckBox = wx.CheckBox(self, -1, _("Show indentation guides"))
855 self._viewIndentationGuideCheckBox.SetValue(config.ReadInt(self._configPrefix + "EditorViewIndentationGuides", False))
856 self._viewRightEdgeCheckBox = wx.CheckBox(self, -1, _("Show right edge"))
857 self._viewRightEdgeCheckBox.SetValue(config.ReadInt(self._configPrefix + "EditorViewRightEdge", False))
858 self._viewLineNumbersCheckBox = wx.CheckBox(self, -1, _("Show line numbers"))
859 self._viewLineNumbersCheckBox.SetValue(config.ReadInt(self._configPrefix + "EditorViewLineNumbers", True))
860 if self._hasTabs:
861 self._hasTabsCheckBox = wx.CheckBox(self, -1, _("Use spaces instead of tabs"))
862 self._hasTabsCheckBox.SetValue(not wx.ConfigBase_Get().ReadInt(self._configPrefix + "EditorUseTabs", False))
863 indentWidthLabel = wx.StaticText(self, -1, _("Indent Width:"))
864 self._indentWidthChoice = wx.Choice(self, -1, choices = ["2", "4", "6", "8", "10"])
865 self._indentWidthChoice.SetStringSelection(str(config.ReadInt(self._configPrefix + "EditorIndentWidth", 4)))
866 textPanelBorderSizer = wx.BoxSizer(wx.VERTICAL)
867 textPanelSizer = wx.BoxSizer(wx.VERTICAL)
868 textFontSizer = wx.BoxSizer(wx.HORIZONTAL)
869 textFontSizer.Add(fontLabel, 0, wx.ALIGN_LEFT | wx.RIGHT | wx.TOP, HALF_SPACE)
870 textFontSizer.Add(self._sampleTextCtrl, 0, wx.ALIGN_LEFT | wx.EXPAND | wx.RIGHT, HALF_SPACE)
871 textFontSizer.Add(chooseFontButton, 0, wx.ALIGN_RIGHT | wx.LEFT, HALF_SPACE)
872 textPanelSizer.Add(textFontSizer, 0, wx.ALL, HALF_SPACE)
873 if self._hasWordWrap:
874 textPanelSizer.Add(self._wordWrapCheckBox, 0, wx.ALL, HALF_SPACE)
875 textPanelSizer.Add(self._viewWhitespaceCheckBox, 0, wx.ALL, HALF_SPACE)
876 textPanelSizer.Add(self._viewEOLCheckBox, 0, wx.ALL, HALF_SPACE)
877 textPanelSizer.Add(self._viewIndentationGuideCheckBox, 0, wx.ALL, HALF_SPACE)
878 textPanelSizer.Add(self._viewRightEdgeCheckBox, 0, wx.ALL, HALF_SPACE)
879 textPanelSizer.Add(self._viewLineNumbersCheckBox, 0, wx.ALL, HALF_SPACE)
880 if self._hasTabs:
881 textPanelSizer.Add(self._hasTabsCheckBox, 0, wx.ALL, HALF_SPACE)
882 textIndentWidthSizer = wx.BoxSizer(wx.HORIZONTAL)
883 textIndentWidthSizer.Add(indentWidthLabel, 0, wx.ALIGN_LEFT | wx.RIGHT | wx.TOP, HALF_SPACE)
884 textIndentWidthSizer.Add(self._indentWidthChoice, 0, wx.ALIGN_LEFT | wx.EXPAND, HALF_SPACE)
885 textPanelSizer.Add(textIndentWidthSizer, 0, wx.ALL, HALF_SPACE)
886 textPanelBorderSizer.Add(textPanelSizer, 0, wx.ALL, SPACE)
887## styleButton = wx.Button(self, -1, _("Choose Style..."))
888## wx.EVT_BUTTON(self, styleButton.GetId(), self.OnChooseStyle)
889## textPanelBorderSizer.Add(styleButton, 0, wx.ALL, SPACE)
890 self.SetSizer(textPanelBorderSizer)
891 self.UpdateSampleFont()
892 if addPage:
893 parent.AddPage(self, _(label))
894
895 def UpdateSampleFont(self):
896 nativeFont = wx.NativeFontInfo()
897 nativeFont.FromString(self._textFont.GetNativeFontInfoDesc())
898 font = wx.NullFont
899 font.SetNativeFontInfo(nativeFont)
900 font.SetPointSize(self._sampleTextCtrl.GetFont().GetPointSize()) # Use the standard point size
901 self._sampleTextCtrl.SetFont(font)
902 self._sampleTextCtrl.SetForegroundColour(self._textColor)
903 self._sampleTextCtrl.SetValue(str(self._textFont.GetPointSize()) + _(" pt. ") + self._textFont.GetFaceName())
904 self._sampleTextCtrl.Refresh()
905 self.Layout()
906
907
908## def OnChooseStyle(self, event):
909## import STCStyleEditor
910## import os
911## base = os.path.split(__file__)[0]
912## config = os.path.abspath(os.path.join(base, 'stc-styles.rc.cfg'))
913##
914## dlg = STCStyleEditor.STCStyleEditDlg(None,
915## 'Python', 'python',
916## #'HTML', 'html',
917## #'XML', 'xml',
918## config)
919## try:
920## dlg.ShowModal()
921## finally:
922## dlg.Destroy()
923
924
925 def OnChooseFont(self, event):
926 data = wx.FontData()
927 data.EnableEffects(True)
928 data.SetInitialFont(self._textFont)
929 data.SetColour(self._textColor)
930 fontDialog = wx.FontDialog(self, data)
931 if fontDialog.ShowModal() == wx.ID_OK:
932 data = fontDialog.GetFontData()
933 self._textFont = data.GetChosenFont()
934 self._textColor = data.GetColour()
935 self.UpdateSampleFont()
936 fontDialog.Destroy()
937
938
939 def OnOK(self, optionsDialog):
940 config = wx.ConfigBase_Get()
941 doViewStuffUpdate = config.ReadInt(self._configPrefix + "EditorViewWhitespace", False) != self._viewWhitespaceCheckBox.GetValue()
942 config.WriteInt(self._configPrefix + "EditorViewWhitespace", self._viewWhitespaceCheckBox.GetValue())
943 doViewStuffUpdate = doViewStuffUpdate or config.ReadInt(self._configPrefix + "EditorViewEOL", False) != self._viewEOLCheckBox.GetValue()
944 config.WriteInt(self._configPrefix + "EditorViewEOL", self._viewEOLCheckBox.GetValue())
945 doViewStuffUpdate = doViewStuffUpdate or config.ReadInt(self._configPrefix + "EditorViewIndentationGuides", False) != self._viewIndentationGuideCheckBox.GetValue()
946 config.WriteInt(self._configPrefix + "EditorViewIndentationGuides", self._viewIndentationGuideCheckBox.GetValue())
947 doViewStuffUpdate = doViewStuffUpdate or config.ReadInt(self._configPrefix + "EditorViewRightEdge", False) != self._viewRightEdgeCheckBox.GetValue()
948 config.WriteInt(self._configPrefix + "EditorViewRightEdge", self._viewRightEdgeCheckBox.GetValue())
949 doViewStuffUpdate = doViewStuffUpdate or config.ReadInt(self._configPrefix + "EditorViewLineNumbers", True) != self._viewLineNumbersCheckBox.GetValue()
950 config.WriteInt(self._configPrefix + "EditorViewLineNumbers", self._viewLineNumbersCheckBox.GetValue())
951 if self._hasWordWrap:
952 doViewStuffUpdate = doViewStuffUpdate or config.ReadInt(self._configPrefix + "EditorWordWrap", False) != self._wordWrapCheckBox.GetValue()
953 config.WriteInt(self._configPrefix + "EditorWordWrap", self._wordWrapCheckBox.GetValue())
954 if self._hasTabs:
955 doViewStuffUpdate = doViewStuffUpdate or not config.ReadInt(self._configPrefix + "EditorUseTabs", True) != self._hasTabsCheckBox.GetValue()
956 config.WriteInt(self._configPrefix + "EditorUseTabs", not self._hasTabsCheckBox.GetValue())
957 newIndentWidth = int(self._indentWidthChoice.GetStringSelection())
958 oldIndentWidth = config.ReadInt(self._configPrefix + "EditorIndentWidth", 4)
959 if newIndentWidth != oldIndentWidth:
960 doViewStuffUpdate = True
961 config.WriteInt(self._configPrefix + "EditorIndentWidth", newIndentWidth)
962 doFontUpdate = self._originalTextFont != self._textFont or self._originalTextColor != self._textColor
963 config.Write(self._configPrefix + "EditorFont", self._textFont.GetNativeFontInfoDesc())
964 config.Write(self._configPrefix + "EditorColor", "%02x%02x%02x" % (self._textColor.Red(), self._textColor.Green(), self._textColor.Blue()))
965 if doViewStuffUpdate or doFontUpdate:
966 for document in optionsDialog.GetDocManager().GetDocuments():
967 if issubclass(document.GetDocumentTemplate().GetDocumentType(), TextDocument):
968 if doViewStuffUpdate:
969 document.UpdateAllViews(hint = "ViewStuff")
970 if doFontUpdate:
971 document.UpdateAllViews(hint = "Font")
972
973
974class TextCtrl(wx.stc.StyledTextCtrl):
975
976 def __init__(self, parent, ID = -1, style = wx.NO_FULL_REPAINT_ON_RESIZE):
977 if ID == -1:
978 ID = wx.NewId()
979 wx.stc.StyledTextCtrl.__init__(self, parent, ID, style = style)
980
981 self._font = None
982 self._fontColor = None
983
984 self.SetVisiblePolicy(wx.stc.STC_VISIBLE_STRICT,1)
985
986 self.CmdKeyClear(wx.stc.STC_KEY_ADD, wx.stc.STC_SCMOD_CTRL)
987 self.CmdKeyClear(wx.stc.STC_KEY_SUBTRACT, wx.stc.STC_SCMOD_CTRL)
988 self.CmdKeyAssign(wx.stc.STC_KEY_PRIOR, wx.stc.STC_SCMOD_CTRL, wx.stc.STC_CMD_ZOOMIN)
989 self.CmdKeyAssign(wx.stc.STC_KEY_NEXT, wx.stc.STC_SCMOD_CTRL, wx.stc.STC_CMD_ZOOMOUT)
990 self.Bind(wx.stc.EVT_STC_ZOOM, self.OnUpdateLineNumberMarginWidth) # auto update line num width on zoom
991 wx.EVT_KEY_DOWN(self, self.OnKeyPressed)
992 self.SetMargins(0,0)
993
994 self.SetUseTabs(0)
995 self.SetTabWidth(4)
996 self.SetIndent(4)
997
998 self.SetViewWhiteSpace(False)
999 self.SetEOLMode(wx.stc.STC_EOL_LF)
1000 self.SetEdgeMode(wx.stc.STC_EDGE_NONE)
1001 self.SetEdgeColumn(78)
1002
1003 self.SetMarginType(1, wx.stc.STC_MARGIN_NUMBER)
1004 self.SetMarginWidth(1, self.EstimatedLineNumberMarginWidth())
1005 self.UpdateStyles()
1006
1007 self.SetCaretForeground("BLACK")
1008
1009 self.SetViewDefaults()
1010 font, color = self.GetFontAndColorFromConfig()
1011 self.SetFont(font)
1012 self.SetFontColor(color)
1013 self.MarkerDefineDefault()
1014
1015 # for multisash initialization
1016 if isinstance(parent, wx.lib.multisash.MultiClient):
1017 while parent.GetParent():
1018 parent = parent.GetParent()
1019 if hasattr(parent, "GetView"):
1020 break
1021 if hasattr(parent, "GetView"):
1022 textEditor = parent.GetView()._textEditor
1023 if textEditor:
1024 doc = textEditor.GetDocPointer()
1025 if doc:
1026 self.SetDocPointer(doc)
1027
1028
1029
1030 def SetViewDefaults(self, configPrefix = "Text", hasWordWrap = True, hasTabs = False):
1031 config = wx.ConfigBase_Get()
1032 self.SetViewWhiteSpace(config.ReadInt(configPrefix + "EditorViewWhitespace", False))
1033 self.SetViewEOL(config.ReadInt(configPrefix + "EditorViewEOL", False))
1034 self.SetIndentationGuides(config.ReadInt(configPrefix + "EditorViewIndentationGuides", False))
1035 self.SetViewRightEdge(config.ReadInt(configPrefix + "EditorViewRightEdge", False))
1036 self.SetViewLineNumbers(config.ReadInt(configPrefix + "EditorViewLineNumbers", True))
1037 if hasWordWrap:
1038 self.SetWordWrap(config.ReadInt(configPrefix + "EditorWordWrap", False))
1039 if hasTabs: # These methods do not exist in STCTextEditor and are meant for subclasses
1040 self.SetUseTabs(config.ReadInt(configPrefix + "EditorUseTabs", False))
1041 self.SetIndent(config.ReadInt(configPrefix + "EditorIndentWidth", 4))
1042 self.SetTabWidth(config.ReadInt(configPrefix + "EditorIndentWidth", 4))
1043 else:
1044 self.SetUseTabs(True)
1045 self.SetIndent(4)
1046 self.SetTabWidth(4)
1047
1048
1049
1050 def GetDefaultFont(self):
1051 """ Subclasses should override this """
1052 return wx.Font(10, wx.MODERN, wx.NORMAL, wx.NORMAL)
1053
1054
1055 def GetDefaultColor(self):
1056 """ Subclasses should override this """
1057 return wx.BLACK
1058
1059
1060 def GetFontAndColorFromConfig(self, configPrefix = "Text"):
1061 font = self.GetDefaultFont()
1062 config = wx.ConfigBase_Get()
1063 fontData = config.Read(configPrefix + "EditorFont", "")
1064 if fontData:
1065 nativeFont = wx.NativeFontInfo()
1066 nativeFont.FromString(fontData)
1067 font.SetNativeFontInfo(nativeFont)
1068 color = self.GetDefaultColor()
1069 colorData = config.Read(configPrefix + "EditorColor", "")
1070 if colorData:
1071 red = int("0x" + colorData[0:2], 16)
1072 green = int("0x" + colorData[2:4], 16)
1073 blue = int("0x" + colorData[4:6], 16)
1074 color = wx.Color(red, green, blue)
1075 return font, color
1076
1077
1078 def GetFont(self):
1079 return self._font
1080
1081 def SetFont(self, font):
1082 self._font = font
1083 self.StyleSetFont(wx.stc.STC_STYLE_DEFAULT, self._font)
1084
1085
1086 def GetFontColor(self):
1087 return self._fontColor
1088
1089
1090 def SetFontColor(self, fontColor = wx.BLACK):
1091 self._fontColor = fontColor
1092 self.StyleSetForeground(wx.stc.STC_STYLE_DEFAULT, "#%02x%02x%02x" % (self._fontColor.Red(), self._fontColor.Green(), self._fontColor.Blue()))
1093
1094
1095 def UpdateStyles(self):
1096 self.StyleClearAll()
1097 return
1098
1099
1100 def EstimatedLineNumberMarginWidth(self):
1101 MARGIN = 4
1102 baseNumbers = "000"
1103 lineNum = self.GetLineCount()
1104 lineNum = lineNum/100
1105 while lineNum >= 10:
1106 lineNum = lineNum/10
1107 baseNumbers = baseNumbers + "0"
1108
1109 return self.TextWidth(wx.stc.STC_STYLE_LINENUMBER, baseNumbers) + MARGIN
1110
1111
1112 def OnUpdateLineNumberMarginWidth(self, event):
1113 self.UpdateLineNumberMarginWidth()
1114
1115
1116 def UpdateLineNumberMarginWidth(self):
1117 if self.GetViewLineNumbers():
1118 self.SetMarginWidth(1, self.EstimatedLineNumberMarginWidth())
1119
1120 def MarkerDefineDefault(self):
1121 """ This must be called after the textcontrol is instantiated """
1122 self.MarkerDefine(TextView.MARKER_NUM, wx.stc.STC_MARK_ROUNDRECT, wx.BLACK, wx.BLUE)
1123
1124
1125 def OnClear(self):
1126 # Used when Delete key is hit.
1127 sel = self.GetSelection()
1128
1129 # Delete the selection or if no selection, the character after the caret.
1130 if sel[0] == sel[1]:
1131 self.SetSelection(sel[0], sel[0] + 1)
1132 else:
1133 # remove any folded lines also.
1134 startLine = self.LineFromPosition(sel[0])
1135 endLine = self.LineFromPosition(sel[1])
1136 endLineStart = self.PositionFromLine(endLine)
1137 if startLine != endLine and sel[1] - endLineStart == 0:
1138 while not self.GetLineVisible(endLine):
1139 endLine += 1
1140 self.SetSelectionEnd(self.PositionFromLine(endLine))
1141
1142 self.Clear()
1143
1144
1145 def OnPaste(self):
1146 # replace any folded lines also.
1147 sel = self.GetSelection()
1148 startLine = self.LineFromPosition(sel[0])
1149 endLine = self.LineFromPosition(sel[1])
1150 endLineStart = self.PositionFromLine(endLine)
1151 if startLine != endLine and sel[1] - endLineStart == 0:
1152 while not self.GetLineVisible(endLine):
1153 endLine += 1
1154 self.SetSelectionEnd(self.PositionFromLine(endLine))
1155
1156 self.Paste()
1157
1158
1159 def OnKeyPressed(self, event):
1160 key = event.GetKeyCode()
1161 if key == wx.WXK_NUMPAD_ADD: #wxBug: For whatever reason, the key accelerators for numpad add and subtract with modifiers are not working so have to trap them here
1162 if event.ControlDown():
1163 self.ToggleFoldAll(expand = True, topLevelOnly = True)
1164 elif event.ShiftDown():
1165 self.ToggleFoldAll(expand = True)
1166 else:
1167 self.ToggleFold(self.GetCurrentLine())
1168 elif key == wx.WXK_NUMPAD_SUBTRACT:
1169 if event.ControlDown():
1170 self.ToggleFoldAll(expand = False, topLevelOnly = True)
1171 elif event.ShiftDown():
1172 self.ToggleFoldAll(expand = False)
1173 else:
1174 self.ToggleFold(self.GetCurrentLine())
1175 else:
1176 event.Skip()
1177
1178
1179 #----------------------------------------------------------------------------
1180 # View Text methods
1181 #----------------------------------------------------------------------------
1182
1183 def GetViewRightEdge(self):
1184 return self.GetEdgeMode() != wx.stc.STC_EDGE_NONE
1185
1186
1187 def SetViewRightEdge(self, viewRightEdge):
1188 if viewRightEdge:
1189 self.SetEdgeMode(wx.stc.STC_EDGE_LINE)
1190 else:
1191 self.SetEdgeMode(wx.stc.STC_EDGE_NONE)
1192
1193
1194 def GetViewLineNumbers(self):
1195 return self.GetMarginWidth(1) > 0
1196
1197
1198 def SetViewLineNumbers(self, viewLineNumbers = True):
1199 if viewLineNumbers:
1200 self.SetMarginWidth(1, self.EstimatedLineNumberMarginWidth())
1201 else:
1202 self.SetMarginWidth(1, 0)
1203
1204
1205 def CanWordWrap(self):
1206 return True
1207
1208
1209 def GetWordWrap(self):
1210 return self.GetWrapMode() == wx.stc.STC_WRAP_WORD
1211
1212
1213 def SetWordWrap(self, wordWrap):
1214 if wordWrap:
1215 self.SetWrapMode(wx.stc.STC_WRAP_WORD)
1216 else:
1217 self.SetWrapMode(wx.stc.STC_WRAP_NONE)
1218
1219
1220#----------------------------------------------------------------------------
1221# Icon Bitmaps - generated by encode_bitmaps.py
1222#----------------------------------------------------------------------------
1223from wx import ImageFromStream, BitmapFromImage
1224import cStringIO
1225
1226
1227def getTextData():
1228 return \
1229'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
1230\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
1231\x00\x00`IDAT8\x8d\xed\x931\x0e\xc00\x08\x03m\x92\xff\xff8q\xa7JU!$\x12\x1d\
1232\xeb\t\t8n\x81\xb4\x86J\xfa]h\x0ee\x83\xb4\xc6\x14\x00\x00R\xcc \t\xcd\xa1\
1233\x08\xd2\xa3\xe1\x08*\t$\x1d\xc4\x012\x0b\x00\xce\xe4\xc8\xe0\t}\xf7\x8f\rV\
1234\xd9\x1a\xec\xe0\xbf\xc1\xd7\x06\xd9\xf5UX\xfdF+m\x03\xb8\x00\xe4\xc74B"x\
1235\xf1\xf4\x00\x00\x00\x00IEND\xaeB`\x82'
1236
1237
1238def getTextBitmap():
1239 return BitmapFromImage(getTextImage())
1240
1241def getTextImage():
1242 stream = cStringIO.StringIO(getTextData())
1243 return ImageFromStream(stream)
1244
1245def getTextIcon():
1246 return wx.IconFromBitmap(getTextBitmap())
1247
1248
1249#----------------------------------------------------------------------------
1250# Menu Bitmaps - generated by encode_bitmaps.py
1251#----------------------------------------------------------------------------
1252#----------------------------------------------------------------------
1253def getZoomInData():
1254 return \
1255'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
1256\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
1257\x00\x00wIDAT8\x8d\xa5\x93Q\x12\x80 \x08D\xb5\xe9X\xee\xe9\xb7{\xd5Gc\xa9\
1258\xacX\xca\x1f\xa0\x8fE0\x92<\xc3\x82\xed*\x08\xa0\xf2I~\x07\x000\x17T,\xdb\
1259\xd6;\x08\xa4\x00\xa4GA\xab\xca\x00\xbc*\x1eD\xb4\x90\xa4O\x1e\xe3\x16f\xcc(\
1260\xc8\x95F\x95\x8d\x02\xef\xa1n\xa0\xce\xc5v\x91zc\xacU\xbey\x03\xf0.\xa8\xb8\
1261\x04\x8c\xac\x04MM\xa1lA\xfe\x85?\x90\xe5=X\x06\\\xebCA\xb3Q\xf34\x14\x00\
1262\x00\x00\x00IEND\xaeB`\x82'
1263
1264def getZoomInBitmap():
1265 return BitmapFromImage(getZoomInImage())
1266
1267def getZoomInImage():
1268 stream = cStringIO.StringIO(getZoomInData())
1269 return ImageFromStream(stream)
1270
1271#----------------------------------------------------------------------
1272def getZoomOutData():
1273 return \
1274'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
1275\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
1276\x00\x00qIDAT8\x8d\xa5\x92Q\x0e\xc0 \x08C-z\xff\x13O\xd9\xd7\x16"\x05\x8d\
1277\xf6O\xa2\x8f"\x05\xa4\x96\x1b5V\xd4\xd1\xd5\x9e!\x15\xdb\x00\x1d]\xe7\x07\
1278\xac\xf6Iv.B*fW\x0e\x90u\xc9 d\x84\x87v\x82\xb4\xf5\x08\'r\x0e\xa2N\x91~\x07\
1279\xd9G\x95\xe2W\xeb\x00\x19\xc4\xd6\\FX\x12\xa3 \xb1:\x05\xacdAG[\xb0y9r`u\
1280\x9d\x83k\xc0\x0b#3@0A\x0c"\x93\x00\x00\x00\x00IEND\xaeB`\x82'
1281
1282
1283def getZoomOutBitmap():
1284 return BitmapFromImage(getZoomOutImage())
1285
1286def getZoomOutImage():
1287 stream = cStringIO.StringIO(getZoomOutData())
1288 return ImageFromStream(stream)
1289
1290
1291