2
# -*- coding: ISO-8859-1 -*-
3
# generated by wxGlade 0.4 on Thu Mar 22 16:41:19 2007
6
from hexeditor.highlighter import color, Highlighter, Attribute #XXX import... better use extension point?
7
from hexeditor import hexedit
8
from framework import util
9
from itertools import chain
11
def irange(fm, to, step=1):
16
def forward_blocks(fm, to, blocksize=512):
18
yield fm, min(blocksize, to - fm)
21
def reverse_blocks(fm, to, blocksize=512):
24
if fm < to: blocksize -= to - fm; fm = to
28
"""keep two contexts, that can be switched back and forth"""
29
def __init__(self, he):
31
self.other_context = None
34
# copy instance variables
36
for key in ('fileobj', 'bin', 'filename', 'readonly', '_modified'):
37
context[key] = self.hexedit.__dict__[key]
38
new_context = self.other_context
39
self.other_context = context
41
if new_context is None:
44
self.hexedit.__dict__.update(new_context)
45
#~ self.hexedit.send_event('OPEN', self.hexedit.filename)
46
self.hexedit.send_event('MODIFY', self.hexedit._modified)
47
self.hexedit.send_event('CHANGE', None, None)
51
class DiffControlPanel(wx.Panel, util.SimpleEventSink):
52
def __init__(self, manager, parent, mainwindow):
53
util.SimpleEventSink.__init__(self)
54
self.hexview = mainwindow.main_widget
55
self.hexeditor = mainwindow.main_widget.hexeditor
56
self.diffedit = DiffEdit(mainwindow.main_widget.hexeditor)
59
# begin wxGlade: DiffControlPanel.__init__
60
kwds["style"] = wx.TAB_TRAVERSAL
61
wx.Panel.__init__(self, *args, **kwds)
62
self.button_toggle = wx.Button(self, -1, _("Toggle Files"))
63
self.button_find_diff = wx.Button(self, -1, _("Find Next Difference"))
64
self.button_previous_diff = wx.Button(self, -1, _("Find Previous Difference"))
65
self.text_ctrl_info = wx.TextCtrl(self, -1, "", style=wx.TE_MULTILINE|wx.TE_READONLY)
67
self.__set_properties()
70
self.Bind(wx.EVT_BUTTON, self.on_toggle, self.button_toggle)
71
self.Bind(wx.EVT_BUTTON, self.on_find_next, self.button_find_diff)
72
self.Bind(wx.EVT_BUTTON, self.on_find_prev, self.button_previous_diff)
76
attribute = Attribute(
77
foreground=color(0,200,0),
78
bordercolor=color(50,255,10),
81
class DiffHighlighter(Highlighter):
82
"""colorize differences between two files"""
83
# - - - highlighter interface
84
def begin_screen_update(self, start_offset, end_offset):
85
"""called once per screen update. the offset range that is beeing
86
updated is passed as parameters"""
87
self.cache_firstoffset = start_offset
88
bin1 = parent.diffedit.other_context is not None and parent.diffedit.other_context['bin']
89
bin2 = self.hexeditor.bin
92
bin1.read(offset, 1) != bin2.read(offset, 1)
93
for offset in irange(start_offset, end_offset+1)]
95
self.different = [False]*(end_offset-start_offset+1)
97
def attribute_for_offset(self, offset):
98
if self.different[offset - self.cache_firstoffset]:
101
manager['hexview.highlighter.diff'] = manager.make_extension_point(
102
factory = DiffHighlighter,
106
self.hexeditor.subscribe(self)
107
manager['hexeditor.diffcontrol'] = manager.make_extension_point(
108
switch = self.diffedit.switch
110
self.Bind(wx.EVT_WINDOW_DESTROY, self.on_destroy)
112
def __set_properties(self):
113
# begin wxGlade: DiffControlPanel.__set_properties
114
self.text_ctrl_info.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_INACTIVEBORDER))
117
def __do_layout(self):
118
# begin wxGlade: DiffControlPanel.__do_layout
119
sizer_1 = wx.BoxSizer(wx.VERTICAL)
120
sizer_1.Add(self.button_toggle, 0, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
121
sizer_1.Add(self.button_find_diff, 0, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
122
sizer_1.Add(self.button_previous_diff, 0, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
123
sizer_1.Add(self.text_ctrl_info, 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
124
self.SetAutoLayout(True)
125
self.SetSizer(sizer_1)
127
sizer_1.SetSizeHints(self)
131
self.diffedit.switch()
132
if manager['gui.handle'].application.checkSaved(manager, self):
133
self.hexeditor.close()
134
self.diffedit.switch()
138
def on_destroy(self, event):
139
self.hexeditor.unsubscribe(self)
140
del manager['hexeditor.diffcontrol']
141
del manager['hexview.highlighter.diff']
142
# XXX check other context for modifications, they're getting lost!
145
def on_toggle(self, event): # wxGlade: DiffControlPanel.<event_handler>
146
self.diffedit.switch()
148
def on_find_next(self, event): # wxGlade: DiffControlPanel.<event_handler>
149
offset = self.find_next_change()
150
if offset is not None:
151
self.hexview.setSelection(offset)
152
manager['gui.utils.notification.statusbar'](_("Difference at offset %d" % (offset)))
154
def on_find_prev(self, event): # wxGlade: DiffControlPanel.<event_handler>
155
offset = self.find_next_change(False)
156
if offset is not None:
157
self.hexview.setSelection(offset)
158
manager['gui.utils.notification.statusbar'](_("Difference at offset %d" % (offset)))
161
self.text_ctrl_info.SetValue("Shown:\n%s\n\nOther:\n%s" % (
162
self.hexeditor.fileobj,
163
self.diffedit.other_context is not None and self.diffedit.other_context['fileobj']
166
def find_next_change(self, forward=True):
167
bin1 = self.diffedit.other_context is not None and self.diffedit.other_context['bin']
168
bin2 = self.hexeditor is not None and self.hexeditor.bin
170
sel_start, sel_end = 0, self.hexeditor.bin.size()
173
progress_dlg = manager['hexeditor.dialogs.progress'](
174
_("Searching for next difference..."),
180
start_offset = self.hexview.getSelection()[0]
185
for offset, blocksize in chain(
186
forward_blocks(start_offset+1, sel_end),
187
forward_blocks(sel_start, start_offset+1)
189
b1 = bin1.read(offset, blocksize)
190
b2 = bin2.read(offset, blocksize)
192
for x, (q1, q2) in enumerate(zip(b1,b2)):
195
# if blocks do not have same length
196
return offset + min(len(b1), len(b2))
197
# update progressbar, check for abort
198
progress_dlg(relative_offset)
199
relative_offset += len(b1)
201
manager['gui.utils.notification.message'](_("No difference found"))
203
for offset, blocksize in chain(
204
reverse_blocks(start_offset, sel_start),
205
reverse_blocks(sel_end-1, start_offset)
207
b1 = bin1.read(offset, blocksize)
208
b2 = bin2.read(offset, blocksize)
210
for x, (q1, q2) in reversed(list(enumerate(zip(b1,b2)))):
213
# if blocks do not have same length
214
return offset + min(len(b1), len(b2))
215
# update progressbar, check for abort
216
progress_dlg(relative_offset)
217
relative_offset += len(b1)
219
manager['gui.utils.notification.message'](_("No difference found"))
222
except KeyboardInterrupt:
223
manager['gui.utils.notification.error'](_("User aborted search"))
225
manager['gui.utils.notification.error'](
226
_("There are no two files!")
229
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
230
# simple event handlers
234
def event_CHANGE(self, offset=None, length=None):
235
"""update undo/redo menu entries"""
238
def event_MODIFY(self, modified):
239
"""some data in model has changed"""
242
def event_CLOSING(self):
243
"""file is beeing closed"""
245
def event_CLOSED(self):
246
"""file was closed"""
249
def event_OPEN(self, filename):
250
"""a new file has been opened"""
253
# end of class DiffControlPanel
257
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
259
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
261
# list of dependant extension points
265
#~ 'gui.handle.application',
269
# list of provided extension points
271
'gui.panels.diffcontrol',
272
'hexeditor.diffcontrol',
277
_ = manager['i18n.translate']
279
manager['gui.panels.diffcontrol'] = manager.make_extension_point(
280
__doc__ = 'Quickly switch between files and provide diff highlighting',
281
label = _("Diff Control"),
282
widget = DiffControlPanel,
283
orientation = 'vertical',
285
shortcut = 'SHIFT+CTRL+D',