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_merge = self.toplevel.get_widget('menuitem_branch_merge')
94
self.menuitem_branch_commit = self.toplevel.get_widget('menuitem_branch_commit')
95
self.menuitem_branch_status = self.toplevel.get_widget('menuitem_branch_status')
96
self.menuitem_branch_missing = self.toplevel.get_widget('menuitem_branch_missing_revisions')
97
self.menuitem_stats = self.toplevel.get_widget('menuitem_stats')
98
self.menuitem_stats_diff = self.toplevel.get_widget('menuitem_stats_diff')
99
self.menuitem_stats_log = self.toplevel.get_widget('menuitem_stats_log')
100
# Get some toolbuttons
101
#self.menutoolbutton_diff = self.toplevel.get_widget('menutoolbutton_diff')
102
self.toolbutton_diff = self.toplevel.get_widget('toolbutton_diff')
103
self.toolbutton_log = self.toplevel.get_widget('toolbutton_log')
104
self.toolbutton_commit = self.toplevel.get_widget('toolbutton_commit')
105
self.toolbutton_pull = self.toplevel.get_widget('toolbutton_pull')
106
self.toolbutton_push = self.toplevel.get_widget('toolbutton_push')
103
107
# Get the drive selector
104
108
self.combobox_drive = gtk.combo_box_new_text()
105
109
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
111
self.vbox_main_right = self.toplevel.get_widget('vbox_main_right')
114
# Dictionary for signal_autoconnect
115
dic = { "on_window_main_destroy": gtk.main_quit,
116
"on_window_main_delete_event": self.on_window_main_delete_event,
117
"on_quit_activate": self.on_window_main_delete_event,
118
"on_about_activate": self.on_about_activate,
119
"on_menuitem_add_files_activate": self.on_menuitem_add_files_activate,
120
"on_menuitem_remove_file_activate": self.on_menuitem_remove_file_activate,
121
"on_menuitem_file_make_directory_activate": self.on_menuitem_file_make_directory_activate,
122
"on_menuitem_file_move_activate": self.on_menuitem_file_move_activate,
123
"on_menuitem_file_rename_activate": self.on_menuitem_file_rename_activate,
124
"on_menuitem_view_show_hidden_files_activate": self.on_menuitem_view_show_hidden_files_activate,
125
"on_menuitem_view_refresh_activate": self.on_menuitem_view_refresh_activate,
126
"on_menuitem_branch_initialize_activate": self.on_menuitem_branch_initialize_activate,
127
"on_menuitem_branch_get_activate": self.on_menuitem_branch_get_activate,
128
"on_menuitem_branch_checkout_activate": self.on_menuitem_branch_checkout_activate,
129
"on_menuitem_branch_merge_activate": self.on_menuitem_branch_merge_activate,
130
"on_menuitem_branch_commit_activate": self.on_menuitem_branch_commit_activate,
131
"on_menuitem_branch_push_activate": self.on_menuitem_branch_push_activate,
132
"on_menuitem_branch_pull_activate": self.on_menuitem_branch_pull_activate,
133
"on_menuitem_branch_status_activate": self.on_menuitem_branch_status_activate,
134
"on_menuitem_branch_missing_revisions_activate": self.on_menuitem_branch_missing_revisions_activate,
135
"on_menuitem_stats_diff_activate": self.on_menuitem_stats_diff_activate,
136
"on_menuitem_stats_log_activate": self.on_menuitem_stats_log_activate,
137
"on_menuitem_stats_infos_activate": self.on_menuitem_stats_infos_activate,
138
"on_toolbutton_refresh_clicked": self.on_menuitem_view_refresh_activate,
139
"on_toolbutton_log_clicked": self.on_menuitem_stats_log_activate,
140
#"on_menutoolbutton_diff_clicked": self.on_menuitem_stats_diff_activate,
141
"on_toolbutton_diff_clicked": self.on_menuitem_stats_diff_activate,
142
"on_toolbutton_commit_clicked": self.on_menuitem_branch_commit_activate,
143
"on_toolbutton_pull_clicked": self.on_menuitem_branch_pull_activate,
144
"on_toolbutton_push_clicked": self.on_menuitem_branch_push_activate,
145
"on_treeview_right_button_press_event": self.on_treeview_right_button_press_event,
146
"on_treeview_right_row_activated": self.on_treeview_right_row_activated,
147
"on_treeview_left_button_press_event": self.on_treeview_left_button_press_event,
148
"on_treeview_left_row_activated": self.on_treeview_left_row_activated }
150
# Connect the signals to the handlers
151
self.toplevel.signal_autoconnect(dic)
121
153
# Apply window size and position
122
154
width = self.pref.get_preference('window_width', 'int')
127
159
self.window.move(x, y)
128
160
# Apply paned position
129
161
pos = self.pref.get_preference('paned_position', 'int')
130
self.window.hpaned_main.set_position(pos)
162
self.hpaned_main.set_position(pos)
164
# Apply menu to the toolbutton
165
#menubutton = self.toplevel.get_widget('menutoolbutton_diff')
166
#menubutton.set_menu(handler.menu.toolbar_diff)
132
168
# Now we can show the window
133
169
self.window.show()
135
171
# Show drive selector if under Win32
136
172
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)
173
self.vbox_main_right.pack_start(self.combobox_drive, False, True, 0)
174
self.vbox_main_right.reorder_child(self.combobox_drive, 0)
139
175
self.combobox_drive.show()
140
176
self.gen_hard_selector()
142
# Acceptable errors when loading files/folders in the treeviews
143
self.acceptable_errors = (errno.ENOENT, errno.ELOOP)
145
178
self._load_left()
147
180
# 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'))
181
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
183
self.set_path(os.getcwd())
158
184
self._load_right()
160
self._just_started = False
162
def set_path(self, path, force_remote=False):
186
def set_path(self, path):
163
188
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)
190
self.wt, self.wtpath = WorkingTree.open_containing(self.path)
191
except errors.NotBranchError:
192
self.notbranch = True
287
194
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
197
def on_about_activate(self, widget):
198
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
201
def on_menuitem_add_files_activate(self, widget):
370
202
""" 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:
203
from add import OliveAdd
204
add = OliveAdd(self.wt, self.wtpath, self.get_selected_right())
378
207
def on_menuitem_branch_get_activate(self, widget):
379
208
""" 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:
209
from branch import BranchDialog
210
branch = BranchDialog(self.get_path())
395
213
def on_menuitem_branch_checkout_activate(self, widget):
396
214
""" 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:
215
from checkout import OliveCheckout
216
checkout = OliveCheckout(self.get_path())
413
219
def on_menuitem_branch_commit_activate(self, widget):
414
220
""" 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:
221
from commit import CommitDialog
222
commit = CommitDialog(self.wt, self.wtpath)
438
225
def on_menuitem_branch_merge_activate(self, widget):
439
226
""" 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:
227
from merge import MergeDialog
228
merge = MergeDialog(self.wt, self.wtpath)
454
231
def on_menuitem_branch_missing_revisions_activate(self, widget):
455
232
""" Branch/Missing revisions menu handler. """
457
from bzrlib.missing import find_unmerged, iter_log_revisions
459
233
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.'))
235
other_branch = local_branch.get_parent()
236
if other_branch is None:
237
error_dialog(_('Parent location is unknown'),
238
_('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'),
241
remote_branch = Branch.open(other_branch)
243
if remote_branch.base == local_branch.base:
244
remote_branch = local_branch
246
ret = len(local_branch.missing_revisions(remote_branch))
249
info_dialog(_('There are missing revisions'),
250
_('%d revision(s) missing.') % ret)
509
info_dialog(_i18n('Local branch up to date'),
510
_i18n('There are no missing revisions.'))
252
info_dialog(_('Local branch up to date'),
253
_('There are no missing revisions.'))
513
255
def on_menuitem_branch_pull_activate(self, widget):
514
256
""" Branch/Pull menu handler. """
515
257
branch_to = self.wt.branch
517
259
location = branch_to.get_parent()
518
260
if location is None:
519
error_dialog(_i18n('Parent location is unknown'),
520
_i18n('Pulling is not possible until there is a parent location.'))
261
error_dialog(_('Parent location is unknown'),
262
_('Pulling is not possible until there is a parent location.'))
523
branch_from = Branch.open(location)
266
branch_from = Branch.open(location)
267
except errors.NotBranchError:
268
error_dialog(_('Directory is not a branch'),
269
_('You can perform this action only in a branch.'))
525
271
if branch_to.get_parent() is None:
526
272
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.') )
274
#old_rh = branch_to.revision_history()
275
#if tree_to is not None:
276
# tree_to.pull(branch_from)
278
# branch_to.pull(branch_from)
279
branch_to.pull(branch_from)
281
# TODO: get the number of pulled revisions
284
info_dialog(_('Pull successful'), _('%d revision(s) pulled.') % ret)
543
286
def on_menuitem_branch_push_activate(self, widget):
544
287
""" 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.'))
288
from push import OlivePush
289
push = OlivePush(self.wt.branch)
562
292
def on_menuitem_branch_status_activate(self, widget):
563
293
""" 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:
294
from status import OliveStatus
295
status = OliveStatus(self.wt, self.wtpath)
570
298
def on_menuitem_branch_initialize_activate(self, widget):
571
299
""" 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)
300
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.'))
303
if not os.path.exists(self.path):
307
existing_bzrdir = bzrdir.BzrDir.open(self.path)
308
except errors.NotBranchError:
309
bzrdir.BzrDir.create_branch_convenience(self.path)
311
if existing_bzrdir.has_branch():
312
if existing_bzrdir.has_workingtree():
313
raise errors.AlreadyBranchError(self.path)
315
raise errors.BranchExistsWithoutWorkingTree(self.path)
317
existing_bzrdir.create_branch()
318
existing_bzrdir.create_workingtree()
319
except errors.AlreadyBranchError, errmsg:
320
error_dialog(_('Directory is already a branch'),
321
_('The current directory (%s) is already a branch.\nYou can start using it, or initialize another directory.') % errmsg)
322
except errors.BranchExistsWithoutWorkingTree, errmsg:
323
error_dialog(_('Branch without a working tree'),
324
_('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.'))
326
info_dialog(_('Initialize successful'),
327
_('Directory successfully initialized.'))
623
330
def on_menuitem_file_make_directory_activate(self, widget):
624
331
""" 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:
332
from mkdir import OliveMkdir
333
mkdir = OliveMkdir(self.wt, self.wtpath)
632
336
def on_menuitem_file_move_activate(self, widget):
633
337
""" 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:
338
from move import OliveMove
339
move = OliveMove(self.wt, self.wtpath, self.get_selected_right())
641
342
def on_menuitem_file_rename_activate(self, widget):
642
343
""" 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:
344
from rename import OliveRename
345
rename = OliveRename(self.wt, self.wtpath, self.get_selected_right())
650
348
def on_menuitem_remove_file_activate(self, widget):
651
349
""" 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)
350
from remove import OliveRemove
351
remove = OliveRemove(self.wt, self.wtpath, self.get_selected_right())
667
354
def on_menuitem_stats_diff_activate(self, widget):
668
355
""" Statistics/Differences... menu handler. """
669
window = DiffWindow(parent=self.window)
356
from bzrlib.plugins.gtk.viz.diffwin import DiffWindow
357
window = DiffWindow()
670
358
parent_tree = self.wt.branch.repository.revision_tree(self.wt.branch.last_revision())
671
359
window.set_diff(self.wt.branch.nick, self.wt, parent_tree)
674
362
def on_menuitem_stats_infos_activate(self, widget):
675
363
""" 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)
364
from info import OliveInfo
365
info = OliveInfo(self.wt)
683
368
def on_menuitem_stats_log_activate(self, widget):
684
369
""" Statistics/Log... menu handler. """
687
branch = self.wt.branch
689
branch = self.remote_branch
691
window = branchwin.BranchWindow(branch, [branch.last_revision()], None,
370
from bzrlib.plugins.gtk.viz.branchwin import BranchWindow
371
window = BranchWindow()
372
window.set_branch(self.wt.branch, self.wt.branch.last_revision(), None)
695
375
def on_menuitem_view_refresh_activate(self, widget):
749
405
if newdir == None:
752
if self.set_path(newdir):
408
self.set_path(newdir)
755
411
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()
412
""" Occurs when somebody right-clicks in the file list. """
413
if event.button == 3:
770
415
from menu import OliveMenu
771
menu = OliveMenu(path=self.get_path(),
772
selected=self.get_selected_right(),
416
menu = OliveMenu(self.get_path(), self.get_selected_right())
774
417
# get the menu items
775
m_open = menu.ui.get_widget('/context_right/open')
776
418
m_add = menu.ui.get_widget('/context_right/add')
777
419
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
420
m_commit = menu.ui.get_widget('/context_right/commit')
782
m_annotate = menu.ui.get_widget('/context_right/annotate')
783
421
m_diff = menu.ui.get_widget('/context_right/diff')
784
422
# check if we're in a branch
786
424
from bzrlib.branch import Branch
787
425
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)
426
m_add.set_sensitive(True)
427
m_remove.set_sensitive(True)
428
m_commit.set_sensitive(True)
429
m_diff.set_sensitive(True)
430
except errors.NotBranchError:
823
431
m_add.set_sensitive(False)
824
432
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
433
m_commit.set_sensitive(False)
829
m_annotate.set_sensitive(False)
830
434
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,
435
menu.right_context_menu().popup(None, None, None, 0,
839
438
def on_treeview_right_row_activated(self, treeview, path, view_column):
840
439
""" Occurs when somebody double-clicks or enters an item in the
842
443
from launch import launch
844
445
newdir = self.get_selected_right()
849
self.set_path(os.path.split(self.get_path())[0])
448
self.set_path(os.path.split(self.get_path())[0])
450
fullpath = self.get_path() + os.sep + newdir
451
if os.path.isdir(fullpath):
452
# selected item is an existant directory
453
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
457
self.refresh_right()
864
459
def on_window_main_delete_event(self, widget, event=None):
865
460
""" Do some stuff before exiting. """
866
width, height = self.window.get_size()
461
width, height = self.window_main.get_size()
867
462
self.pref.set_preference('window_width', width)
868
463
self.pref.set_preference('window_height', height)
869
x, y = self.window.get_position()
464
x, y = self.window_main.get_position()
870
465
self.pref.set_preference('window_x', x)
871
466
self.pref.set_preference('window_y', y)
872
467
self.pref.set_preference('paned_position',
873
self.window.hpaned_main.get_position())
468
self.hpaned_main.get_position())
875
470
self.pref.write()
876
self.window.destroy()
471
self.window_main.destroy()
878
473
def _load_left(self):
879
474
""" Load data into the left panel. (Bookmarks) """
940
526
delta = self.wt.changes_from(tree2, want_unchanged=True)
942
528
# 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),
530
liststore.append([gtk.STOCK_DIRECTORY, item, ''])
961
531
for item in files:
962
532
status = 'unknown'
964
533
if not self.notbranch:
965
534
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':
536
for rpath, rpathnew, id, kind, text_modified, meta_modified in delta.renamed:
537
if rpathnew == filename:
539
for rpath, id, kind in delta.added:
540
if rpath == filename:
542
for rpath, id, kind in delta.removed:
543
if rpath == filename:
545
for rpath, id, kind, text_modified, meta_modified in delta.modified:
546
if rpath == filename:
548
for rpath, id, kind in delta.unchanged:
549
if rpath == filename:
553
# status = fileops.status(path + os.sep + item)
554
#except errors.PermissionDenied:
996
557
if status == 'renamed':
997
st = _i18n('renamed')
998
559
elif status == 'removed':
999
st = _i18n('removed')
1000
561
elif status == 'added':
1002
563
elif status == 'modified':
1003
st = _i18n('modified')
1004
565
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),
569
liststore.append([gtk.STOCK_FILE, item, st])
1029
571
# Create the columns and add them to the TreeView
1030
572
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)
573
tvcolumn_filename = gtk.TreeViewColumn(_('Filename'))
574
tvcolumn_status = gtk.TreeViewColumn(_('Status'))
575
self.treeview_right.append_column(tvcolumn_filename)
576
self.treeview_right.append_column(tvcolumn_status)
1040
578
# Set up the cells
1041
579
cellpb = gtk.CellRendererPixbuf()
1042
580
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)
581
tvcolumn_filename.pack_start(cellpb, False)
582
tvcolumn_filename.pack_start(cell, True)
583
tvcolumn_filename.set_attributes(cellpb, stock_id=0)
584
tvcolumn_filename.add_attribute(cell, 'text', 1)
585
tvcolumn_status.pack_start(cell, True)
586
tvcolumn_status.add_attribute(cell, 'text', 2)
1070
588
# Set sensitivity
1071
589
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
591
def get_selected_right(self):
1084
592
""" Get the selected filename. """
1085
593
treeselection = self.treeview_right.get_selection()
1146
668
def refresh_right(self, path=None):
1147
669
""" 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):
670
from bzrlib.workingtree import WorkingTree
673
path = self.get_path()
675
# A workaround for double-clicking Bookmarks
676
if not os.path.exists(path):
679
# Get ListStore and clear it
680
liststore = self.treeview_right.get_model()
686
# Fill the appropriate lists
687
dotted_files = self.pref.get_preference('dotted_files', 'bool')
688
for item in os.listdir(path):
689
if not dotted_files and item[0] == '.':
691
if os.path.isdir(path + os.sep + item):
700
# Try to open the working tree
703
tree1 = WorkingTree.open_containing(path)[0]
704
except errors.NotBranchError:
706
except errors.PermissionDenied:
707
print "DEBUG: permission denied."
710
branch = tree1.branch
711
tree2 = tree1.branch.repository.revision_tree(branch.last_revision())
713
delta = tree1.changes_from(tree2, want_unchanged=True)
715
# Add'em to the ListStore
717
liststore.append([gtk.STOCK_DIRECTORY, item, ''])
1188
720
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()
721
filename = tree1.relpath(path + os.sep + item)
723
for rpath, rpathnew, id, kind, text_modified, meta_modified in delta.renamed:
724
if rpathnew == filename:
726
for rpath, id, kind in delta.added:
727
if rpath == filename:
729
for rpath, id, kind in delta.removed:
730
if rpath == filename:
732
for rpath, id, kind, text_modified, meta_modified in delta.modified:
733
if rpath == filename:
735
for rpath, id, kind in delta.unchanged:
736
if rpath == filename:
740
# status = fileops.status(path + os.sep + item)
741
#except errors.PermissionDenied:
744
if status == 'renamed':
746
elif status == 'removed':
748
elif status == 'added':
750
elif status == 'modified':
752
elif status == 'unchanged':
756
liststore.append([gtk.STOCK_FILE, item, st])
758
# Add the ListStore to the TreeView
759
self.treeview_right.set_model(liststore)
1365
761
# Set sensitivity
1366
762
self.set_sensitivity()