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