78
78
if response == gtk.RESPONSE_OK:
79
79
self.parent._command_on_selected( self.parent.vc.commit_command(msg) )
80
80
if len(msg.strip()):
81
self.previousentry.prepend_history(1, msg)
81
self.previousentry.prepend_text(msg)
82
82
self.widget.destroy()
83
83
def on_previousentry_activate(self, gentry):
84
84
buf = self.textview.get_buffer()
85
buf.set_text( gentry.gtk_entry().get_text() )
85
buf.set_text( gentry.child.get_text() )
87
87
COL_LOCATION, COL_STATUS, COL_REVISION, COL_TAG, COL_OPTIONS, COL_END = range(tree.COL_END, tree.COL_END+6)
89
89
class VcTreeStore(tree.DiffTreeStore):
90
90
def __init__(self):
91
types = [type("")] * COL_END
92
types[tree.COL_ICON] = type(tree.pixbuf_file)
93
gtk.TreeStore.__init__(self, *types)
95
self._setup_default_styles()
91
tree.DiffTreeStore.__init__(self, 1, COL_END)
96
92
self.textstyle[tree.STATE_MISSING] = '<span foreground="#000088" strikethrough="true" weight="bold">%s</span>'
98
94
################################################################################
110
106
################################################################################
111
107
class VcView(melddoc.MeldDoc, gnomeglade.Component):
108
# Map action names to VC commands and required arguments list
109
action_vc_cmds_map = {
110
"VcCompare": ("diff_command", ()),
111
"VcCommit": ("commit_command", ("",)),
112
"VcUpdate": ("update_command", ()),
113
"VcAdd": ("add_command", ()),
114
"VcAddBinary": ("add_command", ()),
115
"VcRemove": ("remove_command", ()),
116
"VcRevert": ("revert_command", ()),
113
119
def __init__(self, prefs):
114
120
melddoc.MeldDoc.__init__(self, prefs)
134
140
("VcShowIgnored", "filter-ignored-24", _("Ignored"), None, _("Show ignored files"), self.on_button_filter_toggled, False),
137
ui_file = paths.share_dir("glade2/vcview-ui.xml")
143
self.ui_file = paths.share_dir("glade2/vcview-ui.xml")
138
144
self.actiongroup = gtk.ActionGroup('VcviewActions')
139
145
self.actiongroup.set_translation_domain("meld")
140
146
self.actiongroup.add_actions(actions)
141
147
self.actiongroup.add_toggle_actions(toggleactions)
142
self.ui = gtk.UIManager()
143
self.ui.insert_action_group(self.actiongroup, 0)
144
self.ui.add_ui_from_file(ui_file)
145
148
for action in ("VcCompare", "VcFlatten", "VcShowModified",
146
149
"VcShowNormal", "VcShowNonVC", "VcShowIgnored"):
147
150
self.actiongroup.get_action(action).props.is_important = True
184
182
addCol(_("Options"), COL_OPTIONS)
186
184
class ConsoleStream(object):
187
def __init__(this, textview):
188
this.textview = textview
185
def __init__(self, textview):
186
self.textview = textview
189
187
b = textview.get_buffer()
190
this.mark = b.create_mark("END", b.get_end_iter(), 0)
188
self.mark = b.create_mark("END", b.get_end_iter(), 0)
193
b = this.textview.get_buffer()
191
b = self.textview.get_buffer()
194
192
b.insert(b.get_end_iter(), s)
195
this.textview.scroll_mark_onscreen( this.mark )
193
self.textview.scroll_mark_onscreen( self.mark )
196
194
self.consolestream = ConsoleStream(self.consoleview)
197
195
self.location = None
198
196
self.treeview_column_location.set_visible(self.actiongroup.get_action("VcFlatten").get_active())
199
size = self.fileentry.size_request()[1]
200
self.button_jump.set_size_request(size, size)
201
self.button_jump.hide()
197
self.fileentry.show() #TODO: remove once bug 97503 is fixed
202
198
if not self.prefs.vc_console_visible:
203
199
self.on_console_view_toggle(self.console_hide_box)
202
self.combobox_vcs = gtk.ComboBox()
203
self.combobox_vcs.lock = True
204
self.combobox_vcs.set_model(gtk.ListStore(str, object))
205
cell = gtk.CellRendererText()
206
self.combobox_vcs.pack_start(cell, False)
207
self.combobox_vcs.add_attribute(cell, 'text', 0)
208
self.combobox_vcs.lock = False
209
self.hbox2.pack_end(self.combobox_vcs, expand=False)
210
self.combobox_vcs.show()
211
self.combobox_vcs.connect("changed", self.on_vc_change)
213
def update_actions_sensitivity(self):
214
"""Disable actions that use not implemented VC plugin methods
216
for action_name, (meth_name, args) in self.action_vc_cmds_map.items():
217
action = self.actiongroup.get_action(action_name)
219
getattr(self.vc, meth_name)(*args)
220
action.props.sensitive = True
221
except NotImplementedError:
222
action.props.sensitive = False
224
def choose_vc(self, vcs):
225
"""Display VC plugin(s) that can handle the location"""
226
self.combobox_vcs.lock = True
227
self.combobox_vcs.get_model().clear()
228
tooltip_texts = [_("Choose one Version Control"),
229
_("Only one Version Control in this directory")]
231
self.combobox_vcs.get_model().append([avc.NAME, avc])
232
if gtk.pygtk_version >= (2, 12, 0):
233
self.combobox_vcs.set_tooltip_text(tooltip_texts[len(vcs) == 1])
234
self.combobox_vcs.set_sensitive(len(vcs) > 1)
235
self.combobox_vcs.lock = False
236
self.combobox_vcs.set_active(0)
238
def on_vc_change(self, cb):
240
self.vc = cb.get_model()[cb.get_active_iter()][1]
241
self._set_location(self.vc.root)
242
self.update_actions_sensitivity()
205
244
def set_location(self, location):
245
self.choose_vc(vc.get_vcs(os.path.abspath(location or ".")))
247
def _set_location(self, location):
248
self.location = location
206
249
self.model.clear()
207
self.location = location = os.path.abspath(location or ".")
208
self.fileentry.gtk_entry().set_text(location)
209
self.vc = vc.Vc(location)
250
self.fileentry.set_filename(location)
251
self.fileentry.prepend_history(location)
210
252
it = self.model.add_entries( None, [location] )
211
253
self.treeview.grab_focus()
212
254
self.treeview.get_selection().select_iter(it)
314
352
elif empty_patch_ok:
315
353
misc.run_dialog( _("No differences found."), parent=self, messagetype=gtk.MESSAGE_INFO)
355
for path in path_list:
318
356
self.emit("create-diff", [path])
320
def run_diff(self, paths, empty_patch_ok=0):
321
self.scheduler.add_task( self.run_diff_iter(paths, empty_patch_ok).next, atfront=1 )
358
def run_diff(self, path_list, empty_patch_ok=0):
359
for path in path_list:
360
self.scheduler.add_task(self.run_diff_iter([path], empty_patch_ok).next, atfront=1)
323
362
def on_button_press_event(self, text, event):
324
363
if event.button==3:
392
432
misc.run_dialog( _("Select some files first."), parent=self, messagetype=gtk.MESSAGE_INFO)
394
def on_button_update_clicked(self, object):
434
def on_button_update_clicked(self, obj):
395
435
self._command_on_selected( self.vc.update_command() )
396
def on_button_commit_clicked(self, object):
436
def on_button_commit_clicked(self, obj):
397
437
dialog = CommitDialog( self )
400
def on_button_add_clicked(self, object):
440
def on_button_add_clicked(self, obj):
401
441
self._command_on_selected(self.vc.add_command() )
402
def on_button_add_binary_clicked(self, object):
442
def on_button_add_binary_clicked(self, obj):
403
443
self._command_on_selected(self.vc.add_command(binary=1))
404
def on_button_remove_clicked(self, object):
444
def on_button_remove_clicked(self, obj):
405
445
self._command_on_selected(self.vc.remove_command())
406
def on_button_revert_clicked(self, object):
446
def on_button_revert_clicked(self, obj):
407
447
self._command_on_selected(self.vc.revert_command())
408
def on_button_delete_clicked(self, object):
448
def on_button_delete_clicked(self, obj):
409
449
files = self._get_selected_files()
410
450
for name in files:
412
452
if os.path.isfile(name):
414
454
elif os.path.isdir(name):
415
if misc.run_dialog(_("'%s' is a directory.\nRemove recusively?") % os.path.basename(name),
455
if misc.run_dialog(_("'%s' is a directory.\nRemove recursively?") % os.path.basename(name),
417
457
buttonstype=gtk.BUTTONS_OK_CANCEL) == gtk.RESPONSE_OK:
418
458
shutil.rmtree(name)
421
461
workdir = _commonprefix(files)
422
462
self.refresh_partial(workdir)
424
def on_button_diff_clicked(self, object):
464
def on_button_diff_clicked(self, obj):
425
465
files = self._get_selected_files()
427
467
self.run_diff(files, empty_patch_ok=1)
429
def on_button_open_clicked(self, object):
469
def on_button_open_clicked(self, obj):
430
470
self._open_files(self._get_selected_files())
432
472
def show_patch(self, prefix, patch):
435
473
tmpdir = tempfile.mkdtemp("-meld")
436
474
self.tempdirs.append(tmpdir)
438
regex = re.compile(self.vc.PATCH_INDEX_RE, re.M)
439
files = [f.strip() for f in regex.findall(patch)]
477
for fname in self.vc.get_patch_files(patch):
442
478
destfile = os.path.join(tmpdir,fname)
443
479
destdir = os.path.dirname( destfile )
457
493
self.emit("create-diff", d)
459
misc.run_dialog( _("Invoking patch failed, you need GNU patch.")+ "\n'%s'"%" ".join(patchcmd), parent=self)
497
Invoking 'patch' failed.
499
Maybe you don't have 'GNU patch' installed,
500
or you use an untested version of %s.
502
Please send email bug report to:
505
Containing the following information:
508
- source control software type: '%s'
509
- source control software version: 'X.Y.Z'
510
- the output of '%s somefile.txt'
511
- patch command: '%s'
512
""") % (self.vc.NAME,
515
" ".join(self.vc.diff_command()),
517
msg = '\n'.join([line.strip() for line in msg.split('\n')])
518
misc.run_dialog(msg, parent=self)
461
520
def refresh(self):
462
521
self.set_location( self.model.value_path( self.model.get_iter_root(), 0 ) )
473
532
else: # XXX fixme
476
def on_button_jump_press_event(self, button, event):
477
class MyMenu(gtk.Menu):
478
def __init__(self, parent, where, showup=1):
479
gtk.Menu.__init__(self)
481
self.map_id = self.connect("map", lambda item: self.on_map(item,where,showup) )
482
def add_item(self, name, submenu, showup):
483
item = gtk.MenuItem(name)
485
item.set_submenu( MyMenu(self.vcview, submenu, showup ) )
487
def on_map(self, item, where, showup):
489
self.add_item("..", os.path.dirname(where), 1 )
490
self.populate( where, self.listdir(where) )
492
self.disconnect(self.map_id)
494
def listdir(self, d):
496
return [p for p in os.listdir(d) if os.path.isdir( os.path.join(d,p))]
499
def populate(self, where, children):
500
for child in children:
501
cc = self.listdir( os.path.join(where, child) )
502
self.add_item( child, len(cc) and os.path.join(where,child), 0 )
503
menu = MyMenu( self, os.path.abspath(self.location) )
504
menu.popup(None, None, None, event.button, event.time)
506
535
def _update_item_state(self, it, vcentry, location):
508
537
self.model.set_state( it, 0, e.state, e.isdir )
510
self.model.set_value( it, self.model.column_index(col,0), val)
511
set( COL_LOCATION, location )
512
set( COL_STATUS, e.get_status())
513
set( COL_REVISION, e.rev)
515
set( COL_OPTIONS, e.options)
538
def setcol(col, val):
539
self.model.set_value(it, self.model.column_index(col, 0), val)
540
setcol(COL_LOCATION, location)
541
setcol(COL_STATUS, e.get_status())
542
setcol(COL_REVISION, e.rev)
543
setcol(COL_TAG, e.tag)
544
setcol(COL_OPTIONS, e.options)
517
546
def on_file_changed(self, filename):
518
547
it = self.find_iter_by_name(filename)
520
549
path = self.model.value_path(it, 0)
521
dirs, files = self.vc.lookup_files( [], [ (os.path.basename(path), path)] )
550
files = self.vc.lookup_files([], [(os.path.basename(path), path)])[1]
523
552
if e.path == path:
524
553
prefixlen = 1 + len( self.model.value_path( self.model.get_iter_root(), 0 ) )