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
parent_branch_path = self.wt.branch.get_parent()
531
merge = MergeDialog(self.wt, self.wtpath,default_branch_path=parent_branch_path )
535
def on_menuitem_branch_missing_revisions_activate(self, widget):
536
""" Branch/Missing revisions menu handler. """
538
from bzrlib.missing import find_unmerged, iter_log_revisions
540
local_branch = self.wt.branch
541
parent_branch_path = local_branch.get_parent()
542
if parent_branch_path is None:
543
error_dialog(_('Parent location is unknown'),
544
_('Cannot determine missing revisions if no parent location is known.'))
547
parent_branch = Branch.open(parent_branch_path)
549
if parent_branch.base == local_branch.base:
550
parent_branch = local_branch
552
local_extra, remote_extra = find_unmerged(local_branch,parent_branch)
554
if local_extra or remote_extra:
555
def log_revision_one_line_text(log_revision):
556
""" Generates one line description of log_revison ended with end of line."""
557
revision = log_revision.rev
558
txt = "- %s (%s)\n" % (revision.get_summary(), revision.committer, )
559
txt = txt.replace("<"," ") # Seems < > chars are expected to be xml tags ...
560
txt = txt.replace(">"," ")
565
dlg_txt += _('%d local extra revision(s):\n') % (len(local_extra),)
567
for log_revision in iter_log_revisions(local_extra, local_branch.repository, verbose=1):
568
dlg_txt += log_revision_one_line_text(log_revision)
569
if max_revisions <= 0:
570
dlg_txt += _("more ... \n")
575
dlg_txt += _('%d local missing revision(s):\n') % (len(remote_extra),)
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")
584
info_dialog(_('There are missing revisions'),
587
info_dialog(_('Local branch up to date'),
588
_('There are no missing revisions.'))
591
def on_menuitem_branch_pull_activate(self, widget):
592
""" Branch/Pull menu handler. """
593
branch_to = self.wt.branch
595
location = branch_to.get_parent()
597
error_dialog(_('Parent location is unknown'),
598
_('Pulling is not possible until there is a parent location.'))
601
branch_from = Branch.open(location)
603
if branch_to.get_parent() is None:
604
branch_to.set_parent(branch_from.base)
606
ret = branch_to.pull(branch_from)
608
info_dialog(_('Pull successful'), _('%d revision(s) pulled.') % ret)
611
def on_menuitem_branch_update_activate(self, widget):
612
""" Brranch/checkout update menu handler. """
614
ret = self.wt.update()
615
conflicts = self.wt.conflicts()
617
info_dialog(_('Update successful but conflicts generated'), _('Number of conflicts generated: %d.') % (len(conflicts),) )
619
info_dialog(_('Update successful'), _('No conflicts generated.') )
621
def on_menuitem_branch_push_activate(self, widget):
622
""" Branch/Push... menu handler. """
623
push = PushDialog(repository=None,revid=None,branch=self.wt.branch, parent=self.window)
624
response = push.run()
625
if response != gtk.RESPONSE_NONE:
629
def on_menuitem_branch_revert_activate(self, widget):
630
""" Branch/Revert all changes menu handler. """
631
ret = self.wt.revert([])
633
warning_dialog(_('Conflicts detected'),
634
_('Please have a look at the working tree before continuing.'))
636
info_dialog(_('Revert successful'),
637
_('All files reverted to last revision.'))
640
def on_menuitem_branch_status_activate(self, widget):
641
""" Branch/Status... menu handler. """
642
from bzrlib.plugins.gtk.status import StatusDialog
643
status = StatusDialog(self.wt, self.wtpath)
644
response = status.run()
645
if response != gtk.RESPONSE_NONE:
648
def on_menuitem_branch_initialize_activate(self, widget):
649
""" Initialize current directory. """
650
init = InitDialog(self.path, self.window)
651
response = init.run()
652
if response != gtk.RESPONSE_NONE:
655
if response == gtk.RESPONSE_OK:
660
def on_menuitem_branch_tags_activate(self, widget):
661
""" Branch/Tags... menu handler. """
662
from bzrlib.plugins.gtk.tags import TagsWindow
664
window = TagsWindow(self.wt.branch, self.window)
666
window = TagsWindow(self.remote_branch, self.window)
669
def on_menuitem_file_annotate_activate(self, widget):
670
""" File/Annotate... menu handler. """
671
if self.get_selected_right() is None:
672
error_dialog(_('No file was selected'),
673
_('Please select a file from the list.'))
676
branch = self.wt.branch
677
file_id = self.wt.path2id(self.wt.relpath(os.path.join(self.path, self.get_selected_right())))
679
window = GAnnotateWindow(all=False, plain=False)
680
window.set_title(os.path.join(self.path, self.get_selected_right()) + " - Annotate")
681
config = GAnnotateConfig(window)
685
window.annotate(self.wt, branch, file_id)
689
def on_menuitem_file_make_directory_activate(self, widget):
690
""" File/Make directory... menu handler. """
691
from mkdir import OliveMkdir
692
mkdir = OliveMkdir(self.wt, self.wtpath)
695
def on_menuitem_file_move_activate(self, widget):
696
""" File/Move... menu handler. """
697
from move import OliveMove
698
move = OliveMove(self.wt, self.wtpath, self.get_selected_right())
701
def on_menuitem_file_rename_activate(self, widget):
702
""" File/Rename... menu handler. """
703
from rename import OliveRename
704
rename = OliveRename(self.wt, self.wtpath, self.get_selected_right())
707
def on_menuitem_remove_file_activate(self, widget):
708
""" Remove (unversion) selected file. """
709
from remove import OliveRemoveDialog
710
remove = OliveRemoveDialog(self.wt, self.wtpath,
711
selected=self.get_selected_right(),
713
response = remove.run()
715
if response != gtk.RESPONSE_NONE:
718
if response == gtk.RESPONSE_OK:
719
self.set_path(self.path)
724
def on_menuitem_stats_diff_activate(self, widget):
725
""" Statistics/Differences... menu handler. """
726
window = DiffWindow()
727
parent_tree = self.wt.branch.repository.revision_tree(self.wt.branch.last_revision())
728
window.set_diff(self.wt.branch.nick, self.wt, parent_tree)
731
def on_menuitem_stats_infos_activate(self, widget):
732
""" Statistics/Informations... menu handler. """
733
from info import OliveInfo
735
info = OliveInfo(self.remote_branch)
737
info = OliveInfo(self.wt.branch)
740
def on_menuitem_stats_log_activate(self, widget):
741
""" Statistics/Log... menu handler. """
742
window = branchwin.BranchWindow()
744
window.set_branch(self.wt.branch, self.wt.branch.last_revision(), None)
746
window.set_branch(self.remote_branch, self.remote_branch.last_revision(), None)
749
def on_menuitem_view_refresh_activate(self, widget):
750
""" View/Refresh menu handler. """
751
# Refresh the left pane
753
# Refresh the right pane
756
def on_menuitem_view_show_hidden_files_activate(self, widget):
757
""" View/Show hidden files menu handler. """
758
self.pref.set_preference('dotted_files', widget.get_active())
759
if self.path is not None:
762
def on_menuitem_view_show_ignored_files_activate(self, widget):
763
""" Hide/Show ignored files menu handler. """
764
self.pref.set_preference('ignored_files', widget.get_active())
765
if self.path is not None:
768
def on_treeview_left_button_press_event(self, widget, event):
769
""" Occurs when somebody right-clicks in the bookmark list. """
770
if event.button == 3:
771
# Don't show context with nothing selected
772
if self.get_selected_left() == None:
776
from menu import OliveMenu
777
menu = OliveMenu(path=self.get_path(),
778
selected=self.get_selected_left(),
781
menu.left_context_menu().popup(None, None, None, 0,
784
def on_treeview_left_row_activated(self, treeview, path, view_column):
785
""" Occurs when somebody double-clicks or enters an item in the
788
newdir = self.get_selected_left()
792
if self.set_path(newdir):
795
def on_treeview_right_button_press_event(self, widget, event):
796
""" Occurs when somebody right-clicks in the file list. """
797
if event.button == 3:
799
from menu import OliveMenu
800
menu = OliveMenu(path=self.get_path(),
801
selected=self.get_selected_right(),
804
m_open = menu.ui.get_widget('/context_right/open')
805
m_add = menu.ui.get_widget('/context_right/add')
806
m_remove = menu.ui.get_widget('/context_right/remove')
807
m_rename = menu.ui.get_widget('/context_right/rename')
808
m_revert = menu.ui.get_widget('/context_right/revert')
809
m_commit = menu.ui.get_widget('/context_right/commit')
810
m_annotate = menu.ui.get_widget('/context_right/annotate')
811
m_diff = menu.ui.get_widget('/context_right/diff')
812
# check if we're in a branch
814
from bzrlib.branch import Branch
815
Branch.open_containing(self.get_path())
817
m_open.set_sensitive(False)
818
m_add.set_sensitive(False)
819
m_remove.set_sensitive(False)
820
m_rename.set_sensitive(False)
821
m_revert.set_sensitive(False)
822
m_commit.set_sensitive(False)
823
m_annotate.set_sensitive(False)
824
m_diff.set_sensitive(False)
826
m_open.set_sensitive(True)
827
m_add.set_sensitive(True)
828
m_remove.set_sensitive(True)
829
m_rename.set_sensitive(True)
830
m_revert.set_sensitive(True)
831
m_commit.set_sensitive(True)
832
m_annotate.set_sensitive(True)
833
m_diff.set_sensitive(True)
834
except bzrerrors.NotBranchError:
835
m_open.set_sensitive(True)
836
m_add.set_sensitive(False)
837
m_remove.set_sensitive(False)
838
m_rename.set_sensitive(False)
839
m_revert.set_sensitive(False)
840
m_commit.set_sensitive(False)
841
m_annotate.set_sensitive(False)
842
m_diff.set_sensitive(False)
845
menu.right_context_menu().popup(None, None, None, 0,
848
menu.remote_context_menu().popup(None, None, None, 0,
851
def on_treeview_right_row_activated(self, treeview, path, view_column):
852
""" Occurs when somebody double-clicks or enters an item in the
854
from launch import launch
856
newdir = self.get_selected_right()
861
self.set_path(os.path.split(self.get_path())[0])
863
fullpath = os.path.join(self.get_path(), newdir)
864
if os.path.isdir(fullpath):
865
# selected item is an existant directory
866
self.set_path(fullpath)
871
if self._is_remote_dir(self.get_path() + newdir):
872
self.set_path(self.get_path() + newdir)
876
def on_window_main_delete_event(self, widget, event=None):
877
""" Do some stuff before exiting. """
878
width, height = self.window_main.get_size()
879
self.pref.set_preference('window_width', width)
880
self.pref.set_preference('window_height', height)
881
x, y = self.window_main.get_position()
882
self.pref.set_preference('window_x', x)
883
self.pref.set_preference('window_y', y)
884
self.pref.set_preference('paned_position',
885
self.hpaned_main.get_position())
888
self.window_main.destroy()
890
def _load_left(self):
891
""" Load data into the left panel. (Bookmarks) """
893
treestore = gtk.TreeStore(str, str)
896
bookmarks = self.pref.get_bookmarks()
898
# Add them to the TreeStore
899
titer = treestore.append(None, [_('Bookmarks'), None])
900
for item in bookmarks:
901
title = self.pref.get_bookmark_title(item)
902
treestore.append(titer, [title, item])
904
# Create the column and add it to the TreeView
905
self.treeview_left.set_model(treestore)
906
tvcolumn_bookmark = gtk.TreeViewColumn(_('Bookmark'))
907
self.treeview_left.append_column(tvcolumn_bookmark)
910
cell = gtk.CellRendererText()
911
tvcolumn_bookmark.pack_start(cell, True)
912
tvcolumn_bookmark.add_attribute(cell, 'text', 0)
915
self.treeview_left.expand_all()
917
def _load_right(self):
918
""" Load data into the right panel. (Filelist) """
920
# Model: [ icon, dir, name, status text, status, size (int), size (human), mtime (int), mtime (local), fileid ]
921
liststore = gtk.ListStore(gobject.TYPE_STRING,
922
gobject.TYPE_BOOLEAN,
935
# Fill the appropriate lists
936
dotted_files = self.pref.get_preference('dotted_files', 'bool')
937
for item in os.listdir(self.path):
938
if not dotted_files and item[0] == '.':
940
if os.path.isdir(self.path + os.sep + item):
945
if not self.notbranch:
946
branch = self.wt.branch
947
tree2 = self.wt.branch.repository.revision_tree(branch.last_revision())
949
delta = self.wt.changes_from(tree2, want_unchanged=True)
951
# Add'em to the ListStore
953
statinfo = os.stat(self.path + os.sep + item)
954
liststore.append([ gtk.STOCK_DIRECTORY,
962
self._format_date(statinfo.st_mtime),
967
if not self.notbranch:
968
filename = self.wt.relpath(self.path + os.sep + item)
973
for rpath, rpathnew, id, kind, text_modified, meta_modified in delta.renamed:
974
if rpathnew == filename:
977
for rpath, id, kind in delta.added:
978
if rpath == filename:
981
for rpath, id, kind in delta.removed:
982
if rpath == filename:
985
for rpath, id, kind, text_modified, meta_modified in delta.modified:
986
if rpath == filename:
989
for rpath, id, kind in delta.unchanged:
990
if rpath == filename:
993
for rpath, file_class, kind, id, entry in self.wt.list_files():
994
if rpath == filename and file_class == 'I':
999
if status == 'renamed':
1001
elif status == 'removed':
1003
elif status == 'added':
1005
elif status == 'modified':
1007
elif status == 'unchanged':
1009
elif status == 'ignored':
1014
statinfo = os.stat(self.path + os.sep + item)
1015
liststore.append([gtk.STOCK_FILE,
1020
str(statinfo.st_size), # NOTE: if int used there it will fail for large files (size expressed as long int)
1021
self._format_size(statinfo.st_size),
1023
self._format_date(statinfo.st_mtime),
1026
# Create the columns and add them to the TreeView
1027
self.treeview_right.set_model(liststore)
1028
self._tvcolumn_filename = gtk.TreeViewColumn(_('Filename'))
1029
self._tvcolumn_status = gtk.TreeViewColumn(_('Status'))
1030
self._tvcolumn_size = gtk.TreeViewColumn(_('Size'))
1031
self._tvcolumn_mtime = gtk.TreeViewColumn(_('Last modified'))
1032
self.treeview_right.append_column(self._tvcolumn_filename)
1033
self.treeview_right.append_column(self._tvcolumn_status)
1034
self.treeview_right.append_column(self._tvcolumn_size)
1035
self.treeview_right.append_column(self._tvcolumn_mtime)
1038
cellpb = gtk.CellRendererPixbuf()
1039
cell = gtk.CellRendererText()
1040
self._tvcolumn_filename.pack_start(cellpb, False)
1041
self._tvcolumn_filename.pack_start(cell, True)
1042
self._tvcolumn_filename.set_attributes(cellpb, stock_id=0)
1043
self._tvcolumn_filename.add_attribute(cell, 'text', 2)
1044
self._tvcolumn_status.pack_start(cell, True)
1045
self._tvcolumn_status.add_attribute(cell, 'text', 3)
1046
self._tvcolumn_size.pack_start(cell, True)
1047
self._tvcolumn_size.add_attribute(cell, 'text', 6)
1048
self._tvcolumn_mtime.pack_start(cell, True)
1049
self._tvcolumn_mtime.add_attribute(cell, 'text', 8)
1051
# Set up the properties of the TreeView
1052
self.treeview_right.set_headers_visible(True)
1053
self.treeview_right.set_headers_clickable(True)
1054
self.treeview_right.set_search_column(1)
1055
self._tvcolumn_filename.set_resizable(True)
1056
self._tvcolumn_status.set_resizable(True)
1057
self._tvcolumn_size.set_resizable(True)
1058
self._tvcolumn_mtime.set_resizable(True)
1060
liststore.set_sort_func(13, self._sort_filelist_callback, None)
1061
liststore.set_sort_column_id(13, gtk.SORT_ASCENDING)
1062
self._tvcolumn_filename.set_sort_column_id(13)
1063
self._tvcolumn_status.set_sort_column_id(3)
1064
self._tvcolumn_size.set_sort_column_id(5)
1065
self._tvcolumn_mtime.set_sort_column_id(7)
1068
self.set_sensitivity()
1070
def get_selected_fileid(self):
1071
""" Get the file_id of the selected file. """
1072
treeselection = self.treeview_right.get_selection()
1073
(model, iter) = treeselection.get_selected()
1078
return model.get_value(iter, 9)
1080
def get_selected_right(self):
1081
""" Get the selected filename. """
1082
treeselection = self.treeview_right.get_selection()
1083
(model, iter) = treeselection.get_selected()
1088
return model.get_value(iter, 2)
1090
def get_selected_left(self):
1091
""" Get the selected bookmark. """
1092
treeselection = self.treeview_left.get_selection()
1093
(model, iter) = treeselection.get_selected()
1098
return model.get_value(iter, 1)
1100
def set_statusbar(self, message):
1101
""" Set the statusbar message. """
1102
self.statusbar.push(self.context_id, message)
1104
def clear_statusbar(self):
1105
""" Clean the last message from the statusbar. """
1106
self.statusbar.pop(self.context_id)
1108
def set_sensitivity(self):
1109
""" Set menu and toolbar sensitivity. """
1112
self.menuitem_branch_init.set_sensitive(self.notbranch)
1113
self.menuitem_branch_get.set_sensitive(self.notbranch)
1114
self.menuitem_branch_checkout.set_sensitive(self.notbranch)
1115
self.menuitem_branch_pull.set_sensitive(not self.notbranch)
1116
self.menuitem_branch_push.set_sensitive(not self.notbranch)
1117
self.menuitem_branch_update.set_sensitive(not self.notbranch)
1118
self.menuitem_branch_revert.set_sensitive(not self.notbranch)
1119
self.menuitem_branch_merge.set_sensitive(not self.notbranch)
1120
self.menuitem_branch_commit.set_sensitive(not self.notbranch)
1121
self.menuitem_branch_tags.set_sensitive(not self.notbranch)
1122
self.menuitem_branch_status.set_sensitive(not self.notbranch)
1123
self.menuitem_branch_missing.set_sensitive(not self.notbranch)
1124
self.menuitem_branch_conflicts.set_sensitive(not self.notbranch)
1125
self.menuitem_stats.set_sensitive(not self.notbranch)
1126
self.menuitem_stats_diff.set_sensitive(not self.notbranch)
1127
self.menuitem_add_files.set_sensitive(not self.notbranch)
1128
self.menuitem_remove_files.set_sensitive(not self.notbranch)
1129
self.menuitem_file_make_directory.set_sensitive(not self.notbranch)
1130
self.menuitem_file_rename.set_sensitive(not self.notbranch)
1131
self.menuitem_file_move.set_sensitive(not self.notbranch)
1132
self.menuitem_file_annotate.set_sensitive(not self.notbranch)
1133
#self.menutoolbutton_diff.set_sensitive(True)
1134
self.toolbutton_diff.set_sensitive(not self.notbranch)
1135
self.toolbutton_log.set_sensitive(not self.notbranch)
1136
self.toolbutton_commit.set_sensitive(not self.notbranch)
1137
self.toolbutton_pull.set_sensitive(not self.notbranch)
1138
self.toolbutton_push.set_sensitive(not self.notbranch)
1139
self.toolbutton_update.set_sensitive(not self.notbranch)
1142
self.menuitem_branch_init.set_sensitive(False)
1143
self.menuitem_branch_get.set_sensitive(True)
1144
self.menuitem_branch_checkout.set_sensitive(True)
1145
self.menuitem_branch_pull.set_sensitive(False)
1146
self.menuitem_branch_push.set_sensitive(False)
1147
self.menuitem_branch_update.set_sensitive(False)
1148
self.menuitem_branch_revert.set_sensitive(False)
1149
self.menuitem_branch_merge.set_sensitive(False)
1150
self.menuitem_branch_commit.set_sensitive(False)
1151
self.menuitem_branch_tags.set_sensitive(True)
1152
self.menuitem_branch_status.set_sensitive(False)
1153
self.menuitem_branch_missing.set_sensitive(False)
1154
self.menuitem_branch_conflicts.set_sensitive(False)
1155
self.menuitem_stats.set_sensitive(True)
1156
self.menuitem_stats_diff.set_sensitive(False)
1157
self.menuitem_add_files.set_sensitive(False)
1158
self.menuitem_remove_files.set_sensitive(False)
1159
self.menuitem_file_make_directory.set_sensitive(False)
1160
self.menuitem_file_rename.set_sensitive(False)
1161
self.menuitem_file_move.set_sensitive(False)
1162
self.menuitem_file_annotate.set_sensitive(False)
1163
#self.menutoolbutton_diff.set_sensitive(True)
1164
self.toolbutton_diff.set_sensitive(False)
1165
self.toolbutton_log.set_sensitive(True)
1166
self.toolbutton_commit.set_sensitive(False)
1167
self.toolbutton_pull.set_sensitive(False)
1168
self.toolbutton_push.set_sensitive(False)
1169
self.toolbutton_update.set_sensitive(False)
1171
def refresh_left(self):
1172
""" Refresh the bookmark list. """
1174
# Get TreeStore and clear it
1175
treestore = self.treeview_left.get_model()
1178
# Re-read preferences
1182
bookmarks = self.pref.get_bookmarks()
1184
# Add them to the TreeStore
1185
titer = treestore.append(None, [_('Bookmarks'), None])
1186
for item in bookmarks:
1187
title = self.pref.get_bookmark_title(item)
1188
treestore.append(titer, [title, item])
1190
# Add the TreeStore to the TreeView
1191
self.treeview_left.set_model(treestore)
1194
self.treeview_left.expand_all()
1196
def refresh_right(self, path=None):
1197
""" Refresh the file list. """
1200
from bzrlib.workingtree import WorkingTree
1203
path = self.get_path()
1205
# A workaround for double-clicking Bookmarks
1206
if not os.path.exists(path):
1209
# Get ListStore and clear it
1210
liststore = self.treeview_right.get_model()
1213
# Show Status column
1214
self._tvcolumn_status.set_visible(True)
1219
# Fill the appropriate lists
1220
dotted_files = self.pref.get_preference('dotted_files', 'bool')
1221
ignored_files = self.pref.get_preference('ignored_files', 'bool')
1223
for item in os.listdir(path):
1224
if not dotted_files and item[0] == '.':
1226
if os.path.isdir(path + os.sep + item):
1231
# Try to open the working tree
1234
tree1 = WorkingTree.open_containing(path)[0]
1235
except (bzrerrors.NotBranchError, bzrerrors.NoWorkingTree):
1239
branch = tree1.branch
1240
tree2 = tree1.branch.repository.revision_tree(branch.last_revision())
1242
delta = tree1.changes_from(tree2, want_unchanged=True)
1244
# Add'em to the ListStore
1246
statinfo = os.stat(self.path + os.sep + item)
1247
liststore.append([gtk.STOCK_DIRECTORY,
1255
self._format_date(statinfo.st_mtime),
1261
filename = tree1.relpath(path + os.sep + item)
1266
for rpath, rpathnew, id, kind, text_modified, meta_modified in delta.renamed:
1267
if rpathnew == filename:
1270
for rpath, id, kind in delta.added:
1271
if rpath == filename:
1274
for rpath, id, kind in delta.removed:
1275
if rpath == filename:
1278
for rpath, id, kind, text_modified, meta_modified in delta.modified:
1279
if rpath == filename:
1282
for rpath, id, kind in delta.unchanged:
1283
if rpath == filename:
1284
status = 'unchanged'
1286
for rpath, file_class, kind, id, entry in self.wt.list_files():
1287
if rpath == filename and file_class == 'I':
1292
if status == 'renamed':
1294
elif status == 'removed':
1296
elif status == 'added':
1298
elif status == 'modified':
1300
elif status == 'unchanged':
1302
elif status == 'ignored':
1304
if not ignored_files:
1309
statinfo = os.stat(self.path + os.sep + item)
1310
liststore.append([gtk.STOCK_FILE,
1315
str(statinfo.st_size),
1316
self._format_size(statinfo.st_size),
1318
self._format_date(statinfo.st_mtime),
1323
# Get ListStore and clear it
1324
liststore = self.treeview_right.get_model()
1327
# Hide Status column
1328
self._tvcolumn_status.set_visible(False)
1333
self._show_stock_image(gtk.STOCK_REFRESH)
1335
for (name, type) in self.remote_entries:
1336
if type.kind == 'directory':
1338
elif type.kind == 'file':
1342
""" Cache based on revision history. """
1343
def __init__(self, history):
1344
self._history = history
1346
def _lookup_revision(self, revid):
1347
for r in self._history:
1348
if r.revision_id == revid:
1350
rev = repo.get_revision(revid)
1351
self._history.append(rev)
1354
repo = self.remote_branch.repository
1356
revhistory = self.remote_branch.revision_history()
1358
revs = repo.get_revisions(revhistory)
1359
cache = HistoryCache(revs)
1360
except bzrerrors.InvalidHttpResponse:
1361
# Fallback to dummy algorithm, because of LP: #115209
1362
cache = HistoryCache([])
1365
if item.parent_id == self.remote_parent:
1366
rev = cache._lookup_revision(item.revision)
1367
liststore.append([ gtk.STOCK_DIRECTORY,
1375
self._format_date(rev.timestamp),
1378
while gtk.events_pending():
1379
gtk.main_iteration()
1382
if item.parent_id == self.remote_parent:
1383
rev = cache._lookup_revision(item.revision)
1384
liststore.append([ gtk.STOCK_FILE,
1389
str(item.text_size),
1390
self._format_size(item.text_size),
1392
self._format_date(rev.timestamp),
1395
while gtk.events_pending():
1396
gtk.main_iteration()
1398
self.image_location_error.destroy()
1400
# Columns should auto-size
1401
self.treeview_right.columns_autosize()
1404
self.set_sensitivity()
1406
def _harddisks(self):
1407
""" Returns hard drive letters under Win32. """
1412
if sys.platform == 'win32':
1413
print "pyWin32 modules needed to run Olive on Win32."
1419
for drive in string.ascii_uppercase:
1420
if win32file.GetDriveType(drive+':') == win32file.DRIVE_FIXED:
1421
driveletters.append(drive+':')
1424
def gen_hard_selector(self):
1425
""" Generate the hard drive selector under Win32. """
1426
drives = self._harddisks()
1427
for drive in drives:
1428
self.combobox_drive.append_text(drive)
1429
self.combobox_drive.set_active(drives.index(os.getcwd()[0:2]))
1431
def _refresh_drives(self, combobox):
1432
if self._just_started:
1434
model = combobox.get_model()
1435
active = combobox.get_active()
1437
drive = model[active][0]
1438
self.set_path(drive + '\\')
1439
self.refresh_right(drive + '\\')
1441
def check_for_changes(self):
1442
""" Check whether there were changes in the current working tree. """
1443
old_tree = self.wt.branch.repository.revision_tree(self.wt.branch.last_revision())
1444
delta = self.wt.changes_from(old_tree)
1448
if len(delta.added) or len(delta.removed) or len(delta.renamed) or len(delta.modified):
1453
def _sort_filelist_callback(self, model, iter1, iter2, data):
1454
""" The sort callback for the file list, return values:
1459
name1 = model.get_value(iter1, 2)
1460
name2 = model.get_value(iter2, 2)
1462
if model.get_value(iter1, 1):
1463
# item1 is a directory
1464
if not model.get_value(iter2, 1):
1468
# both of them are directories, we compare their names
1471
elif name1 == name2:
1476
# item1 is not a directory
1477
if model.get_value(iter2, 1):
1481
# both of them are files, compare them
1484
elif name1 == name2:
1489
def _format_size(self, size):
1490
""" Format size to a human readable format. """
1492
return "%d[B]" % (size,)
1493
size = size / 1000.0
1495
for metric in ["kB","MB","GB","TB"]:
1498
size = size / 1000.0
1499
return "%.1f[%s]" % (size,metric)
1501
def _format_date(self, timestamp):
1502
""" Format the time (given in secs) to a human readable format. """
1503
return time.ctime(timestamp)
1505
def _is_remote_dir(self, location):
1506
""" Determine whether the given location is a directory or not. """
1508
# We're in local mode
1511
branch, path = Branch.open_containing(location)
1512
for (name, type) in self.remote_entries:
1513
if name == path and type.kind == 'directory':
1516
# Either it's not a directory or not in the inventory
1519
def _show_stock_image(self, stock_id):
1520
""" Show a stock image next to the location entry. """
1521
self.image_location_error.destroy()
1522
self.image_location_error = gtk.image_new_from_stock(stock_id, gtk.ICON_SIZE_BUTTON)
1523
self.hbox_location.pack_start(self.image_location_error, False, False, 0)
1524
if sys.platform == 'win32':
1525
self.hbox_location.reorder_child(self.image_location_error, 2)
1527
self.hbox_location.reorder_child(self.image_location_error, 1)
1528
self.image_location_error.show()
1529
while gtk.events_pending():
1530
gtk.main_iteration()
1535
""" A class which handles Olive's preferences. """
1536
def __init__(self, path=None):
1537
""" Initialize the Preferences class. """
1538
# Some default options
1539
self.defaults = { 'strict_commit' : False,
1540
'dotted_files' : False,
1541
'ignored_files' : True,
1542
'window_width' : 700,
1543
'window_height' : 400,
1546
'paned_position': 200 }
1548
# Create a config parser object
1549
self.config = ConfigParser.RawConfigParser()
1553
if sys.platform == 'win32':
1554
# Windows - no dotted files
1555
self._filename = os.path.expanduser('~/olive.conf')
1557
self._filename = os.path.expanduser('~/.olive.conf')
1559
self._filename = path
1561
# Load the configuration
1564
def _get_default(self, option):
1565
""" Get the default option for a preference. """
1567
ret = self.defaults[option]
1574
""" Refresh the configuration. """
1575
# First write out the changes
1577
# Then load the configuration again
1581
""" Just read the configuration. """
1582
# Re-initialize the config parser object to avoid some bugs
1583
self.config = ConfigParser.RawConfigParser()
1584
self.config.read([self._filename])
1587
""" Write the configuration to the appropriate files. """
1588
fp = open(self._filename, 'w')
1589
self.config.write(fp)
1592
def get_bookmarks(self):
1593
""" Return the list of bookmarks. """
1594
bookmarks = self.config.sections()
1595
if self.config.has_section('preferences'):
1596
bookmarks.remove('preferences')
1599
def add_bookmark(self, path):
1600
""" Add bookmark. """
1602
self.config.add_section(path)
1603
except ConfigParser.DuplicateSectionError:
1608
def get_bookmark_title(self, path):
1609
""" Get bookmark title. """
1611
ret = self.config.get(path, 'title')
1612
except ConfigParser.NoOptionError:
1617
def set_bookmark_title(self, path, title):
1618
""" Set bookmark title. """
1619
# FIXME: What if path isn't listed yet?
1620
# FIXME: Canonicalize paths first?
1621
self.config.set(path, 'title', title)
1623
def remove_bookmark(self, path):
1624
""" Remove bookmark. """
1625
return self.config.remove_section(path)
1627
def set_preference(self, option, value):
1628
""" Set the value of the given option. """
1631
elif value is False:
1634
if self.config.has_section('preferences'):
1635
self.config.set('preferences', option, value)
1637
self.config.add_section('preferences')
1638
self.config.set('preferences', option, value)
1640
def get_preference(self, option, kind='str'):
1641
""" Get the value of the given option.
1643
:param kind: str/bool/int/float. default: str
1645
if self.config.has_option('preferences', option):
1647
return self.config.getboolean('preferences', option)
1649
return self.config.getint('preferences', option)
1650
elif kind == 'float':
1651
return self.config.getfloat('preferences', option)
1653
return self.config.get('preferences', option)
1656
return self._get_default(option)