36
34
from bzrlib.branch import Branch
37
import bzrlib.errors as bzrerrors
38
from bzrlib.lazy_import import lazy_import
39
from bzrlib.ui import ui_factory
35
import bzrlib.errors as errors
40
36
from bzrlib.workingtree import WorkingTree
42
from bzrlib.plugins.gtk import _i18n
43
from bzrlib.plugins.gtk.dialog import error_dialog, info_dialog, warning_dialog
44
from bzrlib.plugins.gtk.errors import show_bzr_error
45
from bzrlib.plugins.gtk.olive.window import OliveGui
47
from bzrlib.plugins.gtk.diff import DiffWindow
48
lazy_import(globals(), """
49
from bzrlib.plugins.gtk.viz import branchwin
51
from bzrlib.plugins.gtk.annotate.gannotate import GAnnotateWindow
52
from bzrlib.plugins.gtk.annotate.config import GAnnotateConfig
53
from bzrlib.plugins.gtk.commit import CommitDialog
54
from bzrlib.plugins.gtk.conflicts import ConflictsDialog
55
from bzrlib.plugins.gtk.initialize import InitDialog
56
from bzrlib.plugins.gtk.push import PushDialog
57
from bzrlib.plugins.gtk.revbrowser import RevisionBrowser
60
""" Display the AboutDialog. """
61
from bzrlib.plugins.gtk import __version__, icon_path
63
iconpath = icon_path() + os.sep
65
dialog = gtk.AboutDialog()
66
dialog.set_name("Olive")
67
dialog.set_version(__version__)
68
dialog.set_copyright("Copyright (C) 2006 Szilveszter Farkas (Phanatic)")
69
dialog.set_website("https://launchpad.net/products/olive")
70
dialog.set_website_label("https://launchpad.net/products/olive")
71
dialog.set_icon_from_file(iconpath+"oliveicon2.png")
72
dialog.set_logo(gtk.gdk.pixbuf_new_from_file(iconpath+"oliveicon2.png"))
73
dialog.set_authors([ _i18n("Lead Developer:"),
74
"Szilveszter Farkas <szilveszter.farkas@gmail.com>",
75
_i18n("Contributors:"),
76
"Jelmer Vernooij <jelmer@samba.org>",
77
"Mateusz Korniak <mateusz.korniak@ant.gliwice.pl>",
78
"Gary van der Merwe <garyvdm@gmail.com>" ])
79
dialog.set_artists([ "Simon Pascal Klein <klepas@klepas.org>",
80
"Jakub Steiner <jimmac@novell.com>" ])
38
# Olive GTK UI version
39
__version__ = '0.11.0'
42
if sys.platform == 'win32':
43
gladefile = os.path.dirname(sys.executable) + "/share/olive/olive.glade"
45
gladefile = "/usr/share/olive/olive.glade"
47
if not os.path.exists(gladefile):
48
# Load from current directory if not installed
49
gladefile = "olive.glade"
51
if not os.path.exists(gladefile):
53
print _('Glade file cannot be found.')
56
from dialog import error_dialog, info_dialog
87
59
""" The main Olive GTK frontend class. This is called when launching the
90
62
def __init__(self):
91
self.window = OliveGui(calling_app = self)
93
self.pref = Preferences()
63
self.toplevel = gtk.glade.XML(gladefile, 'window_main', 'olive-gtk')
65
self.window = self.toplevel.get_widget('window_main')
67
self.pref = OlivePreferences()
96
69
# Initialize the statusbar
97
self.context_id = self.window.statusbar.get_context_id('olive')
100
self.treeview_left = self.window.treeview_left
101
self.treeview_right = self.window.treeview_right
70
self.statusbar = self.toplevel.get_widget('statusbar')
71
self.context_id = self.statusbar.get_context_id('olive')
74
self.window_main = self.toplevel.get_widget('window_main')
76
self.hpaned_main = self.toplevel.get_widget('hpaned_main')
78
self.treeview_left = self.toplevel.get_widget('treeview_left')
79
self.treeview_right = self.toplevel.get_widget('treeview_right')
80
# Get some important menu items
81
self.menuitem_add_files = self.toplevel.get_widget('menuitem_add_files')
82
self.menuitem_remove_files = self.toplevel.get_widget('menuitem_remove_file')
83
self.menuitem_file_make_directory = self.toplevel.get_widget('menuitem_file_make_directory')
84
self.menuitem_file_rename = self.toplevel.get_widget('menuitem_file_rename')
85
self.menuitem_file_move = self.toplevel.get_widget('menuitem_file_move')
86
self.menuitem_view_show_hidden_files = self.toplevel.get_widget('menuitem_view_show_hidden_files')
87
self.menuitem_branch = self.toplevel.get_widget('menuitem_branch')
88
self.menuitem_branch_init = self.toplevel.get_widget('menuitem_branch_initialize')
89
self.menuitem_branch_get = self.toplevel.get_widget('menuitem_branch_get')
90
self.menuitem_branch_checkout = self.toplevel.get_widget('menuitem_branch_checkout')
91
self.menuitem_branch_pull = self.toplevel.get_widget('menuitem_branch_pull')
92
self.menuitem_branch_push = self.toplevel.get_widget('menuitem_branch_push')
93
self.menuitem_branch_commit = self.toplevel.get_widget('menuitem_branch_commit')
94
self.menuitem_branch_status = self.toplevel.get_widget('menuitem_branch_status')
95
self.menuitem_branch_missing = self.toplevel.get_widget('menuitem_branch_missing_revisions')
96
self.menuitem_stats = self.toplevel.get_widget('menuitem_stats')
97
self.menuitem_stats_diff = self.toplevel.get_widget('menuitem_stats_diff')
98
self.menuitem_stats_log = self.toplevel.get_widget('menuitem_stats_log')
99
# Get some toolbuttons
100
#self.menutoolbutton_diff = self.toplevel.get_widget('menutoolbutton_diff')
101
self.toolbutton_diff = self.toplevel.get_widget('toolbutton_diff')
102
self.toolbutton_log = self.toplevel.get_widget('toolbutton_log')
103
self.toolbutton_commit = self.toplevel.get_widget('toolbutton_commit')
104
self.toolbutton_pull = self.toplevel.get_widget('toolbutton_pull')
105
self.toolbutton_push = self.toplevel.get_widget('toolbutton_push')
103
106
# Get the drive selector
104
107
self.combobox_drive = gtk.combo_box_new_text()
105
108
self.combobox_drive.connect("changed", self._refresh_drives)
107
# Get the navigation widgets
108
self.hbox_location = self.window.locationbar
109
self.button_location_up = self.window.button_location_up
110
self.button_location_jump = self.window.button_location_jump
111
self.entry_location = self.window.entry_location
112
self.image_location_error = self.window.image_location_error
114
# Get the History widgets
115
self.check_history = self.window.checkbutton_history
116
self.entry_history = self.window.entry_history_revno
117
self.button_history = self.window.button_history_browse
119
self._just_started = True
110
self.vbox_main_right = self.toplevel.get_widget('vbox_main_right')
113
# Dictionary for signal_autoconnect
114
dic = { "on_window_main_destroy": gtk.main_quit,
115
"on_window_main_delete_event": self.on_window_main_delete_event,
116
"on_quit_activate": self.on_window_main_delete_event,
117
"on_about_activate": self.on_about_activate,
118
"on_menuitem_add_files_activate": self.on_menuitem_add_files_activate,
119
"on_menuitem_remove_file_activate": self.on_menuitem_remove_file_activate,
120
"on_menuitem_file_make_directory_activate": self.on_menuitem_file_make_directory_activate,
121
"on_menuitem_file_move_activate": self.on_menuitem_file_move_activate,
122
"on_menuitem_file_rename_activate": self.on_menuitem_file_rename_activate,
123
"on_menuitem_view_show_hidden_files_activate": self.on_menuitem_view_show_hidden_files_activate,
124
"on_menuitem_view_refresh_activate": self.on_menuitem_view_refresh_activate,
125
"on_menuitem_branch_initialize_activate": self.on_menuitem_branch_initialize_activate,
126
"on_menuitem_branch_get_activate": self.on_menuitem_branch_get_activate,
127
"on_menuitem_branch_checkout_activate": self.on_menuitem_branch_checkout_activate,
128
"on_menuitem_branch_commit_activate": self.on_menuitem_branch_commit_activate,
129
"on_menuitem_branch_push_activate": self.on_menuitem_branch_push_activate,
130
"on_menuitem_branch_pull_activate": self.on_menuitem_branch_pull_activate,
131
"on_menuitem_branch_status_activate": self.on_menuitem_branch_status_activate,
132
"on_menuitem_branch_missing_revisions_activate": self.on_menuitem_branch_missing_revisions_activate,
133
"on_menuitem_stats_diff_activate": self.on_menuitem_stats_diff_activate,
134
"on_menuitem_stats_log_activate": self.on_menuitem_stats_log_activate,
135
"on_menuitem_stats_infos_activate": self.on_menuitem_stats_infos_activate,
136
"on_toolbutton_refresh_clicked": self.on_menuitem_view_refresh_activate,
137
"on_toolbutton_log_clicked": self.on_menuitem_stats_log_activate,
138
#"on_menutoolbutton_diff_clicked": self.on_menuitem_stats_diff_activate,
139
"on_toolbutton_diff_clicked": self.on_menuitem_stats_diff_activate,
140
"on_toolbutton_commit_clicked": self.on_menuitem_branch_commit_activate,
141
"on_toolbutton_pull_clicked": self.on_menuitem_branch_pull_activate,
142
"on_toolbutton_push_clicked": self.on_menuitem_branch_push_activate,
143
"on_treeview_right_button_press_event": self.on_treeview_right_button_press_event,
144
"on_treeview_right_row_activated": self.on_treeview_right_row_activated,
145
"on_treeview_left_button_press_event": self.on_treeview_left_button_press_event,
146
"on_treeview_left_row_activated": self.on_treeview_left_row_activated }
148
# Connect the signals to the handlers
149
self.toplevel.signal_autoconnect(dic)
121
151
# Apply window size and position
122
152
width = self.pref.get_preference('window_width', 'int')
127
157
self.window.move(x, y)
128
158
# Apply paned position
129
159
pos = self.pref.get_preference('paned_position', 'int')
130
self.window.hpaned_main.set_position(pos)
160
self.hpaned_main.set_position(pos)
162
# Apply menu to the toolbutton
163
#menubutton = self.toplevel.get_widget('menutoolbutton_diff')
164
#menubutton.set_menu(handler.menu.toolbar_diff)
132
166
# Now we can show the window
133
167
self.window.show()
135
169
# Show drive selector if under Win32
136
170
if sys.platform == 'win32':
137
self.hbox_location.pack_start(self.combobox_drive, False, False, 0)
138
self.hbox_location.reorder_child(self.combobox_drive, 1)
171
self.vbox_main_right.pack_start(self.combobox_drive, False, True, 0)
172
self.vbox_main_right.reorder_child(self.combobox_drive, 0)
139
173
self.combobox_drive.show()
140
174
self.gen_hard_selector()
142
# Acceptable errors when loading files/folders in the treeviews
143
self.acceptable_errors = (errno.ENOENT, errno.ELOOP)
145
176
self._load_left()
147
178
# Apply menu state
148
self.window.mb_view_showhidden.set_active(self.pref.get_preference('dotted_files', 'bool'))
149
self.window.mb_view_showignored.set_active(self.pref.get_preference('ignored_files', 'bool'))
179
self.menuitem_view_show_hidden_files.set_active(self.pref.get_preference('dotted_files', 'bool'))
151
# We're starting local
153
self.remote_branch = None
154
self.remote_path = None
155
self.remote_revision = None
157
181
self.set_path(os.getcwd())
158
182
self._load_right()
160
self._just_started = False
162
def set_path(self, path, force_remote=False):
184
def set_path(self, path):
163
186
self.notbranch = False
166
# Forcing remote mode (reading data from inventory)
167
self._show_stock_image(gtk.STOCK_DISCONNECT)
169
br = Branch.open_containing(path)[0]
170
except bzrerrors.NotBranchError:
171
self._show_stock_image(gtk.STOCK_DIALOG_ERROR)
172
self.check_history.set_active(False)
173
self.check_history.set_sensitive(False)
175
except bzrerrors.UnsupportedProtocol:
176
self._show_stock_image(gtk.STOCK_DIALOG_ERROR)
177
self.check_history.set_active(False)
178
self.check_history.set_sensitive(False)
181
self._show_stock_image(gtk.STOCK_CONNECT)
186
self.remote_branch, self.remote_path = Branch.open_containing(path)
188
if self.remote_revision is None:
189
self.remote_revision = self.remote_branch.last_revision()
191
self.remote_entries = self.remote_branch.repository.get_inventory(self.remote_revision).entries()
193
if len(self.remote_path) == 0:
194
self.remote_parent = self.remote_branch.repository.get_inventory(self.remote_branch.last_revision()).iter_entries_by_dir().next()[1].file_id
196
for (name, type) in self.remote_entries:
197
if name == self.remote_path:
198
self.remote_parent = type.file_id
201
if not path.endswith('/'):
204
if self.remote_branch.base == path:
205
self.button_location_up.set_sensitive(False)
207
self.button_location_up.set_sensitive(True)
209
if os.path.isdir(path):
210
self.image_location_error.destroy()
215
self.wt, self.wtpath = WorkingTree.open_containing(path)
216
except (bzrerrors.NotBranchError, bzrerrors.NoWorkingTree):
217
self.notbranch = True
219
# If we're in the root, we cannot go up anymore
220
if sys.platform == 'win32':
221
drive, tail = os.path.splitdrive(path)
222
if tail in ('', '/', '\\'):
223
self.button_location_up.set_sensitive(False)
225
self.button_location_up.set_sensitive(True)
228
self.button_location_up.set_sensitive(False)
230
self.button_location_up.set_sensitive(True)
231
elif not os.path.isfile(path):
232
# Doesn't seem to be a file nor a directory, trying to open a
234
self._show_stock_image(gtk.STOCK_DISCONNECT)
236
br = Branch.open_containing(path)[0]
237
except bzrerrors.NotBranchError:
238
self._show_stock_image(gtk.STOCK_DIALOG_ERROR)
239
self.check_history.set_active(False)
240
self.check_history.set_sensitive(False)
242
except bzrerrors.UnsupportedProtocol:
243
self._show_stock_image(gtk.STOCK_DIALOG_ERROR)
244
self.check_history.set_active(False)
245
self.check_history.set_sensitive(False)
248
self._show_stock_image(gtk.STOCK_CONNECT)
253
self.remote_branch, self.remote_path = Branch.open_containing(path)
255
if self.remote_revision is None:
256
self.remote_revision = self.remote_branch.last_revision()
258
self.remote_entries = self.remote_branch.repository.get_inventory(self.remote_revision).entries()
260
if len(self.remote_path) == 0:
261
self.remote_parent = self.remote_branch.repository.get_inventory(self.remote_branch.last_revision()).iter_entries_by_dir().next()[1].file_id
263
for (name, type) in self.remote_entries:
264
if name == self.remote_path:
265
self.remote_parent = type.file_id
268
if not path.endswith('/'):
271
if self.remote_branch.base == path:
272
self.button_location_up.set_sensitive(False)
274
self.button_location_up.set_sensitive(True)
277
self.check_history.set_active(False)
278
self.check_history.set_sensitive(False)
280
self.check_history.set_sensitive(True)
282
self.window.statusbar.push(self.context_id, path)
283
self.entry_location.set_text(path)
188
self.wt, self.wtpath = WorkingTree.open_containing(self.path)
189
except errors.NotBranchError:
190
self.notbranch = True
287
192
def get_path(self):
292
if len(self.remote_path) > 0:
293
return self.remote_branch.base + self.remote_path + '/'
295
return self.remote_branch.base
297
195
def on_about_activate(self, widget):
196
from dialog import about
300
def on_button_history_browse_clicked(self, widget):
301
""" Browse for revision button handler. """
303
br = self.remote_branch
307
revb = RevisionBrowser(br, self.window)
308
response = revb.run()
309
if response != gtk.RESPONSE_NONE:
312
if response == gtk.RESPONSE_OK:
313
if revb.selected_revno is not None:
314
self.entry_history.set_text(revb.selected_revno)
315
self.on_entry_history_revno_activate()
319
def on_button_location_jump_clicked(self, widget):
320
""" Location Jump button handler. """
321
location = self.entry_location.get_text()
323
if self.set_path(location):
326
def on_button_location_up_clicked(self, widget):
327
""" Location Up button handler. """
330
self.set_path(os.path.split(self.get_path())[0])
334
newpath = delim.join(self.get_path().split(delim)[:-2])
336
self.set_path(newpath)
340
def on_checkbutton_history_toggled(self, widget):
341
""" History Mode toggle handler. """
342
if self.check_history.get_active():
343
# History Mode activated
344
self.entry_history.set_sensitive(True)
345
self.button_history.set_sensitive(True)
346
if self.entry_history.get_text() != "":
347
self.on_entry_history_revno_activate()
349
# History Mode deactivated
350
self.entry_history.set_sensitive(False)
351
self.button_history.set_sensitive(False)
353
# Return right window to normal view by acting like we jump to it
354
self.on_button_location_jump_clicked(widget)
357
def on_entry_history_revno_activate(self, widget=None):
358
""" Key pressed handler for the history entry. """
359
path = self.get_path()
362
self.remote_branch = self.wt.branch
364
revno = int(self.entry_history.get_text())
365
self.remote_revision = self.remote_branch.get_rev_id(revno)
366
if self.set_path(path, True):
369
199
def on_menuitem_add_files_activate(self, widget):
370
200
""" Add file(s)... menu handler. """
371
from bzrlib.plugins.gtk.olive.add import AddDialog
372
add = AddDialog(self.wt, self.wtpath, self.get_selected_right(), self.window)
375
if response == gtk.RESPONSE_OK:
201
from add import OliveAdd
202
add = OliveAdd(self.wt, self.wtpath, self.get_selected_right())
378
205
def on_menuitem_branch_get_activate(self, widget):
379
206
""" Branch/Get... menu handler. """
380
from bzrlib.plugins.gtk.branch import BranchDialog
383
branch = BranchDialog(os.getcwd(), self.window, self.remote_branch.base)
385
branch = BranchDialog(self.get_path(), self.window)
386
response = branch.run()
387
if response != gtk.RESPONSE_NONE:
390
if response == gtk.RESPONSE_OK:
207
from branch import BranchDialog
208
branch = BranchDialog(self.get_path())
395
211
def on_menuitem_branch_checkout_activate(self, widget):
396
212
""" Branch/Checkout... menu handler. """
397
from bzrlib.plugins.gtk.checkout import CheckoutDialog
400
checkout = CheckoutDialog(os.getcwd(), self.window, self.remote_branch.base)
402
checkout = CheckoutDialog(self.get_path(), self.window)
403
response = checkout.run()
404
if response != gtk.RESPONSE_NONE:
407
if response == gtk.RESPONSE_OK:
213
from checkout import OliveCheckout
214
checkout = OliveCheckout(self.get_path())
413
217
def on_menuitem_branch_commit_activate(self, widget):
414
218
""" Branch/Commit... menu handler. """
415
selected = self.get_selected_right()
417
selected = os.path.join(self.wtpath, selected)
418
commit = CommitDialog(wt=self.wt,
422
response = commit.run()
423
if response != gtk.RESPONSE_NONE:
426
if response == gtk.RESPONSE_OK:
431
def on_menuitem_branch_conflicts_activate(self, widget):
432
""" Branch/Conflicts... menu handler. """
433
conflicts = ConflictsDialog(self.wt, self.window)
434
response = conflicts.run()
435
if response != gtk.RESPONSE_NONE:
438
def on_menuitem_branch_merge_activate(self, widget):
439
""" Branch/Merge... menu handler. """
440
from bzrlib.plugins.gtk.merge import MergeDialog
442
if self.check_for_changes():
443
error_dialog(_i18n('There are local changes in the branch'),
444
_i18n('Please commit or revert the changes before merging.'))
446
parent_branch_path = self.wt.branch.get_parent()
447
merge = MergeDialog(self.wt, self.wtpath, parent_branch_path, self.window)
448
response = merge.run()
450
if response == gtk.RESPONSE_OK:
219
from commit import CommitDialog
220
commit = CommitDialog(self.wt, self.wtpath)
454
223
def on_menuitem_branch_missing_revisions_activate(self, widget):
455
224
""" Branch/Missing revisions menu handler. """
457
from bzrlib.missing import find_unmerged, iter_log_revisions
459
225
local_branch = self.wt.branch
460
parent_branch_path = local_branch.get_parent()
461
if parent_branch_path is None:
462
error_dialog(_i18n('Parent location is unknown'),
463
_i18n('Cannot determine missing revisions if no parent location is known.'))
227
other_branch = local_branch.get_parent()
228
if other_branch is None:
229
error_dialog(_('Parent location is unknown'),
230
_('Cannot determine missing revisions if no parent location is known.'))
466
parent_branch = Branch.open(parent_branch_path)
468
if parent_branch.base == local_branch.base:
469
parent_branch = local_branch
471
local_extra, remote_extra = find_unmerged(local_branch,parent_branch)
473
if local_extra or remote_extra:
475
## def log_revision_one_line_text(log_revision):
476
## """ Generates one line description of log_revison ended with end of line."""
477
## revision = log_revision.rev
478
## txt = "- %s (%s)\n" % (revision.get_summary(), revision.committer, )
479
## txt = txt.replace("<"," ") # Seems < > chars are expected to be xml tags ...
480
## txt = txt.replace(">"," ")
485
dlg_txt += _i18n('%d local extra revision(s). \n') % (len(local_extra),)
486
## NOTE: We do not want such ugly info about missing revisions
487
## Revision Browser should be used there
488
## max_revisions = 10
489
## for log_revision in iter_log_revisions(local_extra, local_branch.repository, verbose=1):
490
## dlg_txt += log_revision_one_line_text(log_revision)
491
## if max_revisions <= 0:
492
## dlg_txt += _i18n("more ... \n")
494
## max_revisions -= 1
497
dlg_txt += _i18n('%d local missing revision(s).\n') % (len(remote_extra),)
498
## max_revisions = 10
499
## for log_revision in iter_log_revisions(remote_extra, parent_branch.repository, verbose=1):
500
## dlg_txt += log_revision_one_line_text(log_revision)
501
## if max_revisions <= 0:
502
## dlg_txt += _i18n("more ... \n")
504
## max_revisions -= 1
506
info_dialog(_i18n('There are missing revisions'),
233
remote_branch = Branch.open(other_branch)
235
if remote_branch.base == local_branch.base:
236
remote_branch = local_branch
238
ret = len(local_branch.missing_revisions(remote_branch))
241
info_dialog(_('There are missing revisions'),
242
_('%d revision(s) missing.') % ret)
509
info_dialog(_i18n('Local branch up to date'),
510
_i18n('There are no missing revisions.'))
244
info_dialog(_('Local branch up to date'),
245
_('There are no missing revisions.'))
513
247
def on_menuitem_branch_pull_activate(self, widget):
514
248
""" Branch/Pull menu handler. """
515
249
branch_to = self.wt.branch
517
251
location = branch_to.get_parent()
518
252
if location is None:
519
error_dialog(_i18n('Parent location is unknown'),
520
_i18n('Pulling is not possible until there is a parent location.'))
253
error_dialog(_('Parent location is unknown'),
254
_('Pulling is not possible until there is a parent location.'))
523
branch_from = Branch.open(location)
258
branch_from = Branch.open(location)
259
except errors.NotBranchError:
260
error_dialog(_('Directory is not a branch'),
261
_('You can perform this action only in a branch.'))
525
263
if branch_to.get_parent() is None:
526
264
branch_to.set_parent(branch_from.base)
528
ret = branch_to.pull(branch_from)
530
info_dialog(_i18n('Pull successful'), _i18n('%d revision(s) pulled.') % ret)
533
def on_menuitem_branch_update_activate(self, widget):
534
""" Brranch/checkout update menu handler. """
536
ret = self.wt.update()
537
conflicts = self.wt.conflicts()
539
info_dialog(_i18n('Update successful but conflicts generated'), _i18n('Number of conflicts generated: %d.') % (len(conflicts),) )
541
info_dialog(_i18n('Update successful'), _i18n('No conflicts generated.') )
266
#old_rh = branch_to.revision_history()
267
#if tree_to is not None:
268
# tree_to.pull(branch_from)
270
# branch_to.pull(branch_from)
271
branch_to.pull(branch_from)
273
# TODO: get the number of pulled revisions
276
info_dialog(_('Pull successful'), _('%d revision(s) pulled.') % ret)
543
278
def on_menuitem_branch_push_activate(self, widget):
544
279
""" Branch/Push... menu handler. """
545
push = PushDialog(repository=None,revid=None,branch=self.wt.branch, parent=self.window)
546
response = push.run()
547
if response != gtk.RESPONSE_NONE:
551
def on_menuitem_branch_revert_activate(self, widget):
552
""" Branch/Revert all changes menu handler. """
553
ret = self.wt.revert(None)
555
warning_dialog(_i18n('Conflicts detected'),
556
_i18n('Please have a look at the working tree before continuing.'))
558
info_dialog(_i18n('Revert successful'),
559
_i18n('All files reverted to last revision.'))
280
from push import OlivePush
281
push = OlivePush(self.wt.branch)
562
284
def on_menuitem_branch_status_activate(self, widget):
563
285
""" Branch/Status... menu handler. """
564
from bzrlib.plugins.gtk.status import StatusDialog
565
status = StatusDialog(self.wt, self.wtpath)
566
response = status.run()
567
if response != gtk.RESPONSE_NONE:
286
from status import OliveStatus
287
status = OliveStatus(self.wt, self.wtpath)
570
290
def on_menuitem_branch_initialize_activate(self, widget):
571
291
""" Initialize current directory. """
572
init = InitDialog(self.path, self.window)
573
response = init.run()
574
if response != gtk.RESPONSE_NONE:
577
if response == gtk.RESPONSE_OK:
582
def on_menuitem_branch_tags_activate(self, widget):
583
""" Branch/Tags... menu handler. """
584
from bzrlib.plugins.gtk.tags import TagsWindow
586
window = TagsWindow(self.wt.branch, self.window)
588
window = TagsWindow(self.remote_branch, self.window)
591
def on_menuitem_file_annotate_activate(self, widget):
592
""" File/Annotate... menu handler. """
593
if self.get_selected_right() is None:
594
error_dialog(_i18n('No file was selected'),
595
_i18n('Please select a file from the list.'))
598
branch = self.wt.branch
599
file_id = self.wt.path2id(self.wt.relpath(os.path.join(self.path, self.get_selected_right())))
601
window = GAnnotateWindow(all=False, plain=False, parent=self.window)
602
window.set_title(os.path.join(self.path, self.get_selected_right()) + " - Annotate")
603
config = GAnnotateConfig(window)
292
import bzrlib.bzrdir as bzrdir
607
window.annotate(self.wt, branch, file_id)
611
def on_menuitem_file_bookmark_activate(self, widget):
612
""" File/Bookmark current directory menu handler. """
613
if self.pref.add_bookmark(self.path):
614
info_dialog(_i18n('Bookmark successfully added'),
615
_i18n('The current directory was bookmarked. You can reach\nit by selecting it from the left panel.'))
295
if not os.path.exists(self.path):
299
existing_bzrdir = bzrdir.BzrDir.open(self.path)
300
except errors.NotBranchError:
301
bzrdir.BzrDir.create_branch_convenience(self.path)
303
if existing_bzrdir.has_branch():
304
if existing_bzrdir.has_workingtree():
305
raise errors.AlreadyBranchError(self.path)
307
raise errors.BranchExistsWithoutWorkingTree(self.path)
309
existing_bzrdir.create_branch()
310
existing_bzrdir.create_workingtree()
311
except errors.AlreadyBranchError, errmsg:
312
error_dialog(_('Directory is already a branch'),
313
_('The current directory (%s) is already a branch.\nYou can start using it, or initialize another directory.') % errmsg)
314
except errors.BranchExistsWithoutWorkingTree, errmsg:
315
error_dialog(_('Branch without a working tree'),
316
_('The current directory (%s)\nis a branch without a working tree.') % errmsg)
618
warning_dialog(_i18n('Location already bookmarked'),
619
_i18n('The current directory is already bookmarked.\nSee the left panel for reference.'))
318
info_dialog(_('Initialize successful'),
319
_('Directory successfully initialized.'))
623
322
def on_menuitem_file_make_directory_activate(self, widget):
624
323
""" File/Make directory... menu handler. """
625
from bzrlib.plugins.gtk.olive.mkdir import MkdirDialog
626
mkdir = MkdirDialog(self.wt, self.wtpath, self.window)
627
response = mkdir.run()
629
if response == gtk.RESPONSE_OK:
324
from mkdir import OliveMkdir
325
mkdir = OliveMkdir(self.wt, self.wtpath)
632
328
def on_menuitem_file_move_activate(self, widget):
633
329
""" File/Move... menu handler. """
634
from bzrlib.plugins.gtk.olive.move import MoveDialog
635
move = MoveDialog(self.wt, self.wtpath, self.get_selected_right(), self.window)
636
response = move.run()
638
if response == gtk.RESPONSE_OK:
330
from move import OliveMove
331
move = OliveMove(self.wt, self.wtpath, self.get_selected_right())
641
334
def on_menuitem_file_rename_activate(self, widget):
642
335
""" File/Rename... menu handler. """
643
from bzrlib.plugins.gtk.olive.rename import RenameDialog
644
rename = RenameDialog(self.wt, self.wtpath, self.get_selected_right(), self.window)
645
response = rename.run()
647
if response == gtk.RESPONSE_OK:
336
from rename import OliveRename
337
rename = OliveRename(self.wt, self.wtpath, self.get_selected_right())
650
340
def on_menuitem_remove_file_activate(self, widget):
651
341
""" Remove (unversion) selected file. """
652
from bzrlib.plugins.gtk.olive.remove import RemoveDialog
653
remove = RemoveDialog(self.wt, self.wtpath,
654
selected=self.get_selected_right(),
656
response = remove.run()
658
if response != gtk.RESPONSE_NONE:
661
if response == gtk.RESPONSE_OK:
662
self.set_path(self.path)
342
from remove import OliveRemove
343
remove = OliveRemove(self.wt, self.wtpath, self.get_selected_right())
667
346
def on_menuitem_stats_diff_activate(self, widget):
668
347
""" Statistics/Differences... menu handler. """
669
window = DiffWindow(parent=self.window)
348
from bzrlib.plugins.gtk.viz.diffwin import DiffWindow
349
window = DiffWindow()
670
350
parent_tree = self.wt.branch.repository.revision_tree(self.wt.branch.last_revision())
671
351
window.set_diff(self.wt.branch.nick, self.wt, parent_tree)
674
354
def on_menuitem_stats_infos_activate(self, widget):
675
355
""" Statistics/Informations... menu handler. """
676
from bzrlib.plugins.gtk.olive.info import InfoDialog
678
info = InfoDialog(self.remote_branch)
680
info = InfoDialog(self.wt.branch)
356
from info import OliveInfo
357
info = OliveInfo(self.wt)
683
360
def on_menuitem_stats_log_activate(self, widget):
684
361
""" Statistics/Log... menu handler. """
687
branch = self.wt.branch
689
branch = self.remote_branch
691
window = branchwin.BranchWindow(branch, [branch.last_revision()], None,
362
from bzrlib.plugins.gtk.viz.branchwin import BranchWindow
363
window = BranchWindow()
364
window.set_branch(self.wt.branch, self.wt.branch.last_revision(), None)
695
367
def on_menuitem_view_refresh_activate(self, widget):
749
397
if newdir == None:
752
if self.set_path(newdir):
400
self.set_path(newdir)
755
403
def on_treeview_right_button_press_event(self, widget, event):
756
""" Occurs when somebody clicks in the file list. """
757
treepathpos = widget.get_path_at_pos(int(event.x), int(event.y))
758
if event.button == 1:
759
if treepathpos is None and widget.get_selection is not None:
760
treeselection = widget.get_selection()
761
treeselection.unselect_all()
762
elif event.button == 3:
763
treeselection = widget.get_selection()
764
if treepathpos is not None:
765
treeselection.select_path(treepathpos[0])
767
if treeselection is not None:
768
treeselection.unselect_all()
404
""" Occurs when somebody right-clicks in the file list. """
405
if event.button == 3:
770
407
from menu import OliveMenu
771
menu = OliveMenu(path=self.get_path(),
772
selected=self.get_selected_right(),
408
menu = OliveMenu(self.get_path(), self.get_selected_right())
774
409
# get the menu items
775
m_open = menu.ui.get_widget('/context_right/open')
776
410
m_add = menu.ui.get_widget('/context_right/add')
777
411
m_remove = menu.ui.get_widget('/context_right/remove')
778
m_remove_and_delete = menu.ui.get_widget('/context_right/remove_and_delete')
779
m_rename = menu.ui.get_widget('/context_right/rename')
780
m_revert = menu.ui.get_widget('/context_right/revert')
781
412
m_commit = menu.ui.get_widget('/context_right/commit')
782
m_annotate = menu.ui.get_widget('/context_right/annotate')
783
413
m_diff = menu.ui.get_widget('/context_right/diff')
784
414
# check if we're in a branch
786
416
from bzrlib.branch import Branch
787
417
Branch.open_containing(self.get_path())
789
m_open.set_sensitive(False)
790
m_add.set_sensitive(False)
791
m_remove.set_sensitive(False)
792
m_remove_and_delete.set_sensitive(False)
793
m_rename.set_sensitive(False)
794
m_revert.set_sensitive(False)
795
m_commit.set_sensitive(False)
796
m_annotate.set_sensitive(False)
797
m_diff.set_sensitive(False)
799
if treepathpos is None:
800
m_open.set_sensitive(False)
801
m_add.set_sensitive(False)
802
m_remove.set_sensitive(False)
803
m_remove_and_delete.set_sensitive(False)
804
m_rename.set_sensitive(False)
805
m_annotate.set_sensitive(False)
806
m_diff.set_sensitive(False)
807
m_revert.set_sensitive(False)
809
m_open.set_sensitive(True)
810
m_add.set_sensitive(True)
811
m_remove.set_sensitive(True)
812
m_remove_and_delete.set_sensitive(True)
813
m_rename.set_sensitive(True)
814
m_annotate.set_sensitive(True)
815
m_diff.set_sensitive(True)
816
m_revert.set_sensitive(True)
817
m_commit.set_sensitive(True)
818
except bzrerrors.NotBranchError:
819
if treepathpos is None:
820
m_open.set_sensitive(False)
822
m_open.set_sensitive(True)
418
m_add.set_sensitive(True)
419
m_remove.set_sensitive(True)
420
m_commit.set_sensitive(True)
421
m_diff.set_sensitive(True)
422
except errors.NotBranchError:
823
423
m_add.set_sensitive(False)
824
424
m_remove.set_sensitive(False)
825
m_remove_and_delete.set_sensitive(False)
826
m_rename.set_sensitive(False)
827
m_revert.set_sensitive(False)
828
425
m_commit.set_sensitive(False)
829
m_annotate.set_sensitive(False)
830
426
m_diff.set_sensitive(False)
833
menu.right_context_menu().popup(None, None, None, 0,
836
menu.remote_context_menu().popup(None, None, None, 0,
427
menu.right_context_menu().popup(None, None, None, 0,
839
430
def on_treeview_right_row_activated(self, treeview, path, view_column):
840
431
""" Occurs when somebody double-clicks or enters an item in the
842
435
from launch import launch
844
437
newdir = self.get_selected_right()
849
self.set_path(os.path.split(self.get_path())[0])
440
self.set_path(os.path.split(self.get_path())[0])
442
fullpath = self.get_path() + os.sep + newdir
443
if os.path.isdir(fullpath):
444
# selected item is an existant directory
445
self.set_path(fullpath)
851
fullpath = os.path.join(self.get_path(), newdir)
852
if os.path.isdir(fullpath):
853
# selected item is an existant directory
854
self.set_path(fullpath)
859
if self._is_remote_dir(self.get_path() + newdir):
860
self.set_path(self.get_path() + newdir)
862
449
self.refresh_right()
864
451
def on_window_main_delete_event(self, widget, event=None):
865
452
""" Do some stuff before exiting. """
866
width, height = self.window.get_size()
453
width, height = self.window_main.get_size()
867
454
self.pref.set_preference('window_width', width)
868
455
self.pref.set_preference('window_height', height)
869
x, y = self.window.get_position()
456
x, y = self.window_main.get_position()
870
457
self.pref.set_preference('window_x', x)
871
458
self.pref.set_preference('window_y', y)
872
459
self.pref.set_preference('paned_position',
873
self.window.hpaned_main.get_position())
460
self.hpaned_main.get_position())
875
462
self.pref.write()
876
self.window.destroy()
463
self.window_main.destroy()
878
465
def _load_left(self):
879
466
""" Load data into the left panel. (Bookmarks) """
940
518
delta = self.wt.changes_from(tree2, want_unchanged=True)
942
520
# Add'em to the ListStore
945
statinfo = os.stat(self.path + os.sep + item)
947
if e.errno in self.acceptable_errors:
951
liststore.append([ gtk.STOCK_DIRECTORY,
959
self._format_date(statinfo.st_mtime),
522
liststore.append([gtk.STOCK_DIRECTORY, item, ''])
961
523
for item in files:
962
524
status = 'unknown'
964
525
if not self.notbranch:
965
526
filename = self.wt.relpath(self.path + os.sep + item)
970
for rpath, rpathnew, id, kind, text_modified, meta_modified in delta.renamed:
971
if rpathnew == filename:
974
for rpath, id, kind in delta.added:
975
if rpath == filename:
978
for rpath, id, kind in delta.removed:
979
if rpath == filename:
982
for rpath, id, kind, text_modified, meta_modified in delta.modified:
983
if rpath == filename:
986
for rpath, id, kind in delta.unchanged:
987
if rpath == filename:
990
for rpath, file_class, kind, id, entry in self.wt.list_files():
991
if rpath == filename and file_class == 'I':
528
for rpath, rpathnew, id, kind, text_modified, meta_modified in delta.renamed:
529
if rpathnew == filename:
531
for rpath, id, kind in delta.added:
532
if rpath == filename:
534
for rpath, id, kind in delta.removed:
535
if rpath == filename:
537
for rpath, id, kind, text_modified, meta_modified in delta.modified:
538
if rpath == filename:
540
for rpath, id, kind in delta.unchanged:
541
if rpath == filename:
545
# status = fileops.status(path + os.sep + item)
546
#except errors.PermissionDenied:
996
549
if status == 'renamed':
997
st = _i18n('renamed')
998
551
elif status == 'removed':
999
st = _i18n('removed')
1000
553
elif status == 'added':
1002
555
elif status == 'modified':
1003
st = _i18n('modified')
1004
557
elif status == 'unchanged':
1005
st = _i18n('unchanged')
1006
elif status == 'ignored':
1007
st = _i18n('ignored')
1009
st = _i18n('unknown')
1012
statinfo = os.stat(self.path + os.sep + item)
1014
if e.errno in self.acceptable_errors:
1018
liststore.append([gtk.STOCK_FILE,
1023
str(statinfo.st_size), # NOTE: if int used there it will fail for large files (size expressed as long int)
1024
self._format_size(statinfo.st_size),
1026
self._format_date(statinfo.st_mtime),
561
liststore.append([gtk.STOCK_FILE, item, st])
1029
563
# Create the columns and add them to the TreeView
1030
564
self.treeview_right.set_model(liststore)
1031
self._tvcolumn_filename = gtk.TreeViewColumn(_i18n('Filename'))
1032
self._tvcolumn_status = gtk.TreeViewColumn(_i18n('Status'))
1033
self._tvcolumn_size = gtk.TreeViewColumn(_i18n('Size'))
1034
self._tvcolumn_mtime = gtk.TreeViewColumn(_i18n('Last modified'))
1035
self.treeview_right.append_column(self._tvcolumn_filename)
1036
self.treeview_right.append_column(self._tvcolumn_status)
1037
self.treeview_right.append_column(self._tvcolumn_size)
1038
self.treeview_right.append_column(self._tvcolumn_mtime)
565
tvcolumn_filename = gtk.TreeViewColumn(_('Filename'))
566
tvcolumn_status = gtk.TreeViewColumn(_('Status'))
567
self.treeview_right.append_column(tvcolumn_filename)
568
self.treeview_right.append_column(tvcolumn_status)
1040
570
# Set up the cells
1041
571
cellpb = gtk.CellRendererPixbuf()
1042
572
cell = gtk.CellRendererText()
1043
self._tvcolumn_filename.pack_start(cellpb, False)
1044
self._tvcolumn_filename.pack_start(cell, True)
1045
self._tvcolumn_filename.set_attributes(cellpb, stock_id=0)
1046
self._tvcolumn_filename.add_attribute(cell, 'text', 2)
1047
self._tvcolumn_status.pack_start(cell, True)
1048
self._tvcolumn_status.add_attribute(cell, 'text', 3)
1049
self._tvcolumn_size.pack_start(cell, True)
1050
self._tvcolumn_size.add_attribute(cell, 'text', 6)
1051
self._tvcolumn_mtime.pack_start(cell, True)
1052
self._tvcolumn_mtime.add_attribute(cell, 'text', 8)
1054
# Set up the properties of the TreeView
1055
self.treeview_right.set_headers_visible(True)
1056
self.treeview_right.set_headers_clickable(True)
1057
self.treeview_right.set_search_column(1)
1058
self._tvcolumn_filename.set_resizable(True)
1059
self._tvcolumn_status.set_resizable(True)
1060
self._tvcolumn_size.set_resizable(True)
1061
self._tvcolumn_mtime.set_resizable(True)
1063
liststore.set_sort_func(13, self._sort_filelist_callback, None)
1064
liststore.set_sort_column_id(13, gtk.SORT_ASCENDING)
1065
self._tvcolumn_filename.set_sort_column_id(13)
1066
self._tvcolumn_status.set_sort_column_id(3)
1067
self._tvcolumn_size.set_sort_column_id(5)
1068
self._tvcolumn_mtime.set_sort_column_id(7)
573
tvcolumn_filename.pack_start(cellpb, False)
574
tvcolumn_filename.pack_start(cell, True)
575
tvcolumn_filename.set_attributes(cellpb, stock_id=0)
576
tvcolumn_filename.add_attribute(cell, 'text', 1)
577
tvcolumn_status.pack_start(cell, True)
578
tvcolumn_status.add_attribute(cell, 'text', 2)
1070
580
# Set sensitivity
1071
581
self.set_sensitivity()
1073
def get_selected_fileid(self):
1074
""" Get the file_id of the selected file. """
1075
treeselection = self.treeview_right.get_selection()
1076
(model, iter) = treeselection.get_selected()
1081
return model.get_value(iter, 9)
1083
583
def get_selected_right(self):
1084
584
""" Get the selected filename. """
1085
585
treeselection = self.treeview_right.get_selection()
1146
658
def refresh_right(self, path=None):
1147
659
""" Refresh the file list. """
1150
from bzrlib.workingtree import WorkingTree
1153
path = self.get_path()
1155
# A workaround for double-clicking Bookmarks
1156
if not os.path.exists(path):
1159
# Get ListStore and clear it
1160
liststore = self.treeview_right.get_model()
1163
# Show Status column
1164
self._tvcolumn_status.set_visible(True)
1169
# Fill the appropriate lists
1170
dotted_files = self.pref.get_preference('dotted_files', 'bool')
1171
ignored_files = self.pref.get_preference('ignored_files', 'bool')
1173
for item in os.listdir(path):
1174
if not dotted_files and item[0] == '.':
1176
if os.path.isdir(path + os.sep + item):
1181
# Try to open the working tree
1184
tree1 = WorkingTree.open_containing(path)[0]
1185
except (bzrerrors.NotBranchError, bzrerrors.NoWorkingTree):
660
from bzrlib.workingtree import WorkingTree
663
path = self.get_path()
665
# A workaround for double-clicking Bookmarks
666
if not os.path.exists(path):
669
# Get ListStore and clear it
670
liststore = self.treeview_right.get_model()
676
# Fill the appropriate lists
677
dotted_files = self.pref.get_preference('dotted_files', 'bool')
678
for item in os.listdir(path):
679
if not dotted_files and item[0] == '.':
681
if os.path.isdir(path + os.sep + item):
690
# Try to open the working tree
693
tree1 = WorkingTree.open_containing(path)[0]
694
except errors.NotBranchError:
696
except errors.PermissionDenied:
697
print "DEBUG: permission denied."
700
branch = tree1.branch
701
tree2 = tree1.branch.repository.revision_tree(branch.last_revision())
703
delta = tree1.changes_from(tree2, want_unchanged=True)
705
# Add'em to the ListStore
707
liststore.append([gtk.STOCK_DIRECTORY, item, ''])
1188
710
if not notbranch:
1189
branch = tree1.branch
1190
tree2 = tree1.branch.repository.revision_tree(branch.last_revision())
1192
delta = tree1.changes_from(tree2, want_unchanged=True)
1194
# Add'em to the ListStore
1197
statinfo = os.stat(self.path + os.sep + item)
1199
if e.errno in self.acceptable_errors:
1203
liststore.append([gtk.STOCK_DIRECTORY,
1211
self._format_date(statinfo.st_mtime),
1217
filename = tree1.relpath(path + os.sep + item)
1222
for rpath, rpathnew, id, kind, text_modified, meta_modified in delta.renamed:
1223
if rpathnew == filename:
1226
for rpath, id, kind in delta.added:
1227
if rpath == filename:
1230
for rpath, id, kind in delta.removed:
1231
if rpath == filename:
1234
for rpath, id, kind, text_modified, meta_modified in delta.modified:
1235
if rpath == filename:
1238
for rpath, id, kind in delta.unchanged:
1239
if rpath == filename:
1240
status = 'unchanged'
1242
for rpath, file_class, kind, id, entry in self.wt.list_files():
1243
if rpath == filename and file_class == 'I':
1248
if status == 'renamed':
1249
st = _i18n('renamed')
1250
elif status == 'removed':
1251
st = _i18n('removed')
1252
elif status == 'added':
1254
elif status == 'modified':
1255
st = _i18n('modified')
1256
elif status == 'unchanged':
1257
st = _i18n('unchanged')
1258
elif status == 'ignored':
1259
st = _i18n('ignored')
1260
if not ignored_files:
1263
st = _i18n('unknown')
1266
statinfo = os.stat(self.path + os.sep + item)
1268
if e.errno in self.acceptable_errors:
1272
liststore.append([gtk.STOCK_FILE,
1277
str(statinfo.st_size),
1278
self._format_size(statinfo.st_size),
1280
self._format_date(statinfo.st_mtime),
1285
# Get ListStore and clear it
1286
liststore = self.treeview_right.get_model()
1289
# Hide Status column
1290
self._tvcolumn_status.set_visible(False)
1295
self._show_stock_image(gtk.STOCK_REFRESH)
1297
for (name, type) in self.remote_entries:
1298
if type.kind == 'directory':
1300
elif type.kind == 'file':
1304
""" Cache based on revision history. """
1305
def __init__(self, history):
1306
self._history = history
1308
def _lookup_revision(self, revid):
1309
for r in self._history:
1310
if r.revision_id == revid:
1312
rev = repo.get_revision(revid)
1313
self._history.append(rev)
1316
repo = self.remote_branch.repository
1318
revhistory = self.remote_branch.revision_history()
1320
revs = repo.get_revisions(revhistory)
1321
cache = HistoryCache(revs)
1322
except bzrerrors.InvalidHttpResponse:
1323
# Fallback to dummy algorithm, because of LP: #115209
1324
cache = HistoryCache([])
1327
if item.parent_id == self.remote_parent:
1328
rev = cache._lookup_revision(item.revision)
1329
liststore.append([ gtk.STOCK_DIRECTORY,
1337
self._format_date(rev.timestamp),
1340
while gtk.events_pending():
1341
gtk.main_iteration()
1344
if item.parent_id == self.remote_parent:
1345
rev = cache._lookup_revision(item.revision)
1346
liststore.append([ gtk.STOCK_FILE,
1351
str(item.text_size),
1352
self._format_size(item.text_size),
1354
self._format_date(rev.timestamp),
1357
while gtk.events_pending():
1358
gtk.main_iteration()
1360
self.image_location_error.destroy()
1362
# Columns should auto-size
1363
self.treeview_right.columns_autosize()
711
filename = tree1.relpath(path + os.sep + item)
713
for rpath, rpathnew, id, kind, text_modified, meta_modified in delta.renamed:
714
if rpathnew == filename:
716
for rpath, id, kind in delta.added:
717
if rpath == filename:
719
for rpath, id, kind in delta.removed:
720
if rpath == filename:
722
for rpath, id, kind, text_modified, meta_modified in delta.modified:
723
if rpath == filename:
725
for rpath, id, kind in delta.unchanged:
726
if rpath == filename:
730
# status = fileops.status(path + os.sep + item)
731
#except errors.PermissionDenied:
734
if status == 'renamed':
736
elif status == 'removed':
738
elif status == 'added':
740
elif status == 'modified':
742
elif status == 'unchanged':
746
liststore.append([gtk.STOCK_FILE, item, st])
748
# Add the ListStore to the TreeView
749
self.treeview_right.set_model(liststore)
1365
751
# Set sensitivity
1366
752
self.set_sensitivity()