1
# Copyright (C) 2006 by Szilveszter Farkas (Phanatic) <szilveszter.farkas@gmail.com>
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
# GNU General Public License for more details.
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23
gettext.install('olive-gtk')
36
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
40
from bzrlib.workingtree import WorkingTree
42
from bzrlib.plugins.gtk.dialog import error_dialog, info_dialog, warning_dialog
43
from bzrlib.plugins.gtk.errors import show_bzr_error
44
from guifiles import GLADEFILENAME
46
from bzrlib.plugins.gtk.diff import DiffWindow
47
lazy_import(globals(), """
48
from bzrlib.plugins.gtk.viz import branchwin
50
from bzrlib.plugins.gtk.annotate.gannotate import GAnnotateWindow
51
from bzrlib.plugins.gtk.annotate.config import GAnnotateConfig
52
from bzrlib.plugins.gtk.commit import CommitDialog
53
from bzrlib.plugins.gtk.conflicts import ConflictsDialog
54
from bzrlib.plugins.gtk.initialize import InitDialog
55
from bzrlib.plugins.gtk.push import PushDialog
56
from bzrlib.plugins.gtk.revbrowser import RevisionBrowser
59
""" Display the AboutDialog. """
60
from bzrlib.plugins.gtk import __version__
61
from bzrlib.plugins.gtk.olive.guifiles import GLADEFILENAME
63
# Load AboutDialog description
64
dglade = gtk.glade.XML(GLADEFILENAME, 'aboutdialog')
65
dialog = dglade.get_widget('aboutdialog')
68
dialog.set_version(__version__)
69
dialog.set_authors([ _("Lead Developer:"),
70
"Szilveszter Farkas <szilveszter.farkas@gmail.com>",
72
"Jelmer Vernooij <jelmer@samba.org>",
73
"Mateusz Korniak <mateusz.korniak@ant.gliwice.pl>",
74
"Gary van der Merwe <garyvdm@gmail.com>" ])
75
dialog.set_artists([ "Simon Pascal Klein <klepas@klepas.org>",
76
"Jakub Steiner <jimmac@novell.com>" ])
83
""" The main Olive GTK frontend class. This is called when launching the
87
self.toplevel = gtk.glade.XML(GLADEFILENAME, 'window_main', 'olive-gtk')
88
self.window = self.toplevel.get_widget('window_main')
89
self.pref = Preferences()
92
# Initialize the statusbar
93
self.statusbar = self.toplevel.get_widget('statusbar')
94
self.context_id = self.statusbar.get_context_id('olive')
97
self.window_main = self.toplevel.get_widget('window_main')
99
self.hpaned_main = self.toplevel.get_widget('hpaned_main')
101
self.treeview_left = self.toplevel.get_widget('treeview_left')
102
self.treeview_right = self.toplevel.get_widget('treeview_right')
103
# Get some important menu items
104
self.menuitem_add_files = self.toplevel.get_widget('menuitem_add_files')
105
self.menuitem_remove_files = self.toplevel.get_widget('menuitem_remove_file')
106
self.menuitem_file_make_directory = self.toplevel.get_widget('menuitem_file_make_directory')
107
self.menuitem_file_rename = self.toplevel.get_widget('menuitem_file_rename')
108
self.menuitem_file_move = self.toplevel.get_widget('menuitem_file_move')
109
self.menuitem_file_annotate = self.toplevel.get_widget('menuitem_file_annotate')
110
self.menuitem_view_show_hidden_files = self.toplevel.get_widget('menuitem_view_show_hidden_files')
111
self.menuitem_view_show_ignored_files = self.toplevel.get_widget('menuitem_view_show_ignored_files')
112
self.menuitem_branch = self.toplevel.get_widget('menuitem_branch')
113
self.menuitem_branch_init = self.toplevel.get_widget('menuitem_branch_initialize')
114
self.menuitem_branch_get = self.toplevel.get_widget('menuitem_branch_get')
115
self.menuitem_branch_checkout = self.toplevel.get_widget('menuitem_branch_checkout')
116
self.menuitem_branch_pull = self.toplevel.get_widget('menuitem_branch_pull')
117
self.menuitem_branch_push = self.toplevel.get_widget('menuitem_branch_push')
118
self.menuitem_branch_update = self.toplevel.get_widget('menuitem_branch_update')
119
self.menuitem_branch_revert = self.toplevel.get_widget('menuitem_branch_revert')
120
self.menuitem_branch_merge = self.toplevel.get_widget('menuitem_branch_merge')
121
self.menuitem_branch_commit = self.toplevel.get_widget('menuitem_branch_commit')
122
self.menuitem_branch_tags = self.toplevel.get_widget('menuitem_branch_tags')
123
self.menuitem_branch_status = self.toplevel.get_widget('menuitem_branch_status')
124
self.menuitem_branch_missing = self.toplevel.get_widget('menuitem_branch_missing_revisions')
125
self.menuitem_branch_conflicts = self.toplevel.get_widget('menuitem_branch_conflicts')
126
self.menuitem_stats = self.toplevel.get_widget('menuitem_stats')
127
self.menuitem_stats_diff = self.toplevel.get_widget('menuitem_stats_diff')
128
self.menuitem_stats_log = self.toplevel.get_widget('menuitem_stats_log')
129
# Get some toolbuttons
130
#self.menutoolbutton_diff = self.toplevel.get_widget('menutoolbutton_diff')
131
self.toolbutton_diff = self.toplevel.get_widget('toolbutton_diff')
132
self.toolbutton_log = self.toplevel.get_widget('toolbutton_log')
133
self.toolbutton_commit = self.toplevel.get_widget('toolbutton_commit')
134
self.toolbutton_pull = self.toplevel.get_widget('toolbutton_pull')
135
self.toolbutton_push = self.toplevel.get_widget('toolbutton_push')
136
self.toolbutton_update = self.toplevel.get_widget('toolbutton_update')
137
# Get the drive selector
138
self.combobox_drive = gtk.combo_box_new_text()
139
self.combobox_drive.connect("changed", self._refresh_drives)
141
# Get the navigation widgets
142
self.hbox_location = self.toplevel.get_widget('hbox_location')
143
self.button_location_up = self.toplevel.get_widget('button_location_up')
144
self.button_location_jump = self.toplevel.get_widget('button_location_jump')
145
self.entry_location = self.toplevel.get_widget('entry_location')
146
self.image_location_error = self.toplevel.get_widget('image_location_error')
148
# Get the History widgets
149
self.check_history = self.toplevel.get_widget('checkbutton_history')
150
self.entry_history = self.toplevel.get_widget('entry_history_revno')
151
self.button_history = self.toplevel.get_widget('button_history_browse')
153
self.vbox_main_right = self.toplevel.get_widget('vbox_main_right')
155
# Dictionary for signal_autoconnect
156
dic = { "on_window_main_destroy": gtk.main_quit,
157
"on_window_main_delete_event": self.on_window_main_delete_event,
158
"on_quit_activate": self.on_window_main_delete_event,
159
"on_about_activate": self.on_about_activate,
160
"on_menuitem_add_files_activate": self.on_menuitem_add_files_activate,
161
"on_menuitem_remove_file_activate": self.on_menuitem_remove_file_activate,
162
"on_menuitem_file_make_directory_activate": self.on_menuitem_file_make_directory_activate,
163
"on_menuitem_file_move_activate": self.on_menuitem_file_move_activate,
164
"on_menuitem_file_rename_activate": self.on_menuitem_file_rename_activate,
165
"on_menuitem_file_annotate_activate": self.on_menuitem_file_annotate_activate,
166
"on_menuitem_view_show_hidden_files_activate": self.on_menuitem_view_show_hidden_files_activate,
167
"on_menuitem_view_show_ignored_files_activate": self.on_menuitem_view_show_ignored_files_activate,
168
"on_menuitem_view_refresh_activate": self.on_menuitem_view_refresh_activate,
169
"on_menuitem_branch_initialize_activate": self.on_menuitem_branch_initialize_activate,
170
"on_menuitem_branch_get_activate": self.on_menuitem_branch_get_activate,
171
"on_menuitem_branch_checkout_activate": self.on_menuitem_branch_checkout_activate,
172
"on_menuitem_branch_revert_activate": self.on_menuitem_branch_revert_activate,
173
"on_menuitem_branch_merge_activate": self.on_menuitem_branch_merge_activate,
174
"on_menuitem_branch_commit_activate": self.on_menuitem_branch_commit_activate,
175
"on_menuitem_branch_push_activate": self.on_menuitem_branch_push_activate,
176
"on_menuitem_branch_pull_activate": self.on_menuitem_branch_pull_activate,
177
"on_menuitem_branch_update_activate": self.on_menuitem_branch_update_activate,
178
"on_menuitem_branch_tags_activate": self.on_menuitem_branch_tags_activate,
179
"on_menuitem_branch_status_activate": self.on_menuitem_branch_status_activate,
180
"on_menuitem_branch_missing_revisions_activate": self.on_menuitem_branch_missing_revisions_activate,
181
"on_menuitem_branch_conflicts_activate": self.on_menuitem_branch_conflicts_activate,
182
"on_menuitem_stats_diff_activate": self.on_menuitem_stats_diff_activate,
183
"on_menuitem_stats_log_activate": self.on_menuitem_stats_log_activate,
184
"on_menuitem_stats_infos_activate": self.on_menuitem_stats_infos_activate,
185
"on_toolbutton_refresh_clicked": self.on_menuitem_view_refresh_activate,
186
"on_toolbutton_log_clicked": self.on_menuitem_stats_log_activate,
187
#"on_menutoolbutton_diff_clicked": self.on_menuitem_stats_diff_activate,
188
"on_toolbutton_diff_clicked": self.on_menuitem_stats_diff_activate,
189
"on_toolbutton_commit_clicked": self.on_menuitem_branch_commit_activate,
190
"on_toolbutton_pull_clicked": self.on_menuitem_branch_pull_activate,
191
"on_toolbutton_push_clicked": self.on_menuitem_branch_push_activate,
192
"on_toolbutton_update_clicked": self.on_menuitem_branch_update_activate,
193
"on_treeview_right_button_press_event": self.on_treeview_right_button_press_event,
194
"on_treeview_right_row_activated": self.on_treeview_right_row_activated,
195
"on_treeview_left_button_press_event": self.on_treeview_left_button_press_event,
196
"on_treeview_left_row_activated": self.on_treeview_left_row_activated,
197
"on_button_location_up_clicked": self.on_button_location_up_clicked,
198
"on_button_location_jump_clicked": self.on_button_location_jump_clicked,
199
"on_entry_location_key_press_event": self.on_entry_location_key_press_event,
200
"on_checkbutton_history_toggled": self.on_checkbutton_history_toggled,
201
"on_entry_history_revno_key_press_event": self.on_entry_history_revno_key_press_event,
202
"on_button_history_browse_clicked": self.on_button_history_browse_clicked
205
# Connect the signals to the handlers
206
self.toplevel.signal_autoconnect(dic)
208
self._just_started = True
210
# Apply window size and position
211
width = self.pref.get_preference('window_width', 'int')
212
height = self.pref.get_preference('window_height', 'int')
213
self.window.resize(width, height)
214
x = self.pref.get_preference('window_x', 'int')
215
y = self.pref.get_preference('window_y', 'int')
216
self.window.move(x, y)
217
# Apply paned position
218
pos = self.pref.get_preference('paned_position', 'int')
219
self.hpaned_main.set_position(pos)
221
# Apply menu to the toolbutton
222
#menubutton = self.toplevel.get_widget('menutoolbutton_diff')
223
#menubutton.set_menu(handler.menu.toolbar_diff)
225
# Now we can show the window
228
# Show drive selector if under Win32
229
if sys.platform == 'win32':
230
self.hbox_location.pack_start(self.combobox_drive, False, False, 0)
231
self.hbox_location.reorder_child(self.combobox_drive, 1)
232
self.combobox_drive.show()
233
self.gen_hard_selector()
238
self.menuitem_view_show_hidden_files.set_active(self.pref.get_preference('dotted_files', 'bool'))
239
self.menuitem_view_show_ignored_files.set_active(self.pref.get_preference('ignored_files', 'bool'))
241
# We're starting local
243
self.remote_branch = None
244
self.remote_path = None
245
self.remote_revision = None
247
self.set_path(os.getcwd())
250
self._just_started = False
252
def set_path(self, path, force_remote=False):
253
self.notbranch = False
256
# Forcing remote mode (reading data from inventory)
257
self._show_stock_image(gtk.STOCK_DISCONNECT)
259
br = Branch.open_containing(path)[0]
260
except bzrerrors.NotBranchError:
261
self._show_stock_image(gtk.STOCK_DIALOG_ERROR)
262
self.check_history.set_active(False)
263
self.check_history.set_sensitive(False)
265
except bzrerrors.UnsupportedProtocol:
266
self._show_stock_image(gtk.STOCK_DIALOG_ERROR)
267
self.check_history.set_active(False)
268
self.check_history.set_sensitive(False)
271
self._show_stock_image(gtk.STOCK_CONNECT)
276
self.remote_branch, self.remote_path = Branch.open_containing(path)
278
if self.remote_revision is None:
279
self.remote_revision = self.remote_branch.last_revision()
281
self.remote_entries = self.remote_branch.repository.get_inventory(self.remote_revision).entries()
283
if len(self.remote_path) == 0:
284
self.remote_parent = self.remote_branch.repository.get_inventory(self.remote_branch.last_revision()).iter_entries_by_dir().next()[1].file_id
286
for (name, type) in self.remote_entries:
287
if name == self.remote_path:
288
self.remote_parent = type.file_id
291
if not path.endswith('/'):
294
if self.remote_branch.base == path:
295
self.button_location_up.set_sensitive(False)
297
self.button_location_up.set_sensitive(True)
299
if os.path.isdir(path):
300
self.image_location_error.destroy()
305
self.wt, self.wtpath = WorkingTree.open_containing(path)
306
except (bzrerrors.NotBranchError, bzrerrors.NoWorkingTree):
307
self.notbranch = True
309
# If we're in the root, we cannot go up anymore
310
if sys.platform == 'win32':
311
drive, tail = os.path.splitdrive(path)
312
if tail in ('', '/', '\\'):
313
self.button_location_up.set_sensitive(False)
315
self.button_location_up.set_sensitive(True)
318
self.button_location_up.set_sensitive(False)
320
self.button_location_up.set_sensitive(True)
321
elif not os.path.isfile(path):
322
# Doesn't seem to be a file nor a directory, trying to open a
324
self._show_stock_image(gtk.STOCK_DISCONNECT)
326
br = Branch.open_containing(path)[0]
327
except bzrerrors.NotBranchError:
328
self._show_stock_image(gtk.STOCK_DIALOG_ERROR)
329
self.check_history.set_active(False)
330
self.check_history.set_sensitive(False)
332
except bzrerrors.UnsupportedProtocol:
333
self._show_stock_image(gtk.STOCK_DIALOG_ERROR)
334
self.check_history.set_active(False)
335
self.check_history.set_sensitive(False)
338
self._show_stock_image(gtk.STOCK_CONNECT)
343
self.remote_branch, self.remote_path = Branch.open_containing(path)
345
if self.remote_revision is None:
346
self.remote_revision = self.remote_branch.last_revision()
348
self.remote_entries = self.remote_branch.repository.get_inventory(self.remote_revision).entries()
350
if len(self.remote_path) == 0:
351
self.remote_parent = self.remote_branch.repository.get_inventory(self.remote_branch.last_revision()).iter_entries_by_dir().next()[1].file_id
353
for (name, type) in self.remote_entries:
354
if name == self.remote_path:
355
self.remote_parent = type.file_id
358
if not path.endswith('/'):
361
if self.remote_branch.base == path:
362
self.button_location_up.set_sensitive(False)
364
self.button_location_up.set_sensitive(True)
367
self.check_history.set_active(False)
368
self.check_history.set_sensitive(False)
370
self.check_history.set_sensitive(True)
372
self.statusbar.push(self.context_id, path)
373
self.entry_location.set_text(path)
382
if len(self.remote_path) > 0:
383
return self.remote_branch.base + self.remote_path + '/'
385
return self.remote_branch.base
387
def on_about_activate(self, widget):
390
def on_button_history_browse_clicked(self, widget):
391
""" Browse for revision button handler. """
393
br = self.remote_branch
397
revb = RevisionBrowser(br, self.window)
398
response = revb.run()
399
if response != gtk.RESPONSE_NONE:
402
if response == gtk.RESPONSE_OK:
403
if revb.selected_revno is not None:
404
self.entry_history.set_text(revb.selected_revno)
408
def on_button_location_jump_clicked(self, widget):
409
""" Location Jump button handler. """
410
location = self.entry_location.get_text()
412
if self.set_path(location):
415
def on_button_location_up_clicked(self, widget):
416
""" Location Up button handler. """
419
self.set_path(os.path.split(self.get_path())[0])
423
newpath = delim.join(self.get_path().split(delim)[:-2])
425
self.set_path(newpath)
429
def on_checkbutton_history_toggled(self, widget):
430
""" History Mode toggle handler. """
431
if self.check_history.get_active():
432
# History Mode activated
433
self.entry_history.set_sensitive(True)
434
self.button_history.set_sensitive(True)
436
# History Mode deactivated
437
self.entry_history.set_sensitive(False)
438
self.button_history.set_sensitive(False)
441
def on_entry_history_revno_key_press_event(self, widget, event):
442
""" Key pressed handler for the history entry. """
443
if event.keyval == 65293:
444
# Return was hit, so we have to load that specific revision
445
# Emulate being remote, so inventory should be used
446
path = self.get_path()
449
self.remote_branch = self.wt.branch
451
revno = int(self.entry_history.get_text())
452
self.remote_revision = self.remote_branch.get_rev_id(revno)
453
if self.set_path(path, True):
456
def on_entry_location_key_press_event(self, widget, event):
457
""" Key pressed handler for the location entry. """
458
if event.keyval == 65293:
459
# Return was hit, so we have to jump
460
self.on_button_location_jump_clicked(widget)
462
def on_menuitem_add_files_activate(self, widget):
463
""" Add file(s)... menu handler. """
464
from add import OliveAdd
465
add = OliveAdd(self.wt, self.wtpath, self.get_selected_right())
468
def on_menuitem_branch_get_activate(self, widget):
469
""" Branch/Get... menu handler. """
470
from bzrlib.plugins.gtk.branch import BranchDialog
473
branch = BranchDialog(os.getcwd(), self.window, self.remote_branch.base)
475
branch = BranchDialog(self.get_path(), self.window)
476
response = branch.run()
477
if response != gtk.RESPONSE_NONE:
480
if response == gtk.RESPONSE_OK:
485
def on_menuitem_branch_checkout_activate(self, widget):
486
""" Branch/Checkout... menu handler. """
487
from bzrlib.plugins.gtk.checkout import CheckoutDialog
490
checkout = CheckoutDialog(os.getcwd(), self.window, self.remote_branch.base)
492
checkout = CheckoutDialog(self.get_path(), self.window)
493
response = checkout.run()
494
if response != gtk.RESPONSE_NONE:
497
if response == gtk.RESPONSE_OK:
503
def on_menuitem_branch_commit_activate(self, widget):
504
""" Branch/Commit... menu handler. """
505
# def __init__(self, wt, wtpath, notbranch, selected=None, parent=None):
506
selected = self.get_selected_right()
508
selected = os.path.join(self.wtpath, selected)
509
commit = CommitDialog(wt=self.wt,
513
response = commit.run()
514
if response != gtk.RESPONSE_NONE:
517
if response == gtk.RESPONSE_OK:
522
def on_menuitem_branch_conflicts_activate(self, widget):
523
""" Branch/Conflicts... menu handler. """
524
conflicts = ConflictsDialog(self.wt, self.window)
525
response = conflicts.run()
526
if response != gtk.RESPONSE_NONE:
529
def on_menuitem_branch_merge_activate(self, widget):
530
""" Branch/Merge... menu handler. """
531
from bzrlib.plugins.gtk.merge import MergeDialog
533
if self.check_for_changes():
534
error_dialog(_('There are local changes in the branch'),
535
_('Please commit or revert the changes before merging.'))
537
parent_branch_path = self.wt.branch.get_parent()
538
merge = MergeDialog(self.wt, self.wtpath,default_branch_path=parent_branch_path )
542
def on_menuitem_branch_missing_revisions_activate(self, widget):
543
""" Branch/Missing revisions menu handler. """
545
from bzrlib.missing import find_unmerged, iter_log_revisions
547
local_branch = self.wt.branch
548
parent_branch_path = local_branch.get_parent()
549
if parent_branch_path is None:
550
error_dialog(_('Parent location is unknown'),
551
_('Cannot determine missing revisions if no parent location is known.'))
554
parent_branch = Branch.open(parent_branch_path)
556
if parent_branch.base == local_branch.base:
557
parent_branch = local_branch
559
local_extra, remote_extra = find_unmerged(local_branch,parent_branch)
561
if local_extra or remote_extra:
563
## def log_revision_one_line_text(log_revision):
564
## """ Generates one line description of log_revison ended with end of line."""
565
## revision = log_revision.rev
566
## txt = "- %s (%s)\n" % (revision.get_summary(), revision.committer, )
567
## txt = txt.replace("<"," ") # Seems < > chars are expected to be xml tags ...
568
## txt = txt.replace(">"," ")
573
dlg_txt += _('%d local extra revision(s). \n') % (len(local_extra),)
574
## NOTE: We do not want such ugly info about missing revisions
575
## Revision Browser should be used there
576
## max_revisions = 10
577
## for log_revision in iter_log_revisions(local_extra, local_branch.repository, verbose=1):
578
## dlg_txt += log_revision_one_line_text(log_revision)
579
## if max_revisions <= 0:
580
## dlg_txt += _("more ... \n")
582
## max_revisions -= 1
585
dlg_txt += _('%d local missing revision(s).\n') % (len(remote_extra),)
586
## max_revisions = 10
587
## for log_revision in iter_log_revisions(remote_extra, parent_branch.repository, verbose=1):
588
## dlg_txt += log_revision_one_line_text(log_revision)
589
## if max_revisions <= 0:
590
## dlg_txt += _("more ... \n")
592
## max_revisions -= 1
594
info_dialog(_('There are missing revisions'),
597
info_dialog(_('Local branch up to date'),
598
_('There are no missing revisions.'))
601
def on_menuitem_branch_pull_activate(self, widget):
602
""" Branch/Pull menu handler. """
603
branch_to = self.wt.branch
605
location = branch_to.get_parent()
607
error_dialog(_('Parent location is unknown'),
608
_('Pulling is not possible until there is a parent location.'))
611
branch_from = Branch.open(location)
613
if branch_to.get_parent() is None:
614
branch_to.set_parent(branch_from.base)
616
ret = branch_to.pull(branch_from)
618
info_dialog(_('Pull successful'), _('%d revision(s) pulled.') % ret)
621
def on_menuitem_branch_update_activate(self, widget):
622
""" Brranch/checkout update menu handler. """
624
ret = self.wt.update()
625
conflicts = self.wt.conflicts()
627
info_dialog(_('Update successful but conflicts generated'), _('Number of conflicts generated: %d.') % (len(conflicts),) )
629
info_dialog(_('Update successful'), _('No conflicts generated.') )
631
def on_menuitem_branch_push_activate(self, widget):
632
""" Branch/Push... menu handler. """
633
push = PushDialog(repository=None,revid=None,branch=self.wt.branch, parent=self.window)
634
response = push.run()
635
if response != gtk.RESPONSE_NONE:
639
def on_menuitem_branch_revert_activate(self, widget):
640
""" Branch/Revert all changes menu handler. """
641
ret = self.wt.revert([])
643
warning_dialog(_('Conflicts detected'),
644
_('Please have a look at the working tree before continuing.'))
646
info_dialog(_('Revert successful'),
647
_('All files reverted to last revision.'))
650
def on_menuitem_branch_status_activate(self, widget):
651
""" Branch/Status... menu handler. """
652
from bzrlib.plugins.gtk.status import StatusDialog
653
status = StatusDialog(self.wt, self.wtpath)
654
response = status.run()
655
if response != gtk.RESPONSE_NONE:
658
def on_menuitem_branch_initialize_activate(self, widget):
659
""" Initialize current directory. """
660
init = InitDialog(self.path, self.window)
661
response = init.run()
662
if response != gtk.RESPONSE_NONE:
665
if response == gtk.RESPONSE_OK:
670
def on_menuitem_branch_tags_activate(self, widget):
671
""" Branch/Tags... menu handler. """
672
from bzrlib.plugins.gtk.tags import TagsWindow
674
window = TagsWindow(self.wt.branch, self.window)
676
window = TagsWindow(self.remote_branch, self.window)
679
def on_menuitem_file_annotate_activate(self, widget):
680
""" File/Annotate... menu handler. """
681
if self.get_selected_right() is None:
682
error_dialog(_('No file was selected'),
683
_('Please select a file from the list.'))
686
branch = self.wt.branch
687
file_id = self.wt.path2id(self.wt.relpath(os.path.join(self.path, self.get_selected_right())))
689
window = GAnnotateWindow(all=False, plain=False, parent=self.window)
690
window.set_title(os.path.join(self.path, self.get_selected_right()) + " - Annotate")
691
config = GAnnotateConfig(window)
695
window.annotate(self.wt, branch, file_id)
699
def on_menuitem_file_make_directory_activate(self, widget):
700
""" File/Make directory... menu handler. """
701
from mkdir import OliveMkdir
702
mkdir = OliveMkdir(self.wt, self.wtpath)
705
def on_menuitem_file_move_activate(self, widget):
706
""" File/Move... menu handler. """
707
from move import OliveMove
708
move = OliveMove(self.wt, self.wtpath, self.get_selected_right())
711
def on_menuitem_file_rename_activate(self, widget):
712
""" File/Rename... menu handler. """
713
from rename import OliveRename
714
rename = OliveRename(self.wt, self.wtpath, self.get_selected_right())
717
def on_menuitem_remove_file_activate(self, widget):
718
""" Remove (unversion) selected file. """
719
from remove import OliveRemoveDialog
720
remove = OliveRemoveDialog(self.wt, self.wtpath,
721
selected=self.get_selected_right(),
723
response = remove.run()
725
if response != gtk.RESPONSE_NONE:
728
if response == gtk.RESPONSE_OK:
729
self.set_path(self.path)
734
def on_menuitem_stats_diff_activate(self, widget):
735
""" Statistics/Differences... menu handler. """
736
window = DiffWindow(parent=self.window)
737
parent_tree = self.wt.branch.repository.revision_tree(self.wt.branch.last_revision())
738
window.set_diff(self.wt.branch.nick, self.wt, parent_tree)
741
def on_menuitem_stats_infos_activate(self, widget):
742
""" Statistics/Informations... menu handler. """
743
from info import OliveInfo
745
info = OliveInfo(self.remote_branch)
747
info = OliveInfo(self.wt.branch)
750
def on_menuitem_stats_log_activate(self, widget):
751
""" Statistics/Log... menu handler. """
754
branch = self.wt.branch
756
branch = self.remote_branch
758
window = branchwin.BranchWindow(branch, branch.last_revision(), None, parent=self.window)
761
def on_menuitem_view_refresh_activate(self, widget):
762
""" View/Refresh menu handler. """
763
# Refresh the left pane
765
# Refresh the right pane
768
def on_menuitem_view_show_hidden_files_activate(self, widget):
769
""" View/Show hidden files menu handler. """
770
self.pref.set_preference('dotted_files', widget.get_active())
771
if self.path is not None:
774
def on_menuitem_view_show_ignored_files_activate(self, widget):
775
""" Hide/Show ignored files menu handler. """
776
self.pref.set_preference('ignored_files', widget.get_active())
777
if self.path is not None:
780
def on_treeview_left_button_press_event(self, widget, event):
781
""" Occurs when somebody right-clicks in the bookmark list. """
782
if event.button == 3:
783
# Don't show context with nothing selected
784
if self.get_selected_left() == None:
788
from menu import OliveMenu
789
menu = OliveMenu(path=self.get_path(),
790
selected=self.get_selected_left(),
793
menu.left_context_menu().popup(None, None, None, 0,
796
def on_treeview_left_row_activated(self, treeview, path, view_column):
797
""" Occurs when somebody double-clicks or enters an item in the
800
newdir = self.get_selected_left()
804
if self.set_path(newdir):
807
def on_treeview_right_button_press_event(self, widget, event):
808
""" Occurs when somebody right-clicks in the file list. """
809
if event.button == 3:
811
from menu import OliveMenu
812
menu = OliveMenu(path=self.get_path(),
813
selected=self.get_selected_right(),
816
m_open = menu.ui.get_widget('/context_right/open')
817
m_add = menu.ui.get_widget('/context_right/add')
818
m_remove = menu.ui.get_widget('/context_right/remove')
819
m_rename = menu.ui.get_widget('/context_right/rename')
820
m_revert = menu.ui.get_widget('/context_right/revert')
821
m_commit = menu.ui.get_widget('/context_right/commit')
822
m_annotate = menu.ui.get_widget('/context_right/annotate')
823
m_diff = menu.ui.get_widget('/context_right/diff')
824
# check if we're in a branch
826
from bzrlib.branch import Branch
827
Branch.open_containing(self.get_path())
829
m_open.set_sensitive(False)
830
m_add.set_sensitive(False)
831
m_remove.set_sensitive(False)
832
m_rename.set_sensitive(False)
833
m_revert.set_sensitive(False)
834
m_commit.set_sensitive(False)
835
m_annotate.set_sensitive(False)
836
m_diff.set_sensitive(False)
838
m_open.set_sensitive(True)
839
m_add.set_sensitive(True)
840
m_remove.set_sensitive(True)
841
m_rename.set_sensitive(True)
842
m_revert.set_sensitive(True)
843
m_commit.set_sensitive(True)
844
m_annotate.set_sensitive(True)
845
m_diff.set_sensitive(True)
846
except bzrerrors.NotBranchError:
847
m_open.set_sensitive(True)
848
m_add.set_sensitive(False)
849
m_remove.set_sensitive(False)
850
m_rename.set_sensitive(False)
851
m_revert.set_sensitive(False)
852
m_commit.set_sensitive(False)
853
m_annotate.set_sensitive(False)
854
m_diff.set_sensitive(False)
857
menu.right_context_menu().popup(None, None, None, 0,
860
menu.remote_context_menu().popup(None, None, None, 0,
863
def on_treeview_right_row_activated(self, treeview, path, view_column):
864
""" Occurs when somebody double-clicks or enters an item in the
866
from launch import launch
868
newdir = self.get_selected_right()
873
self.set_path(os.path.split(self.get_path())[0])
875
fullpath = os.path.join(self.get_path(), newdir)
876
if os.path.isdir(fullpath):
877
# selected item is an existant directory
878
self.set_path(fullpath)
883
if self._is_remote_dir(self.get_path() + newdir):
884
self.set_path(self.get_path() + newdir)
888
def on_window_main_delete_event(self, widget, event=None):
889
""" Do some stuff before exiting. """
890
width, height = self.window_main.get_size()
891
self.pref.set_preference('window_width', width)
892
self.pref.set_preference('window_height', height)
893
x, y = self.window_main.get_position()
894
self.pref.set_preference('window_x', x)
895
self.pref.set_preference('window_y', y)
896
self.pref.set_preference('paned_position',
897
self.hpaned_main.get_position())
900
self.window_main.destroy()
902
def _load_left(self):
903
""" Load data into the left panel. (Bookmarks) """
905
treestore = gtk.TreeStore(str, str)
908
bookmarks = self.pref.get_bookmarks()
910
# Add them to the TreeStore
911
titer = treestore.append(None, [_('Bookmarks'), None])
912
for item in bookmarks:
913
title = self.pref.get_bookmark_title(item)
914
treestore.append(titer, [title, item])
916
# Create the column and add it to the TreeView
917
self.treeview_left.set_model(treestore)
918
tvcolumn_bookmark = gtk.TreeViewColumn(_('Bookmark'))
919
self.treeview_left.append_column(tvcolumn_bookmark)
922
cell = gtk.CellRendererText()
923
tvcolumn_bookmark.pack_start(cell, True)
924
tvcolumn_bookmark.add_attribute(cell, 'text', 0)
927
self.treeview_left.expand_all()
929
def _load_right(self):
930
""" Load data into the right panel. (Filelist) """
932
# Model: [ icon, dir, name, status text, status, size (int), size (human), mtime (int), mtime (local), fileid ]
933
liststore = gtk.ListStore(gobject.TYPE_STRING,
934
gobject.TYPE_BOOLEAN,
947
# Fill the appropriate lists
948
dotted_files = self.pref.get_preference('dotted_files', 'bool')
949
for item in os.listdir(self.path):
950
if not dotted_files and item[0] == '.':
952
if os.path.isdir(self.path + os.sep + item):
957
if not self.notbranch:
958
branch = self.wt.branch
959
tree2 = self.wt.branch.repository.revision_tree(branch.last_revision())
961
delta = self.wt.changes_from(tree2, want_unchanged=True)
963
# Add'em to the ListStore
965
statinfo = os.stat(self.path + os.sep + item)
966
liststore.append([ gtk.STOCK_DIRECTORY,
974
self._format_date(statinfo.st_mtime),
979
if not self.notbranch:
980
filename = self.wt.relpath(self.path + os.sep + item)
985
for rpath, rpathnew, id, kind, text_modified, meta_modified in delta.renamed:
986
if rpathnew == filename:
989
for rpath, id, kind in delta.added:
990
if rpath == filename:
993
for rpath, id, kind in delta.removed:
994
if rpath == filename:
997
for rpath, id, kind, text_modified, meta_modified in delta.modified:
998
if rpath == filename:
1001
for rpath, id, kind in delta.unchanged:
1002
if rpath == filename:
1003
status = 'unchanged'
1005
for rpath, file_class, kind, id, entry in self.wt.list_files():
1006
if rpath == filename and file_class == 'I':
1011
if status == 'renamed':
1013
elif status == 'removed':
1015
elif status == 'added':
1017
elif status == 'modified':
1019
elif status == 'unchanged':
1021
elif status == 'ignored':
1026
statinfo = os.stat(self.path + os.sep + item)
1027
liststore.append([gtk.STOCK_FILE,
1032
str(statinfo.st_size), # NOTE: if int used there it will fail for large files (size expressed as long int)
1033
self._format_size(statinfo.st_size),
1035
self._format_date(statinfo.st_mtime),
1038
# Create the columns and add them to the TreeView
1039
self.treeview_right.set_model(liststore)
1040
self._tvcolumn_filename = gtk.TreeViewColumn(_('Filename'))
1041
self._tvcolumn_status = gtk.TreeViewColumn(_('Status'))
1042
self._tvcolumn_size = gtk.TreeViewColumn(_('Size'))
1043
self._tvcolumn_mtime = gtk.TreeViewColumn(_('Last modified'))
1044
self.treeview_right.append_column(self._tvcolumn_filename)
1045
self.treeview_right.append_column(self._tvcolumn_status)
1046
self.treeview_right.append_column(self._tvcolumn_size)
1047
self.treeview_right.append_column(self._tvcolumn_mtime)
1050
cellpb = gtk.CellRendererPixbuf()
1051
cell = gtk.CellRendererText()
1052
self._tvcolumn_filename.pack_start(cellpb, False)
1053
self._tvcolumn_filename.pack_start(cell, True)
1054
self._tvcolumn_filename.set_attributes(cellpb, stock_id=0)
1055
self._tvcolumn_filename.add_attribute(cell, 'text', 2)
1056
self._tvcolumn_status.pack_start(cell, True)
1057
self._tvcolumn_status.add_attribute(cell, 'text', 3)
1058
self._tvcolumn_size.pack_start(cell, True)
1059
self._tvcolumn_size.add_attribute(cell, 'text', 6)
1060
self._tvcolumn_mtime.pack_start(cell, True)
1061
self._tvcolumn_mtime.add_attribute(cell, 'text', 8)
1063
# Set up the properties of the TreeView
1064
self.treeview_right.set_headers_visible(True)
1065
self.treeview_right.set_headers_clickable(True)
1066
self.treeview_right.set_search_column(1)
1067
self._tvcolumn_filename.set_resizable(True)
1068
self._tvcolumn_status.set_resizable(True)
1069
self._tvcolumn_size.set_resizable(True)
1070
self._tvcolumn_mtime.set_resizable(True)
1072
liststore.set_sort_func(13, self._sort_filelist_callback, None)
1073
liststore.set_sort_column_id(13, gtk.SORT_ASCENDING)
1074
self._tvcolumn_filename.set_sort_column_id(13)
1075
self._tvcolumn_status.set_sort_column_id(3)
1076
self._tvcolumn_size.set_sort_column_id(5)
1077
self._tvcolumn_mtime.set_sort_column_id(7)
1080
self.set_sensitivity()
1082
def get_selected_fileid(self):
1083
""" Get the file_id of the selected file. """
1084
treeselection = self.treeview_right.get_selection()
1085
(model, iter) = treeselection.get_selected()
1090
return model.get_value(iter, 9)
1092
def get_selected_right(self):
1093
""" Get the selected filename. """
1094
treeselection = self.treeview_right.get_selection()
1095
(model, iter) = treeselection.get_selected()
1100
return model.get_value(iter, 2)
1102
def get_selected_left(self):
1103
""" Get the selected bookmark. """
1104
treeselection = self.treeview_left.get_selection()
1105
(model, iter) = treeselection.get_selected()
1110
return model.get_value(iter, 1)
1112
def set_statusbar(self, message):
1113
""" Set the statusbar message. """
1114
self.statusbar.push(self.context_id, message)
1116
def clear_statusbar(self):
1117
""" Clean the last message from the statusbar. """
1118
self.statusbar.pop(self.context_id)
1120
def set_sensitivity(self):
1121
""" Set menu and toolbar sensitivity. """
1124
self.menuitem_branch_init.set_sensitive(self.notbranch)
1125
self.menuitem_branch_get.set_sensitive(self.notbranch)
1126
self.menuitem_branch_checkout.set_sensitive(self.notbranch)
1127
self.menuitem_branch_pull.set_sensitive(not self.notbranch)
1128
self.menuitem_branch_push.set_sensitive(not self.notbranch)
1129
self.menuitem_branch_update.set_sensitive(not self.notbranch)
1130
self.menuitem_branch_revert.set_sensitive(not self.notbranch)
1131
self.menuitem_branch_merge.set_sensitive(not self.notbranch)
1132
self.menuitem_branch_commit.set_sensitive(not self.notbranch)
1133
self.menuitem_branch_tags.set_sensitive(not self.notbranch)
1134
self.menuitem_branch_status.set_sensitive(not self.notbranch)
1135
self.menuitem_branch_missing.set_sensitive(not self.notbranch)
1136
self.menuitem_branch_conflicts.set_sensitive(not self.notbranch)
1137
self.menuitem_stats.set_sensitive(not self.notbranch)
1138
self.menuitem_stats_diff.set_sensitive(not self.notbranch)
1139
self.menuitem_add_files.set_sensitive(not self.notbranch)
1140
self.menuitem_remove_files.set_sensitive(not self.notbranch)
1141
self.menuitem_file_make_directory.set_sensitive(not self.notbranch)
1142
self.menuitem_file_rename.set_sensitive(not self.notbranch)
1143
self.menuitem_file_move.set_sensitive(not self.notbranch)
1144
self.menuitem_file_annotate.set_sensitive(not self.notbranch)
1145
#self.menutoolbutton_diff.set_sensitive(True)
1146
self.toolbutton_diff.set_sensitive(not self.notbranch)
1147
self.toolbutton_log.set_sensitive(not self.notbranch)
1148
self.toolbutton_commit.set_sensitive(not self.notbranch)
1149
self.toolbutton_pull.set_sensitive(not self.notbranch)
1150
self.toolbutton_push.set_sensitive(not self.notbranch)
1151
self.toolbutton_update.set_sensitive(not self.notbranch)
1154
self.menuitem_branch_init.set_sensitive(False)
1155
self.menuitem_branch_get.set_sensitive(True)
1156
self.menuitem_branch_checkout.set_sensitive(True)
1157
self.menuitem_branch_pull.set_sensitive(False)
1158
self.menuitem_branch_push.set_sensitive(False)
1159
self.menuitem_branch_update.set_sensitive(False)
1160
self.menuitem_branch_revert.set_sensitive(False)
1161
self.menuitem_branch_merge.set_sensitive(False)
1162
self.menuitem_branch_commit.set_sensitive(False)
1163
self.menuitem_branch_tags.set_sensitive(True)
1164
self.menuitem_branch_status.set_sensitive(False)
1165
self.menuitem_branch_missing.set_sensitive(False)
1166
self.menuitem_branch_conflicts.set_sensitive(False)
1167
self.menuitem_stats.set_sensitive(True)
1168
self.menuitem_stats_diff.set_sensitive(False)
1169
self.menuitem_add_files.set_sensitive(False)
1170
self.menuitem_remove_files.set_sensitive(False)
1171
self.menuitem_file_make_directory.set_sensitive(False)
1172
self.menuitem_file_rename.set_sensitive(False)
1173
self.menuitem_file_move.set_sensitive(False)
1174
self.menuitem_file_annotate.set_sensitive(False)
1175
#self.menutoolbutton_diff.set_sensitive(True)
1176
self.toolbutton_diff.set_sensitive(False)
1177
self.toolbutton_log.set_sensitive(True)
1178
self.toolbutton_commit.set_sensitive(False)
1179
self.toolbutton_pull.set_sensitive(False)
1180
self.toolbutton_push.set_sensitive(False)
1181
self.toolbutton_update.set_sensitive(False)
1183
def refresh_left(self):
1184
""" Refresh the bookmark list. """
1186
# Get TreeStore and clear it
1187
treestore = self.treeview_left.get_model()
1190
# Re-read preferences
1194
bookmarks = self.pref.get_bookmarks()
1196
# Add them to the TreeStore
1197
titer = treestore.append(None, [_('Bookmarks'), None])
1198
for item in bookmarks:
1199
title = self.pref.get_bookmark_title(item)
1200
treestore.append(titer, [title, item])
1202
# Add the TreeStore to the TreeView
1203
self.treeview_left.set_model(treestore)
1206
self.treeview_left.expand_all()
1208
def refresh_right(self, path=None):
1209
""" Refresh the file list. """
1212
from bzrlib.workingtree import WorkingTree
1215
path = self.get_path()
1217
# A workaround for double-clicking Bookmarks
1218
if not os.path.exists(path):
1221
# Get ListStore and clear it
1222
liststore = self.treeview_right.get_model()
1225
# Show Status column
1226
self._tvcolumn_status.set_visible(True)
1231
# Fill the appropriate lists
1232
dotted_files = self.pref.get_preference('dotted_files', 'bool')
1233
ignored_files = self.pref.get_preference('ignored_files', 'bool')
1235
for item in os.listdir(path):
1236
if not dotted_files and item[0] == '.':
1238
if os.path.isdir(path + os.sep + item):
1243
# Try to open the working tree
1246
tree1 = WorkingTree.open_containing(path)[0]
1247
except (bzrerrors.NotBranchError, bzrerrors.NoWorkingTree):
1251
branch = tree1.branch
1252
tree2 = tree1.branch.repository.revision_tree(branch.last_revision())
1254
delta = tree1.changes_from(tree2, want_unchanged=True)
1256
# Add'em to the ListStore
1258
statinfo = os.stat(self.path + os.sep + item)
1259
liststore.append([gtk.STOCK_DIRECTORY,
1267
self._format_date(statinfo.st_mtime),
1273
filename = tree1.relpath(path + os.sep + item)
1278
for rpath, rpathnew, id, kind, text_modified, meta_modified in delta.renamed:
1279
if rpathnew == filename:
1282
for rpath, id, kind in delta.added:
1283
if rpath == filename:
1286
for rpath, id, kind in delta.removed:
1287
if rpath == filename:
1290
for rpath, id, kind, text_modified, meta_modified in delta.modified:
1291
if rpath == filename:
1294
for rpath, id, kind in delta.unchanged:
1295
if rpath == filename:
1296
status = 'unchanged'
1298
for rpath, file_class, kind, id, entry in self.wt.list_files():
1299
if rpath == filename and file_class == 'I':
1304
if status == 'renamed':
1306
elif status == 'removed':
1308
elif status == 'added':
1310
elif status == 'modified':
1312
elif status == 'unchanged':
1314
elif status == 'ignored':
1316
if not ignored_files:
1321
statinfo = os.stat(self.path + os.sep + item)
1322
liststore.append([gtk.STOCK_FILE,
1327
str(statinfo.st_size),
1328
self._format_size(statinfo.st_size),
1330
self._format_date(statinfo.st_mtime),
1335
# Get ListStore and clear it
1336
liststore = self.treeview_right.get_model()
1339
# Hide Status column
1340
self._tvcolumn_status.set_visible(False)
1345
self._show_stock_image(gtk.STOCK_REFRESH)
1347
for (name, type) in self.remote_entries:
1348
if type.kind == 'directory':
1350
elif type.kind == 'file':
1354
""" Cache based on revision history. """
1355
def __init__(self, history):
1356
self._history = history
1358
def _lookup_revision(self, revid):
1359
for r in self._history:
1360
if r.revision_id == revid:
1362
rev = repo.get_revision(revid)
1363
self._history.append(rev)
1366
repo = self.remote_branch.repository
1368
revhistory = self.remote_branch.revision_history()
1370
revs = repo.get_revisions(revhistory)
1371
cache = HistoryCache(revs)
1372
except bzrerrors.InvalidHttpResponse:
1373
# Fallback to dummy algorithm, because of LP: #115209
1374
cache = HistoryCache([])
1377
if item.parent_id == self.remote_parent:
1378
rev = cache._lookup_revision(item.revision)
1379
liststore.append([ gtk.STOCK_DIRECTORY,
1387
self._format_date(rev.timestamp),
1390
while gtk.events_pending():
1391
gtk.main_iteration()
1394
if item.parent_id == self.remote_parent:
1395
rev = cache._lookup_revision(item.revision)
1396
liststore.append([ gtk.STOCK_FILE,
1401
str(item.text_size),
1402
self._format_size(item.text_size),
1404
self._format_date(rev.timestamp),
1407
while gtk.events_pending():
1408
gtk.main_iteration()
1410
self.image_location_error.destroy()
1412
# Columns should auto-size
1413
self.treeview_right.columns_autosize()
1416
self.set_sensitivity()
1418
def _harddisks(self):
1419
""" Returns hard drive letters under Win32. """
1424
if sys.platform == 'win32':
1425
print "pyWin32 modules needed to run Olive on Win32."
1431
for drive in string.ascii_uppercase:
1432
if win32file.GetDriveType(drive+':') == win32file.DRIVE_FIXED:
1433
driveletters.append(drive+':')
1436
def gen_hard_selector(self):
1437
""" Generate the hard drive selector under Win32. """
1438
drives = self._harddisks()
1439
for drive in drives:
1440
self.combobox_drive.append_text(drive)
1441
self.combobox_drive.set_active(drives.index(os.getcwd()[0:2]))
1443
def _refresh_drives(self, combobox):
1444
if self._just_started:
1446
model = combobox.get_model()
1447
active = combobox.get_active()
1449
drive = model[active][0]
1450
self.set_path(drive + '\\')
1451
self.refresh_right(drive + '\\')
1453
def check_for_changes(self):
1454
""" Check whether there were changes in the current working tree. """
1455
old_tree = self.wt.branch.repository.revision_tree(self.wt.branch.last_revision())
1456
delta = self.wt.changes_from(old_tree)
1460
if len(delta.added) or len(delta.removed) or len(delta.renamed) or len(delta.modified):
1465
def _sort_filelist_callback(self, model, iter1, iter2, data):
1466
""" The sort callback for the file list, return values:
1471
name1 = model.get_value(iter1, 2)
1472
name2 = model.get_value(iter2, 2)
1474
if model.get_value(iter1, 1):
1475
# item1 is a directory
1476
if not model.get_value(iter2, 1):
1480
# both of them are directories, we compare their names
1483
elif name1 == name2:
1488
# item1 is not a directory
1489
if model.get_value(iter2, 1):
1493
# both of them are files, compare them
1496
elif name1 == name2:
1501
def _format_size(self, size):
1502
""" Format size to a human readable format. """
1504
return "%d[B]" % (size,)
1505
size = size / 1000.0
1507
for metric in ["kB","MB","GB","TB"]:
1510
size = size / 1000.0
1511
return "%.1f[%s]" % (size,metric)
1513
def _format_date(self, timestamp):
1514
""" Format the time (given in secs) to a human readable format. """
1515
return time.ctime(timestamp)
1517
def _is_remote_dir(self, location):
1518
""" Determine whether the given location is a directory or not. """
1520
# We're in local mode
1523
branch, path = Branch.open_containing(location)
1524
for (name, type) in self.remote_entries:
1525
if name == path and type.kind == 'directory':
1528
# Either it's not a directory or not in the inventory
1531
def _show_stock_image(self, stock_id):
1532
""" Show a stock image next to the location entry. """
1533
self.image_location_error.destroy()
1534
self.image_location_error = gtk.image_new_from_stock(stock_id, gtk.ICON_SIZE_BUTTON)
1535
self.hbox_location.pack_start(self.image_location_error, False, False, 0)
1536
if sys.platform == 'win32':
1537
self.hbox_location.reorder_child(self.image_location_error, 2)
1539
self.hbox_location.reorder_child(self.image_location_error, 1)
1540
self.image_location_error.show()
1541
while gtk.events_pending():
1542
gtk.main_iteration()
1547
""" A class which handles Olive's preferences. """
1548
def __init__(self, path=None):
1549
""" Initialize the Preferences class. """
1550
# Some default options
1551
self.defaults = { 'strict_commit' : False,
1552
'dotted_files' : False,
1553
'ignored_files' : True,
1554
'window_width' : 700,
1555
'window_height' : 400,
1558
'paned_position': 200 }
1560
# Create a config parser object
1561
self.config = ConfigParser.RawConfigParser()
1565
if sys.platform == 'win32':
1566
# Windows - no dotted files
1567
self._filename = os.path.expanduser('~/olive.conf')
1569
self._filename = os.path.expanduser('~/.olive.conf')
1571
self._filename = path
1573
# Load the configuration
1576
def _get_default(self, option):
1577
""" Get the default option for a preference. """
1579
ret = self.defaults[option]
1586
""" Refresh the configuration. """
1587
# First write out the changes
1589
# Then load the configuration again
1593
""" Just read the configuration. """
1594
# Re-initialize the config parser object to avoid some bugs
1595
self.config = ConfigParser.RawConfigParser()
1596
self.config.read([self._filename])
1599
""" Write the configuration to the appropriate files. """
1600
fp = open(self._filename, 'w')
1601
self.config.write(fp)
1604
def get_bookmarks(self):
1605
""" Return the list of bookmarks. """
1606
bookmarks = self.config.sections()
1607
if self.config.has_section('preferences'):
1608
bookmarks.remove('preferences')
1611
def add_bookmark(self, path):
1612
""" Add bookmark. """
1614
self.config.add_section(path)
1615
except ConfigParser.DuplicateSectionError:
1620
def get_bookmark_title(self, path):
1621
""" Get bookmark title. """
1623
ret = self.config.get(path, 'title')
1624
except ConfigParser.NoOptionError:
1629
def set_bookmark_title(self, path, title):
1630
""" Set bookmark title. """
1631
# FIXME: What if path isn't listed yet?
1632
# FIXME: Canonicalize paths first?
1633
self.config.set(path, 'title', title)
1635
def remove_bookmark(self, path):
1636
""" Remove bookmark. """
1637
return self.config.remove_section(path)
1639
def set_preference(self, option, value):
1640
""" Set the value of the given option. """
1643
elif value is False:
1646
if self.config.has_section('preferences'):
1647
self.config.set('preferences', option, value)
1649
self.config.add_section('preferences')
1650
self.config.set('preferences', option, value)
1652
def get_preference(self, option, kind='str'):
1653
""" Get the value of the given option.
1655
:param kind: str/bool/int/float. default: str
1657
if self.config.has_option('preferences', option):
1659
return self.config.getboolean('preferences', option)
1661
return self.config.getint('preferences', option)
1662
elif kind == 'float':
1663
return self.config.getfloat('preferences', option)
1665
return self.config.get('preferences', option)
1668
return self._get_default(option)