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
22
gettext.install('olive-gtk')
34
from bzrlib.branch import Branch
35
import bzrlib.errors as bzrerrors
36
from bzrlib.workingtree import WorkingTree
38
from dialog import error_dialog, info_dialog, warning_dialog
39
from errors import show_bzr_error
40
from guifiles import GLADEFILENAME
42
# import this classes only once
44
from bzrlib.plugins.gtk.viz.diffwin import DiffWindow
45
from bzrlib.plugins.gtk.viz.branchwin import BranchWindow
46
from bzrlib.plugins.gtk.annotate.gannotate import GAnnotateWindow
47
from bzrlib.plugins.gtk.annotate.config import GAnnotateConfig
49
# olive+bzr-gtk not installed. try to import from sources
50
path = os.path.dirname(os.path.dirname(__file__))
51
if path not in sys.path:
53
from viz.diffwin import DiffWindow
54
from viz.branchwin import BranchWindow
55
from annotate.gannotate import GAnnotateWindow
56
from annotate.config import GAnnotateConfig
60
""" The main Olive GTK frontend class. This is called when launching the
64
self.toplevel = gtk.glade.XML(GLADEFILENAME, 'window_main', 'olive-gtk')
66
self.window = self.toplevel.get_widget('window_main')
68
self.pref = OlivePreferences()
72
# Initialize the statusbar
73
self.statusbar = self.toplevel.get_widget('statusbar')
74
self.context_id = self.statusbar.get_context_id('olive')
77
self.window_main = self.toplevel.get_widget('window_main')
79
self.hpaned_main = self.toplevel.get_widget('hpaned_main')
81
self.treeview_left = self.toplevel.get_widget('treeview_left')
82
self.treeview_right = self.toplevel.get_widget('treeview_right')
83
# Get some important menu items
84
self.menuitem_add_files = self.toplevel.get_widget('menuitem_add_files')
85
self.menuitem_remove_files = self.toplevel.get_widget('menuitem_remove_file')
86
self.menuitem_file_make_directory = self.toplevel.get_widget('menuitem_file_make_directory')
87
self.menuitem_file_rename = self.toplevel.get_widget('menuitem_file_rename')
88
self.menuitem_file_move = self.toplevel.get_widget('menuitem_file_move')
89
self.menuitem_file_annotate = self.toplevel.get_widget('menuitem_file_annotate')
90
self.menuitem_view_show_hidden_files = self.toplevel.get_widget('menuitem_view_show_hidden_files')
91
self.menuitem_branch = self.toplevel.get_widget('menuitem_branch')
92
self.menuitem_branch_init = self.toplevel.get_widget('menuitem_branch_initialize')
93
self.menuitem_branch_get = self.toplevel.get_widget('menuitem_branch_get')
94
self.menuitem_branch_checkout = self.toplevel.get_widget('menuitem_branch_checkout')
95
self.menuitem_branch_pull = self.toplevel.get_widget('menuitem_branch_pull')
96
self.menuitem_branch_push = self.toplevel.get_widget('menuitem_branch_push')
97
self.menuitem_branch_revert = self.toplevel.get_widget('menuitem_branch_revert')
98
self.menuitem_branch_merge = self.toplevel.get_widget('menuitem_branch_merge')
99
self.menuitem_branch_commit = self.toplevel.get_widget('menuitem_branch_commit')
100
self.menuitem_branch_status = self.toplevel.get_widget('menuitem_branch_status')
101
self.menuitem_branch_missing = self.toplevel.get_widget('menuitem_branch_missing_revisions')
102
self.menuitem_stats = self.toplevel.get_widget('menuitem_stats')
103
self.menuitem_stats_diff = self.toplevel.get_widget('menuitem_stats_diff')
104
self.menuitem_stats_log = self.toplevel.get_widget('menuitem_stats_log')
105
# Get some toolbuttons
106
#self.menutoolbutton_diff = self.toplevel.get_widget('menutoolbutton_diff')
107
self.toolbutton_diff = self.toplevel.get_widget('toolbutton_diff')
108
self.toolbutton_log = self.toplevel.get_widget('toolbutton_log')
109
self.toolbutton_commit = self.toplevel.get_widget('toolbutton_commit')
110
self.toolbutton_pull = self.toplevel.get_widget('toolbutton_pull')
111
self.toolbutton_push = self.toplevel.get_widget('toolbutton_push')
112
# Get the drive selector
113
self.combobox_drive = gtk.combo_box_new_text()
114
self.combobox_drive.connect("changed", self._refresh_drives)
116
self.vbox_main_right = self.toplevel.get_widget('vbox_main_right')
119
# Dictionary for signal_autoconnect
120
dic = { "on_window_main_destroy": gtk.main_quit,
121
"on_window_main_delete_event": self.on_window_main_delete_event,
122
"on_quit_activate": self.on_window_main_delete_event,
123
"on_about_activate": self.on_about_activate,
124
"on_menuitem_add_files_activate": self.on_menuitem_add_files_activate,
125
"on_menuitem_remove_file_activate": self.on_menuitem_remove_file_activate,
126
"on_menuitem_file_make_directory_activate": self.on_menuitem_file_make_directory_activate,
127
"on_menuitem_file_move_activate": self.on_menuitem_file_move_activate,
128
"on_menuitem_file_rename_activate": self.on_menuitem_file_rename_activate,
129
"on_menuitem_file_annotate_activate": self.on_menuitem_file_annotate_activate,
130
"on_menuitem_view_show_hidden_files_activate": self.on_menuitem_view_show_hidden_files_activate,
131
"on_menuitem_view_refresh_activate": self.on_menuitem_view_refresh_activate,
132
"on_menuitem_branch_initialize_activate": self.on_menuitem_branch_initialize_activate,
133
"on_menuitem_branch_get_activate": self.on_menuitem_branch_get_activate,
134
"on_menuitem_branch_checkout_activate": self.on_menuitem_branch_checkout_activate,
135
"on_menuitem_branch_revert_activate": self.on_menuitem_branch_revert_activate,
136
"on_menuitem_branch_merge_activate": self.on_menuitem_branch_merge_activate,
137
"on_menuitem_branch_commit_activate": self.on_menuitem_branch_commit_activate,
138
"on_menuitem_branch_push_activate": self.on_menuitem_branch_push_activate,
139
"on_menuitem_branch_pull_activate": self.on_menuitem_branch_pull_activate,
140
"on_menuitem_branch_status_activate": self.on_menuitem_branch_status_activate,
141
"on_menuitem_branch_missing_revisions_activate": self.on_menuitem_branch_missing_revisions_activate,
142
"on_menuitem_stats_diff_activate": self.on_menuitem_stats_diff_activate,
143
"on_menuitem_stats_log_activate": self.on_menuitem_stats_log_activate,
144
"on_menuitem_stats_infos_activate": self.on_menuitem_stats_infos_activate,
145
"on_toolbutton_refresh_clicked": self.on_menuitem_view_refresh_activate,
146
"on_toolbutton_log_clicked": self.on_menuitem_stats_log_activate,
147
#"on_menutoolbutton_diff_clicked": self.on_menuitem_stats_diff_activate,
148
"on_toolbutton_diff_clicked": self.on_menuitem_stats_diff_activate,
149
"on_toolbutton_commit_clicked": self.on_menuitem_branch_commit_activate,
150
"on_toolbutton_pull_clicked": self.on_menuitem_branch_pull_activate,
151
"on_toolbutton_push_clicked": self.on_menuitem_branch_push_activate,
152
"on_treeview_right_button_press_event": self.on_treeview_right_button_press_event,
153
"on_treeview_right_row_activated": self.on_treeview_right_row_activated,
154
"on_treeview_left_button_press_event": self.on_treeview_left_button_press_event,
155
"on_treeview_left_row_activated": self.on_treeview_left_row_activated }
157
# Connect the signals to the handlers
158
self.toplevel.signal_autoconnect(dic)
160
self._just_started = True
162
# Apply window size and position
163
width = self.pref.get_preference('window_width', 'int')
164
height = self.pref.get_preference('window_height', 'int')
165
self.window.resize(width, height)
166
x = self.pref.get_preference('window_x', 'int')
167
y = self.pref.get_preference('window_y', 'int')
168
self.window.move(x, y)
169
# Apply paned position
170
pos = self.pref.get_preference('paned_position', 'int')
171
self.hpaned_main.set_position(pos)
173
# Apply menu to the toolbutton
174
#menubutton = self.toplevel.get_widget('menutoolbutton_diff')
175
#menubutton.set_menu(handler.menu.toolbar_diff)
177
# Now we can show the window
180
# Show drive selector if under Win32
181
if sys.platform == 'win32':
182
self.vbox_main_right.pack_start(self.combobox_drive, False, True, 0)
183
self.vbox_main_right.reorder_child(self.combobox_drive, 0)
184
self.combobox_drive.show()
185
self.gen_hard_selector()
190
self.menuitem_view_show_hidden_files.set_active(self.pref.get_preference('dotted_files', 'bool'))
192
self.set_path(os.getcwd())
195
self._just_started = False
197
def set_path(self, path):
199
self.notbranch = False
202
self.wt, self.wtpath = WorkingTree.open_containing(self.path)
203
except (bzrerrors.NotBranchError, bzrerrors.NoWorkingTree):
204
self.notbranch = True
206
self.statusbar.push(self.context_id, path)
211
def on_about_activate(self, widget):
212
from dialog import about
215
def on_menuitem_add_files_activate(self, widget):
216
""" Add file(s)... menu handler. """
217
from add import OliveAdd
218
add = OliveAdd(self.wt, self.wtpath, self.get_selected_right())
221
def on_menuitem_branch_get_activate(self, widget):
222
""" Branch/Get... menu handler. """
223
from branch import BranchDialog
224
branch = BranchDialog(self.get_path())
227
def on_menuitem_branch_checkout_activate(self, widget):
228
""" Branch/Checkout... menu handler. """
229
from checkout import OliveCheckout
230
checkout = OliveCheckout(self.get_path())
233
def on_menuitem_branch_commit_activate(self, widget):
234
""" Branch/Commit... menu handler. """
235
from commit import CommitDialog
236
commit = CommitDialog(self.wt, self.wtpath, self.notbranch, self.get_selected_right(), self.window)
237
response = commit.run()
238
if response != gtk.RESPONSE_NONE:
241
if response == gtk.RESPONSE_OK:
246
def on_menuitem_branch_merge_activate(self, widget):
247
""" Branch/Merge... menu handler. """
248
from merge import MergeDialog
250
if self.check_for_changes():
251
error_dialog(_('There are local changes in the branch'),
252
_('Please commit or revert the changes before merging.'))
254
merge = MergeDialog(self.wt, self.wtpath)
257
def on_menuitem_branch_missing_revisions_activate(self, widget):
258
""" Branch/Missing revisions menu handler. """
259
local_branch = self.wt.branch
261
other_branch = local_branch.get_parent()
262
if other_branch is None:
263
error_dialog(_('Parent location is unknown'),
264
_('Cannot determine missing revisions if no parent location is known.'))
267
remote_branch = Branch.open(other_branch)
269
if remote_branch.base == local_branch.base:
270
remote_branch = local_branch
272
ret = len(local_branch.missing_revisions(remote_branch))
275
info_dialog(_('There are missing revisions'),
276
_('%d revision(s) missing.') % ret)
278
info_dialog(_('Local branch up to date'),
279
_('There are no missing revisions.'))
282
def on_menuitem_branch_pull_activate(self, widget):
283
""" Branch/Pull menu handler. """
284
branch_to = self.wt.branch
286
location = branch_to.get_parent()
288
error_dialog(_('Parent location is unknown'),
289
_('Pulling is not possible until there is a parent location.'))
292
branch_from = Branch.open(location)
294
if branch_to.get_parent() is None:
295
branch_to.set_parent(branch_from.base)
297
#old_rh = branch_to.revision_history()
298
#if tree_to is not None:
299
# tree_to.pull(branch_from)
301
# branch_to.pull(branch_from)
302
ret = branch_to.pull(branch_from)
304
info_dialog(_('Pull successful'), _('%d revision(s) pulled.') % ret)
306
def on_menuitem_branch_push_activate(self, widget):
307
""" Branch/Push... menu handler. """
308
from push import OlivePush
309
push = OlivePush(self.wt.branch)
313
def on_menuitem_branch_revert_activate(self, widget):
314
""" Branch/Revert all changes menu handler. """
315
ret = self.wt.revert([])
317
warning_dialog(_('Conflicts detected'),
318
_('Please have a look at the working tree before continuing.'))
320
info_dialog(_('Revert successful'),
321
_('All files reverted to last revision.'))
324
def on_menuitem_branch_status_activate(self, widget):
325
""" Branch/Status... menu handler. """
326
from status import OliveStatus
327
status = OliveStatus(self.wt, self.wtpath)
331
def on_menuitem_branch_initialize_activate(self, widget):
332
""" Initialize current directory. """
333
import bzrlib.bzrdir as bzrdir
335
if not os.path.exists(self.path):
339
existing_bzrdir = bzrdir.BzrDir.open(self.path)
340
except bzrerrors.NotBranchError:
341
bzrdir.BzrDir.create_branch_convenience(self.path)
343
if existing_bzrdir.has_branch():
344
if existing_bzrdir.has_workingtree():
345
raise bzrerrors.AlreadyBranchError(self.path)
347
raise bzrerrors.BranchExistsWithoutWorkingTree(self.path)
349
existing_bzrdir.create_branch()
350
existing_bzrdir.create_workingtree()
351
info_dialog(_('Initialize successful'),
352
_('Directory successfully initialized.'))
355
def on_menuitem_file_annotate_activate(self, widget):
356
""" File/Annotate... menu handler. """
357
if self.get_selected_right() is None:
358
error_dialog(_('No file was selected'),
359
_('Please select a file from the list.'))
362
branch = self.wt.branch
363
file_id = self.wt.path2id(self.wt.relpath(os.path.join(self.path, self.get_selected_right())))
365
window = GAnnotateWindow(all=False, plain=False)
366
window.set_title(os.path.join(self.path, self.get_selected_right()) + " - Annotate")
367
config = GAnnotateConfig(window)
371
window.annotate(self.wt, branch, file_id)
375
def on_menuitem_file_make_directory_activate(self, widget):
376
""" File/Make directory... menu handler. """
377
from mkdir import OliveMkdir
378
mkdir = OliveMkdir(self.wt, self.wtpath)
381
def on_menuitem_file_move_activate(self, widget):
382
""" File/Move... menu handler. """
383
from move import OliveMove
384
move = OliveMove(self.wt, self.wtpath, self.get_selected_right())
387
def on_menuitem_file_rename_activate(self, widget):
388
""" File/Rename... menu handler. """
389
from rename import OliveRename
390
rename = OliveRename(self.wt, self.wtpath, self.get_selected_right())
393
def on_menuitem_remove_file_activate(self, widget):
394
""" Remove (unversion) selected file. """
395
from remove import OliveRemoveDialog
396
remove = OliveRemoveDialog(self.wt, self.wtpath,
397
selected=self.get_selected_right(),
399
response = remove.run()
401
if response != gtk.RESPONSE_NONE:
404
if response == gtk.RESPONSE_OK:
405
self.set_path(self.path)
410
def on_menuitem_stats_diff_activate(self, widget):
411
""" Statistics/Differences... menu handler. """
412
window = DiffWindow()
413
parent_tree = self.wt.branch.repository.revision_tree(self.wt.branch.last_revision())
414
window.set_diff(self.wt.branch.nick, self.wt, parent_tree)
417
def on_menuitem_stats_infos_activate(self, widget):
418
""" Statistics/Informations... menu handler. """
419
from info import OliveInfo
420
info = OliveInfo(self.wt)
423
def on_menuitem_stats_log_activate(self, widget):
424
""" Statistics/Log... menu handler. """
425
window = BranchWindow()
426
window.set_branch(self.wt.branch, self.wt.branch.last_revision(), None)
429
def on_menuitem_view_refresh_activate(self, widget):
430
""" View/Refresh menu handler. """
431
# Refresh the left pane
433
# Refresh the right pane
436
def on_menuitem_view_show_hidden_files_activate(self, widget):
437
""" View/Show hidden files menu handler. """
438
self.pref.set_preference('dotted_files', widget.get_active())
439
if self.path is not None:
442
def on_treeview_left_button_press_event(self, widget, event):
443
""" Occurs when somebody right-clicks in the bookmark list. """
444
if event.button == 3:
445
# Don't show context with nothing selected
446
if self.get_selected_left() == None:
450
from menu import OliveMenu
451
menu = OliveMenu(path=self.get_path(),
452
selected=self.get_selected_left(),
455
menu.left_context_menu().popup(None, None, None, 0,
458
def on_treeview_left_row_activated(self, treeview, path, view_column):
459
""" Occurs when somebody double-clicks or enters an item in the
462
newdir = self.get_selected_left()
466
self.set_path(newdir)
469
def on_treeview_right_button_press_event(self, widget, event):
470
""" Occurs when somebody right-clicks in the file list. """
471
if event.button == 3:
473
from menu import OliveMenu
474
menu = OliveMenu(path=self.get_path(),
475
selected=self.get_selected_right(),
478
m_add = menu.ui.get_widget('/context_right/add')
479
m_remove = menu.ui.get_widget('/context_right/remove')
480
m_rename = menu.ui.get_widget('/context_right/rename')
481
m_revert = menu.ui.get_widget('/context_right/revert')
482
m_commit = menu.ui.get_widget('/context_right/commit')
483
m_diff = menu.ui.get_widget('/context_right/diff')
484
# check if we're in a branch
486
from bzrlib.branch import Branch
487
Branch.open_containing(self.get_path())
488
m_add.set_sensitive(True)
489
m_remove.set_sensitive(True)
490
m_rename.set_sensitive(True)
491
m_revert.set_sensitive(True)
492
m_commit.set_sensitive(True)
493
m_diff.set_sensitive(True)
494
except bzrerrors.NotBranchError:
495
m_add.set_sensitive(False)
496
m_remove.set_sensitive(False)
497
m_rename.set_sensitive(False)
498
m_revert.set_sensitive(False)
499
m_commit.set_sensitive(False)
500
m_diff.set_sensitive(False)
502
menu.right_context_menu().popup(None, None, None, 0,
505
def on_treeview_right_row_activated(self, treeview, path, view_column):
506
""" Occurs when somebody double-clicks or enters an item in the
508
from launch import launch
510
newdir = self.get_selected_right()
513
self.set_path(os.path.split(self.get_path())[0])
515
fullpath = os.path.join(self.get_path(), newdir)
516
if os.path.isdir(fullpath):
517
# selected item is an existant directory
518
self.set_path(fullpath)
524
def on_window_main_delete_event(self, widget, event=None):
525
""" Do some stuff before exiting. """
526
width, height = self.window_main.get_size()
527
self.pref.set_preference('window_width', width)
528
self.pref.set_preference('window_height', height)
529
x, y = self.window_main.get_position()
530
self.pref.set_preference('window_x', x)
531
self.pref.set_preference('window_y', y)
532
self.pref.set_preference('paned_position',
533
self.hpaned_main.get_position())
536
self.window_main.destroy()
538
def _load_left(self):
539
""" Load data into the left panel. (Bookmarks) """
541
treestore = gtk.TreeStore(str, str)
544
bookmarks = self.pref.get_bookmarks()
546
# Add them to the TreeStore
547
titer = treestore.append(None, [_('Bookmarks'), None])
548
for item in bookmarks:
549
title = self.pref.get_bookmark_title(item)
550
treestore.append(titer, [title, item])
552
# Create the column and add it to the TreeView
553
self.treeview_left.set_model(treestore)
554
tvcolumn_bookmark = gtk.TreeViewColumn(_('Bookmark'))
555
self.treeview_left.append_column(tvcolumn_bookmark)
558
cell = gtk.CellRendererText()
559
tvcolumn_bookmark.pack_start(cell, True)
560
tvcolumn_bookmark.add_attribute(cell, 'text', 0)
563
self.treeview_left.expand_all()
565
def _add_updir_to_dirlist(self, dirlist, curdir):
566
"""Add .. to the top of directories list if we not in root directory
568
:param dirlist: list of directories (modified in place)
569
:param curdir: current directory
575
if sys.platform == 'win32':
576
drive, tail = os.path.splitdrive(curdir)
577
if tail in ('', '/', '\\'):
583
# insert always as first element
584
dirlist.insert(0, '..')
586
def _load_right(self):
587
""" Load data into the right panel. (Filelist) """
589
liststore = gtk.ListStore(str, str, str)
594
# Fill the appropriate lists
595
dotted_files = self.pref.get_preference('dotted_files', 'bool')
596
for item in os.listdir(self.path):
597
if not dotted_files and item[0] == '.':
599
if os.path.isdir(self.path + os.sep + item):
608
# add updir link to dirs
609
self._add_updir_to_dirlist(dirs, self.path)
611
if not self.notbranch:
612
branch = self.wt.branch
613
tree2 = self.wt.branch.repository.revision_tree(branch.last_revision())
615
delta = self.wt.changes_from(tree2, want_unchanged=True)
617
# Add'em to the ListStore
619
liststore.append([gtk.STOCK_DIRECTORY, item, ''])
622
if not self.notbranch:
623
filename = self.wt.relpath(self.path + os.sep + item)
625
for rpath, rpathnew, id, kind, text_modified, meta_modified in delta.renamed:
626
if rpathnew == filename:
628
for rpath, id, kind in delta.added:
629
if rpath == filename:
631
for rpath, id, kind in delta.removed:
632
if rpath == filename:
634
for rpath, id, kind, text_modified, meta_modified in delta.modified:
635
if rpath == filename:
637
for rpath, id, kind in delta.unchanged:
638
if rpath == filename:
640
for rpath, file_class, kind, id, entry in self.wt.list_files():
641
if rpath == filename and file_class == 'I':
645
# status = fileops.status(path + os.sep + item)
646
#except errors.PermissionDenied:
649
if status == 'renamed':
651
elif status == 'removed':
653
elif status == 'added':
655
elif status == 'modified':
657
elif status == 'unchanged':
659
elif status == 'ignored':
663
liststore.append([gtk.STOCK_FILE, item, st])
665
# Create the columns and add them to the TreeView
666
self.treeview_right.set_model(liststore)
667
tvcolumn_filename = gtk.TreeViewColumn(_('Filename'))
668
tvcolumn_status = gtk.TreeViewColumn(_('Status'))
669
self.treeview_right.append_column(tvcolumn_filename)
670
self.treeview_right.append_column(tvcolumn_status)
673
cellpb = gtk.CellRendererPixbuf()
674
cell = gtk.CellRendererText()
675
tvcolumn_filename.pack_start(cellpb, False)
676
tvcolumn_filename.pack_start(cell, True)
677
tvcolumn_filename.set_attributes(cellpb, stock_id=0)
678
tvcolumn_filename.add_attribute(cell, 'text', 1)
679
tvcolumn_status.pack_start(cell, True)
680
tvcolumn_status.add_attribute(cell, 'text', 2)
683
self.set_sensitivity()
685
def get_selected_right(self):
686
""" Get the selected filename. """
687
treeselection = self.treeview_right.get_selection()
688
(model, iter) = treeselection.get_selected()
693
return model.get_value(iter, 1)
695
def get_selected_left(self):
696
""" Get the selected bookmark. """
697
treeselection = self.treeview_left.get_selection()
698
(model, iter) = treeselection.get_selected()
703
return model.get_value(iter, 1)
705
def set_statusbar(self, message):
706
""" Set the statusbar message. """
707
self.statusbar.push(self.context_id, message)
709
def clear_statusbar(self):
710
""" Clean the last message from the statusbar. """
711
self.statusbar.pop(self.context_id)
713
def set_sensitivity(self):
714
""" Set menu and toolbar sensitivity. """
715
self.menuitem_branch_init.set_sensitive(self.notbranch)
716
self.menuitem_branch_get.set_sensitive(self.notbranch)
717
self.menuitem_branch_checkout.set_sensitive(self.notbranch)
718
self.menuitem_branch_pull.set_sensitive(not self.notbranch)
719
self.menuitem_branch_push.set_sensitive(not self.notbranch)
720
self.menuitem_branch_revert.set_sensitive(not self.notbranch)
721
self.menuitem_branch_merge.set_sensitive(not self.notbranch)
722
self.menuitem_branch_commit.set_sensitive(not self.notbranch)
723
self.menuitem_branch_status.set_sensitive(not self.notbranch)
724
self.menuitem_branch_missing.set_sensitive(not self.notbranch)
725
self.menuitem_stats.set_sensitive(not self.notbranch)
726
self.menuitem_add_files.set_sensitive(not self.notbranch)
727
self.menuitem_remove_files.set_sensitive(not self.notbranch)
728
self.menuitem_file_make_directory.set_sensitive(not self.notbranch)
729
self.menuitem_file_rename.set_sensitive(not self.notbranch)
730
self.menuitem_file_move.set_sensitive(not self.notbranch)
731
self.menuitem_file_annotate.set_sensitive(not self.notbranch)
732
#self.menutoolbutton_diff.set_sensitive(True)
733
self.toolbutton_diff.set_sensitive(not self.notbranch)
734
self.toolbutton_log.set_sensitive(not self.notbranch)
735
self.toolbutton_commit.set_sensitive(not self.notbranch)
736
self.toolbutton_pull.set_sensitive(not self.notbranch)
737
self.toolbutton_push.set_sensitive(not self.notbranch)
739
def refresh_left(self):
740
""" Refresh the bookmark list. """
742
# Get TreeStore and clear it
743
treestore = self.treeview_left.get_model()
746
# Re-read preferences
750
bookmarks = self.pref.get_bookmarks()
752
# Add them to the TreeStore
753
titer = treestore.append(None, [_('Bookmarks'), None])
754
for item in bookmarks:
755
title = self.pref.get_bookmark_title(item)
756
treestore.append(titer, [title, item])
758
# Add the TreeStore to the TreeView
759
self.treeview_left.set_model(treestore)
762
self.treeview_left.expand_all()
764
def refresh_right(self, path=None):
765
""" Refresh the file list. """
766
from bzrlib.workingtree import WorkingTree
769
path = self.get_path()
771
# A workaround for double-clicking Bookmarks
772
if not os.path.exists(path):
775
# Get ListStore and clear it
776
liststore = self.treeview_right.get_model()
782
# Fill the appropriate lists
783
dotted_files = self.pref.get_preference('dotted_files', 'bool')
784
for item in os.listdir(path):
785
if not dotted_files and item[0] == '.':
787
if os.path.isdir(path + os.sep + item):
796
# add updir link to dirs
797
self._add_updir_to_dirlist(dirs, path)
799
# Try to open the working tree
802
tree1 = WorkingTree.open_containing(path)[0]
803
except (bzrerrors.NotBranchError, bzrerrors.NoWorkingTree):
807
branch = tree1.branch
808
tree2 = tree1.branch.repository.revision_tree(branch.last_revision())
810
delta = tree1.changes_from(tree2, want_unchanged=True)
812
# Add'em to the ListStore
814
liststore.append([gtk.STOCK_DIRECTORY, item, ''])
818
filename = tree1.relpath(path + os.sep + item)
820
for rpath, rpathnew, id, kind, text_modified, meta_modified in delta.renamed:
821
if rpathnew == filename:
823
for rpath, id, kind in delta.added:
824
if rpath == filename:
826
for rpath, id, kind in delta.removed:
827
if rpath == filename:
829
for rpath, id, kind, text_modified, meta_modified in delta.modified:
830
if rpath == filename:
832
for rpath, id, kind in delta.unchanged:
833
if rpath == filename:
835
for rpath, file_class, kind, id, entry in self.wt.list_files():
836
if rpath == filename and file_class == 'I':
840
# status = fileops.status(path + os.sep + item)
841
#except errors.PermissionDenied:
844
if status == 'renamed':
846
elif status == 'removed':
848
elif status == 'added':
850
elif status == 'modified':
852
elif status == 'unchanged':
854
elif status == 'ignored':
858
liststore.append([gtk.STOCK_FILE, item, st])
860
# Add the ListStore to the TreeView
861
self.treeview_right.set_model(liststore)
864
self.set_sensitivity()
866
def _harddisks(self):
867
""" Returns hard drive letters under Win32. """
872
if sys.platform == 'win32':
873
print "pyWin32 modules needed to run Olive on Win32."
879
for drive in string.ascii_uppercase:
880
if win32file.GetDriveType(drive+':') == win32file.DRIVE_FIXED:
881
driveletters.append(drive+':')
884
def gen_hard_selector(self):
885
""" Generate the hard drive selector under Win32. """
886
drives = self._harddisks()
888
self.combobox_drive.append_text(drive)
889
self.combobox_drive.set_active(drives.index(os.getcwd()[0:2]))
891
def _refresh_drives(self, combobox):
892
if self._just_started:
894
model = combobox.get_model()
895
active = combobox.get_active()
897
drive = model[active][0]
898
self.set_path(drive + '\\')
899
self.refresh_right(drive + '\\')
901
def check_for_changes(self):
902
""" Check whether there were changes in the current working tree. """
903
old_tree = self.wt.branch.repository.revision_tree(self.wt.branch.last_revision())
904
delta = self.wt.changes_from(old_tree)
908
if len(delta.added) or len(delta.removed) or len(delta.renamed) or len(delta.modified):
915
class OlivePreferences:
916
""" A class which handles Olive's preferences. """
918
""" Initialize the Preferences class. """
919
# Some default options
920
self.defaults = { 'strict_commit' : False,
921
'dotted_files' : False,
922
'window_width' : 700,
923
'window_height' : 400,
926
'paned_position': 200 }
928
# Create a config parser object
929
self.config = ConfigParser.RawConfigParser()
931
# Load the configuration
934
def _get_default(self, option):
935
""" Get the default option for a preference. """
937
ret = self.defaults[option]
944
""" Refresh the configuration. """
945
# First write out the changes
947
# Then load the configuration again
951
""" Just read the configuration. """
952
# Re-initialize the config parser object to avoid some bugs
953
self.config = ConfigParser.RawConfigParser()
954
if sys.platform == 'win32':
955
# Windows - no dotted files
956
self.config.read([os.path.expanduser('~/olive.conf')])
958
self.config.read([os.path.expanduser('~/.olive.conf')])
961
""" Write the configuration to the appropriate files. """
962
if sys.platform == 'win32':
963
# Windows - no dotted files
964
fp = open(os.path.expanduser('~/olive.conf'), 'w')
965
self.config.write(fp)
968
fp = open(os.path.expanduser('~/.olive.conf'), 'w')
969
self.config.write(fp)
972
def get_bookmarks(self):
973
""" Return the list of bookmarks. """
974
bookmarks = self.config.sections()
975
if self.config.has_section('preferences'):
976
bookmarks.remove('preferences')
979
def add_bookmark(self, path):
980
""" Add bookmark. """
982
self.config.add_section(path)
983
except ConfigParser.DuplicateSectionError:
988
def get_bookmark_title(self, path):
989
""" Get bookmark title. """
991
ret = self.config.get(path, 'title')
992
except ConfigParser.NoOptionError:
997
def set_bookmark_title(self, path, title):
998
""" Set bookmark title. """
999
self.config.set(path, 'title', title)
1001
def remove_bookmark(self, path):
1002
""" Remove bookmark. """
1003
return self.config.remove_section(path)
1005
def set_preference(self, option, value):
1006
""" Set the value of the given option. """
1009
elif value is False:
1012
if self.config.has_section('preferences'):
1013
self.config.set('preferences', option, value)
1015
self.config.add_section('preferences')
1016
self.config.set('preferences', option, value)
1018
def get_preference(self, option, kind='str'):
1019
""" Get the value of the given option.
1021
:param kind: str/bool/int/float. default: str
1023
if self.config.has_option('preferences', option):
1025
return self.config.getboolean('preferences', option)
1027
return self.config.getint('preferences', option)
1028
elif kind == 'float':
1029
return self.config.getfloat('preferences', option)
1031
return self.config.get('preferences', option)
1034
return self._get_default(option)