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