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