1 #----------------------------------------------------------------------------
2 # Name: STCTextEditor.py
3 # Purpose: Text Editor for wx.lib.pydocview tbat uses the Styled Text Control
5 # Author: Peter Yared, Morgan Hua
9 # Copyright: (c) 2003-2006 ActiveGrid, Inc.
10 # License: wxWindows License
11 #----------------------------------------------------------------------------
16 import wx
.lib
.multisash
17 import wx
.lib
.pydocview
24 #----------------------------------------------------------------------------
26 #----------------------------------------------------------------------------
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()
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()
43 #----------------------------------------------------------------------------
45 #----------------------------------------------------------------------------
47 class TextDocument(wx
.lib
.docview
.Document
):
51 wx
.lib
.docview
.Document
.__init
__(self
)
52 self
._inModify
= False
55 def SaveObject(self
, fileObject
):
56 view
= self
.GetFirstView()
57 fileObject
.write(view
.GetValue())
62 def LoadObject(self
, fileObject
):
63 view
= self
.GetFirstView()
64 data
= fileObject
.read()
71 view
= self
.GetFirstView()
73 return view
.IsModified()
77 def Modify(self
, modify
):
82 view
= self
.GetFirstView()
83 if not modify
and view
:
86 wx
.lib
.docview
.Document
.Modify(self
, modify
) # this must called be after the SetModifyFalse call above.
88 self
._inModify
= False
91 def OnCreateCommandProcessor(self
):
92 # Don't create a command processor, it has its own
96 # Use this to override MultiClient.Select to prevent yellow background.
97 def MultiClientSelectBGNotYellow(a
):
98 a
.GetParent().multiView
.UnSelect()
100 #a.SetBackgroundColour(wx.Colour(255,255,0)) # Yellow
103 class TextView(wx
.lib
.docview
.View
):
107 #----------------------------------------------------------------------------
109 #----------------------------------------------------------------------------
112 wx
.lib
.docview
.View
.__init
__(self
)
113 self
._textEditor
= None
114 self
._markerCount
= 0
115 self
._commandProcessor
= None
119 def GetCtrlClass(self
):
120 """ Used in split window to instantiate new instances """
125 if wx
.Platform
== "__WXMAC__":
126 # look for active one first
127 self
._textEditor
= self
._GetActiveCtrl
(self
._dynSash
)
128 if self
._textEditor
== None: # it is possible none are active
129 # look for any existing one
130 self
._textEditor
= self
._FindCtrl
(self
._dynSash
)
131 return self
._textEditor
134 def SetCtrl(self
, ctrl
):
135 self
._textEditor
= ctrl
138 def OnCreatePrintout(self
):
139 """ for Print Preview and Print """
140 return TextPrintout(self
, self
.GetDocument().GetPrintableName())
143 def OnCreate(self
, doc
, flags
):
144 frame
= wx
.GetApp().CreateDocumentFrame(self
, doc
, flags
, style
= wx
.DEFAULT_FRAME_STYLE | wx
.NO_FULL_REPAINT_ON_RESIZE
)
145 # wxBug: DynamicSashWindow doesn't work on Mac, so revert to
146 # multisash implementation
147 if wx
.Platform
== "__WXMAC__":
148 wx
.lib
.multisash
.MultiClient
.Select
= MultiClientSelectBGNotYellow
149 self
._dynSash
= wx
.lib
.multisash
.MultiSash(frame
, -1)
150 self
._dynSash
.SetDefaultChildClass(self
.GetCtrlClass()) # wxBug: MultiSash instantiates the first TextCtrl with this call
152 self
._textEditor
= self
.GetCtrl() # wxBug: grab the TextCtrl from the MultiSash datastructure
154 self
._dynSash
= wx
.gizmos
.DynamicSashWindow(frame
, -1, style
=wx
.CLIP_CHILDREN
)
155 self
._dynSash
._view
= self
156 self
._textEditor
= self
.GetCtrlClass()(self
._dynSash
, -1, style
=wx
.NO_BORDER
)
157 wx
.EVT_LEFT_DOWN(self
._textEditor
, self
.OnLeftClick
)
158 self
._textEditor
.Bind(wx
.stc
.EVT_STC_MODIFIED
, self
.OnModify
)
160 self
._CreateSizer
(frame
)
167 def OnModify(self
, event
):
168 self
.GetDocument().Modify(self
._textEditor
.GetModify())
171 def _CreateSizer(self
, frame
):
172 sizer
= wx
.BoxSizer(wx
.HORIZONTAL
)
173 sizer
.Add(self
._dynSash
, 1, wx
.EXPAND
)
174 frame
.SetSizer(sizer
)
177 def OnLeftClick(self
, event
):
182 def OnUpdate(self
, sender
= None, hint
= None):
183 if wx
.lib
.docview
.View
.OnUpdate(self
, sender
, hint
):
186 if hint
== "ViewStuff":
187 self
.GetCtrl().SetViewDefaults()
189 font
, color
= self
.GetCtrl().GetFontAndColorFromConfig()
190 self
.GetCtrl().SetFont(font
)
191 self
.GetCtrl().SetFontColor(color
)
194 def OnActivateView(self
, activate
, activeView
, deactiveView
):
195 if activate
and self
.GetCtrl():
196 # In MDI mode just calling set focus doesn't work and in SDI mode using CallAfter causes an endless loop
197 if self
.GetDocumentManager().GetFlags() & wx
.lib
.docview
.DOC_SDI
:
200 wx
.CallAfter(self
.SetFocus
)
205 self
.GetCtrl().SetFocus()
208 def OnClose(self
, deleteWindow
= True):
209 if not wx
.lib
.docview
.View
.OnClose(self
, deleteWindow
):
212 if deleteWindow
and self
.GetFrame():
213 self
.GetFrame().Destroy()
217 def ProcessEvent(self
, event
):
220 self
.GetCtrl().Undo()
222 elif id == wx
.ID_REDO
:
223 self
.GetCtrl().Redo()
225 elif id == wx
.ID_CUT
:
228 elif id == wx
.ID_COPY
:
229 self
.GetCtrl().Copy()
231 elif id == wx
.ID_PASTE
:
232 self
.GetCtrl().OnPaste()
234 elif id == wx
.ID_CLEAR
:
235 self
.GetCtrl().OnClear()
237 elif id == wx
.ID_SELECTALL
:
238 self
.GetCtrl().SetSelection(0, -1)
240 elif id == VIEW_WHITESPACE_ID
:
241 self
.GetCtrl().SetViewWhiteSpace(not self
.GetCtrl().GetViewWhiteSpace())
243 elif id == VIEW_EOL_ID
:
244 self
.GetCtrl().SetViewEOL(not self
.GetCtrl().GetViewEOL())
246 elif id == VIEW_INDENTATION_GUIDES_ID
:
247 self
.GetCtrl().SetIndentationGuides(not self
.GetCtrl().GetIndentationGuides())
249 elif id == VIEW_RIGHT_EDGE_ID
:
250 self
.GetCtrl().SetViewRightEdge(not self
.GetCtrl().GetViewRightEdge())
252 elif id == VIEW_LINE_NUMBERS_ID
:
253 self
.GetCtrl().SetViewLineNumbers(not self
.GetCtrl().GetViewLineNumbers())
255 elif id == ZOOM_NORMAL_ID
:
256 self
.GetCtrl().SetZoom(0)
258 elif id == ZOOM_IN_ID
:
259 self
.GetCtrl().CmdKeyExecute(wx
.stc
.STC_CMD_ZOOMIN
)
261 elif id == ZOOM_OUT_ID
:
262 self
.GetCtrl().CmdKeyExecute(wx
.stc
.STC_CMD_ZOOMOUT
)
264 elif id == CHOOSE_FONT_ID
:
267 elif id == WORD_WRAP_ID
:
268 self
.GetCtrl().SetWordWrap(not self
.GetCtrl().GetWordWrap())
270 elif id == FindService
.FindService
.FIND_ID
:
273 elif id == FindService
.FindService
.FIND_PREVIOUS_ID
:
274 self
.DoFind(forceFindPrevious
= True)
276 elif id == FindService
.FindService
.FIND_NEXT_ID
:
277 self
.DoFind(forceFindNext
= True)
279 elif id == FindService
.FindService
.REPLACE_ID
:
280 self
.OnFind(replace
= True)
282 elif id == FindService
.FindService
.FINDONE_ID
:
285 elif id == FindService
.FindService
.REPLACEONE_ID
:
286 self
.DoFind(replace
= True)
288 elif id == FindService
.FindService
.REPLACEALL_ID
:
289 self
.DoFind(replaceAll
= True)
291 elif id == FindService
.FindService
.GOTO_LINE_ID
:
292 self
.OnGotoLine(event
)
295 return wx
.lib
.docview
.View
.ProcessEvent(self
, event
)
298 def ProcessUpdateUIEvent(self
, event
):
299 if not self
.GetCtrl():
304 event
.Enable(self
.GetCtrl().CanUndo())
305 event
.SetText(_("&Undo\tCtrl+Z")) # replace menu string
307 elif id == wx
.ID_REDO
:
308 event
.Enable(self
.GetCtrl().CanRedo())
309 event
.SetText(_("&Redo\tCtrl+Y")) # replace menu string
311 elif (id == wx
.ID_CUT
313 or id == wx
.ID_CLEAR
):
314 hasSelection
= self
.GetCtrl().GetSelectionStart() != self
.GetCtrl().GetSelectionEnd()
315 event
.Enable(hasSelection
)
317 elif id == wx
.ID_PASTE
:
318 event
.Enable(self
.GetCtrl().CanPaste())
320 elif id == wx
.ID_SELECTALL
:
321 hasText
= self
.GetCtrl().GetTextLength() > 0
322 event
.Enable(hasText
)
327 elif id == VIEW_WHITESPACE_ID
:
328 hasText
= self
.GetCtrl().GetTextLength() > 0
329 event
.Enable(hasText
)
330 event
.Check(self
.GetCtrl().GetViewWhiteSpace())
332 elif id == VIEW_EOL_ID
:
333 hasText
= self
.GetCtrl().GetTextLength() > 0
334 event
.Enable(hasText
)
335 event
.Check(self
.GetCtrl().GetViewEOL())
337 elif id == VIEW_INDENTATION_GUIDES_ID
:
338 hasText
= self
.GetCtrl().GetTextLength() > 0
339 event
.Enable(hasText
)
340 event
.Check(self
.GetCtrl().GetIndentationGuides())
342 elif id == VIEW_RIGHT_EDGE_ID
:
343 hasText
= self
.GetCtrl().GetTextLength() > 0
344 event
.Enable(hasText
)
345 event
.Check(self
.GetCtrl().GetViewRightEdge())
347 elif id == VIEW_LINE_NUMBERS_ID
:
348 hasText
= self
.GetCtrl().GetTextLength() > 0
349 event
.Enable(hasText
)
350 event
.Check(self
.GetCtrl().GetViewLineNumbers())
355 elif id == ZOOM_NORMAL_ID
:
356 event
.Enable(self
.GetCtrl().GetZoom() != 0)
358 elif id == ZOOM_IN_ID
:
359 event
.Enable(self
.GetCtrl().GetZoom() < 20)
361 elif id == ZOOM_OUT_ID
:
362 event
.Enable(self
.GetCtrl().GetZoom() > -10)
364 elif id == CHOOSE_FONT_ID
:
367 elif id == WORD_WRAP_ID
:
368 event
.Enable(self
.GetCtrl().CanWordWrap())
369 event
.Check(self
.GetCtrl().CanWordWrap() and self
.GetCtrl().GetWordWrap())
371 elif id == FindService
.FindService
.FIND_ID
:
372 hasText
= self
.GetCtrl().GetTextLength() > 0
373 event
.Enable(hasText
)
375 elif id == FindService
.FindService
.FIND_PREVIOUS_ID
:
376 hasText
= self
.GetCtrl().GetTextLength() > 0
377 event
.Enable(hasText
and
378 self
._FindServiceHasString
() and
379 self
.GetCtrl().GetSelection()[0] > 0)
381 elif id == FindService
.FindService
.FIND_NEXT_ID
:
382 hasText
= self
.GetCtrl().GetTextLength() > 0
383 event
.Enable(hasText
and
384 self
._FindServiceHasString
() and
385 self
.GetCtrl().GetSelection()[0] < self
.GetCtrl().GetLength())
387 elif id == FindService
.FindService
.REPLACE_ID
:
388 hasText
= self
.GetCtrl().GetTextLength() > 0
389 event
.Enable(hasText
)
391 elif id == FindService
.FindService
.GOTO_LINE_ID
:
394 elif id == TEXT_STATUS_BAR_ID
:
395 self
.OnUpdateStatusBar(event
)
398 return wx
.lib
.docview
.View
.ProcessUpdateUIEvent(self
, event
)
401 def _GetParentFrame(self
):
402 return wx
.GetTopLevelParent(self
.GetFrame())
404 def _GetActiveCtrl(self
, parent
):
405 """ Walk through the MultiSash windows and find the active Control """
406 if isinstance(parent
, wx
.lib
.multisash
.MultiClient
) and parent
.selected
:
408 if hasattr(parent
, "GetChildren"):
409 for child
in parent
.GetChildren():
410 found
= self
._GetActiveCtrl
(child
)
416 def _FindCtrl(self
, parent
):
417 """ Walk through the MultiSash windows and find the first TextCtrl """
418 if isinstance(parent
, self
.GetCtrlClass()):
420 if hasattr(parent
, "GetChildren"):
421 for child
in parent
.GetChildren():
422 found
= self
._FindCtrl
(child
)
428 #----------------------------------------------------------------------------
429 # Methods for TextDocument to call
430 #----------------------------------------------------------------------------
432 def IsModified(self
):
433 if not self
.GetCtrl():
435 return self
.GetCtrl().GetModify()
438 def SetModifyFalse(self
):
439 self
.GetCtrl().SetSavePoint()
444 return self
.GetCtrl().GetText()
449 def SetValue(self
, value
):
450 self
.GetCtrl().SetText(value
)
451 self
.GetCtrl().UpdateLineNumberMarginWidth()
452 self
.GetCtrl().EmptyUndoBuffer()
455 #----------------------------------------------------------------------------
457 #----------------------------------------------------------------------------
459 def OnUpdateStatusBar(self
, event
):
460 statusBar
= self
._GetParentFrame
().GetStatusBar()
461 statusBar
.SetInsertMode(self
.GetCtrl().GetOvertype() == 0)
462 statusBar
.SetLineNumber(self
.GetCtrl().GetCurrentLine() + 1)
463 statusBar
.SetColumnNumber(self
.GetCtrl().GetColumn(self
.GetCtrl().GetCurrentPos()) + 1)
466 #----------------------------------------------------------------------------
468 #----------------------------------------------------------------------------
470 def OnChooseFont(self
):
472 data
.EnableEffects(True)
473 data
.SetInitialFont(self
.GetCtrl().GetFont())
474 data
.SetColour(self
.GetCtrl().GetFontColor())
475 fontDialog
= wx
.FontDialog(self
.GetFrame(), data
)
476 fontDialog
.CenterOnParent()
477 if fontDialog
.ShowModal() == wx
.ID_OK
:
478 data
= fontDialog
.GetFontData()
479 self
.GetCtrl().SetFont(data
.GetChosenFont())
480 self
.GetCtrl().SetFontColor(data
.GetColour())
481 self
.GetCtrl().UpdateStyles()
485 #----------------------------------------------------------------------------
487 #----------------------------------------------------------------------------
489 def OnFind(self
, replace
= False):
490 findService
= wx
.GetApp().GetService(FindService
.FindService
)
492 findService
.ShowFindReplaceDialog(findString
= self
.GetCtrl().GetSelectedText(), replace
= replace
)
495 def DoFind(self
, forceFindNext
= False, forceFindPrevious
= False, replace
= False, replaceAll
= False):
496 findService
= wx
.GetApp().GetService(FindService
.FindService
)
499 findString
= findService
.GetFindString()
500 if len(findString
) == 0:
502 replaceString
= findService
.GetReplaceString()
503 flags
= findService
.GetFlags()
504 startLoc
, endLoc
= self
.GetCtrl().GetSelection()
506 wholeWord
= flags
& wx
.FR_WHOLEWORD
> 0
507 matchCase
= flags
& wx
.FR_MATCHCASE
> 0
508 regExp
= flags
& FindService
.FindService
.FR_REGEXP
> 0
509 down
= flags
& wx
.FR_DOWN
> 0
510 wrap
= flags
& FindService
.FindService
.FR_WRAP
> 0
512 if forceFindPrevious
: # this is from function keys, not dialog box
514 wrap
= False # user would want to know they're at the end of file
517 wrap
= False # user would want to know they're at the end of file
521 # On replace dialog operations, user is allowed to replace the currently highlighted text to determine if it should be replaced or not.
522 # 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.
523 # If the text is a match, then replace it.
525 result
, start
, end
, replText
= findService
.DoFind(findString
, replaceString
, self
.GetCtrl().GetSelectedText(), 0, 0, True, matchCase
, wholeWord
, regExp
, replace
)
527 self
.GetCtrl().ReplaceSelection(replText
)
528 self
.GetDocument().Modify(True)
529 wx
.GetApp().GetTopWindow().PushStatusText(_("1 occurrence of \"%s\" replaced") % findString
)
531 startLoc
+= len(replText
) # advance start location past replacement string to new text
533 elif result
== FindService
.FIND_SYNTAXERROR
:
535 wx
.GetApp().GetTopWindow().PushStatusText(_("Invalid regular expression \"%s\"") % findString
)
538 text
= self
.GetCtrl().GetText()
540 # Find the next matching text occurance or if it is a ReplaceAll, replace all occurances
541 # 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
542 result
, start
, end
, text
= findService
.DoFind(findString
, replaceString
, text
, startLoc
, endLoc
, down
, matchCase
, wholeWord
, regExp
, False, replaceAll
, wrap
)
544 self
.GetCtrl().SetTargetStart(0)
545 self
.GetCtrl().SetTargetEnd(self
.GetCtrl().GetLength())
546 self
.GetCtrl().ReplaceTarget(text
) # Doing a SetText causes a clear document to be shown when undoing, so using replacetarget instead
547 self
.GetDocument().Modify(True)
549 wx
.GetApp().GetTopWindow().PushStatusText(_("1 occurrence of \"%s\" replaced") % findString
)
551 wx
.GetApp().GetTopWindow().PushStatusText(_("%i occurrences of \"%s\" replaced") % (result
, findString
))
553 self
.GetCtrl().SetSelection(start
, end
)
554 self
.GetCtrl().EnsureVisible(self
.GetCtrl().LineFromPosition(end
)) # show bottom then scroll up to top
555 self
.GetCtrl().EnsureVisible(self
.GetCtrl().LineFromPosition(start
)) # do this after ensuring bottom is visible
556 wx
.GetApp().GetTopWindow().PushStatusText(_("Found \"%s\".") % findString
)
557 elif result
== FindService
.FIND_SYNTAXERROR
:
558 # Dialog for this case gets popped up by the FindService.
559 wx
.GetApp().GetTopWindow().PushStatusText(_("Invalid regular expression \"%s\"") % findString
)
561 wx
.MessageBox(_("Can't find \"%s\".") % findString
, "Find",
562 wx
.OK | wx
.ICON_INFORMATION
)
565 def _FindServiceHasString(self
):
566 findService
= wx
.GetApp().GetService(FindService
.FindService
)
567 if not findService
or not findService
.GetFindString():
572 def OnGotoLine(self
, event
):
573 findService
= wx
.GetApp().GetService(FindService
.FindService
)
575 line
= findService
.GetLineNumber(self
.GetDocumentManager().FindSuitableParent())
578 self
.GetCtrl().EnsureVisible(line
)
579 self
.GetCtrl().GotoLine(line
)
582 def GotoLine(self
, lineNum
):
584 lineNum
= lineNum
- 1 # line numbering for editor is 0 based, we are 1 based.
585 self
.GetCtrl().EnsureVisibleEnforcePolicy(lineNum
)
586 self
.GetCtrl().GotoLine(lineNum
)
589 def SetSelection(self
, start
, end
):
590 self
.GetCtrl().SetSelection(start
, end
)
593 def EnsureVisible(self
, line
):
594 self
.GetCtrl().EnsureVisible(line
-1) # line numbering for editor is 0 based, we are 1 based.
597 def EnsureVisibleEnforcePolicy(self
, line
):
598 self
.GetCtrl().EnsureVisibleEnforcePolicy(line
-1) # line numbering for editor is 0 based, we are 1 based.
601 def LineFromPosition(self
, pos
):
602 return self
.GetCtrl().LineFromPosition(pos
)+1 # line numbering for editor is 0 based, we are 1 based.
605 def PositionFromLine(self
, line
):
606 return self
.GetCtrl().PositionFromLine(line
-1) # line numbering for editor is 0 based, we are 1 based.
609 def GetLineEndPosition(self
, line
):
610 return self
.GetCtrl().GetLineEndPosition(line
-1) # line numbering for editor is 0 based, we are 1 based.
613 def GetLine(self
, lineNum
):
614 return self
.GetCtrl().GetLine(lineNum
-1) # line numbering for editor is 0 based, we are 1 based.
617 def MarkerDefine(self
):
618 """ This must be called after the texteditor is instantiated """
619 self
.GetCtrl().MarkerDefine(TextView
.MARKER_NUM
, wx
.stc
.STC_MARK_CIRCLE
, wx
.BLACK
, wx
.BLUE
)
622 def MarkerToggle(self
, lineNum
= -1, marker_index
=MARKER_NUM
, mask
=MARKER_MASK
):
624 lineNum
= self
.GetCtrl().GetCurrentLine()
625 if self
.GetCtrl().MarkerGet(lineNum
) & mask
:
626 self
.GetCtrl().MarkerDelete(lineNum
, marker_index
)
627 self
._markerCount
-= 1
629 self
.GetCtrl().MarkerAdd(lineNum
, marker_index
)
630 self
._markerCount
+= 1
633 def MarkerAdd(self
, lineNum
= -1, marker_index
=MARKER_NUM
, mask
=MARKER_MASK
):
635 lineNum
= self
.GetCtrl().GetCurrentLine()
636 self
.GetCtrl().MarkerAdd(lineNum
, marker_index
)
637 self
._markerCount
+= 1
640 def MarkerDelete(self
, lineNum
= -1, marker_index
=MARKER_NUM
, mask
=MARKER_MASK
):
642 lineNum
= self
.GetCtrl().GetCurrentLine()
643 if self
.GetCtrl().MarkerGet(lineNum
) & mask
:
644 self
.GetCtrl().MarkerDelete(lineNum
, marker_index
)
645 self
._markerCount
-= 1
647 def MarkerDeleteAll(self
, marker_num
=MARKER_NUM
):
648 self
.GetCtrl().MarkerDeleteAll(marker_num
)
649 if marker_num
== self
.MARKER_NUM
:
650 self
._markerCount
= 0
653 def MarkerNext(self
, lineNum
= -1):
655 lineNum
= self
.GetCtrl().GetCurrentLine() + 1 # start search below current line
656 foundLine
= self
.GetCtrl().MarkerNext(lineNum
, self
.MARKER_MASK
)
658 # wrap to top of file
659 foundLine
= self
.GetCtrl().MarkerNext(0, self
.MARKER_MASK
)
661 wx
.GetApp().GetTopWindow().PushStatusText(_("No markers"))
664 self
.GotoLine(foundLine
+ 1)
667 def MarkerPrevious(self
, lineNum
= -1):
669 lineNum
= self
.GetCtrl().GetCurrentLine() - 1 # start search above current line
671 lineNum
= self
.GetCtrl().GetLineCount()
673 foundLine
= self
.GetCtrl().MarkerPrevious(lineNum
, self
.MARKER_MASK
)
675 # wrap to bottom of file
676 foundLine
= self
.GetCtrl().MarkerPrevious(self
.GetCtrl().GetLineCount(), self
.MARKER_MASK
)
678 wx
.GetApp().GetTopWindow().PushStatusText(_("No markers"))
681 self
.GotoLine(foundLine
+ 1)
684 def MarkerExists(self
, lineNum
= -1, mask
=MARKER_MASK
):
686 lineNum
= self
.GetCtrl().GetCurrentLine()
687 if self
.GetCtrl().MarkerGet(lineNum
) & mask
:
692 def GetMarkerLines(self
, mask
=MARKER_MASK
):
694 for lineNum
in range(self
.GetCtrl().GetLineCount()):
695 if self
.GetCtrl().MarkerGet(lineNum
) & mask
:
696 retval
.append(lineNum
)
699 def GetMarkerCount(self
):
700 return self
._markerCount
703 class TextService(wx
.lib
.pydocview
.DocService
):
707 wx
.lib
.pydocview
.DocService
.__init
__(self
)
710 def InstallControls(self
, frame
, menuBar
= None, toolBar
= None, statusBar
= None, document
= None):
711 if document
and document
.GetDocumentTemplate().GetDocumentType() != TextDocument
:
713 if not document
and wx
.GetApp().GetDocumentManager().GetFlags() & wx
.lib
.docview
.DOC_SDI
:
716 statusBar
= TextStatusBar(frame
, TEXT_STATUS_BAR_ID
)
717 frame
.SetStatusBar(statusBar
)
718 wx
.EVT_UPDATE_UI(frame
, TEXT_STATUS_BAR_ID
, frame
.ProcessUpdateUIEvent
)
720 viewMenu
= menuBar
.GetMenu(menuBar
.FindMenu(_("&View")))
722 viewMenu
.AppendSeparator()
724 textMenu
.AppendCheckItem(VIEW_WHITESPACE_ID
, _("&Whitespace"), _("Shows or hides whitespace"))
725 wx
.EVT_MENU(frame
, VIEW_WHITESPACE_ID
, frame
.ProcessEvent
)
726 wx
.EVT_UPDATE_UI(frame
, VIEW_WHITESPACE_ID
, frame
.ProcessUpdateUIEvent
)
727 textMenu
.AppendCheckItem(VIEW_EOL_ID
, _("&End of Line Markers"), _("Shows or hides indicators at the end of each line"))
728 wx
.EVT_MENU(frame
, VIEW_EOL_ID
, frame
.ProcessEvent
)
729 wx
.EVT_UPDATE_UI(frame
, VIEW_EOL_ID
, frame
.ProcessUpdateUIEvent
)
730 textMenu
.AppendCheckItem(VIEW_INDENTATION_GUIDES_ID
, _("&Indentation Guides"), _("Shows or hides indentations"))
731 wx
.EVT_MENU(frame
, VIEW_INDENTATION_GUIDES_ID
, frame
.ProcessEvent
)
732 wx
.EVT_UPDATE_UI(frame
, VIEW_INDENTATION_GUIDES_ID
, frame
.ProcessUpdateUIEvent
)
733 textMenu
.AppendCheckItem(VIEW_RIGHT_EDGE_ID
, _("&Right Edge"), _("Shows or hides the right edge marker"))
734 wx
.EVT_MENU(frame
, VIEW_RIGHT_EDGE_ID
, frame
.ProcessEvent
)
735 wx
.EVT_UPDATE_UI(frame
, VIEW_RIGHT_EDGE_ID
, frame
.ProcessUpdateUIEvent
)
736 textMenu
.AppendCheckItem(VIEW_LINE_NUMBERS_ID
, _("&Line Numbers"), _("Shows or hides the line numbers"))
737 wx
.EVT_MENU(frame
, VIEW_LINE_NUMBERS_ID
, frame
.ProcessEvent
)
738 wx
.EVT_UPDATE_UI(frame
, VIEW_LINE_NUMBERS_ID
, frame
.ProcessUpdateUIEvent
)
740 viewMenu
.AppendMenu(TEXT_ID
, _("&Text"), textMenu
)
741 wx
.EVT_UPDATE_UI(frame
, TEXT_ID
, frame
.ProcessUpdateUIEvent
)
743 isWindows
= (wx
.Platform
== '__WXMSW__')
746 zoomMenu
.Append(ZOOM_NORMAL_ID
, _("Normal Size"), _("Sets the document to its normal size"))
747 wx
.EVT_MENU(frame
, ZOOM_NORMAL_ID
, frame
.ProcessEvent
)
748 wx
.EVT_UPDATE_UI(frame
, ZOOM_NORMAL_ID
, frame
.ProcessUpdateUIEvent
)
750 zoomMenu
.Append(ZOOM_IN_ID
, _("Zoom In\tCtrl+Page Up"), _("Zooms the document to a larger size"))
752 zoomMenu
.Append(ZOOM_IN_ID
, _("Zoom In"), _("Zooms the document to a larger size"))
753 wx
.EVT_MENU(frame
, ZOOM_IN_ID
, frame
.ProcessEvent
)
754 wx
.EVT_UPDATE_UI(frame
, ZOOM_IN_ID
, frame
.ProcessUpdateUIEvent
)
756 zoomMenu
.Append(ZOOM_OUT_ID
, _("Zoom Out\tCtrl+Page Down"), _("Zooms the document to a smaller size"))
758 zoomMenu
.Append(ZOOM_OUT_ID
, _("Zoom Out"), _("Zooms the document to a smaller size"))
759 wx
.EVT_MENU(frame
, ZOOM_OUT_ID
, frame
.ProcessEvent
)
760 wx
.EVT_UPDATE_UI(frame
, ZOOM_OUT_ID
, frame
.ProcessUpdateUIEvent
)
762 viewMenu
.AppendMenu(ZOOM_ID
, _("&Zoom"), zoomMenu
)
763 wx
.EVT_UPDATE_UI(frame
, ZOOM_ID
, frame
.ProcessUpdateUIEvent
)
765 formatMenuIndex
= menuBar
.FindMenu(_("&Format"))
766 if formatMenuIndex
> -1:
767 formatMenu
= menuBar
.GetMenu(formatMenuIndex
)
769 formatMenu
= wx
.Menu()
770 if not menuBar
.FindItemById(CHOOSE_FONT_ID
):
771 formatMenu
.Append(CHOOSE_FONT_ID
, _("&Font..."), _("Sets the font to use"))
772 wx
.EVT_MENU(frame
, CHOOSE_FONT_ID
, frame
.ProcessEvent
)
773 wx
.EVT_UPDATE_UI(frame
, CHOOSE_FONT_ID
, frame
.ProcessUpdateUIEvent
)
774 if not menuBar
.FindItemById(WORD_WRAP_ID
):
775 formatMenu
.AppendCheckItem(WORD_WRAP_ID
, _("Word Wrap"), _("Wraps text horizontally when checked"))
776 wx
.EVT_MENU(frame
, WORD_WRAP_ID
, frame
.ProcessEvent
)
777 wx
.EVT_UPDATE_UI(frame
, WORD_WRAP_ID
, frame
.ProcessUpdateUIEvent
)
778 if formatMenuIndex
== -1:
779 viewMenuIndex
= menuBar
.FindMenu(_("&View"))
780 menuBar
.Insert(viewMenuIndex
+ 1, formatMenu
, _("&Format"))
782 # wxBug: wxToolBar::GetToolPos doesn't exist, need it to find cut tool and then insert find in front of it.
783 toolBar
.AddSeparator()
784 toolBar
.AddTool(ZOOM_IN_ID
, getZoomInBitmap(), shortHelpString
= _("Zoom In"), longHelpString
= _("Zooms the document to a larger size"))
785 toolBar
.AddTool(ZOOM_OUT_ID
, getZoomOutBitmap(), shortHelpString
= _("Zoom Out"), longHelpString
= _("Zooms the document to a smaller size"))
789 def ProcessUpdateUIEvent(self
, event
):
792 or id == VIEW_WHITESPACE_ID
794 or id == VIEW_INDENTATION_GUIDES_ID
795 or id == VIEW_RIGHT_EDGE_ID
796 or id == VIEW_LINE_NUMBERS_ID
798 or id == ZOOM_NORMAL_ID
801 or id == CHOOSE_FONT_ID
802 or id == WORD_WRAP_ID
):
809 class TextStatusBar(wx
.StatusBar
):
811 # 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
813 def __init__(self
, parent
, id, style
= wx
.ST_SIZEGRIP
, name
= "statusBar"):
814 wx
.StatusBar
.__init
__(self
, parent
, id, style
, name
)
815 self
.SetFieldsCount(4)
816 self
.SetStatusWidths([-1, 50, 50, 55])
818 def SetInsertMode(self
, insert
= True):
823 if self
.GetStatusText(1) != newText
: # wxBug: Need to check if the text has changed, otherwise it flickers under win32
824 self
.SetStatusText(newText
, 1)
826 def SetLineNumber(self
, lineNumber
):
827 newText
= _("Ln %i") % lineNumber
828 if self
.GetStatusText(2) != newText
:
829 self
.SetStatusText(newText
, 2)
831 def SetColumnNumber(self
, colNumber
):
832 newText
= _("Col %i") % colNumber
833 if self
.GetStatusText(3) != newText
:
834 self
.SetStatusText(newText
, 3)
837 class TextOptionsPanel(wx
.Panel
):
840 def __init__(self
, parent
, id, configPrefix
= "Text", label
= "Text", hasWordWrap
= True, hasTabs
= False, addPage
=True, hasFolding
=False):
841 wx
.Panel
.__init
__(self
, parent
, id)
842 self
._configPrefix
= configPrefix
843 self
._hasWordWrap
= hasWordWrap
844 self
._hasTabs
= hasTabs
845 self
._hasFolding
= hasFolding
848 config
= wx
.ConfigBase_Get()
849 self
._textFont
= wx
.Font(10, wx
.MODERN
, wx
.NORMAL
, wx
.NORMAL
)
850 fontData
= config
.Read(self
._configPrefix
+ "EditorFont", "")
852 nativeFont
= wx
.NativeFontInfo()
853 nativeFont
.FromString(fontData
)
854 self
._textFont
.SetNativeFontInfo(nativeFont
)
855 self
._originalTextFont
= self
._textFont
856 self
._textColor
= wx
.BLACK
857 colorData
= config
.Read(self
._configPrefix
+ "EditorColor", "")
859 red
= int("0x" + colorData
[0:2], 16)
860 green
= int("0x" + colorData
[2:4], 16)
861 blue
= int("0x" + colorData
[4:6], 16)
862 self
._textColor
= wx
.Color(red
, green
, blue
)
863 self
._originalTextColor
= self
._textColor
864 fontLabel
= wx
.StaticText(self
, -1, _("Font:"))
865 self
._sampleTextCtrl
= wx
.TextCtrl(self
, -1, "", size
= (125, 21))
866 self
._sampleTextCtrl
.SetEditable(False)
867 chooseFontButton
= wx
.Button(self
, -1, _("Choose Font..."))
868 wx
.EVT_BUTTON(self
, chooseFontButton
.GetId(), self
.OnChooseFont
)
869 if self
._hasWordWrap
:
870 self
._wordWrapCheckBox
= wx
.CheckBox(self
, -1, _("Wrap words inside text area"))
871 self
._wordWrapCheckBox
.SetValue(wx
.ConfigBase_Get().ReadInt(self
._configPrefix
+ "EditorWordWrap", False))
872 self
._viewWhitespaceCheckBox
= wx
.CheckBox(self
, -1, _("Show whitespace"))
873 self
._viewWhitespaceCheckBox
.SetValue(config
.ReadInt(self
._configPrefix
+ "EditorViewWhitespace", False))
874 self
._viewEOLCheckBox
= wx
.CheckBox(self
, -1, _("Show end of line markers"))
875 self
._viewEOLCheckBox
.SetValue(config
.ReadInt(self
._configPrefix
+ "EditorViewEOL", False))
876 self
._viewIndentationGuideCheckBox
= wx
.CheckBox(self
, -1, _("Show indentation guides"))
877 self
._viewIndentationGuideCheckBox
.SetValue(config
.ReadInt(self
._configPrefix
+ "EditorViewIndentationGuides", False))
878 self
._viewRightEdgeCheckBox
= wx
.CheckBox(self
, -1, _("Show right edge"))
879 self
._viewRightEdgeCheckBox
.SetValue(config
.ReadInt(self
._configPrefix
+ "EditorViewRightEdge", False))
880 self
._viewLineNumbersCheckBox
= wx
.CheckBox(self
, -1, _("Show line numbers"))
881 self
._viewLineNumbersCheckBox
.SetValue(config
.ReadInt(self
._configPrefix
+ "EditorViewLineNumbers", True))
883 self
._viewFoldingCheckBox
= wx
.CheckBox(self
, -1, _("Show folding"))
884 self
._viewFoldingCheckBox
.SetValue(config
.ReadInt(self
._configPrefix
+ "EditorViewFolding", True))
886 self
._hasTabsCheckBox
= wx
.CheckBox(self
, -1, _("Use spaces instead of tabs"))
887 self
._hasTabsCheckBox
.SetValue(not wx
.ConfigBase_Get().ReadInt(self
._configPrefix
+ "EditorUseTabs", False))
888 indentWidthLabel
= wx
.StaticText(self
, -1, _("Indent Width:"))
889 self
._indentWidthChoice
= wx
.Choice(self
, -1, choices
= ["2", "4", "6", "8", "10"])
890 self
._indentWidthChoice
.SetStringSelection(str(config
.ReadInt(self
._configPrefix
+ "EditorIndentWidth", 4)))
891 textPanelBorderSizer
= wx
.BoxSizer(wx
.VERTICAL
)
892 textPanelSizer
= wx
.BoxSizer(wx
.VERTICAL
)
893 textFontSizer
= wx
.BoxSizer(wx
.HORIZONTAL
)
894 textFontSizer
.Add(fontLabel
, 0, wx
.ALIGN_LEFT | wx
.RIGHT | wx
.TOP
, HALF_SPACE
)
895 textFontSizer
.Add(self
._sampleTextCtrl
, 1, wx
.ALIGN_LEFT | wx
.EXPAND | wx
.RIGHT
, HALF_SPACE
)
896 textFontSizer
.Add(chooseFontButton
, 0, wx
.ALIGN_RIGHT | wx
.LEFT
, HALF_SPACE
)
897 textPanelSizer
.Add(textFontSizer
, 0, wx
.ALL|wx
.EXPAND
, HALF_SPACE
)
898 if self
._hasWordWrap
:
899 textPanelSizer
.Add(self
._wordWrapCheckBox
, 0, wx
.ALL
, HALF_SPACE
)
900 textPanelSizer
.Add(self
._viewWhitespaceCheckBox
, 0, wx
.ALL
, HALF_SPACE
)
901 textPanelSizer
.Add(self
._viewEOLCheckBox
, 0, wx
.ALL
, HALF_SPACE
)
902 textPanelSizer
.Add(self
._viewIndentationGuideCheckBox
, 0, wx
.ALL
, HALF_SPACE
)
903 textPanelSizer
.Add(self
._viewRightEdgeCheckBox
, 0, wx
.ALL
, HALF_SPACE
)
904 textPanelSizer
.Add(self
._viewLineNumbersCheckBox
, 0, wx
.ALL
, HALF_SPACE
)
906 textPanelSizer
.Add(self
._viewFoldingCheckBox
, 0, wx
.ALL
, HALF_SPACE
)
908 textPanelSizer
.Add(self
._hasTabsCheckBox
, 0, wx
.ALL
, HALF_SPACE
)
909 textIndentWidthSizer
= wx
.BoxSizer(wx
.HORIZONTAL
)
910 textIndentWidthSizer
.Add(indentWidthLabel
, 0, wx
.ALIGN_LEFT | wx
.RIGHT | wx
.TOP
, HALF_SPACE
)
911 textIndentWidthSizer
.Add(self
._indentWidthChoice
, 0, wx
.ALIGN_LEFT | wx
.EXPAND
, HALF_SPACE
)
912 textPanelSizer
.Add(textIndentWidthSizer
, 0, wx
.ALL
, HALF_SPACE
)
913 textPanelBorderSizer
.Add(textPanelSizer
, 0, wx
.ALL|wx
.EXPAND
, SPACE
)
914 ## styleButton = wx.Button(self, -1, _("Choose Style..."))
915 ## wx.EVT_BUTTON(self, styleButton.GetId(), self.OnChooseStyle)
916 ## textPanelBorderSizer.Add(styleButton, 0, wx.ALL, SPACE)
917 self
.SetSizer(textPanelBorderSizer
)
918 self
.UpdateSampleFont()
920 parent
.AddPage(self
, _(label
))
922 def UpdateSampleFont(self
):
923 nativeFont
= wx
.NativeFontInfo()
924 nativeFont
.FromString(self
._textFont
.GetNativeFontInfoDesc())
926 font
.SetNativeFontInfo(nativeFont
)
927 font
.SetPointSize(self
._sampleTextCtrl
.GetFont().GetPointSize()) # Use the standard point size
928 self
._sampleTextCtrl
.SetFont(font
)
929 self
._sampleTextCtrl
.SetForegroundColour(self
._textColor
)
930 self
._sampleTextCtrl
.SetValue(str(self
._textFont
.GetPointSize()) + _(" pt. ") + self
._textFont
.GetFaceName())
931 self
._sampleTextCtrl
.Refresh()
935 ## def OnChooseStyle(self, event):
936 ## import STCStyleEditor
938 ## base = os.path.split(__file__)[0]
939 ## config = os.path.abspath(os.path.join(base, 'stc-styles.rc.cfg'))
941 ## dlg = STCStyleEditor.STCStyleEditDlg(None,
942 ## 'Python', 'python',
946 ## dlg.CenterOnParent()
953 def OnChooseFont(self
, event
):
955 data
.EnableEffects(True)
956 data
.SetInitialFont(self
._textFont
)
957 data
.SetColour(self
._textColor
)
958 fontDialog
= wx
.FontDialog(self
, data
)
959 fontDialog
.CenterOnParent()
960 if fontDialog
.ShowModal() == wx
.ID_OK
:
961 data
= fontDialog
.GetFontData()
962 self
._textFont
= data
.GetChosenFont()
963 self
._textColor
= data
.GetColour()
964 self
.UpdateSampleFont()
968 def OnOK(self
, optionsDialog
):
969 config
= wx
.ConfigBase_Get()
970 doViewStuffUpdate
= config
.ReadInt(self
._configPrefix
+ "EditorViewWhitespace", False) != self
._viewWhitespaceCheckBox
.GetValue()
971 config
.WriteInt(self
._configPrefix
+ "EditorViewWhitespace", self
._viewWhitespaceCheckBox
.GetValue())
972 doViewStuffUpdate
= doViewStuffUpdate
or config
.ReadInt(self
._configPrefix
+ "EditorViewEOL", False) != self
._viewEOLCheckBox
.GetValue()
973 config
.WriteInt(self
._configPrefix
+ "EditorViewEOL", self
._viewEOLCheckBox
.GetValue())
974 doViewStuffUpdate
= doViewStuffUpdate
or config
.ReadInt(self
._configPrefix
+ "EditorViewIndentationGuides", False) != self
._viewIndentationGuideCheckBox
.GetValue()
975 config
.WriteInt(self
._configPrefix
+ "EditorViewIndentationGuides", self
._viewIndentationGuideCheckBox
.GetValue())
976 doViewStuffUpdate
= doViewStuffUpdate
or config
.ReadInt(self
._configPrefix
+ "EditorViewRightEdge", False) != self
._viewRightEdgeCheckBox
.GetValue()
977 config
.WriteInt(self
._configPrefix
+ "EditorViewRightEdge", self
._viewRightEdgeCheckBox
.GetValue())
978 doViewStuffUpdate
= doViewStuffUpdate
or config
.ReadInt(self
._configPrefix
+ "EditorViewLineNumbers", True) != self
._viewLineNumbersCheckBox
.GetValue()
979 config
.WriteInt(self
._configPrefix
+ "EditorViewLineNumbers", self
._viewLineNumbersCheckBox
.GetValue())
981 doViewStuffUpdate
= doViewStuffUpdate
or config
.ReadInt(self
._configPrefix
+ "EditorViewFolding", True) != self
._viewFoldingCheckBox
.GetValue()
982 config
.WriteInt(self
._configPrefix
+ "EditorViewFolding", self
._viewFoldingCheckBox
.GetValue())
983 if self
._hasWordWrap
:
984 doViewStuffUpdate
= doViewStuffUpdate
or config
.ReadInt(self
._configPrefix
+ "EditorWordWrap", False) != self
._wordWrapCheckBox
.GetValue()
985 config
.WriteInt(self
._configPrefix
+ "EditorWordWrap", self
._wordWrapCheckBox
.GetValue())
987 doViewStuffUpdate
= doViewStuffUpdate
or not config
.ReadInt(self
._configPrefix
+ "EditorUseTabs", True) != self
._hasTabsCheckBox
.GetValue()
988 config
.WriteInt(self
._configPrefix
+ "EditorUseTabs", not self
._hasTabsCheckBox
.GetValue())
989 newIndentWidth
= int(self
._indentWidthChoice
.GetStringSelection())
990 oldIndentWidth
= config
.ReadInt(self
._configPrefix
+ "EditorIndentWidth", 4)
991 if newIndentWidth
!= oldIndentWidth
:
992 doViewStuffUpdate
= True
993 config
.WriteInt(self
._configPrefix
+ "EditorIndentWidth", newIndentWidth
)
994 doFontUpdate
= self
._originalTextFont
!= self
._textFont
or self
._originalTextColor
!= self
._textColor
995 config
.Write(self
._configPrefix
+ "EditorFont", self
._textFont
.GetNativeFontInfoDesc())
996 config
.Write(self
._configPrefix
+ "EditorColor", "%02x%02x%02x" % (self
._textColor
.Red(), self
._textColor
.Green(), self
._textColor
.Blue()))
997 if doViewStuffUpdate
or doFontUpdate
:
998 for document
in optionsDialog
.GetDocManager().GetDocuments():
999 if issubclass(document
.GetDocumentTemplate().GetDocumentType(), TextDocument
):
1000 if doViewStuffUpdate
:
1001 document
.UpdateAllViews(hint
= "ViewStuff")
1003 document
.UpdateAllViews(hint
= "Font")
1007 return getTextIcon()
1010 class TextCtrl(wx
.stc
.StyledTextCtrl
):
1012 def __init__(self
, parent
, id=-1, style
=wx
.NO_FULL_REPAINT_ON_RESIZE
):
1013 wx
.stc
.StyledTextCtrl
.__init
__(self
, parent
, id, style
=style
)
1015 if isinstance(parent
, wx
.gizmos
.DynamicSashWindow
):
1016 self
._dynSash
= parent
1017 self
.SetupDSScrollBars()
1018 self
.Bind(wx
.gizmos
.EVT_DYNAMIC_SASH_SPLIT
, self
.OnDSSplit
)
1019 self
.Bind(wx
.gizmos
.EVT_DYNAMIC_SASH_UNIFY
, self
.OnDSUnify
)
1022 self
._fontColor
= None
1024 self
.SetVisiblePolicy(wx
.stc
.STC_VISIBLE_STRICT
,1)
1026 self
.CmdKeyClear(wx
.stc
.STC_KEY_ADD
, wx
.stc
.STC_SCMOD_CTRL
)
1027 self
.CmdKeyClear(wx
.stc
.STC_KEY_SUBTRACT
, wx
.stc
.STC_SCMOD_CTRL
)
1028 self
.CmdKeyAssign(wx
.stc
.STC_KEY_PRIOR
, wx
.stc
.STC_SCMOD_CTRL
, wx
.stc
.STC_CMD_ZOOMIN
)
1029 self
.CmdKeyAssign(wx
.stc
.STC_KEY_NEXT
, wx
.stc
.STC_SCMOD_CTRL
, wx
.stc
.STC_CMD_ZOOMOUT
)
1030 self
.Bind(wx
.stc
.EVT_STC_ZOOM
, self
.OnUpdateLineNumberMarginWidth
) # auto update line num width on zoom
1031 wx
.EVT_KEY_DOWN(self
, self
.OnKeyPressed
)
1032 wx
.EVT_KILL_FOCUS(self
, self
.OnKillFocus
)
1033 wx
.EVT_SET_FOCUS(self
, self
.OnFocus
)
1034 self
.SetMargins(0,0)
1040 self
.SetViewWhiteSpace(False)
1041 self
.SetEOLMode(wx
.stc
.STC_EOL_LF
)
1042 self
.SetEdgeMode(wx
.stc
.STC_EDGE_NONE
)
1043 self
.SetEdgeColumn(78)
1045 self
.SetMarginType(1, wx
.stc
.STC_MARGIN_NUMBER
)
1046 self
.SetMarginWidth(1, self
.EstimatedLineNumberMarginWidth())
1049 self
.SetCaretForeground("BLACK")
1051 self
.SetViewDefaults()
1052 font
, color
= self
.GetFontAndColorFromConfig()
1054 self
.SetFontColor(color
)
1055 self
.MarkerDefineDefault()
1057 # for multisash initialization
1058 if isinstance(parent
, wx
.lib
.multisash
.MultiClient
):
1059 while parent
.GetParent():
1060 parent
= parent
.GetParent()
1061 if hasattr(parent
, "GetView"):
1063 if hasattr(parent
, "GetView"):
1064 textEditor
= parent
.GetView()._textEditor
1066 doc
= textEditor
.GetDocPointer()
1068 self
.SetDocPointer(doc
)
1071 def OnFocus(self
, event
):
1072 # wxBug: On Mac, the STC control may fire a focus/kill focus event
1073 # on shutdown even if the control is in an invalid state. So check
1074 # before handling the event.
1075 if self
.IsBeingDeleted():
1078 self
.SetSelBackground(1, "BLUE")
1079 self
.SetSelForeground(1, "WHITE")
1080 if hasattr(self
, "_dynSash"):
1081 self
._dynSash
._view
.SetCtrl(self
)
1085 def OnKillFocus(self
, event
):
1086 # wxBug: On Mac, the STC control may fire a focus/kill focus event
1087 # on shutdown even if the control is in an invalid state. So check
1088 # before handling the event.
1089 if self
.IsBeingDeleted():
1091 self
.SetSelBackground(0, "BLUE")
1092 self
.SetSelForeground(0, "WHITE")
1093 self
.SetSelBackground(1, "#C0C0C0")
1094 # Don't set foreground color, use syntax highlighted default colors.
1098 def SetViewDefaults(self
, configPrefix
="Text", hasWordWrap
=True, hasTabs
=False, hasFolding
=False):
1099 config
= wx
.ConfigBase_Get()
1100 self
.SetViewWhiteSpace(config
.ReadInt(configPrefix
+ "EditorViewWhitespace", False))
1101 self
.SetViewEOL(config
.ReadInt(configPrefix
+ "EditorViewEOL", False))
1102 self
.SetIndentationGuides(config
.ReadInt(configPrefix
+ "EditorViewIndentationGuides", False))
1103 self
.SetViewRightEdge(config
.ReadInt(configPrefix
+ "EditorViewRightEdge", False))
1104 self
.SetViewLineNumbers(config
.ReadInt(configPrefix
+ "EditorViewLineNumbers", True))
1106 self
.SetViewFolding(config
.ReadInt(configPrefix
+ "EditorViewFolding", True))
1108 self
.SetWordWrap(config
.ReadInt(configPrefix
+ "EditorWordWrap", False))
1109 if hasTabs
: # These methods do not exist in STCTextEditor and are meant for subclasses
1110 self
.SetUseTabs(config
.ReadInt(configPrefix
+ "EditorUseTabs", False))
1111 self
.SetIndent(config
.ReadInt(configPrefix
+ "EditorIndentWidth", 4))
1112 self
.SetTabWidth(config
.ReadInt(configPrefix
+ "EditorIndentWidth", 4))
1114 self
.SetUseTabs(True)
1119 def GetDefaultFont(self
):
1120 """ Subclasses should override this """
1121 return wx
.Font(10, wx
.MODERN
, wx
.NORMAL
, wx
.NORMAL
)
1124 def GetDefaultColor(self
):
1125 """ Subclasses should override this """
1129 def GetFontAndColorFromConfig(self
, configPrefix
= "Text"):
1130 font
= self
.GetDefaultFont()
1131 config
= wx
.ConfigBase_Get()
1132 fontData
= config
.Read(configPrefix
+ "EditorFont", "")
1134 nativeFont
= wx
.NativeFontInfo()
1135 nativeFont
.FromString(fontData
)
1136 font
.SetNativeFontInfo(nativeFont
)
1137 color
= self
.GetDefaultColor()
1138 colorData
= config
.Read(configPrefix
+ "EditorColor", "")
1140 red
= int("0x" + colorData
[0:2], 16)
1141 green
= int("0x" + colorData
[2:4], 16)
1142 blue
= int("0x" + colorData
[4:6], 16)
1143 color
= wx
.Color(red
, green
, blue
)
1151 def SetFont(self
, font
):
1153 self
.StyleSetFont(wx
.stc
.STC_STYLE_DEFAULT
, self
._font
)
1156 def GetFontColor(self
):
1157 return self
._fontColor
1160 def SetFontColor(self
, fontColor
= wx
.BLACK
):
1161 self
._fontColor
= fontColor
1162 self
.StyleSetForeground(wx
.stc
.STC_STYLE_DEFAULT
, "#%02x%02x%02x" % (self
._fontColor
.Red(), self
._fontColor
.Green(), self
._fontColor
.Blue()))
1165 def UpdateStyles(self
):
1166 self
.StyleClearAll()
1170 def EstimatedLineNumberMarginWidth(self
):
1173 lineNum
= self
.GetLineCount()
1174 lineNum
= lineNum
/100
1175 while lineNum
>= 10:
1176 lineNum
= lineNum
/10
1177 baseNumbers
= baseNumbers
+ "0"
1179 return self
.TextWidth(wx
.stc
.STC_STYLE_LINENUMBER
, baseNumbers
) + MARGIN
1182 def OnUpdateLineNumberMarginWidth(self
, event
):
1183 self
.UpdateLineNumberMarginWidth()
1186 def UpdateLineNumberMarginWidth(self
):
1187 if self
.GetViewLineNumbers():
1188 self
.SetMarginWidth(1, self
.EstimatedLineNumberMarginWidth())
1190 def MarkerDefineDefault(self
):
1191 """ This must be called after the textcontrol is instantiated """
1192 self
.MarkerDefine(TextView
.MARKER_NUM
, wx
.stc
.STC_MARK_ROUNDRECT
, wx
.BLACK
, wx
.BLUE
)
1196 # Used when Delete key is hit.
1197 sel
= self
.GetSelection()
1199 # Delete the selection or if no selection, the character after the caret.
1200 if sel
[0] == sel
[1]:
1201 self
.SetSelection(sel
[0], sel
[0] + 1)
1203 # remove any folded lines also.
1204 startLine
= self
.LineFromPosition(sel
[0])
1205 endLine
= self
.LineFromPosition(sel
[1])
1206 endLineStart
= self
.PositionFromLine(endLine
)
1207 if startLine
!= endLine
and sel
[1] - endLineStart
== 0:
1208 while not self
.GetLineVisible(endLine
):
1210 self
.SetSelectionEnd(self
.PositionFromLine(endLine
))
1216 # replace any folded lines also.
1217 sel
= self
.GetSelection()
1218 startLine
= self
.LineFromPosition(sel
[0])
1219 endLine
= self
.LineFromPosition(sel
[1])
1220 endLineStart
= self
.PositionFromLine(endLine
)
1221 if startLine
!= endLine
and sel
[1] - endLineStart
== 0:
1222 while not self
.GetLineVisible(endLine
):
1224 self
.SetSelectionEnd(self
.PositionFromLine(endLine
))
1229 def OnKeyPressed(self
, event
):
1230 key
= event
.GetKeyCode()
1231 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
1232 if event
.ControlDown():
1233 self
.ToggleFoldAll(expand
= True, topLevelOnly
= True)
1234 elif event
.ShiftDown():
1235 self
.ToggleFoldAll(expand
= True)
1237 self
.ToggleFold(self
.GetCurrentLine())
1238 elif key
== wx
.WXK_NUMPAD_SUBTRACT
:
1239 if event
.ControlDown():
1240 self
.ToggleFoldAll(expand
= False, topLevelOnly
= True)
1241 elif event
.ShiftDown():
1242 self
.ToggleFoldAll(expand
= False)
1244 self
.ToggleFold(self
.GetCurrentLine())
1249 #----------------------------------------------------------------------------
1251 #----------------------------------------------------------------------------
1253 def GetViewRightEdge(self
):
1254 return self
.GetEdgeMode() != wx
.stc
.STC_EDGE_NONE
1257 def SetViewRightEdge(self
, viewRightEdge
):
1259 self
.SetEdgeMode(wx
.stc
.STC_EDGE_LINE
)
1261 self
.SetEdgeMode(wx
.stc
.STC_EDGE_NONE
)
1264 def GetViewLineNumbers(self
):
1265 return self
.GetMarginWidth(1) > 0
1268 def SetViewLineNumbers(self
, viewLineNumbers
= True):
1270 self
.SetMarginWidth(1, self
.EstimatedLineNumberMarginWidth())
1272 self
.SetMarginWidth(1, 0)
1275 def GetViewFolding(self
):
1276 return self
.GetMarginWidth(2) > 0
1279 def SetViewFolding(self
, viewFolding
= True):
1281 self
.SetMarginWidth(2, 12)
1283 self
.SetMarginWidth(2, 0)
1286 def CanWordWrap(self
):
1290 def GetWordWrap(self
):
1291 return self
.GetWrapMode() == wx
.stc
.STC_WRAP_WORD
1294 def SetWordWrap(self
, wordWrap
):
1296 self
.SetWrapMode(wx
.stc
.STC_WRAP_WORD
)
1298 self
.SetWrapMode(wx
.stc
.STC_WRAP_NONE
)
1301 #----------------------------------------------------------------------------
1302 # DynamicSashWindow methods
1303 #----------------------------------------------------------------------------
1305 def SetupDSScrollBars(self
):
1306 # hook the scrollbars provided by the wxDynamicSashWindow
1308 v_bar
= self
._dynSash
.GetVScrollBar(self
)
1309 h_bar
= self
._dynSash
.GetHScrollBar(self
)
1310 v_bar
.Bind(wx
.EVT_SCROLL
, self
.OnDSSBScroll
)
1311 h_bar
.Bind(wx
.EVT_SCROLL
, self
.OnDSSBScroll
)
1312 v_bar
.Bind(wx
.EVT_SET_FOCUS
, self
.OnDSSBFocus
)
1313 h_bar
.Bind(wx
.EVT_SET_FOCUS
, self
.OnDSSBFocus
)
1315 # And set the wxStyledText to use these scrollbars instead
1316 # of its built-in ones.
1317 self
.SetVScrollBar(v_bar
)
1318 self
.SetHScrollBar(h_bar
)
1321 def OnDSSplit(self
, evt
):
1322 newCtrl
= self
._dynSash
._view
.GetCtrlClass()(self
._dynSash
, -1, style
=wx
.NO_BORDER
)
1323 newCtrl
.SetDocPointer(self
.GetDocPointer()) # use the same document
1324 self
.SetupDSScrollBars()
1325 if self
== self
._dynSash
._view
.GetCtrl(): # originally had focus
1326 wx
.CallAfter(self
.SetFocus
) # do this to set colors correctly. wxBug: for some reason, if we don't do a CallAfter, it immediately calls OnKillFocus right after our SetFocus.
1329 def OnDSUnify(self
, evt
):
1330 self
.SetupDSScrollBars()
1331 self
.SetFocus() # do this to set colors correctly
1334 def OnDSSBScroll(self
, evt
):
1335 # redirect the scroll events from the _dynSash's scrollbars to the STC
1336 self
.GetEventHandler().ProcessEvent(evt
)
1339 def OnDSSBFocus(self
, evt
):
1340 # when the scrollbar gets the focus move it back to the STC
1344 def DSProcessEvent(self
, event
):
1345 # wxHack: Needed for customized right mouse click menu items.
1346 if hasattr(self
, "_dynSash"):
1347 if event
.GetId() == wx
.ID_SELECTALL
:
1348 # force focus so that select all occurs in the window user right clicked on.
1351 return self
._dynSash
._view
.ProcessEvent(event
)
1355 def DSProcessUpdateUIEvent(self
, event
):
1356 # wxHack: Needed for customized right mouse click menu items.
1357 if hasattr(self
, "_dynSash"):
1359 if (id == wx
.ID_SELECTALL
# allow select all even in non-active window, then force focus to it, see above ProcessEvent
1361 or id == wx
.ID_REDO
):
1362 pass # allow these actions even in non-active window
1363 else: # disallow events in non-active windows. Cut/Copy/Paste/Delete is too confusing user experience.
1364 if self
._dynSash
._view
.GetCtrl() != self
:
1368 return self
._dynSash
._view
.ProcessUpdateUIEvent(event
)
1372 class TextPrintout(wx
.lib
.docview
.DocPrintout
):
1373 """ for Print Preview and Print """
1376 def OnPreparePrinting(self
):
1377 """ initialization """
1380 ppiScreenX
, ppiScreenY
= self
.GetPPIScreen()
1381 ppiPrinterX
, ppiPrinterY
= self
.GetPPIPrinter()
1382 scaleX
= float(ppiPrinterX
)/ppiScreenX
1383 scaleY
= float(ppiPrinterY
)/ppiScreenY
1385 pageWidth
, pageHeight
= self
.GetPageSizePixels()
1386 self
._scaleFactorX
= scaleX
/pageWidth
1387 self
._scaleFactorY
= scaleY
/pageHeight
1390 overallScaleX
= self
._scaleFactorX
* w
1391 overallScaleY
= self
._scaleFactorY
* h
1393 txtCtrl
= self
._printoutView
.GetCtrl()
1394 font
, color
= txtCtrl
.GetFontAndColorFromConfig()
1397 self
._fontHeight
= font
.GetPointSize() + 1
1398 self
._pageLines
= int((h
/overallScaleY
- (2 * self
._margin
))/self
._fontHeight
)
1399 self
._maxLines
= txtCtrl
.GetLineCount()
1400 self
._numPages
, remainder
= divmod(self
._maxLines
, self
._pageLines
)
1405 lineNum
= self
._maxLines
1406 while lineNum
>= 10:
1407 lineNum
= lineNum
/10
1409 self
._printFormat
= "%%0%sd: %%s" % spaces
1412 def OnPrintPage(self
, page
):
1413 """ Prints the given page of the view """
1416 txtCtrl
= self
._printoutView
.GetCtrl()
1417 font
, color
= txtCtrl
.GetFontAndColorFromConfig()
1421 dc
.SetUserScale(self
._scaleFactorX
* w
, self
._scaleFactorY
* h
)
1425 dc
.DrawText("%s - page %s" % (self
.GetTitle(), page
), self
._margin
, self
._margin
/2)
1427 startY
= self
._margin
1428 startLine
= (page
- 1) * self
._pageLines
1429 endLine
= min((startLine
+ self
._pageLines
), self
._maxLines
)
1430 for i
in range(startLine
, endLine
):
1431 text
= txtCtrl
.GetLine(i
).rstrip()
1432 startY
+= self
._fontHeight
1433 if txtCtrl
.GetViewLineNumbers():
1434 dc
.DrawText(self
._printFormat
% (i
+1, text
), self
._margin
, startY
)
1436 dc
.DrawText(text
, self
._margin
, startY
)
1443 def HasPage(self
, pageNum
):
1444 return pageNum
<= self
._numPages
1447 def GetPageInfo(self
):
1449 maxPage
= self
._numPages
1451 selPageTo
= self
._numPages
1452 return (minPage
, maxPage
, selPageFrom
, selPageTo
)
1455 #----------------------------------------------------------------------------
1456 # Icon Bitmaps - generated by encode_bitmaps.py
1457 #----------------------------------------------------------------------------
1458 from wx
import ImageFromStream
, BitmapFromImage
1464 "\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
1465 \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
1466 \x00\x015IDAT8\x8d\xad\x90\xb1N\xc2P\x14\x86\xbf\x02/\xe0\xec#\x18g\xc3\xe6T\
1467 \x13':1\x18H\x98\x14\x12\x17G\x177\x17\x9c4a\xc5\xc0d0\xc2\xccdLx\x02^@+\t\
1468 \xc1\x90\xf6r\xdb\xc6\x94\xe5:\\\xdbP)\xc5DOr\x92\x9b{\xff\xfb\xfd\xff9\xc6h\
1469 l+\xbek.\x02\x00\xec\x99\x03\x80\xeb\xf8\\\x9d\x1d\x1bd\xd5hl\xab\xd7O\x15\
1470 \xf7x\xa1\xfb\xeeq\xa4^>\x94\xba\xb8yRF.\xcf\xa6.D\xa0Nw\x18C\xad\xb2\x19\
1471 \x9f\x0f\xca\x165\xd1V\xed\xebZj\x92\xc2\\\x04\xec\x02\xd5\x8a\x89\xb7\xd4\
1472 \x97n\xa8\xe3?\x0f\x86\x08\x19dNP\x00\xf0\x96\xd0\x7f\xd0\t\x84\x0c(U-\x0eK&\
1473 \xd3P\x8bz\xcdV6 \x8a\xed\x86\x99f\xe9\x00{\xe6\xb0\x13\xc2\xa0\xd3\xd7\t\
1474 \x84\x9f\x10\xec\x9dTp\x1d\xb1=A\xa9j\x01\xc4\xb1\x01&\xfe\x9a~\x1d\xe0:Zu\
1475 \x7f\xdb\x05@J/!(\xd6\x1bL\xde\xec\xcd\x00!\x03\xa6!\x1c\x9dVR\x9d\xdf\xe5\
1476 \x96\x04\xd1au\xd3\xab3\xef\x9f_f\x03\xa2\xa5\x15\xeb\x8d\xc4\xc36\xe7\x18 \
1477 \xa5G\xaf\xd9J\xb8f\xcd\xfc\xb3\x0c#\x97\xff\xb58\xadr\x7f\xfa\xfd\x1f\x80/\
1478 \x04\x1f\x8fW\x0e^\xc3\x12\x00\x00\x00\x00IEND\xaeB`\x82"
1481 def getTextBitmap():
1482 return BitmapFromImage(getTextImage())
1485 stream
= cStringIO
.StringIO(getTextData())
1486 return ImageFromStream(stream
)
1489 return wx
.IconFromBitmap(getTextBitmap())
1492 #----------------------------------------------------------------------------
1493 # Menu Bitmaps - generated by encode_bitmaps.py
1494 #----------------------------------------------------------------------------
1495 #----------------------------------------------------------------------
1496 def getZoomInData():
1498 '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
1499 \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
1500 \x00\x01TIDAT8\x8d\x8d\x93\xbbJ\x03A\x14\x86\xbf\xd9,\xc6\xd8E%`)VF[{\xc1v\
1501 \xf1\x82\x8f\xb0\xb94\xda\xa5\x13\x11\x8b`\xa9h\x10F\xe3#H.\xa6\x15\xccKhg\
1502 \x10\xc1B\x8bTF\x90\xc0X\x8c3\xbb\xd9\xcdF\x7f\x18\xf6\xec\x9cs\xbe\xfd\xe70\
1503 +\x84\x93"\xacb\xc1W\xe1\xf7\xeb\xfa\x8d`\x82\xdcXcI\x8e\x02AM\x02\t\xe1\xa4\
1504 (\x16|uz)y\x19\xc0\xc9\xdd;\x99\xee!\x00\xd9\xbd\x00\xd6\xaf\x95\xc7B\xac\
1505 \x03\xd3\x1c\xd6\xc2t\x10\xf7\x13\x8e\xe0\x14\x0b\xbe\xa2$m\xf3\xca\xea\xacM\
1506 \xe6\xd2\xc1\xcaWdl>#\x0e\x8c\xed\xe7n\x90|\xa8\x96m\xbc~ y\x04Z\xcd\x86\xda\
1507 \xda\xde\xb1Gq\x00\xb2S\t\xfeB\x9aK\xa8\xb1\x0e\xf2\x15I.\xad\x0bo\x8f\xf4\
1508 \x97\xab\xe7z\x88\x1f\xdf\xf0\xfa9\x1e\xe0x\x9eG\xbf\x16X\xcd\xb8Ar\xc6\xd5\
1509 \x0b4\xd4\xf3\xbcd\x07F_\xc3 \x1e\x0c\xa3Y\x08\x9f\x1f~\xefA\xab\xd9P\x9dN\
1510 \x07\x80\xddcI\xc6\x85\xf9\xb4.8\xabhwK\xbd+6\x16\xf5\xdeZ=%F\x00\xa0\xa7\
1511 \x0b`@F\xc6\xf6\xd3\xc5&@\x0c"\xa2\xff\x82\x01\x85-\xb7\x9a\re\x00QH\x0c0N\
1512 \x06\x1a\x85\xbcym}\x0f\xfe\x92\x19\xdc\xf2~\xdb\xee\xdd\xf7\xf4\xf3_\x0e\
1513 \xa2N\xc2\xfa\x01MYp\xbc\xe4a\x0f\xa9\x00\x00\x00\x00IEND\xaeB`\x82'
1515 def getZoomInBitmap():
1516 return BitmapFromImage(getZoomInImage())
1518 def getZoomInImage():
1519 stream
= cStringIO
.StringIO(getZoomInData())
1520 return ImageFromStream(stream
)
1522 #----------------------------------------------------------------------
1523 def getZoomOutData():
1525 '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
1526 \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
1527 \x00\x01RIDAT8\x8d\x8d\x93\xbbJ\x03A\x14\x86\xbf\xd9\x04\x93\x90J\x0cj#Dl\
1528 \xf4\x01\xec\x05\xdb\xc5\x0b>B\x92]\x1b+\xed,D\xb0\xb4\x08\x9afc|\x04\xc9\
1529 \x85\xb4>\x84\x95`\x93\x80`\x15\xd8*\x98\x84\xc0X\xcc\xce\xde7\xf8\xc30\x97=\
1530 \xf3\xcd\x7f\xce\xcc\na\xe4\x08\xabQ\xaf\xc9\xf0\xfc\xa5\xf3*X\xa1|b\xa3\xe5\
1531 D\x81 W\x81\x840r4\xea5\xf9\xf0\xe40Y@\xf3+\xf8\xb8\xbe\x16\x8c\xdd\x96\x9d\
1532 \n1\xf4\xc0\xdf\xdc\xb6\x01\xa8\xca\x19[\x05\xfc\x96%aY\x96\x0c\xdb\xae\xca\
1533 \x99\xea7\x8b\x91@w.\xf9x\xbcL\xb8\xf0k\xa0O\x1e{\xd31Q\x1d\xdd\xaaC\xfa\xbd\
1534 \xae<=;\xf7!F<\xd7,md\xc4\xf8\x0e\xf6\xaf\x1d\xb6\x8b*p\xa7\x0c\x95\xd0\x86\
1535 \xc9\x02\xbe\xa7\xe9\x00\xc34M\xdc\x96MA\xa8[,y\xc8r>h\x00ow6\xa6if;\x98K\
1536 \x95\xd6\xef\x12(\xc0t\x99~b8\x7f\xf0\xdeA\xbf\xd7\x95\xc3\xe1\x10\x80\x8b{\
1537 \x87R\x1e*\xde\xd55oTq\xf7Fm\x8ew\xd5\xdaa\'\'"\x00P\xd5\x05\xd0 -m\xfb\xf3\
1538 \xf9\x04 \x01\x11\xf1\x7fA\x83\xc2\x96\xfb\xbd\xae\xd4\x808$\x01H\x93\x86\
1539 \xc6!?\xe6 x\xca\xab\xa4\x0bwp5\xf0\xd7\xdeG\xaa\xff\x97\x83\xb8\x93\xb0\xfe\
1540 \x00\xc3\xa8ov\xfd\xe4\x9c\xa2\x00\x00\x00\x00IEND\xaeB`\x82'
1543 def getZoomOutBitmap():
1544 return BitmapFromImage(getZoomOutImage())
1546 def getZoomOutImage():
1547 stream
= cStringIO
.StringIO(getZoomOutData())
1548 return ImageFromStream(stream
)