'''
This software is licensed under the GPL (GNU General Public License) version 2
as it appears here: http://www.gnu.org/copyleft/gpl.html
It is also included with this archive as `gpl.txt <gpl.txt>`_.
'''
import wx
import wx.lib.mixins.listctrl as listmix
class Editable(wx.ListCtrl, listmix.TextEditMixin, listmix.ListCtrlAutoWidthMixin):
def __init__(self, parent, id, style):
wx.ListCtrl.__init__(self, parent, id, style=style)
listmix.TextEditMixin.__init__(self)
listmix.ListCtrlAutoWidthMixin.__init__(self)
def reconstruct(suf, x):
if isinstance(x, (str, unicode)):
yield suf, x
elif type(x) is dict:
for key,value in x.iteritems():
for i,j in reconstruct(key+suf, value):
yield i, j
DOC = ''' \
When editing a document, any time you type the string in the 'input' column'
and use the "Transforms -> Perform Trigger" command, the string in the
'output' column replaces it, with the following special symbols:
%C - the cursor position after expansion
%L - will perform an auto-indenting return
See the help for example uses.
One may want to use such functionality for single or double quotes: '', ""
parens or square/curly/pointy braces: (), [], {}, <>
or even html tag expansion: ahref->"<a href='http://", "'></a>"
Double-click to edit an entry in-place.
When a trigger is a suffix of another trigger, the longer trigger will be
preserved, the shorter trigger will be tossed. Watch the log for such
entries.
NOTE: If any of your entries begins with a single or double quote, and is a
valid Python string definition, then it will be interpreted as the string
defined (allowing for escaped tabs, line endings, unicode characters, etc.).'''
class TriggerDialog(wx.Dialog):
def __init__(self, parent, stc, dct):
wx.Dialog.__init__(self, parent, -1, "Set your Triggers",
style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER,
size=(800, 400), pos=(0,0))
self.stc = stc
self.parent = parent
self.dct = dct
self.Bind(wx.EVT_CLOSE, self.OnClose)
def addbutton(sizer, name, fcn, id):
it = wx.Button(self, id, name)
sizer.Add(it, 0, wx.RIGHT, border=5)
self.Bind(wx.EVT_BUTTON, fcn, it)
sizer = wx.BoxSizer(wx.VERTICAL)
#description/help text
sizer.Add(wx.StaticText(self, -1, DOC), 0, wx.LEFT|wx.RIGHT, border=5)
#wx.ListCtrl with editor
self.list = Editable(self, -1, style=wx.LC_REPORT|wx.BORDER_NONE)
self.list.InsertColumn(0, "input");self.list.SetColumnWidth(0, 160)
self.list.InsertColumn(1, "output");self.list.SetColumnWidth(1, 80)
self.ResetData(dct)
sizer.Add(self.list, 2, flag=wx.GROW|wx.ALL, border=5)
buttons = wx.BoxSizer(wx.HORIZONTAL)
#new/delete
addbutton(buttons, "New Trigger", self.OnNew, wx.NewId())
addbutton(buttons, "Delete Trigger", self.OnDelete, wx.NewId())
buttons.Add(wx.StaticText(self, -1, ' '), 1, wx.GROW)
#OK/cancel
addbutton(buttons, "OK", self.OnOK, wx.OK)
addbutton(buttons, "Cancel", self.OnCancel, wx.CANCEL)
sizer.Add(buttons, 0, wx.ALIGN_CENTER|wx.LEFT, border=5)
sizer.Fit(self)
self.SetSizer(sizer)
def ResetData(self, data):
self.list.DeleteAllItems()
for x in reconstruct('', data):
x_ = []
for L in x:
try:
L = str(L)
except:
pass
if not isinstance(L, unicode):
Lx = L.encode('string-escape')
if Lx != L:
L = repr(L)
x_.append(L)
i,j = x_
indx = self.list.InsertStringItem(65536, 'X')
self.list.SetStringItem(indx, 0, i)
self.list.SetStringItem(indx, 1, j)
def OnNew(self, evt):
index = self.list.InsertStringItem(65536, 'X')
self.list.SetStringItem(index, 0, 'X')
self.list.SetStringItem(index, 1, 'X')
def OnDelete(self, evt):
selected = self.list.GetNextItem(-1, state=wx.LIST_STATE_SELECTED)
if selected != -1:
self.list.DeleteItem(selected)
def OnClose(self, evt):
self.OnCancel(evt)
def OnOK(self, evt):
d = {}
for row in xrange(self.list.GetItemCount()):
#handle string escapes
item = [self.list.GetItem(row, 0).GetText(),
self.list.GetItem(row, 1).GetText()]
item_ = []
for i in item:
if i and i[0] in ['"', "'"]:
try:
i = [j for j in compiler.parse(str(i)).getChildren()[:1] if isinstance(j, basestring)][0]
except Exception, e:
pass
item_.append(i)
p, r = item_
if not p:
if len(l) or len(r):
print "null trigger has nonnull replacement %r"%r
continue
if len(r) == 0:
print "nonnull trigger %r has null replacement"%p
pr = None
x = d
good = 1
for le,ch in enumerate(p[::-1]):
n = x.get(ch, None)
if isinstance(n, (str, unicode)):
if p[-le-1:] == p:
print "duplicate trigger %r with replacement %r is now removed"%(p, r)
break
print "trigger %r with replacement %r is a suffix of %r, is now removed"%(p[-le-1:], n, p)
n = None
if n is None:
n = x[ch] = {}
pr, x = x, n
else:
if len(x) != 0:
print "trigger %r with replacement %r is a suffix of some entry, and is now removed"%(p, r)
continue
pr[p[0]] = r
## print repr(d)
self.stc.triggers.clear()
self.stc.triggers.update(d)
self.Destroy()
def OnCancel(self, evt):
self.Destroy()
|