19
from gi.repository import GObject
20
from gi.repository import Gdk
21
from gi.repository import Gtk
22
from gi.repository import Pango
26
25
from bzrlib import patiencediff
27
26
from bzrlib.errors import NoSuchRevision
28
27
from bzrlib.revision import NULL_REVISION, CURRENT_REVISION
30
from colormap import AnnotateColorSaturation
29
from bzrlib.plugins.gtk.annotate.colormap import AnnotateColorSaturation
30
from bzrlib.plugins.gtk.i18n import _i18n
31
31
from bzrlib.plugins.gtk.revisionview import RevisionView
32
32
from bzrlib.plugins.gtk.window import Window
167
168
def _highlight_annotation(self, model, path, iter, now):
168
169
revision_id, = model.get(iter, REVISION_ID_COL)
169
170
revision = self.revisions[revision_id]
170
model.set(iter, HIGHLIGHT_COLOR_COL,
171
self.annotate_colormap.get_color(revision, now))
171
# XXX sinzui 2011-08-12: What does get_color return?
172
color = self.annotate_colormap.get_color(revision, now)
173
model.set_value(iter, HIGHLIGHT_COLOR_COL, color)
173
175
def _selected_revision(self):
174
176
(path, col) = self.annoview.get_cursor()
193
195
self.revisionview = self._create_log_view()
194
196
self.annoview = self._create_annotate_view()
196
vbox = gtk.VBox(False)
198
vbox = Gtk.VBox(homogeneous=False, spacing=0)
199
sw = gtk.ScrolledWindow()
200
sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
201
sw.set_shadow_type(gtk.SHADOW_IN)
201
sw = Gtk.ScrolledWindow()
202
sw.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
203
sw.set_shadow_type(Gtk.ShadowType.IN)
202
204
sw.add(self.annoview)
203
205
self.annoview.gwindow = self
209
swbox.pack_start(sw, True, True, 0)
210
hbox = gtk.HBox(False, 6)
212
hbox = Gtk.HBox(homogeneous=False, spacing=6)
211
213
self.back_button = self._create_back_button()
212
hbox.pack_start(self.back_button, expand=False, fill=True)
214
hbox.pack_start(self.back_button, False, True, 0)
213
215
self.forward_button = self._create_forward_button()
214
hbox.pack_start(self.forward_button, expand=False, fill=True)
216
hbox.pack_start(self.forward_button, False, True, 0)
215
217
self.find_button = self._create_find_button()
216
hbox.pack_start(self.find_button, expand=False, fill=True)
218
hbox.pack_start(self.find_button, False, True, 0)
217
219
self.goto_button = self._create_goto_button()
218
hbox.pack_start(self.goto_button, expand=False, fill=True)
220
hbox.pack_start(self.goto_button, False, True, 0)
220
vbox.pack_start(hbox, expand=False, fill=True)
222
vbox.pack_start(hbox, False, True, 0)
222
self.pane = pane = gtk.VPaned()
224
self.pane = pane = Gtk.Paned.new(Gtk.Orientation.VERTICAL)
224
226
pane.add2(self.revisionview)
226
vbox.pack_start(pane, expand=True, fill=True)
228
vbox.pack_start(pane, True, True, 0)
228
230
self._search = SearchBox()
229
swbox.pack_start(self._search, expand=False, fill=True)
230
accels = gtk.AccelGroup()
231
accels.connect_group(gtk.keysyms.f, gtk.gdk.CONTROL_MASK,
231
swbox.pack_start(self._search, False, True, 0)
232
accels = Gtk.AccelGroup()
233
accels.connect(Gdk.KEY_f, Gdk.ModifierType.CONTROL_MASK,
234
Gtk.AccelFlags.LOCKED,
233
235
self._search_by_text)
234
accels.connect_group(gtk.keysyms.g, gtk.gdk.CONTROL_MASK,
236
accels.connect(Gdk.KEY_g, Gdk.ModifierType.CONTROL_MASK,
237
Gtk.AccelFlags.LOCKED,
236
238
self._search_by_line)
237
239
self.add_accel_group(accels)
269
271
def _create_annotate_view(self):
271
273
tv.set_rules_hint(False)
272
274
tv.connect("cursor-changed", self._activate_selected_revision)
274
276
tv.connect("row-activated", self.line_diff)
276
cell = gtk.CellRendererText()
278
cell = Gtk.CellRendererText()
277
279
cell.set_property("xalign", 1.0)
278
280
cell.set_property("ypad", 0)
279
281
cell.set_property("family", "Monospace")
280
cell.set_property("cell-background-gdk",
281
tv.get_style().bg[gtk.STATE_NORMAL])
282
col = gtk.TreeViewColumn()
283
"cell-background-rgba",
284
tv.get_style_context().get_background_color(Gtk.StateType.NORMAL))
285
col = Gtk.TreeViewColumn()
283
286
col.set_resizable(False)
284
col.pack_start(cell, expand=True)
287
col.pack_start(cell, True)
285
288
col.add_attribute(cell, "text", LINE_NUM_COL)
286
289
tv.append_column(col)
288
cell = gtk.CellRendererText()
291
style_context = self.get_style_context()
293
cell = Gtk.CellRendererText()
289
294
cell.set_property("ypad", 0)
290
cell.set_property("ellipsize", pango.ELLIPSIZE_END)
291
cell.set_property("cell-background-gdk",
292
self.get_style().bg[gtk.STATE_NORMAL])
293
col = gtk.TreeViewColumn("Committer")
295
cell.set_property("ellipsize", Pango.EllipsizeMode.END)
297
"cell-background-rgba",
298
style_context.get_background_color(Gtk.StateType.NORMAL))
299
col = Gtk.TreeViewColumn("Committer")
294
300
col.set_resizable(True)
295
col.pack_start(cell, expand=True)
301
col.pack_start(cell, True)
296
302
col.add_attribute(cell, "text", COMMITTER_COL)
297
303
tv.append_column(col)
299
cell = gtk.CellRendererText()
305
cell = Gtk.CellRendererText()
300
306
cell.set_property("xalign", 1.0)
301
307
cell.set_property("ypad", 0)
302
cell.set_property("cell-background-gdk",
303
self.get_style().bg[gtk.STATE_NORMAL])
304
col = gtk.TreeViewColumn("Revno")
309
"cell-background-rgba",
310
style_context.get_background_color(Gtk.StateType.NORMAL))
311
col = Gtk.TreeViewColumn("Revno")
305
312
col.set_resizable(False)
306
col.pack_start(cell, expand=True)
313
col.pack_start(cell, True)
307
314
col.add_attribute(cell, "markup", REVNO_COL)
308
315
tv.append_column(col)
310
cell = gtk.CellRendererText()
317
cell = Gtk.CellRendererText()
311
318
cell.set_property("ypad", 0)
312
319
cell.set_property("family", "Monospace")
313
col = gtk.TreeViewColumn()
320
col = Gtk.TreeViewColumn()
314
321
col.set_resizable(False)
315
col.pack_start(cell, expand=True)
322
col.pack_start(cell, True)
316
323
# col.add_attribute(cell, "foreground", HIGHLIGHT_COLOR_COL)
317
324
col.add_attribute(cell, "background", HIGHLIGHT_COLOR_COL)
318
325
col.add_attribute(cell, "text", TEXT_LINE_COL)
319
326
tv.append_column(col)
321
# FIXME: Now that C-f is now used for search by text we
322
# may as well disable the auto search.
323
tv.set_search_column(LINE_NUM_COL)
328
# interactive substring search
329
def search_equal_func(model, column, key, iter):
330
return model.get_value(iter, TEXT_LINE_COL).lower().find(key.lower()) == -1
332
tv.set_enable_search(True)
333
tv.set_search_equal_func(search_equal_func, None)
332
342
def _create_back_button(self):
333
button = gtk.Button()
343
button = Gtk.Button()
334
344
button.set_use_stock(True)
335
345
button.set_label("gtk-go-back")
336
346
button.connect("clicked", lambda w: self.go_back())
337
button.set_relief(gtk.RELIEF_NONE)
347
button.set_relief(Gtk.ReliefStyle.NONE)
341
351
def _create_forward_button(self):
342
button = gtk.Button()
352
button = Gtk.Button()
343
353
button.set_use_stock(True)
344
354
button.set_label("gtk-go-forward")
345
355
button.connect("clicked", lambda w: self.go_forward())
346
button.set_relief(gtk.RELIEF_NONE)
356
button.set_relief(Gtk.ReliefStyle.NONE)
348
358
button.set_sensitive(False)
351
361
def _create_find_button(self):
352
button = gtk.Button()
362
button = Gtk.Button()
353
363
button.set_use_stock(True)
354
364
button.set_label("gtk-find")
355
365
button.set_tooltip_text("Search for text (Ctrl+F)")
356
366
button.connect("clicked", self._search_by_text)
357
button.set_relief(gtk.RELIEF_NONE)
367
button.set_relief(Gtk.ReliefStyle.NONE)
359
369
button.set_sensitive(True)
362
372
def _create_goto_button(self):
363
button = gtk.Button()
373
button = Gtk.Button()
364
374
button.set_label("Goto Line")
365
375
button.set_tooltip_text("Scroll to a line by entering its number (Ctrl+G)")
366
376
button.connect("clicked", self._search_by_line)
367
button.set_relief(gtk.RELIEF_NONE)
377
button.set_relief(Gtk.ReliefStyle.NONE)
369
379
button.set_sensitive(True)
393
403
rev_id = self._selected_revision()
394
404
if self.file_id in target_tree:
395
405
offset = self.get_scroll_offset(target_tree)
396
(row,), col = self.annoview.get_cursor()
406
path, col = self.annoview.get_cursor()
407
(row,) = path.get_indices()
397
408
self.annotate(target_tree, self.branch, self.file_id)
398
409
new_row = row+offset
401
self.annoview.set_cursor(new_row)
412
new_path = Gtk.TreePath(path=new_row)
413
self.annoview.set_cursor(new_path, None, False)
449
462
self.__cache[revision_id] = revision
450
463
return self.__cache[revision_id]
452
class SearchBox(gtk.HBox):
466
class SearchBox(Gtk.HBox):
453
467
"""A button box for searching in text or lines of annotations"""
454
468
def __init__(self):
455
gtk.HBox.__init__(self, False, 6)
469
super(SearchBox, self).__init__(homogeneous=False, spacing=6)
458
button = gtk.Button()
460
image.set_from_stock('gtk-stop', gtk.ICON_SIZE_BUTTON)
472
button = Gtk.Button()
474
image.set_from_stock('gtk-stop', Gtk.IconSize.BUTTON)
461
475
button.set_image(image)
462
button.set_relief(gtk.RELIEF_NONE)
463
button.connect("clicked", lambda w: self.hide_all())
464
self.pack_start(button, expand=False, fill=False)
476
button.set_relief(Gtk.ReliefStyle.NONE)
477
button.connect("clicked", lambda w: self.hide())
478
self.pack_start(button, False, False, 0)
468
482
self._label = label
469
self.pack_start(label, expand=False, fill=False)
483
self.pack_start(label, False, False, 0)
472
486
self._entry = entry
473
487
entry.connect("activate", lambda w, d: self._do_search(d),
475
self.pack_start(entry, expand=False, fill=False)
489
self.pack_start(entry, False, False, 0)
477
491
# Next/previous buttons
478
button = gtk.Button('_Next')
480
image.set_from_stock('gtk-go-forward', gtk.ICON_SIZE_BUTTON)
492
button = Gtk.Button(_i18n('_Next'), use_underline=True)
494
image.set_from_stock('gtk-go-forward', Gtk.IconSize.BUTTON)
481
495
button.set_image(image)
482
496
button.connect("clicked", lambda w, d: self._do_search(d),
484
self.pack_start(button, expand=False, fill=False)
498
self.pack_start(button, False, False, 0)
486
button = gtk.Button('_Previous')
488
image.set_from_stock('gtk-go-back', gtk.ICON_SIZE_BUTTON)
500
button = Gtk.Button(_i18n('_Previous'), use_underline=True)
502
image.set_from_stock('gtk-go-back', Gtk.IconSize.BUTTON)
489
503
button.set_image(image)
490
504
button.connect("clicked", lambda w, d: self._do_search(d),
492
self.pack_start(button, expand=False, fill=False)
506
self.pack_start(button, False, False, 0)
495
check = gtk.CheckButton('Match case')
509
check = Gtk.CheckButton('Match case')
496
510
self._match_case = check
497
self.pack_start(check, expand=False, fill=False)
511
self.pack_start(check, False, False, 0)
499
check = gtk.CheckButton('Regexp')
513
check = Gtk.CheckButton('Regexp')
500
514
check.connect("toggled", lambda w: self._set_label())
501
515
self._regexp = check
502
self.pack_start(check, expand=False, fill=False)
516
self.pack_start(check, False, False, 0)
504
518
self._view = None
505
519
self._column = None