2
# -*- coding: UTF-8 -*-
4
# Copyright (C) 2006 by Szilveszter Farkas (Phanatic) <szilveszter.farkas@gmail.com>
6
# This program is free software; you can redistribute it and/or modify
7
# it under the terms of the GNU General Public License as published by
8
# the Free Software Foundation; either version 2 of the License, or
9
# (at your option) any later version.
11
# This program is distributed in the hope that it will be useful,
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
# GNU General Public License for more details.
16
# You should have received a copy of the GNU General Public License
17
# along with this program; if not, write to the Free Software
18
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26
gettext.install('olive-gtk')
39
from bzrlib.branch import Branch
40
import bzrlib.errors as bzrerrors
41
from bzrlib.lazy_import import lazy_import
42
from bzrlib.ui import ui_factory
43
from bzrlib.workingtree import WorkingTree
45
from bzrlib.plugins.gtk.dialog import error_dialog, info_dialog, warning_dialog
46
from bzrlib.plugins.gtk.errors import show_bzr_error
47
from guifiles import GLADEFILENAME
49
from bzrlib.plugins.gtk.diff import DiffWindow
50
lazy_import(globals(), """
51
from bzrlib.plugins.gtk.viz import branchwin
53
from bzrlib.plugins.gtk.annotate.gannotate import GAnnotateWindow
54
from bzrlib.plugins.gtk.annotate.config import GAnnotateConfig
55
from bzrlib.plugins.gtk.commit import CommitDialog
56
from bzrlib.plugins.gtk.conflicts import ConflictsDialog
57
from bzrlib.plugins.gtk.initialize import InitDialog
58
from bzrlib.plugins.gtk.push import PushDialog
59
from bzrlib.plugins.gtk.revbrowser import RevisionBrowser
62
""" Display the AboutDialog. """
63
from bzrlib.plugins.gtk import __version__
64
from bzrlib.plugins.gtk.olive.guifiles import GLADEFILENAME
66
# Load AboutDialog description
67
dglade = gtk.glade.XML(GLADEFILENAME, 'aboutdialog')
68
dialog = dglade.get_widget('aboutdialog')
71
dialog.set_version(__version__)
72
dialog.set_authors([ _("Lead Developer:"),
73
"Szilveszter Farkas <szilveszter.farkas@gmail.com>",
75
"Jelmer Vernooij <jelmer@samba.org>",
76
"Mateusz Korniak <mateusz.korniak@ant.gliwice.pl>",
77
"Gary van der Merwe <garyvdm@gmail.com>" ])
78
dialog.set_artists([ "Simon Pascal Klein <klepas@klepas.org>",
79
"Jakub Steiner <jimmac@novell.com>" ])
86
""" The main Olive GTK frontend class. This is called when launching the
90
self.toplevel = gtk.glade.XML(GLADEFILENAME, 'window_main', 'olive-gtk')
91
self.window = self.toplevel.get_widget('window_main')
92
self.pref = Preferences()
95
# Initialize the statusbar
96
self.statusbar = self.toplevel.get_widget('statusbar')
97
self.context_id = self.statusbar.get_context_id('olive')
100
self.window_main = self.toplevel.get_widget('window_main')
102
self.hpaned_main = self.toplevel.get_widget('hpaned_main')
104
self.treeview_left = self.toplevel.get_widget('treeview_left')
105
self.treeview_right = self.toplevel.get_widget('treeview_right')
106
# Get some important menu items
107
self.menuitem_add_files = self.toplevel.get_widget('menuitem_add_files')
108
self.menuitem_remove_files = self.toplevel.get_widget('menuitem_remove_file')
109
self.menuitem_file_make_directory = self.toplevel.get_widget('menuitem_file_make_directory')
110
self.menuitem_file_rename = self.toplevel.get_widget('menuitem_file_rename')
111
self.menuitem_file_move = self.toplevel.get_widget('menuitem_file_move')
112
self.menuitem_file_annotate = self.toplevel.get_widget('menuitem_file_annotate')
113
self.menuitem_view_show_hidden_files = self.toplevel.get_widget('menuitem_view_show_hidden_files')
114
self.menuitem_view_show_ignored_files = self.toplevel.get_widget('menuitem_view_show_ignored_files')
115
self.menuitem_branch = self.toplevel.get_widget('menuitem_branch')
116
self.menuitem_branch_init = self.toplevel.get_widget('menuitem_branch_initialize')
117
self.menuitem_branch_get = self.toplevel.get_widget('menuitem_branch_get')
118
self.menuitem_branch_checkout = self.toplevel.get_widget('menuitem_branch_checkout')
119
self.menuitem_branch_pull = self.toplevel.get_widget('menuitem_branch_pull')
120
self.menuitem_branch_push = self.toplevel.get_widget('menuitem_branch_push')
121
self.menuitem_branch_update = self.toplevel.get_widget('menuitem_branch_update')
122
self.menuitem_branch_revert = self.toplevel.get_widget('menuitem_branch_revert')
123
self.menuitem_branch_merge = self.toplevel.get_widget('menuitem_branch_merge')
124
self.menuitem_branch_commit = self.toplevel.get_widget('menuitem_branch_commit')
125
self.menuitem_branch_tags = self.toplevel.get_widget('menuitem_branch_tags')
126
self.menuitem_branch_status = self.toplevel.get_widget('menuitem_branch_status')
127
self.menuitem_branch_missing = self.toplevel.get_widget('menuitem_branch_missing_revisions')
128
self.menuitem_branch_conflicts = self.toplevel.get_widget('menuitem_branch_conflicts')
129
self.menuitem_stats = self.toplevel.get_widget('menuitem_stats')
130
self.menuitem_stats_diff = self.toplevel.get_widget('menuitem_stats_diff')
131
self.menuitem_stats_log = self.toplevel.get_widget('menuitem_stats_log')
132
# Get some toolbuttons
133
#self.menutoolbutton_diff = self.toplevel.get_widget('menutoolbutton_diff')
134
self.toolbutton_diff = self.toplevel.get_widget('toolbutton_diff')
135
self.toolbutton_log = self.toplevel.get_widget('toolbutton_log')
136
self.toolbutton_commit = self.toplevel.get_widget('toolbutton_commit')
137
self.toolbutton_pull = self.toplevel.get_widget('toolbutton_pull')
138
self.toolbutton_push = self.toplevel.get_widget('toolbutton_push')
139
self.toolbutton_update = self.toplevel.get_widget('toolbutton_update')
140
# Get the drive selector
141
self.combobox_drive = gtk.combo_box_new_text()
142
self.combobox_drive.connect("changed", self._refresh_drives)
144
# Get the navigation widgets
145
self.hbox_location = self.toplevel.get_widget('hbox_location')
146
self.button_location_up = self.toplevel.get_widget('button_location_up')
147
self.button_location_jump = self.toplevel.get_widget('button_location_jump')
148
self.entry_location = self.toplevel.get_widget('entry_location')
149
self.image_location_error = self.toplevel.get_widget('image_location_error')
151
# Get the History widgets
152
self.check_history = self.toplevel.get_widget('checkbutton_history')
153
self.entry_history = self.toplevel.get_widget('entry_history_revno')
154
self.button_history = self.toplevel.get_widget('button_history_browse')
156
self.vbox_main_right = self.toplevel.get_widget('vbox_main_right')
158
# Dictionary for signal_autoconnect
159
dic = { "on_window_main_destroy": gtk.main_quit,
160
"on_window_main_delete_event": self.on_window_main_delete_event,
161
"on_quit_activate": self.on_window_main_delete_event,
162
"on_about_activate": self.on_about_activate,
163
"on_menuitem_add_files_activate": self.on_menuitem_add_files_activate,
164
"on_menuitem_remove_file_activate": self.on_menuitem_remove_file_activate,
165
"on_menuitem_file_make_directory_activate": self.on_menuitem_file_make_directory_activate,
166
"on_menuitem_file_move_activate": self.on_menuitem_file_move_activate,
167
"on_menuitem_file_rename_activate": self.on_menuitem_file_rename_activate,
168
"on_menuitem_file_annotate_activate": self.on_menuitem_file_annotate_activate,
169
"on_menuitem_view_show_hidden_files_activate": self.on_menuitem_view_show_hidden_files_activate,
170
"on_menuitem_view_show_ignored_files_activate": self.on_menuitem_view_show_ignored_files_activate,
171
"on_menuitem_view_refresh_activate": self.on_menuitem_view_refresh_activate,
172
"on_menuitem_branch_initialize_activate": self.on_menuitem_branch_initialize_activate,
173
"on_menuitem_branch_get_activate": self.on_menuitem_branch_get_activate,
174
"on_menuitem_branch_checkout_activate": self.on_menuitem_branch_checkout_activate,
175
"on_menuitem_branch_revert_activate": self.on_menuitem_branch_revert_activate,
176
"on_menuitem_branch_merge_activate": self.on_menuitem_branch_merge_activate,
177
"on_menuitem_branch_commit_activate": self.on_menuitem_branch_commit_activate,
178
"on_menuitem_branch_push_activate": self.on_menuitem_branch_push_activate,
179
"on_menuitem_branch_pull_activate": self.on_menuitem_branch_pull_activate,
180
"on_menuitem_branch_update_activate": self.on_menuitem_branch_update_activate,
181
"on_menuitem_branch_tags_activate": self.on_menuitem_branch_tags_activate,
182
"on_menuitem_branch_status_activate": self.on_menuitem_branch_status_activate,
183
"on_menuitem_branch_missing_revisions_activate": self.on_menuitem_branch_missing_revisions_activate,
184
"on_menuitem_branch_conflicts_activate": self.on_menuitem_branch_conflicts_activate,
185
"on_menuitem_stats_diff_activate": self.on_menuitem_stats_diff_activate,
186
"on_menuitem_stats_log_activate": self.on_menuitem_stats_log_activate,
187
"on_menuitem_stats_infos_activate": self.on_menuitem_stats_infos_activate,
188
"on_toolbutton_refresh_clicked": self.on_menuitem_view_refresh_activate,
189
"on_toolbutton_log_clicked": self.on_menuitem_stats_log_activate,
190
#"on_menutoolbutton_diff_clicked": self.on_menuitem_stats_diff_activate,
191
"on_toolbutton_diff_clicked": self.on_menuitem_stats_diff_activate,
192
"on_toolbutton_commit_clicked": self.on_menuitem_branch_commit_activate,
193
"on_toolbutton_pull_clicked": self.on_menuitem_branch_pull_activate,
194
"on_toolbutton_push_clicked": self.on_menuitem_branch_push_activate,
195
"on_toolbutton_update_clicked": self.on_menuitem_branch_update_activate,
196
"on_treeview_right_button_press_event": self.on_treeview_right_button_press_event,
197
"on_treeview_right_row_activated": self.on_treeview_right_row_activated,
198
"on_treeview_left_button_press_event": self.on_treeview_left_button_press_event,
199
"on_treeview_left_row_activated": self.on_treeview_left_row_activated,
200
"on_button_location_up_clicked": self.on_button_location_up_clicked,
201
"on_button_location_jump_clicked": self.on_button_location_jump_clicked,
202
"on_entry_location_key_press_event": self.on_entry_location_key_press_event,
203
"on_checkbutton_history_toggled": self.on_checkbutton_history_toggled,
204
"on_entry_history_revno_key_press_event": self.on_entry_history_revno_key_press_event,
205
"on_button_history_browse_clicked": self.on_button_history_browse_clicked
208
# Connect the signals to the handlers
209
self.toplevel.signal_autoconnect(dic)
211
self._just_started = True
213
# Apply window size and position
214
width = self.pref.get_preference('window_width', 'int')
215
height = self.pref.get_preference('window_height', 'int')
216
self.window.resize(width, height)
217
x = self.pref.get_preference('window_x', 'int')
218
y = self.pref.get_preference('window_y', 'int')
219
self.window.move(x, y)
220
# Apply paned position
221
pos = self.pref.get_preference('paned_position', 'int')
222
self.hpaned_main.set_position(pos)
224
# Apply menu to the toolbutton
225
#menubutton = self.toplevel.get_widget('menutoolbutton_diff')
226
#menubutton.set_menu(handler.menu.toolbar_diff)
228
# Now we can show the window
231
# Show drive selector if under Win32
232
if sys.platform == 'win32':
233
self.hbox_location.pack_start(self.combobox_drive, False, False, 0)
234
self.hbox_location.reorder_child(self.combobox_drive, 1)
235
self.combobox_drive.show()
236
self.gen_hard_selector()
241
self.menuitem_view_show_hidden_files.set_active(self.pref.get_preference('dotted_files', 'bool'))
242
self.menuitem_view_show_ignored_files.set_active(self.pref.get_preference('ignored_files', 'bool'))
244
# We're starting local
246
self.remote_branch = None
247
self.remote_path = None
248
self.remote_revision = None
250
self.set_path(os.getcwd())
253
self._just_started = False
255
def set_path(self, path, force_remote=False):
256
self.notbranch = False
259
# Forcing remote mode (reading data from inventory)
260
self._show_stock_image(gtk.STOCK_DISCONNECT)
262
br = Branch.open_containing(path)[0]
263
except bzrerrors.NotBranchError:
264
self._show_stock_image(gtk.STOCK_DIALOG_ERROR)
265
self.check_history.set_active(False)
266
self.check_history.set_sensitive(False)
268
except bzrerrors.UnsupportedProtocol:
269
self._show_stock_image(gtk.STOCK_DIALOG_ERROR)
270
self.check_history.set_active(False)
271
self.check_history.set_sensitive(False)
274
self._show_stock_image(gtk.STOCK_CONNECT)
279
self.remote_branch, self.remote_path = Branch.open_containing(path)
281
if self.remote_revision is None:
282
self.remote_revision = self.remote_branch.last_revision()
284
self.remote_entries = self.remote_branch.repository.get_inventory(self.remote_revision).entries()
286
if len(self.remote_path) == 0:
287
self.remote_parent = self.remote_branch.repository.get_inventory(self.remote_branch.last_revision()).iter_entries_by_dir().next()[1].file_id
289
for (name, type) in self.remote_entries:
290
if name == self.remote_path:
291
self.remote_parent = type.file_id
294
if not path.endswith('/'):
297
if self.remote_branch.base == path:
298
self.button_location_up.set_sensitive(False)
300
self.button_location_up.set_sensitive(True)
302
if os.path.isdir(path):
303
self.image_location_error.destroy()
308
self.wt, self.wtpath = WorkingTree.open_containing(path)
309
except (bzrerrors.NotBranchError, bzrerrors.NoWorkingTree):
310
self.notbranch = True
312
# If we're in the root, we cannot go up anymore
313
if sys.platform == 'win32':
314
drive, tail = os.path.splitdrive(path)
315
if tail in ('', '/', '\\'):
316
self.button_location_up.set_sensitive(False)
318
self.button_location_up.set_sensitive(True)
321
self.button_location_up.set_sensitive(False)
323
self.button_location_up.set_sensitive(True)
324
elif not os.path.isfile(path):
325
# Doesn't seem to be a file nor a directory, trying to open a
327
self._show_stock_image(gtk.STOCK_DISCONNECT)
329
br = Branch.open_containing(path)[0]
330
except bzrerrors.NotBranchError:
331
self._show_stock_image(gtk.STOCK_DIALOG_ERROR)
332
self.check_history.set_active(False)
333
self.check_history.set_sensitive(False)
335
except bzrerrors.UnsupportedProtocol:
336
self._show_stock_image(gtk.STOCK_DIALOG_ERROR)
337
self.check_history.set_active(False)
338
self.check_history.set_sensitive(False)
341
self._show_stock_image(gtk.STOCK_CONNECT)
346
self.remote_branch, self.remote_path = Branch.open_containing(path)
348
if self.remote_revision is None:
349
self.remote_revision = self.remote_branch.last_revision()
351
self.remote_entries = self.remote_branch.repository.get_inventory(self.remote_revision).entries()
353
if len(self.remote_path) == 0:
354
self.remote_parent = self.remote_branch.repository.get_inventory(self.remote_branch.last_revision()).iter_entries_by_dir().next()[1].file_id
356
for (name, type) in self.remote_entries:
357
if name == self.remote_path:
358
self.remote_parent = type.file_id
361
if not path.endswith('/'):
364
if self.remote_branch.base == path:
365
self.button_location_up.set_sensitive(False)
367
self.button_location_up.set_sensitive(True)
370
self.check_history.set_active(False)
371
self.check_history.set_sensitive(False)
373
self.check_history.set_sensitive(True)
375
self.statusbar.push(self.context_id, path)
376
self.entry_location.set_text(path)
385
if len(self.remote_path) > 0:
386
return self.remote_branch.base + self.remote_path + '/'
388
return self.remote_branch.base
390
def on_about_activate(self, widget):
393
def on_button_history_browse_clicked(self, widget):
394
""" Browse for revision button handler. """
396
br = self.remote_branch
400
revb = RevisionBrowser(br, self.window)
401
response = revb.run()
402
if response != gtk.RESPONSE_NONE:
405
if response == gtk.RESPONSE_OK:
406
if revb.selected_revno is not None:
407
self.entry_history.set_text(revb.selected_revno)
411
def on_button_location_jump_clicked(self, widget):
412
""" Location Jump button handler. """
413
location = self.entry_location.get_text()
415
if self.set_path(location):
418
def on_button_location_up_clicked(self, widget):
419
""" Location Up button handler. """
422
self.set_path(os.path.split(self.get_path())[0])
426
newpath = delim.join(self.get_path().split(delim)[:-2])
428
self.set_path(newpath)
432
def on_checkbutton_history_toggled(self, widget):
433
""" History Mode toggle handler. """
434
if self.check_history.get_active():
435
# History Mode activated
436
self.entry_history.set_sensitive(True)
437
self.button_history.set_sensitive(True)
439
# History Mode deactivated
440
self.entry_history.set_sensitive(False)
441
self.button_history.set_sensitive(False)
444
def on_entry_history_revno_key_press_event(self, widget, event):
445
""" Key pressed handler for the history entry. """
446
if event.keyval == 65293:
447
# Return was hit, so we have to load that specific revision
448
# Emulate being remote, so inventory should be used
449
path = self.get_path()
452
self.remote_branch = self.wt.branch
454
revno = int(self.entry_history.get_text())
455
self.remote_revision = self.remote_branch.get_rev_id(revno)
456
if self.set_path(path, True):
459
def on_entry_location_key_press_event(self, widget, event):
460
""" Key pressed handler for the location entry. """
461
if event.keyval == 65293:
462
# Return was hit, so we have to jump
463
self.on_button_location_jump_clicked(widget)
465
def on_menuitem_add_files_activate(self, widget):
466
""" Add file(s)... menu handler. """
467
from add import OliveAdd
468
add = OliveAdd(self.wt, self.wtpath, self.get_selected_right())
471
def on_menuitem_branch_get_activate(self, widget):
472
""" Branch/Get... menu handler. """
473
from bzrlib.plugins.gtk.branch import BranchDialog
476
branch = BranchDialog(os.getcwd(), self.window, self.remote_branch.base)
478
branch = BranchDialog(self.get_path(), self.window)
479
response = branch.run()
480
if response != gtk.RESPONSE_NONE:
483
if response == gtk.RESPONSE_OK:
488
def on_menuitem_branch_checkout_activate(self, widget):
489
""" Branch/Checkout... menu handler. """
490
from bzrlib.plugins.gtk.checkout import CheckoutDialog
493
checkout = CheckoutDialog(os.getcwd(), self.window, self.remote_branch.base)
495
checkout = CheckoutDialog(self.get_path(), self.window)
496
response = checkout.run()
497
if response != gtk.RESPONSE_NONE:
500
if response == gtk.RESPONSE_OK:
506
def on_menuitem_branch_commit_activate(self, widget):
507
""" Branch/Commit... menu handler. """
508
# def __init__(self, wt, wtpath, notbranch, selected=None, parent=None):
509
selected = self.get_selected_right()
511
selected = os.path.join(self.wtpath, selected)
512
commit = CommitDialog(wt=self.wt,
516
response = commit.run()
517
if response != gtk.RESPONSE_NONE:
520
if response == gtk.RESPONSE_OK:
525
def on_menuitem_branch_conflicts_activate(self, widget):
526
""" Branch/Conflicts... menu handler. """
527
conflicts = ConflictsDialog(self.wt, self.window)
528
response = conflicts.run()
529
if response != gtk.RESPONSE_NONE:
532
def on_menuitem_branch_merge_activate(self, widget):
533
""" Branch/Merge... menu handler. """
534
from bzrlib.plugins.gtk.merge import MergeDialog
536
if self.check_for_changes():
537
error_dialog(_('There are local changes in the branch'),
538
_('Please commit or revert the changes before merging.'))
540
parent_branch_path = self.wt.branch.get_parent()
541
merge = MergeDialog(self.wt, self.wtpath,default_branch_path=parent_branch_path )
545
def on_menuitem_branch_missing_revisions_activate(self, widget):
546
""" Branch/Missing revisions menu handler. """
548
from bzrlib.missing import find_unmerged, iter_log_revisions
550
local_branch = self.wt.branch
551
parent_branch_path = local_branch.get_parent()
552
if parent_branch_path is None:
553
error_dialog(_('Parent location is unknown'),
554
_('Cannot determine missing revisions if no parent location is known.'))
557
parent_branch = Branch.open(parent_branch_path)
559
if parent_branch.base == local_branch.base:
560
parent_branch = local_branch
562
local_extra, remote_extra = find_unmerged(local_branch,parent_branch)
564
if local_extra or remote_extra:
566
## def log_revision_one_line_text(log_revision):
567
## """ Generates one line description of log_revison ended with end of line."""
568
## revision = log_revision.rev
569
## txt = "- %s (%s)\n" % (revision.get_summary(), revision.committer, )
570
## txt = txt.replace("<"," ") # Seems < > chars are expected to be xml tags ...
571
## txt = txt.replace(">"," ")
576
dlg_txt += _('%d local extra revision(s). \n') % (len(local_extra),)
577
## NOTE: We do not want such ugly info about missing revisions
578
## Revision Browser should be used there
579
## max_revisions = 10
580
## for log_revision in iter_log_revisions(local_extra, local_branch.repository, verbose=1):
581
## dlg_txt += log_revision_one_line_text(log_revision)
582
## if max_revisions <= 0:
583
## dlg_txt += _("more ... \n")
585
## max_revisions -= 1
588
dlg_txt += _('%d local missing revision(s).\n') % (len(remote_extra),)
589
## max_revisions = 10
590
## for log_revision in iter_log_revisions(remote_extra, parent_branch.repository, verbose=1):
591
## dlg_txt += log_revision_one_line_text(log_revision)
592
## if max_revisions <= 0:
593
## dlg_txt += _("more ... \n")
595
## max_revisions -= 1
597
info_dialog(_('There are missing revisions'),
600
info_dialog(_('Local branch up to date'),
601
_('There are no missing revisions.'))
604
def on_menuitem_branch_pull_activate(self, widget):
605
""" Branch/Pull menu handler. """
606
branch_to = self.wt.branch
608
location = branch_to.get_parent()
610
error_dialog(_('Parent location is unknown'),
611
_('Pulling is not possible until there is a parent location.'))
614
branch_from = Branch.open(location)
616
if branch_to.get_parent() is None:
617
branch_to.set_parent(branch_from.base)
619
ret = branch_to.pull(branch_from)
621
info_dialog(_('Pull successful'), _('%d revision(s) pulled.') % ret)
624
def on_menuitem_branch_update_activate(self, widget):
625
""" Brranch/checkout update menu handler. """
627
ret = self.wt.update()
628
conflicts = self.wt.conflicts()
630
info_dialog(_('Update successful but conflicts generated'), _('Number of conflicts generated: %d.') % (len(conflicts),) )
632
info_dialog(_('Update successful'), _('No conflicts generated.') )
634
def on_menuitem_branch_push_activate(self, widget):
635
""" Branch/Push... menu handler. """
636
push = PushDialog(repository=None,revid=None,branch=self.wt.branch, parent=self.window)
637
response = push.run()
638
if response != gtk.RESPONSE_NONE:
642
def on_menuitem_branch_revert_activate(self, widget):
643
""" Branch/Revert all changes menu handler. """
644
ret = self.wt.revert([])
646
warning_dialog(_('Conflicts detected'),
647
_('Please have a look at the working tree before continuing.'))
649
info_dialog(_('Revert successful'),
650
_('All files reverted to last revision.'))
653
def on_menuitem_branch_status_activate(self, widget):
654
""" Branch/Status... menu handler. """
655
from bzrlib.plugins.gtk.status import StatusDialog
656
status = StatusDialog(self.wt, self.wtpath)
657
response = status.run()
658
if response != gtk.RESPONSE_NONE:
661
def on_menuitem_branch_initialize_activate(self, widget):
662
""" Initialize current directory. """
663
init = InitDialog(self.path, self.window)
664
response = init.run()
665
if response != gtk.RESPONSE_NONE:
668
if response == gtk.RESPONSE_OK:
673
def on_menuitem_branch_tags_activate(self, widget):
674
""" Branch/Tags... menu handler. """
675
from bzrlib.plugins.gtk.tags import TagsWindow
677
window = TagsWindow(self.wt.branch, self.window)
679
window = TagsWindow(self.remote_branch, self.window)
682
def on_menuitem_file_annotate_activate(self, widget):
683
""" File/Annotate... menu handler. """
684
if self.get_selected_right() is None:
685
error_dialog(_('No file was selected'),
686
_('Please select a file from the list.'))
689
branch = self.wt.branch
690
file_id = self.wt.path2id(self.wt.relpath(os.path.join(self.path, self.get_selected_right())))
692
window = GAnnotateWindow(all=False, plain=False, parent=self.window)
693
window.set_title(os.path.join(self.path, self.get_selected_right()) + " - Annotate")
694
config = GAnnotateConfig(window)
698
window.annotate(self.wt, branch, file_id)
702
def on_menuitem_file_make_directory_activate(self, widget):
703
""" File/Make directory... menu handler. """
704
from mkdir import OliveMkdir
705
mkdir = OliveMkdir(self.wt, self.wtpath)
708
def on_menuitem_file_move_activate(self, widget):
709
""" File/Move... menu handler. """
710
from move import OliveMove
711
move = OliveMove(self.wt, self.wtpath, self.get_selected_right())
714
def on_menuitem_file_rename_activate(self, widget):
715
""" File/Rename... menu handler. """
716
from rename import OliveRename
717
rename = OliveRename(self.wt, self.wtpath, self.get_selected_right())
720
def on_menuitem_remove_file_activate(self, widget):
721
""" Remove (unversion) selected file. """
722
from remove import OliveRemoveDialog
723
remove = OliveRemoveDialog(self.wt, self.wtpath,
724
selected=self.get_selected_right(),
726
response = remove.run()
728
if response != gtk.RESPONSE_NONE:
731
if response == gtk.RESPONSE_OK:
732
self.set_path(self.path)
737
def on_menuitem_stats_diff_activate(self, widget):
738
""" Statistics/Differences... menu handler. """
739
window = DiffWindow(parent=self.window)
740
parent_tree = self.wt.branch.repository.revision_tree(self.wt.branch.last_revision())
741
window.set_diff(self.wt.branch.nick, self.wt, parent_tree)
744
def on_menuitem_stats_infos_activate(self, widget):
745
""" Statistics/Informations... menu handler. """
746
from info import OliveInfo
748
info = OliveInfo(self.remote_branch)
750
info = OliveInfo(self.wt.branch)
753
def on_menuitem_stats_log_activate(self, widget):
754
""" Statistics/Log... menu handler. """
757
branch = self.wt.branch
759
branch = self.remote_branch
761
window = branchwin.BranchWindow(branch, branch.last_revision(), None, parent=self.window)
764
def on_menuitem_view_refresh_activate(self, widget):
765
""" View/Refresh menu handler. """
766
# Refresh the left pane
768
# Refresh the right pane
771
def on_menuitem_view_show_hidden_files_activate(self, widget):
772
""" View/Show hidden files menu handler. """
773
self.pref.set_preference('dotted_files', widget.get_active())
774
if self.path is not None:
777
def on_menuitem_view_show_ignored_files_activate(self, widget):
778
""" Hide/Show ignored files menu handler. """
779
self.pref.set_preference('ignored_files', widget.get_active())
780
if self.path is not None:
783
def on_treeview_left_button_press_event(self, widget, event):
784
""" Occurs when somebody right-clicks in the bookmark list. """
785
if event.button == 3:
786
# Don't show context with nothing selected
787
if self.get_selected_left() == None:
791
from menu import OliveMenu
792
menu = OliveMenu(path=self.get_path(),
793
selected=self.get_selected_left(),
796
menu.left_context_menu().popup(None, None, None, 0,
799
def on_treeview_left_row_activated(self, treeview, path, view_column):
800
""" Occurs when somebody double-clicks or enters an item in the
803
newdir = self.get_selected_left()
807
if self.set_path(newdir):
810
def on_treeview_right_button_press_event(self, widget, event):
811
""" Occurs when somebody right-clicks in the file list. """
812
if event.button == 3:
814
from menu import OliveMenu
815
menu = OliveMenu(path=self.get_path(),
816
selected=self.get_selected_right(),
819
m_open = menu.ui.get_widget('/context_right/open')
820
m_add = menu.ui.get_widget('/context_right/add')
821
m_remove = menu.ui.get_widget('/context_right/remove')
822
m_rename = menu.ui.get_widget('/context_right/rename')
823
m_revert = menu.ui.get_widget('/context_right/revert')
824
m_commit = menu.ui.get_widget('/context_right/commit')
825
m_annotate = menu.ui.get_widget('/context_right/annotate')
826
m_diff = menu.ui.get_widget('/context_right/diff')
827
# check if we're in a branch
829
from bzrlib.branch import Branch
830
Branch.open_containing(self.get_path())
832
m_open.set_sensitive(False)
833
m_add.set_sensitive(False)
834
m_remove.set_sensitive(False)
835
m_rename.set_sensitive(False)
836
m_revert.set_sensitive(False)
837
m_commit.set_sensitive(False)
838
m_annotate.set_sensitive(False)
839
m_diff.set_sensitive(False)
841
m_open.set_sensitive(True)
842
m_add.set_sensitive(True)
843
m_remove.set_sensitive(True)
844
m_rename.set_sensitive(True)
845
m_revert.set_sensitive(True)
846
m_commit.set_sensitive(True)
847
m_annotate.set_sensitive(True)
848
m_diff.set_sensitive(True)
849
except bzrerrors.NotBranchError:
850
m_open.set_sensitive(True)
851
m_add.set_sensitive(False)
852
m_remove.set_sensitive(False)
853
m_rename.set_sensitive(False)
854
m_revert.set_sensitive(False)
855
m_commit.set_sensitive(False)
856
m_annotate.set_sensitive(False)
857
m_diff.set_sensitive(False)
860
menu.right_context_menu().popup(None, None, None, 0,
863
menu.remote_context_menu().popup(None, None, None, 0,
866
def on_treeview_right_row_activated(self, treeview, path, view_column):
867
""" Occurs when somebody double-clicks or enters an item in the
869
from launch import launch
871
newdir = self.get_selected_right()
876
self.set_path(os.path.split(self.get_path())[0])
878
fullpath = os.path.join(self.get_path(), newdir)
879
if os.path.isdir(fullpath):
880
# selected item is an existant directory
881
self.set_path(fullpath)
886
if self._is_remote_dir(self.get_path() + newdir):
887
self.set_path(self.get_path() + newdir)
891
def on_window_main_delete_event(self, widget, event=None):
892
""" Do some stuff before exiting. """
893
width, height = self.window_main.get_size()
894
self.pref.set_preference('window_width', width)
895
self.pref.set_preference('window_height', height)
896
x, y = self.window_main.get_position()
897
self.pref.set_preference('window_x', x)
898
self.pref.set_preference('window_y', y)
899
self.pref.set_preference('paned_position',
900
self.hpaned_main.get_position())
903
self.window_main.destroy()
905
def _load_left(self):
906
""" Load data into the left panel. (Bookmarks) """
908
treestore = gtk.TreeStore(str, str)
911
bookmarks = self.pref.get_bookmarks()
913
# Add them to the TreeStore
914
titer = treestore.append(None, [_('Bookmarks'), None])
915
for item in bookmarks:
916
title = self.pref.get_bookmark_title(item)
917
treestore.append(titer, [title, item])
919
# Create the column and add it to the TreeView
920
self.treeview_left.set_model(treestore)
921
tvcolumn_bookmark = gtk.TreeViewColumn(_('Bookmark'))
922
self.treeview_left.append_column(tvcolumn_bookmark)
925
cell = gtk.CellRendererText()
926
tvcolumn_bookmark.pack_start(cell, True)
927
tvcolumn_bookmark.add_attribute(cell, 'text', 0)
930
self.treeview_left.expand_all()
932
def _load_right(self):
933
""" Load data into the right panel. (Filelist) """
935
# Model: [ icon, dir, name, status text, status, size (int), size (human), mtime (int), mtime (local), fileid ]
936
liststore = gtk.ListStore(gobject.TYPE_STRING,
937
gobject.TYPE_BOOLEAN,
950
# Fill the appropriate lists
951
dotted_files = self.pref.get_preference('dotted_files', 'bool')
952
for item in os.listdir(self.path):
953
if not dotted_files and item[0] == '.':
955
if os.path.isdir(self.path + os.sep + item):
960
if not self.notbranch:
961
branch = self.wt.branch
962
tree2 = self.wt.branch.repository.revision_tree(branch.last_revision())
964
delta = self.wt.changes_from(tree2, want_unchanged=True)
966
# Add'em to the ListStore
969
statinfo = os.stat(self.path + os.sep + item)
975
liststore.append([ gtk.STOCK_DIRECTORY,
983
self._format_date(statinfo.st_mtime),
988
if not self.notbranch:
989
filename = self.wt.relpath(self.path + os.sep + item)
994
for rpath, rpathnew, id, kind, text_modified, meta_modified in delta.renamed:
995
if rpathnew == filename:
998
for rpath, id, kind in delta.added:
999
if rpath == filename:
1002
for rpath, id, kind in delta.removed:
1003
if rpath == filename:
1006
for rpath, id, kind, text_modified, meta_modified in delta.modified:
1007
if rpath == filename:
1010
for rpath, id, kind in delta.unchanged:
1011
if rpath == filename:
1012
status = 'unchanged'
1014
for rpath, file_class, kind, id, entry in self.wt.list_files():
1015
if rpath == filename and file_class == 'I':
1020
if status == 'renamed':
1022
elif status == 'removed':
1024
elif status == 'added':
1026
elif status == 'modified':
1028
elif status == 'unchanged':
1030
elif status == 'ignored':
1036
statinfo = os.stat(self.path + os.sep + item)
1042
liststore.append([gtk.STOCK_FILE,
1047
str(statinfo.st_size), # NOTE: if int used there it will fail for large files (size expressed as long int)
1048
self._format_size(statinfo.st_size),
1050
self._format_date(statinfo.st_mtime),
1053
# Create the columns and add them to the TreeView
1054
self.treeview_right.set_model(liststore)
1055
self._tvcolumn_filename = gtk.TreeViewColumn(_('Filename'))
1056
self._tvcolumn_status = gtk.TreeViewColumn(_('Status'))
1057
self._tvcolumn_size = gtk.TreeViewColumn(_('Size'))
1058
self._tvcolumn_mtime = gtk.TreeViewColumn(_('Last modified'))
1059
self.treeview_right.append_column(self._tvcolumn_filename)
1060
self.treeview_right.append_column(self._tvcolumn_status)
1061
self.treeview_right.append_column(self._tvcolumn_size)
1062
self.treeview_right.append_column(self._tvcolumn_mtime)
1065
cellpb = gtk.CellRendererPixbuf()
1066
cell = gtk.CellRendererText()
1067
self._tvcolumn_filename.pack_start(cellpb, False)
1068
self._tvcolumn_filename.pack_start(cell, True)
1069
self._tvcolumn_filename.set_attributes(cellpb, stock_id=0)
1070
self._tvcolumn_filename.add_attribute(cell, 'text', 2)
1071
self._tvcolumn_status.pack_start(cell, True)
1072
self._tvcolumn_status.add_attribute(cell, 'text', 3)
1073
self._tvcolumn_size.pack_start(cell, True)
1074
self._tvcolumn_size.add_attribute(cell, 'text', 6)
1075
self._tvcolumn_mtime.pack_start(cell, True)
1076
self._tvcolumn_mtime.add_attribute(cell, 'text', 8)
1078
# Set up the properties of the TreeView
1079
self.treeview_right.set_headers_visible(True)
1080
self.treeview_right.set_headers_clickable(True)
1081
self.treeview_right.set_search_column(1)
1082
self._tvcolumn_filename.set_resizable(True)
1083
self._tvcolumn_status.set_resizable(True)
1084
self._tvcolumn_size.set_resizable(True)
1085
self._tvcolumn_mtime.set_resizable(True)
1087
liststore.set_sort_func(13, self._sort_filelist_callback, None)
1088
liststore.set_sort_column_id(13, gtk.SORT_ASCENDING)
1089
self._tvcolumn_filename.set_sort_column_id(13)
1090
self._tvcolumn_status.set_sort_column_id(3)
1091
self._tvcolumn_size.set_sort_column_id(5)
1092
self._tvcolumn_mtime.set_sort_column_id(7)
1095
self.set_sensitivity()
1097
def get_selected_fileid(self):
1098
""" Get the file_id of the selected file. """
1099
treeselection = self.treeview_right.get_selection()
1100
(model, iter) = treeselection.get_selected()
1105
return model.get_value(iter, 9)
1107
def get_selected_right(self):
1108
""" Get the selected filename. """
1109
treeselection = self.treeview_right.get_selection()
1110
(model, iter) = treeselection.get_selected()
1115
return model.get_value(iter, 2)
1117
def get_selected_left(self):
1118
""" Get the selected bookmark. """
1119
treeselection = self.treeview_left.get_selection()
1120
(model, iter) = treeselection.get_selected()
1125
return model.get_value(iter, 1)
1127
def set_statusbar(self, message):
1128
""" Set the statusbar message. """
1129
self.statusbar.push(self.context_id, message)
1131
def clear_statusbar(self):
1132
""" Clean the last message from the statusbar. """
1133
self.statusbar.pop(self.context_id)
1135
def set_sensitivity(self):
1136
""" Set menu and toolbar sensitivity. """
1139
self.menuitem_branch_init.set_sensitive(self.notbranch)
1140
self.menuitem_branch_get.set_sensitive(self.notbranch)
1141
self.menuitem_branch_checkout.set_sensitive(self.notbranch)
1142
self.menuitem_branch_pull.set_sensitive(not self.notbranch)
1143
self.menuitem_branch_push.set_sensitive(not self.notbranch)
1144
self.menuitem_branch_update.set_sensitive(not self.notbranch)
1145
self.menuitem_branch_revert.set_sensitive(not self.notbranch)
1146
self.menuitem_branch_merge.set_sensitive(not self.notbranch)
1147
self.menuitem_branch_commit.set_sensitive(not self.notbranch)
1148
self.menuitem_branch_tags.set_sensitive(not self.notbranch)
1149
self.menuitem_branch_status.set_sensitive(not self.notbranch)
1150
self.menuitem_branch_missing.set_sensitive(not self.notbranch)
1151
self.menuitem_branch_conflicts.set_sensitive(not self.notbranch)
1152
self.menuitem_stats.set_sensitive(not self.notbranch)
1153
self.menuitem_stats_diff.set_sensitive(not self.notbranch)
1154
self.menuitem_add_files.set_sensitive(not self.notbranch)
1155
self.menuitem_remove_files.set_sensitive(not self.notbranch)
1156
self.menuitem_file_make_directory.set_sensitive(not self.notbranch)
1157
self.menuitem_file_rename.set_sensitive(not self.notbranch)
1158
self.menuitem_file_move.set_sensitive(not self.notbranch)
1159
self.menuitem_file_annotate.set_sensitive(not self.notbranch)
1160
#self.menutoolbutton_diff.set_sensitive(True)
1161
self.toolbutton_diff.set_sensitive(not self.notbranch)
1162
self.toolbutton_log.set_sensitive(not self.notbranch)
1163
self.toolbutton_commit.set_sensitive(not self.notbranch)
1164
self.toolbutton_pull.set_sensitive(not self.notbranch)
1165
self.toolbutton_push.set_sensitive(not self.notbranch)
1166
self.toolbutton_update.set_sensitive(not self.notbranch)
1169
self.menuitem_branch_init.set_sensitive(False)
1170
self.menuitem_branch_get.set_sensitive(True)
1171
self.menuitem_branch_checkout.set_sensitive(True)
1172
self.menuitem_branch_pull.set_sensitive(False)
1173
self.menuitem_branch_push.set_sensitive(False)
1174
self.menuitem_branch_update.set_sensitive(False)
1175
self.menuitem_branch_revert.set_sensitive(False)
1176
self.menuitem_branch_merge.set_sensitive(False)
1177
self.menuitem_branch_commit.set_sensitive(False)
1178
self.menuitem_branch_tags.set_sensitive(True)
1179
self.menuitem_branch_status.set_sensitive(False)
1180
self.menuitem_branch_missing.set_sensitive(False)
1181
self.menuitem_branch_conflicts.set_sensitive(False)
1182
self.menuitem_stats.set_sensitive(True)
1183
self.menuitem_stats_diff.set_sensitive(False)
1184
self.menuitem_add_files.set_sensitive(False)
1185
self.menuitem_remove_files.set_sensitive(False)
1186
self.menuitem_file_make_directory.set_sensitive(False)
1187
self.menuitem_file_rename.set_sensitive(False)
1188
self.menuitem_file_move.set_sensitive(False)
1189
self.menuitem_file_annotate.set_sensitive(False)
1190
#self.menutoolbutton_diff.set_sensitive(True)
1191
self.toolbutton_diff.set_sensitive(False)
1192
self.toolbutton_log.set_sensitive(True)
1193
self.toolbutton_commit.set_sensitive(False)
1194
self.toolbutton_pull.set_sensitive(False)
1195
self.toolbutton_push.set_sensitive(False)
1196
self.toolbutton_update.set_sensitive(False)
1198
def refresh_left(self):
1199
""" Refresh the bookmark list. """
1201
# Get TreeStore and clear it
1202
treestore = self.treeview_left.get_model()
1205
# Re-read preferences
1209
bookmarks = self.pref.get_bookmarks()
1211
# Add them to the TreeStore
1212
titer = treestore.append(None, [_('Bookmarks'), None])
1213
for item in bookmarks:
1214
title = self.pref.get_bookmark_title(item)
1215
treestore.append(titer, [title, item])
1217
# Add the TreeStore to the TreeView
1218
self.treeview_left.set_model(treestore)
1221
self.treeview_left.expand_all()
1223
def refresh_right(self, path=None):
1224
""" Refresh the file list. """
1227
from bzrlib.workingtree import WorkingTree
1230
path = self.get_path()
1232
# A workaround for double-clicking Bookmarks
1233
if not os.path.exists(path):
1236
# Get ListStore and clear it
1237
liststore = self.treeview_right.get_model()
1240
# Show Status column
1241
self._tvcolumn_status.set_visible(True)
1246
# Fill the appropriate lists
1247
dotted_files = self.pref.get_preference('dotted_files', 'bool')
1248
ignored_files = self.pref.get_preference('ignored_files', 'bool')
1250
for item in os.listdir(path):
1251
if not dotted_files and item[0] == '.':
1253
if os.path.isdir(path + os.sep + item):
1258
# Try to open the working tree
1261
tree1 = WorkingTree.open_containing(path)[0]
1262
except (bzrerrors.NotBranchError, bzrerrors.NoWorkingTree):
1266
branch = tree1.branch
1267
tree2 = tree1.branch.repository.revision_tree(branch.last_revision())
1269
delta = tree1.changes_from(tree2, want_unchanged=True)
1271
# Add'em to the ListStore
1274
statinfo = os.stat(self.path + os.sep + item)
1280
liststore.append([gtk.STOCK_DIRECTORY,
1288
self._format_date(statinfo.st_mtime),
1294
filename = tree1.relpath(path + os.sep + item)
1299
for rpath, rpathnew, id, kind, text_modified, meta_modified in delta.renamed:
1300
if rpathnew == filename:
1303
for rpath, id, kind in delta.added:
1304
if rpath == filename:
1307
for rpath, id, kind in delta.removed:
1308
if rpath == filename:
1311
for rpath, id, kind, text_modified, meta_modified in delta.modified:
1312
if rpath == filename:
1315
for rpath, id, kind in delta.unchanged:
1316
if rpath == filename:
1317
status = 'unchanged'
1319
for rpath, file_class, kind, id, entry in self.wt.list_files():
1320
if rpath == filename and file_class == 'I':
1325
if status == 'renamed':
1327
elif status == 'removed':
1329
elif status == 'added':
1331
elif status == 'modified':
1333
elif status == 'unchanged':
1335
elif status == 'ignored':
1337
if not ignored_files:
1343
statinfo = os.stat(self.path + os.sep + item)
1349
liststore.append([gtk.STOCK_FILE,
1354
str(statinfo.st_size),
1355
self._format_size(statinfo.st_size),
1357
self._format_date(statinfo.st_mtime),
1362
# Get ListStore and clear it
1363
liststore = self.treeview_right.get_model()
1366
# Hide Status column
1367
self._tvcolumn_status.set_visible(False)
1372
self._show_stock_image(gtk.STOCK_REFRESH)
1374
for (name, type) in self.remote_entries:
1375
if type.kind == 'directory':
1377
elif type.kind == 'file':
1381
""" Cache based on revision history. """
1382
def __init__(self, history):
1383
self._history = history
1385
def _lookup_revision(self, revid):
1386
for r in self._history:
1387
if r.revision_id == revid:
1389
rev = repo.get_revision(revid)
1390
self._history.append(rev)
1393
repo = self.remote_branch.repository
1395
revhistory = self.remote_branch.revision_history()
1397
revs = repo.get_revisions(revhistory)
1398
cache = HistoryCache(revs)
1399
except bzrerrors.InvalidHttpResponse:
1400
# Fallback to dummy algorithm, because of LP: #115209
1401
cache = HistoryCache([])
1404
if item.parent_id == self.remote_parent:
1405
rev = cache._lookup_revision(item.revision)
1406
liststore.append([ gtk.STOCK_DIRECTORY,
1414
self._format_date(rev.timestamp),
1417
while gtk.events_pending():
1418
gtk.main_iteration()
1421
if item.parent_id == self.remote_parent:
1422
rev = cache._lookup_revision(item.revision)
1423
liststore.append([ gtk.STOCK_FILE,
1428
str(item.text_size),
1429
self._format_size(item.text_size),
1431
self._format_date(rev.timestamp),
1434
while gtk.events_pending():
1435
gtk.main_iteration()
1437
self.image_location_error.destroy()
1439
# Columns should auto-size
1440
self.treeview_right.columns_autosize()
1443
self.set_sensitivity()
1445
def _harddisks(self):
1446
""" Returns hard drive letters under Win32. """
1451
if sys.platform == 'win32':
1452
print "pyWin32 modules needed to run Olive on Win32."
1458
for drive in string.ascii_uppercase:
1459
if win32file.GetDriveType(drive+':') == win32file.DRIVE_FIXED:
1460
driveletters.append(drive+':')
1463
def gen_hard_selector(self):
1464
""" Generate the hard drive selector under Win32. """
1465
drives = self._harddisks()
1466
for drive in drives:
1467
self.combobox_drive.append_text(drive)
1468
self.combobox_drive.set_active(drives.index(os.getcwd()[0:2]))
1470
def _refresh_drives(self, combobox):
1471
if self._just_started:
1473
model = combobox.get_model()
1474
active = combobox.get_active()
1476
drive = model[active][0]
1477
self.set_path(drive + '\\')
1478
self.refresh_right(drive + '\\')
1480
def check_for_changes(self):
1481
""" Check whether there were changes in the current working tree. """
1482
old_tree = self.wt.branch.repository.revision_tree(self.wt.branch.last_revision())
1483
delta = self.wt.changes_from(old_tree)
1487
if len(delta.added) or len(delta.removed) or len(delta.renamed) or len(delta.modified):
1492
def _sort_filelist_callback(self, model, iter1, iter2, data):
1493
""" The sort callback for the file list, return values:
1498
name1 = model.get_value(iter1, 2)
1499
name2 = model.get_value(iter2, 2)
1501
if model.get_value(iter1, 1):
1502
# item1 is a directory
1503
if not model.get_value(iter2, 1):
1507
# both of them are directories, we compare their names
1510
elif name1 == name2:
1515
# item1 is not a directory
1516
if model.get_value(iter2, 1):
1520
# both of them are files, compare them
1523
elif name1 == name2:
1528
def _format_size(self, size):
1529
""" Format size to a human readable format. """
1531
return "%d[B]" % (size,)
1532
size = size / 1000.0
1534
for metric in ["kB","MB","GB","TB"]:
1537
size = size / 1000.0
1538
return "%.1f[%s]" % (size,metric)
1540
def _format_date(self, timestamp):
1541
""" Format the time (given in secs) to a human readable format. """
1542
return time.ctime(timestamp)
1544
def _is_remote_dir(self, location):
1545
""" Determine whether the given location is a directory or not. """
1547
# We're in local mode
1550
branch, path = Branch.open_containing(location)
1551
for (name, type) in self.remote_entries:
1552
if name == path and type.kind == 'directory':
1555
# Either it's not a directory or not in the inventory
1558
def _show_stock_image(self, stock_id):
1559
""" Show a stock image next to the location entry. """
1560
self.image_location_error.destroy()
1561
self.image_location_error = gtk.image_new_from_stock(stock_id, gtk.ICON_SIZE_BUTTON)
1562
self.hbox_location.pack_start(self.image_location_error, False, False, 0)
1563
if sys.platform == 'win32':
1564
self.hbox_location.reorder_child(self.image_location_error, 2)
1566
self.hbox_location.reorder_child(self.image_location_error, 1)
1567
self.image_location_error.show()
1568
while gtk.events_pending():
1569
gtk.main_iteration()
1574
""" A class which handles Olive's preferences. """
1575
def __init__(self, path=None):
1576
""" Initialize the Preferences class. """
1577
# Some default options
1578
self.defaults = { 'strict_commit' : False,
1579
'dotted_files' : False,
1580
'ignored_files' : True,
1581
'window_width' : 700,
1582
'window_height' : 400,
1585
'paned_position': 200 }
1587
# Create a config parser object
1588
self.config = ConfigParser.RawConfigParser()
1592
if sys.platform == 'win32':
1593
# Windows - no dotted files
1594
self._filename = os.path.expanduser('~/olive.conf')
1596
self._filename = os.path.expanduser('~/.olive.conf')
1598
self._filename = path
1600
# Load the configuration
1603
def _get_default(self, option):
1604
""" Get the default option for a preference. """
1606
ret = self.defaults[option]
1613
""" Refresh the configuration. """
1614
# First write out the changes
1616
# Then load the configuration again
1620
""" Just read the configuration. """
1621
# Re-initialize the config parser object to avoid some bugs
1622
self.config = ConfigParser.RawConfigParser()
1623
self.config.read([self._filename])
1626
""" Write the configuration to the appropriate files. """
1627
fp = open(self._filename, 'w')
1628
self.config.write(fp)
1631
def get_bookmarks(self):
1632
""" Return the list of bookmarks. """
1633
bookmarks = self.config.sections()
1634
if self.config.has_section('preferences'):
1635
bookmarks.remove('preferences')
1638
def add_bookmark(self, path):
1639
""" Add bookmark. """
1641
self.config.add_section(path)
1642
except ConfigParser.DuplicateSectionError:
1647
def get_bookmark_title(self, path):
1648
""" Get bookmark title. """
1650
ret = self.config.get(path, 'title')
1651
except ConfigParser.NoOptionError:
1656
def set_bookmark_title(self, path, title):
1657
""" Set bookmark title. """
1658
# FIXME: What if path isn't listed yet?
1659
# FIXME: Canonicalize paths first?
1660
self.config.set(path, 'title', title)
1662
def remove_bookmark(self, path):
1663
""" Remove bookmark. """
1664
return self.config.remove_section(path)
1666
def set_preference(self, option, value):
1667
""" Set the value of the given option. """
1670
elif value is False:
1673
if self.config.has_section('preferences'):
1674
self.config.set('preferences', option, value)
1676
self.config.add_section('preferences')
1677
self.config.set('preferences', option, value)
1679
def get_preference(self, option, kind='str'):
1680
""" Get the value of the given option.
1682
:param kind: str/bool/int/float. default: str
1684
if self.config.has_option('preferences', option):
1686
return self.config.getboolean('preferences', option)
1688
return self.config.getint('preferences', option)
1689
elif kind == 'float':
1690
return self.config.getfloat('preferences', option)
1692
return self.config.get('preferences', option)
1695
return self._get_default(option)