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
commit = CommitDialog(self.wt, self.wtpath, self.notbranch, self.get_selected_right(), self.window)
506
response = commit.run()
507
if response != gtk.RESPONSE_NONE:
510
if response == gtk.RESPONSE_OK:
515
def on_menuitem_branch_conflicts_activate(self, widget):
516
""" Branch/Conflicts... menu handler. """
517
conflicts = ConflictsDialog(self.wt, self.window)
518
response = conflicts.run()
519
if response != gtk.RESPONSE_NONE:
522
def on_menuitem_branch_merge_activate(self, widget):
523
""" Branch/Merge... menu handler. """
524
from bzrlib.plugins.gtk.merge import MergeDialog
526
if self.check_for_changes():
527
error_dialog(_('There are local changes in the branch'),
528
_('Please commit or revert the changes before merging.'))
530
merge = MergeDialog(self.wt, self.wtpath)
534
def on_menuitem_branch_missing_revisions_activate(self, widget):
535
""" Branch/Missing revisions menu handler. """
536
local_branch = self.wt.branch
538
other_branch = local_branch.get_parent()
539
if other_branch is None:
540
error_dialog(_('Parent location is unknown'),
541
_('Cannot determine missing revisions if no parent location is known.'))
544
remote_branch = Branch.open(other_branch)
546
if remote_branch.base == local_branch.base:
547
remote_branch = local_branch
549
ret = len(local_branch.missing_revisions(remote_branch))
552
info_dialog(_('There are missing revisions'),
553
_('%d revision(s) missing.') % ret)
555
info_dialog(_('Local branch up to date'),
556
_('There are no missing revisions.'))
559
def on_menuitem_branch_pull_activate(self, widget):
560
""" Branch/Pull menu handler. """
561
branch_to = self.wt.branch
563
location = branch_to.get_parent()
565
error_dialog(_('Parent location is unknown'),
566
_('Pulling is not possible until there is a parent location.'))
569
branch_from = Branch.open(location)
571
if branch_to.get_parent() is None:
572
branch_to.set_parent(branch_from.base)
574
ret = branch_to.pull(branch_from)
576
info_dialog(_('Pull successful'), _('%d revision(s) pulled.') % ret)
579
def on_menuitem_branch_update_activate(self, widget):
580
""" Brranch/checkout update menu handler. """
582
ret = self.wt.update()
583
conflicts = self.wt.conflicts()
585
info_dialog(_('Update successful but conflicts generated'), _('Number of conflicts generated: %d.') % (len(conflicts),) )
587
info_dialog(_('Update successful'), _('No conflicts generated.') )
589
def on_menuitem_branch_push_activate(self, widget):
590
""" Branch/Push... menu handler. """
591
push = PushDialog(repository=None,revid=None,branch=self.wt.branch, parent=self.window)
592
response = push.run()
593
if response != gtk.RESPONSE_NONE:
597
def on_menuitem_branch_revert_activate(self, widget):
598
""" Branch/Revert all changes menu handler. """
599
ret = self.wt.revert([])
601
warning_dialog(_('Conflicts detected'),
602
_('Please have a look at the working tree before continuing.'))
604
info_dialog(_('Revert successful'),
605
_('All files reverted to last revision.'))
608
def on_menuitem_branch_status_activate(self, widget):
609
""" Branch/Status... menu handler. """
610
from bzrlib.plugins.gtk.status import StatusDialog
611
status = StatusDialog(self.wt, self.wtpath)
612
response = status.run()
613
if response != gtk.RESPONSE_NONE:
616
def on_menuitem_branch_initialize_activate(self, widget):
617
""" Initialize current directory. """
618
init = InitDialog(self.path, self.window)
619
response = init.run()
620
if response != gtk.RESPONSE_NONE:
623
if response == gtk.RESPONSE_OK:
628
def on_menuitem_branch_tags_activate(self, widget):
629
""" Branch/Tags... menu handler. """
630
from bzrlib.plugins.gtk.tags import TagsWindow
632
window = TagsWindow(self.wt.branch, self.window)
634
window = TagsWindow(self.remote_branch, self.window)
637
def on_menuitem_file_annotate_activate(self, widget):
638
""" File/Annotate... menu handler. """
639
if self.get_selected_right() is None:
640
error_dialog(_('No file was selected'),
641
_('Please select a file from the list.'))
644
branch = self.wt.branch
645
file_id = self.wt.path2id(self.wt.relpath(os.path.join(self.path, self.get_selected_right())))
647
window = GAnnotateWindow(all=False, plain=False)
648
window.set_title(os.path.join(self.path, self.get_selected_right()) + " - Annotate")
649
config = GAnnotateConfig(window)
653
window.annotate(self.wt, branch, file_id)
657
def on_menuitem_file_make_directory_activate(self, widget):
658
""" File/Make directory... menu handler. """
659
from mkdir import OliveMkdir
660
mkdir = OliveMkdir(self.wt, self.wtpath)
663
def on_menuitem_file_move_activate(self, widget):
664
""" File/Move... menu handler. """
665
from move import OliveMove
666
move = OliveMove(self.wt, self.wtpath, self.get_selected_right())
669
def on_menuitem_file_rename_activate(self, widget):
670
""" File/Rename... menu handler. """
671
from rename import OliveRename
672
rename = OliveRename(self.wt, self.wtpath, self.get_selected_right())
675
def on_menuitem_remove_file_activate(self, widget):
676
""" Remove (unversion) selected file. """
677
from remove import OliveRemoveDialog
678
remove = OliveRemoveDialog(self.wt, self.wtpath,
679
selected=self.get_selected_right(),
681
response = remove.run()
683
if response != gtk.RESPONSE_NONE:
686
if response == gtk.RESPONSE_OK:
687
self.set_path(self.path)
692
def on_menuitem_stats_diff_activate(self, widget):
693
""" Statistics/Differences... menu handler. """
694
window = DiffWindow()
695
parent_tree = self.wt.branch.repository.revision_tree(self.wt.branch.last_revision())
696
window.set_diff(self.wt.branch.nick, self.wt, parent_tree)
699
def on_menuitem_stats_infos_activate(self, widget):
700
""" Statistics/Informations... menu handler. """
701
from info import OliveInfo
703
info = OliveInfo(self.remote_branch)
705
info = OliveInfo(self.wt.branch)
708
def on_menuitem_stats_log_activate(self, widget):
709
""" Statistics/Log... menu handler. """
710
window = branchwin.BranchWindow()
712
window.set_branch(self.wt.branch, self.wt.branch.last_revision(), None)
714
window.set_branch(self.remote_branch, self.remote_branch.last_revision(), None)
717
def on_menuitem_view_refresh_activate(self, widget):
718
""" View/Refresh menu handler. """
719
# Refresh the left pane
721
# Refresh the right pane
724
def on_menuitem_view_show_hidden_files_activate(self, widget):
725
""" View/Show hidden files menu handler. """
726
self.pref.set_preference('dotted_files', widget.get_active())
727
if self.path is not None:
730
def on_menuitem_view_show_ignored_files_activate(self, widget):
731
""" Hide/Show ignored files menu handler. """
732
self.pref.set_preference('ignored_files', widget.get_active())
733
if self.path is not None:
736
def on_treeview_left_button_press_event(self, widget, event):
737
""" Occurs when somebody right-clicks in the bookmark list. """
738
if event.button == 3:
739
# Don't show context with nothing selected
740
if self.get_selected_left() == None:
744
from menu import OliveMenu
745
menu = OliveMenu(path=self.get_path(),
746
selected=self.get_selected_left(),
749
menu.left_context_menu().popup(None, None, None, 0,
752
def on_treeview_left_row_activated(self, treeview, path, view_column):
753
""" Occurs when somebody double-clicks or enters an item in the
756
newdir = self.get_selected_left()
760
if self.set_path(newdir):
763
def on_treeview_right_button_press_event(self, widget, event):
764
""" Occurs when somebody right-clicks in the file list. """
765
if event.button == 3:
767
from menu import OliveMenu
768
menu = OliveMenu(path=self.get_path(),
769
selected=self.get_selected_right(),
772
m_open = menu.ui.get_widget('/context_right/open')
773
m_add = menu.ui.get_widget('/context_right/add')
774
m_remove = menu.ui.get_widget('/context_right/remove')
775
m_rename = menu.ui.get_widget('/context_right/rename')
776
m_revert = menu.ui.get_widget('/context_right/revert')
777
m_commit = menu.ui.get_widget('/context_right/commit')
778
m_annotate = menu.ui.get_widget('/context_right/annotate')
779
m_diff = menu.ui.get_widget('/context_right/diff')
780
# check if we're in a branch
782
from bzrlib.branch import Branch
783
Branch.open_containing(self.get_path())
785
m_open.set_sensitive(False)
786
m_add.set_sensitive(False)
787
m_remove.set_sensitive(False)
788
m_rename.set_sensitive(False)
789
m_revert.set_sensitive(False)
790
m_commit.set_sensitive(False)
791
m_annotate.set_sensitive(False)
792
m_diff.set_sensitive(False)
794
m_open.set_sensitive(True)
795
m_add.set_sensitive(True)
796
m_remove.set_sensitive(True)
797
m_rename.set_sensitive(True)
798
m_revert.set_sensitive(True)
799
m_commit.set_sensitive(True)
800
m_annotate.set_sensitive(True)
801
m_diff.set_sensitive(True)
802
except bzrerrors.NotBranchError:
803
m_open.set_sensitive(True)
804
m_add.set_sensitive(False)
805
m_remove.set_sensitive(False)
806
m_rename.set_sensitive(False)
807
m_revert.set_sensitive(False)
808
m_commit.set_sensitive(False)
809
m_annotate.set_sensitive(False)
810
m_diff.set_sensitive(False)
813
menu.right_context_menu().popup(None, None, None, 0,
816
menu.remote_context_menu().popup(None, None, None, 0,
819
def on_treeview_right_row_activated(self, treeview, path, view_column):
820
""" Occurs when somebody double-clicks or enters an item in the
822
from launch import launch
824
newdir = self.get_selected_right()
829
self.set_path(os.path.split(self.get_path())[0])
831
fullpath = os.path.join(self.get_path(), newdir)
832
if os.path.isdir(fullpath):
833
# selected item is an existant directory
834
self.set_path(fullpath)
839
if self._is_remote_dir(self.get_path() + newdir):
840
self.set_path(self.get_path() + newdir)
844
def on_window_main_delete_event(self, widget, event=None):
845
""" Do some stuff before exiting. """
846
width, height = self.window_main.get_size()
847
self.pref.set_preference('window_width', width)
848
self.pref.set_preference('window_height', height)
849
x, y = self.window_main.get_position()
850
self.pref.set_preference('window_x', x)
851
self.pref.set_preference('window_y', y)
852
self.pref.set_preference('paned_position',
853
self.hpaned_main.get_position())
856
self.window_main.destroy()
858
def _load_left(self):
859
""" Load data into the left panel. (Bookmarks) """
861
treestore = gtk.TreeStore(str, str)
864
bookmarks = self.pref.get_bookmarks()
866
# Add them to the TreeStore
867
titer = treestore.append(None, [_('Bookmarks'), None])
868
for item in bookmarks:
869
title = self.pref.get_bookmark_title(item)
870
treestore.append(titer, [title, item])
872
# Create the column and add it to the TreeView
873
self.treeview_left.set_model(treestore)
874
tvcolumn_bookmark = gtk.TreeViewColumn(_('Bookmark'))
875
self.treeview_left.append_column(tvcolumn_bookmark)
878
cell = gtk.CellRendererText()
879
tvcolumn_bookmark.pack_start(cell, True)
880
tvcolumn_bookmark.add_attribute(cell, 'text', 0)
883
self.treeview_left.expand_all()
885
def _load_right(self):
886
""" Load data into the right panel. (Filelist) """
888
# Model: [ icon, dir, name, status text, status, size (int), size (human), mtime (int), mtime (local), fileid ]
889
liststore = gtk.ListStore(gobject.TYPE_STRING,
890
gobject.TYPE_BOOLEAN,
903
# Fill the appropriate lists
904
dotted_files = self.pref.get_preference('dotted_files', 'bool')
905
for item in os.listdir(self.path):
906
if not dotted_files and item[0] == '.':
908
if os.path.isdir(self.path + os.sep + item):
913
if not self.notbranch:
914
branch = self.wt.branch
915
tree2 = self.wt.branch.repository.revision_tree(branch.last_revision())
917
delta = self.wt.changes_from(tree2, want_unchanged=True)
919
# Add'em to the ListStore
921
statinfo = os.stat(self.path + os.sep + item)
922
liststore.append([ gtk.STOCK_DIRECTORY,
930
self._format_date(statinfo.st_mtime),
935
if not self.notbranch:
936
filename = self.wt.relpath(self.path + os.sep + item)
941
for rpath, rpathnew, id, kind, text_modified, meta_modified in delta.renamed:
942
if rpathnew == filename:
945
for rpath, id, kind in delta.added:
946
if rpath == filename:
949
for rpath, id, kind in delta.removed:
950
if rpath == filename:
953
for rpath, id, kind, text_modified, meta_modified in delta.modified:
954
if rpath == filename:
957
for rpath, id, kind in delta.unchanged:
958
if rpath == filename:
961
for rpath, file_class, kind, id, entry in self.wt.list_files():
962
if rpath == filename and file_class == 'I':
967
if status == 'renamed':
969
elif status == 'removed':
971
elif status == 'added':
973
elif status == 'modified':
975
elif status == 'unchanged':
977
elif status == 'ignored':
982
statinfo = os.stat(self.path + os.sep + item)
983
liststore.append([gtk.STOCK_FILE,
988
str(statinfo.st_size), # NOTE: if int used there it will fail for large files (size expressed as long int)
989
self._format_size(statinfo.st_size),
991
self._format_date(statinfo.st_mtime),
994
# Create the columns and add them to the TreeView
995
self.treeview_right.set_model(liststore)
996
self._tvcolumn_filename = gtk.TreeViewColumn(_('Filename'))
997
self._tvcolumn_status = gtk.TreeViewColumn(_('Status'))
998
self._tvcolumn_size = gtk.TreeViewColumn(_('Size'))
999
self._tvcolumn_mtime = gtk.TreeViewColumn(_('Last modified'))
1000
self.treeview_right.append_column(self._tvcolumn_filename)
1001
self.treeview_right.append_column(self._tvcolumn_status)
1002
self.treeview_right.append_column(self._tvcolumn_size)
1003
self.treeview_right.append_column(self._tvcolumn_mtime)
1006
cellpb = gtk.CellRendererPixbuf()
1007
cell = gtk.CellRendererText()
1008
self._tvcolumn_filename.pack_start(cellpb, False)
1009
self._tvcolumn_filename.pack_start(cell, True)
1010
self._tvcolumn_filename.set_attributes(cellpb, stock_id=0)
1011
self._tvcolumn_filename.add_attribute(cell, 'text', 2)
1012
self._tvcolumn_status.pack_start(cell, True)
1013
self._tvcolumn_status.add_attribute(cell, 'text', 3)
1014
self._tvcolumn_size.pack_start(cell, True)
1015
self._tvcolumn_size.add_attribute(cell, 'text', 6)
1016
self._tvcolumn_mtime.pack_start(cell, True)
1017
self._tvcolumn_mtime.add_attribute(cell, 'text', 8)
1019
# Set up the properties of the TreeView
1020
self.treeview_right.set_headers_visible(True)
1021
self.treeview_right.set_headers_clickable(True)
1022
self.treeview_right.set_search_column(1)
1023
self._tvcolumn_filename.set_resizable(True)
1024
self._tvcolumn_status.set_resizable(True)
1025
self._tvcolumn_size.set_resizable(True)
1026
self._tvcolumn_mtime.set_resizable(True)
1028
liststore.set_sort_func(13, self._sort_filelist_callback, None)
1029
liststore.set_sort_column_id(13, gtk.SORT_ASCENDING)
1030
self._tvcolumn_filename.set_sort_column_id(13)
1031
self._tvcolumn_status.set_sort_column_id(3)
1032
self._tvcolumn_size.set_sort_column_id(5)
1033
self._tvcolumn_mtime.set_sort_column_id(7)
1036
self.set_sensitivity()
1038
def get_selected_fileid(self):
1039
""" Get the file_id of the selected file. """
1040
treeselection = self.treeview_right.get_selection()
1041
(model, iter) = treeselection.get_selected()
1046
return model.get_value(iter, 9)
1048
def get_selected_right(self):
1049
""" Get the selected filename. """
1050
treeselection = self.treeview_right.get_selection()
1051
(model, iter) = treeselection.get_selected()
1056
return model.get_value(iter, 2)
1058
def get_selected_left(self):
1059
""" Get the selected bookmark. """
1060
treeselection = self.treeview_left.get_selection()
1061
(model, iter) = treeselection.get_selected()
1066
return model.get_value(iter, 1)
1068
def set_statusbar(self, message):
1069
""" Set the statusbar message. """
1070
self.statusbar.push(self.context_id, message)
1072
def clear_statusbar(self):
1073
""" Clean the last message from the statusbar. """
1074
self.statusbar.pop(self.context_id)
1076
def set_sensitivity(self):
1077
""" Set menu and toolbar sensitivity. """
1080
self.menuitem_branch_init.set_sensitive(self.notbranch)
1081
self.menuitem_branch_get.set_sensitive(self.notbranch)
1082
self.menuitem_branch_checkout.set_sensitive(self.notbranch)
1083
self.menuitem_branch_pull.set_sensitive(not self.notbranch)
1084
self.menuitem_branch_push.set_sensitive(not self.notbranch)
1085
self.menuitem_branch_update.set_sensitive(not self.notbranch)
1086
self.menuitem_branch_revert.set_sensitive(not self.notbranch)
1087
self.menuitem_branch_merge.set_sensitive(not self.notbranch)
1088
self.menuitem_branch_commit.set_sensitive(not self.notbranch)
1089
self.menuitem_branch_tags.set_sensitive(not self.notbranch)
1090
self.menuitem_branch_status.set_sensitive(not self.notbranch)
1091
self.menuitem_branch_missing.set_sensitive(not self.notbranch)
1092
self.menuitem_branch_conflicts.set_sensitive(not self.notbranch)
1093
self.menuitem_stats.set_sensitive(not self.notbranch)
1094
self.menuitem_stats_diff.set_sensitive(not self.notbranch)
1095
self.menuitem_add_files.set_sensitive(not self.notbranch)
1096
self.menuitem_remove_files.set_sensitive(not self.notbranch)
1097
self.menuitem_file_make_directory.set_sensitive(not self.notbranch)
1098
self.menuitem_file_rename.set_sensitive(not self.notbranch)
1099
self.menuitem_file_move.set_sensitive(not self.notbranch)
1100
self.menuitem_file_annotate.set_sensitive(not self.notbranch)
1101
#self.menutoolbutton_diff.set_sensitive(True)
1102
self.toolbutton_diff.set_sensitive(not self.notbranch)
1103
self.toolbutton_log.set_sensitive(not self.notbranch)
1104
self.toolbutton_commit.set_sensitive(not self.notbranch)
1105
self.toolbutton_pull.set_sensitive(not self.notbranch)
1106
self.toolbutton_push.set_sensitive(not self.notbranch)
1107
self.toolbutton_update.set_sensitive(not self.notbranch)
1110
self.menuitem_branch_init.set_sensitive(False)
1111
self.menuitem_branch_get.set_sensitive(True)
1112
self.menuitem_branch_checkout.set_sensitive(True)
1113
self.menuitem_branch_pull.set_sensitive(False)
1114
self.menuitem_branch_push.set_sensitive(False)
1115
self.menuitem_branch_update.set_sensitive(False)
1116
self.menuitem_branch_revert.set_sensitive(False)
1117
self.menuitem_branch_merge.set_sensitive(False)
1118
self.menuitem_branch_commit.set_sensitive(False)
1119
self.menuitem_branch_tags.set_sensitive(True)
1120
self.menuitem_branch_status.set_sensitive(False)
1121
self.menuitem_branch_missing.set_sensitive(False)
1122
self.menuitem_branch_conflicts.set_sensitive(False)
1123
self.menuitem_stats.set_sensitive(True)
1124
self.menuitem_stats_diff.set_sensitive(False)
1125
self.menuitem_add_files.set_sensitive(False)
1126
self.menuitem_remove_files.set_sensitive(False)
1127
self.menuitem_file_make_directory.set_sensitive(False)
1128
self.menuitem_file_rename.set_sensitive(False)
1129
self.menuitem_file_move.set_sensitive(False)
1130
self.menuitem_file_annotate.set_sensitive(False)
1131
#self.menutoolbutton_diff.set_sensitive(True)
1132
self.toolbutton_diff.set_sensitive(False)
1133
self.toolbutton_log.set_sensitive(True)
1134
self.toolbutton_commit.set_sensitive(False)
1135
self.toolbutton_pull.set_sensitive(False)
1136
self.toolbutton_push.set_sensitive(False)
1137
self.toolbutton_update.set_sensitive(False)
1139
def refresh_left(self):
1140
""" Refresh the bookmark list. """
1142
# Get TreeStore and clear it
1143
treestore = self.treeview_left.get_model()
1146
# Re-read preferences
1150
bookmarks = self.pref.get_bookmarks()
1152
# Add them to the TreeStore
1153
titer = treestore.append(None, [_('Bookmarks'), None])
1154
for item in bookmarks:
1155
title = self.pref.get_bookmark_title(item)
1156
treestore.append(titer, [title, item])
1158
# Add the TreeStore to the TreeView
1159
self.treeview_left.set_model(treestore)
1162
self.treeview_left.expand_all()
1164
def refresh_right(self, path=None):
1165
""" Refresh the file list. """
1168
from bzrlib.workingtree import WorkingTree
1171
path = self.get_path()
1173
# A workaround for double-clicking Bookmarks
1174
if not os.path.exists(path):
1177
# Get ListStore and clear it
1178
liststore = self.treeview_right.get_model()
1181
# Show Status column
1182
self._tvcolumn_status.set_visible(True)
1187
# Fill the appropriate lists
1188
dotted_files = self.pref.get_preference('dotted_files', 'bool')
1189
ignored_files = self.pref.get_preference('ignored_files', 'bool')
1191
for item in os.listdir(path):
1192
if not dotted_files and item[0] == '.':
1194
if os.path.isdir(path + os.sep + item):
1199
# Try to open the working tree
1202
tree1 = WorkingTree.open_containing(path)[0]
1203
except (bzrerrors.NotBranchError, bzrerrors.NoWorkingTree):
1207
branch = tree1.branch
1208
tree2 = tree1.branch.repository.revision_tree(branch.last_revision())
1210
delta = tree1.changes_from(tree2, want_unchanged=True)
1212
# Add'em to the ListStore
1214
statinfo = os.stat(self.path + os.sep + item)
1215
liststore.append([gtk.STOCK_DIRECTORY,
1223
self._format_date(statinfo.st_mtime),
1229
filename = tree1.relpath(path + os.sep + item)
1234
for rpath, rpathnew, id, kind, text_modified, meta_modified in delta.renamed:
1235
if rpathnew == filename:
1238
for rpath, id, kind in delta.added:
1239
if rpath == filename:
1242
for rpath, id, kind in delta.removed:
1243
if rpath == filename:
1246
for rpath, id, kind, text_modified, meta_modified in delta.modified:
1247
if rpath == filename:
1250
for rpath, id, kind in delta.unchanged:
1251
if rpath == filename:
1252
status = 'unchanged'
1254
for rpath, file_class, kind, id, entry in self.wt.list_files():
1255
if rpath == filename and file_class == 'I':
1260
if status == 'renamed':
1262
elif status == 'removed':
1264
elif status == 'added':
1266
elif status == 'modified':
1268
elif status == 'unchanged':
1270
elif status == 'ignored':
1272
if not ignored_files:
1277
statinfo = os.stat(self.path + os.sep + item)
1278
liststore.append([gtk.STOCK_FILE,
1283
str(statinfo.st_size),
1284
self._format_size(statinfo.st_size),
1286
self._format_date(statinfo.st_mtime),
1291
# Get ListStore and clear it
1292
liststore = self.treeview_right.get_model()
1295
# Hide Status column
1296
self._tvcolumn_status.set_visible(False)
1301
self._show_stock_image(gtk.STOCK_REFRESH)
1303
for (name, type) in self.remote_entries:
1304
if type.kind == 'directory':
1306
elif type.kind == 'file':
1310
""" Cache based on revision history. """
1311
def __init__(self, history):
1312
self._history = history
1314
def _lookup_revision(self, revid):
1315
for r in self._history:
1316
if r.revision_id == revid:
1318
rev = repo.get_revision(revid)
1319
self._history.append(rev)
1322
repo = self.remote_branch.repository
1324
revhistory = self.remote_branch.revision_history()
1326
revs = repo.get_revisions(revhistory)
1327
cache = HistoryCache(revs)
1328
except bzrerrors.InvalidHttpResponse:
1329
# Fallback to dummy algorithm, because of LP: #115209
1330
cache = HistoryCache([])
1333
if item.parent_id == self.remote_parent:
1334
rev = cache._lookup_revision(item.revision)
1335
liststore.append([ gtk.STOCK_DIRECTORY,
1343
self._format_date(rev.timestamp),
1346
while gtk.events_pending():
1347
gtk.main_iteration()
1350
if item.parent_id == self.remote_parent:
1351
rev = cache._lookup_revision(item.revision)
1352
liststore.append([ gtk.STOCK_FILE,
1357
str(item.text_size),
1358
self._format_size(item.text_size),
1360
self._format_date(rev.timestamp),
1363
while gtk.events_pending():
1364
gtk.main_iteration()
1366
self.image_location_error.destroy()
1368
# Columns should auto-size
1369
self.treeview_right.columns_autosize()
1372
self.set_sensitivity()
1374
def _harddisks(self):
1375
""" Returns hard drive letters under Win32. """
1380
if sys.platform == 'win32':
1381
print "pyWin32 modules needed to run Olive on Win32."
1387
for drive in string.ascii_uppercase:
1388
if win32file.GetDriveType(drive+':') == win32file.DRIVE_FIXED:
1389
driveletters.append(drive+':')
1392
def gen_hard_selector(self):
1393
""" Generate the hard drive selector under Win32. """
1394
drives = self._harddisks()
1395
for drive in drives:
1396
self.combobox_drive.append_text(drive)
1397
self.combobox_drive.set_active(drives.index(os.getcwd()[0:2]))
1399
def _refresh_drives(self, combobox):
1400
if self._just_started:
1402
model = combobox.get_model()
1403
active = combobox.get_active()
1405
drive = model[active][0]
1406
self.set_path(drive + '\\')
1407
self.refresh_right(drive + '\\')
1409
def check_for_changes(self):
1410
""" Check whether there were changes in the current working tree. """
1411
old_tree = self.wt.branch.repository.revision_tree(self.wt.branch.last_revision())
1412
delta = self.wt.changes_from(old_tree)
1416
if len(delta.added) or len(delta.removed) or len(delta.renamed) or len(delta.modified):
1421
def _sort_filelist_callback(self, model, iter1, iter2, data):
1422
""" The sort callback for the file list, return values:
1427
name1 = model.get_value(iter1, 2)
1428
name2 = model.get_value(iter2, 2)
1430
if model.get_value(iter1, 1):
1431
# item1 is a directory
1432
if not model.get_value(iter2, 1):
1436
# both of them are directories, we compare their names
1439
elif name1 == name2:
1444
# item1 is not a directory
1445
if model.get_value(iter2, 1):
1449
# both of them are files, compare them
1452
elif name1 == name2:
1457
def _format_size(self, size):
1458
""" Format size to a human readable format. """
1460
return "%d[B]" % (size,)
1461
size = size / 1000.0
1463
for metric in ["kB","MB","GB","TB"]:
1466
size = size / 1000.0
1467
return "%.1f[%s]" % (size,metric)
1469
def _format_date(self, timestamp):
1470
""" Format the time (given in secs) to a human readable format. """
1471
return time.ctime(timestamp)
1473
def _is_remote_dir(self, location):
1474
""" Determine whether the given location is a directory or not. """
1476
# We're in local mode
1479
branch, path = Branch.open_containing(location)
1480
for (name, type) in self.remote_entries:
1481
if name == path and type.kind == 'directory':
1484
# Either it's not a directory or not in the inventory
1487
def _show_stock_image(self, stock_id):
1488
""" Show a stock image next to the location entry. """
1489
self.image_location_error.destroy()
1490
self.image_location_error = gtk.image_new_from_stock(stock_id, gtk.ICON_SIZE_BUTTON)
1491
self.hbox_location.pack_start(self.image_location_error, False, False, 0)
1492
if sys.platform == 'win32':
1493
self.hbox_location.reorder_child(self.image_location_error, 2)
1495
self.hbox_location.reorder_child(self.image_location_error, 1)
1496
self.image_location_error.show()
1497
while gtk.events_pending():
1498
gtk.main_iteration()
1503
""" A class which handles Olive's preferences. """
1504
def __init__(self, path=None):
1505
""" Initialize the Preferences class. """
1506
# Some default options
1507
self.defaults = { 'strict_commit' : False,
1508
'dotted_files' : False,
1509
'ignored_files' : True,
1510
'window_width' : 700,
1511
'window_height' : 400,
1514
'paned_position': 200 }
1516
# Create a config parser object
1517
self.config = ConfigParser.RawConfigParser()
1521
if sys.platform == 'win32':
1522
# Windows - no dotted files
1523
self._filename = os.path.expanduser('~/olive.conf')
1525
self._filename = os.path.expanduser('~/.olive.conf')
1527
self._filename = path
1529
# Load the configuration
1532
def _get_default(self, option):
1533
""" Get the default option for a preference. """
1535
ret = self.defaults[option]
1542
""" Refresh the configuration. """
1543
# First write out the changes
1545
# Then load the configuration again
1549
""" Just read the configuration. """
1550
# Re-initialize the config parser object to avoid some bugs
1551
self.config = ConfigParser.RawConfigParser()
1552
self.config.read([self._filename])
1555
""" Write the configuration to the appropriate files. """
1556
fp = open(self._filename, 'w')
1557
self.config.write(fp)
1560
def get_bookmarks(self):
1561
""" Return the list of bookmarks. """
1562
bookmarks = self.config.sections()
1563
if self.config.has_section('preferences'):
1564
bookmarks.remove('preferences')
1567
def add_bookmark(self, path):
1568
""" Add bookmark. """
1570
self.config.add_section(path)
1571
except ConfigParser.DuplicateSectionError:
1576
def get_bookmark_title(self, path):
1577
""" Get bookmark title. """
1579
ret = self.config.get(path, 'title')
1580
except ConfigParser.NoOptionError:
1585
def set_bookmark_title(self, path, title):
1586
""" Set bookmark title. """
1587
# FIXME: What if path isn't listed yet?
1588
# FIXME: Canonicalize paths first?
1589
self.config.set(path, 'title', title)
1591
def remove_bookmark(self, path):
1592
""" Remove bookmark. """
1593
return self.config.remove_section(path)
1595
def set_preference(self, option, value):
1596
""" Set the value of the given option. """
1599
elif value is False:
1602
if self.config.has_section('preferences'):
1603
self.config.set('preferences', option, value)
1605
self.config.add_section('preferences')
1606
self.config.set('preferences', option, value)
1608
def get_preference(self, option, kind='str'):
1609
""" Get the value of the given option.
1611
:param kind: str/bool/int/float. default: str
1613
if self.config.has_option('preferences', option):
1615
return self.config.getboolean('preferences', option)
1617
return self.config.getint('preferences', option)
1618
elif kind == 'float':
1619
return self.config.getfloat('preferences', option)
1621
return self.config.get('preferences', option)
1624
return self._get_default(option)