ed_log.py
8.66 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
###############################################################################
# Name: Cody Precord #
# Purpose: Log output viewer for the shelf #
# Author: Cody Precord <cprecord@editra.org> #
# Copyright: (c) 2008 Cody Precord <staff@editra.org> #
# License: wxWindows License #
###############################################################################
"""
Editra LogViewer
This module provides classes for managing the log display and filtering of its
messages. The module also exports an implementation of a shelf plugin for
displaying a L{LogViewer} in the Shelf.
"""
__author__ = "Cody Precord <cprecord@editra.org>"
__svnid__ = "$Id: ed_log.py 72223 2012-07-28 17:35:57Z CJP $"
__revision__ = "$Revision: 72223 $"
#--------------------------------------------------------------------------#
# Imports
import os
import re
import wx
# Editra Libraries
import ed_msg
import eclib
import iface
import plugin
from profiler import Profile_Get
import ed_glob
import ed_basewin
#-----------------------------------------------------------------------------#
# Globals
_ = wx.GetTranslation
SHOW_ALL_MSG = 'ALL'
#-----------------------------------------------------------------------------#
# Interface Implementation
class EdLogViewer(plugin.Plugin):
"""Shelf interface implementation for the log viewer"""
plugin.Implements(iface.ShelfI)
__name__ = u'Editra Log'
@staticmethod
def AllowMultiple():
"""EdLogger allows multiple instances"""
return True
@staticmethod
def CreateItem(parent):
"""Returns a log viewr panel"""
return LogViewer(parent)
def GetBitmap(self):
"""Get the log viewers tab icon
@return: wx.Bitmap
"""
bmp = wx.ArtProvider.GetBitmap(str(self.GetId()), wx.ART_MENU)
return bmp
@staticmethod
def GetId():
"""Plugin menu identifier ID"""
return ed_glob.ID_LOGGER
@staticmethod
def GetMenuEntry(menu):
"""Get the menu entry for the log viewer
@param menu: the menu items parent menu
"""
return wx.MenuItem(menu, ed_glob.ID_LOGGER, _("Editra Log"),
_("View Editra's console log"))
def GetName(self):
"""Return the name of this control"""
return self.__name__
@staticmethod
def IsStockable():
"""EdLogViewer can be saved in the shelf preference stack"""
return True
#-----------------------------------------------------------------------------#
# LogViewer Ui Implementation
class LogViewer(ed_basewin.EdBaseCtrlBox):
"""LogViewer is a control for displaying and working with output
from Editra's log.
"""
def __init__(self, parent):
super(LogViewer, self).__init__(parent)
# Attributes
self._buffer = LogBuffer(self)
self.SetWindow(self._buffer)
self._srcfilter = None
self._clear = None
# Layout
self.__DoLayout()
# Event Handlers
self.Bind(wx.EVT_BUTTON,
lambda evt: self._buffer.Clear(), self._clear)
self.Bind(wx.EVT_CHOICE, self.OnChoice, self._srcfilter)
self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy)
# Message Handlers
ed_msg.Subscribe(self.OnThemeChange, ed_msg.EDMSG_THEME_CHANGED)
def OnDestroy(self, evt):
"""Cleanup and unsubscribe from messages"""
if evt.GetId() == self.GetId():
ed_msg.Unsubscribe(self.OnThemeChange)
def __DoLayout(self):
"""Layout the log viewer window"""
# Setup ControlBar
ctrlbar = self.CreateControlBar(wx.TOP)
# View Choice
self._srcfilter = wx.Choice(ctrlbar, wx.ID_ANY, choices=[])
ctrlbar.AddControl(wx.StaticText(ctrlbar,
label=_("Show output from") + ":"))
ctrlbar.AddControl(self._srcfilter)
# Clear Button
ctrlbar.AddStretchSpacer()
self._clear = self.AddPlateButton(_("Clear"), ed_glob.ID_DELETE,
wx.ALIGN_RIGHT)
def OnChoice(self, evt):
"""Set the filter based on the choice controls value
@param evt: wx.CommandEvent
"""
self._buffer.SetFilter(self._srcfilter.GetStringSelection())
def OnThemeChange(self, msg):
"""Update the buttons icon when the icon theme changes
@param msg: Message Object
"""
cbmp = wx.ArtProvider.GetBitmap(str(ed_glob.ID_DELETE), wx.ART_MENU)
self._clear.SetBitmap(cbmp)
self._clear.Refresh()
def SetSources(self, srclist):
"""Set the list of available log sources in the choice control
@param srclist: list of log sources
"""
choice = self._srcfilter.GetStringSelection()
lst = sorted(srclist)
lst.insert(0, _("All"))
self._srcfilter.SetItems(lst)
if not self._srcfilter.SetStringSelection(choice):
self._srcfilter.SetSelection(0)
#-----------------------------------------------------------------------------#
class LogBuffer(eclib.OutputBuffer):
"""Buffer for displaying log messages that are sent on Editra's
log channel.
@todo: make line buffering configurable through interface
"""
RE_WARN_MSG = re.compile(r'\[err\]|\[error\]|\[warn\]')
ERROR_STYLE = eclib.OPB_STYLE_MAX + 1
def __init__(self, parent):
super(LogBuffer, self).__init__(parent)
# Attributes
self._filter = SHOW_ALL_MSG
self._srcs = list()
self.SetLineBuffering(2000)
# Setup
font = Profile_Get('FONT1', 'font', wx.Font(11, wx.FONTFAMILY_MODERN,
wx.FONTSTYLE_NORMAL,
wx.FONTWEIGHT_NORMAL))
self.SetFont(font)
style = (font.GetFaceName(), font.GetPointSize(), "#FF0000")
self.StyleSetSpec(LogBuffer.ERROR_STYLE,
"face:%s,size:%d,fore:#FFFFFF,back:%s" % style)
# Event Handlers
self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy, self)
# Subscribe to Editra's Log
ed_msg.Subscribe(self.UpdateLog, ed_msg.EDMSG_LOG_ALL)
def OnDestroy(self, evt):
"""Unregister from receiving any more log messages"""
if evt.GetId() == self.GetId():
ed_msg.Unsubscribe(self.UpdateLog)
evt.Skip()
def AddFilter(self, src):
"""Add a new filter source
@param src: filter source string
@postcondition: if src is new the parent window is updated
"""
if src not in self._srcs:
self._srcs.append(src)
self.Parent.SetSources(self._srcs)
def ApplyStyles(self, start, txt):
"""Apply coloring to error and warning messages
@note: overridden from L{outbuff.OutputBuffer}
@param start: Start position of text that needs styling in the buffer
@param txt: The string of text that starts at the start position in the
buffer.
"""
for group in LogBuffer.RE_WARN_MSG.finditer(txt):
sty_s = start + group.start()
sty_e = start + group.end()
self.StartStyling(sty_s, 0xff)
# Highlight error messages with ERROR_STYLE
self.SetStyling(sty_e - sty_s, LogBuffer.ERROR_STYLE)
def SetFilter(self, src):
"""Set the level of what is shown in the display
@param src: Only show messages from src
@return: bool
"""
if src in self._srcs:
self._filter = src
return True
elif src == _("All"):
self._filter = SHOW_ALL_MSG
return True
else:
return False
def UpdateLog(self, msg):
"""Add a new log message
@param msg: Message Object containing a LogMsg
"""
if wx.Thread_IsMain():
self.DoUpdateLog(msg)
else:
# Delegate to main thread
wx.CallAfter(self.DoUpdateLog, msg)
def DoUpdateLog(self, msg):
if not self.IsRunning():
self.Start(200)
# Check filters
logmsg = msg.GetData()
org = logmsg.Origin
if org not in self._srcs:
self.AddFilter(org)
if self._filter == SHOW_ALL_MSG:
self.AppendUpdate(unicode(logmsg) + unicode(os.linesep))
elif self._filter == logmsg.Origin:
msg = u"[%s][%s]%s" % (logmsg.ClockTime, logmsg.Type, logmsg.Value)
self.AppendUpdate(msg + unicode(os.linesep))
else:
pass