/b-gtk/fix-viz

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/b-gtk/fix-viz

« back to all changes in this revision

Viewing changes to olive/__init__.py

  • Committer: Jelmer Vernooij
  • Date: 2006-09-30 10:21:43 UTC
  • Revision ID: jelmer@samba.org-20060930102143-c0ef64d6ca860c21
Merge some files from Olive and bzr-gtk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
16
16
 
17
17
import os
18
18
import sys
19
 
import time
20
 
import errno
21
 
 
22
 
# gettext support
23
 
import gettext
24
 
gettext.install('olive-gtk')
25
19
 
26
20
try:
27
21
    import pygtk
29
23
except:
30
24
    pass
31
25
 
32
 
import gobject
33
26
import gtk
34
27
import gtk.gdk
 
28
import gtk.glade
35
29
 
36
30
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
 
31
import bzrlib.errors as errors
40
32
from bzrlib.workingtree import WorkingTree
41
33
 
42
 
from bzrlib.plugins.gtk import _i18n
43
 
from bzrlib.plugins.gtk.dialog import error_dialog, info_dialog, warning_dialog
44
 
from bzrlib.plugins.gtk.errors import show_bzr_error
45
 
from bzrlib.plugins.gtk.olive.window import OliveGui
46
 
 
47
 
from bzrlib.plugins.gtk.diff import DiffWindow
48
 
lazy_import(globals(), """
49
 
from bzrlib.plugins.gtk.viz import branchwin
50
 
""")
51
 
from bzrlib.plugins.gtk.annotate.gannotate import GAnnotateWindow
52
 
from bzrlib.plugins.gtk.annotate.config import GAnnotateConfig
53
 
from bzrlib.plugins.gtk.commit import CommitDialog
54
 
from bzrlib.plugins.gtk.conflicts import ConflictsDialog
55
 
from bzrlib.plugins.gtk.initialize import InitDialog
56
 
from bzrlib.plugins.gtk.push import PushDialog
57
 
from bzrlib.plugins.gtk.revbrowser import RevisionBrowser
58
 
 
59
 
def about():
60
 
    """ Display the AboutDialog. """
61
 
    from bzrlib.plugins.gtk import __version__, icon_path
62
 
    
63
 
    iconpath = icon_path() + os.sep
64
 
    
65
 
    dialog = gtk.AboutDialog()
66
 
    dialog.set_name("Olive")
67
 
    dialog.set_version(__version__)
68
 
    dialog.set_copyright("Copyright (C) 2006 Szilveszter Farkas (Phanatic)")
69
 
    dialog.set_website("https://launchpad.net/products/olive")
70
 
    dialog.set_website_label("https://launchpad.net/products/olive")
71
 
    dialog.set_icon_from_file(iconpath+"oliveicon2.png")
72
 
    dialog.set_logo(gtk.gdk.pixbuf_new_from_file(iconpath+"oliveicon2.png"))
73
 
    dialog.set_authors([ _i18n("Lead Developer:"),
74
 
                         "Szilveszter Farkas <szilveszter.farkas@gmail.com>",
75
 
                         _i18n("Contributors:"),
76
 
                         "Jelmer Vernooij <jelmer@samba.org>",
77
 
                         "Mateusz Korniak <mateusz.korniak@ant.gliwice.pl>",
78
 
                         "Gary van der Merwe <garyvdm@gmail.com>" ])
79
 
    dialog.set_artists([ "Simon Pascal Klein <klepas@klepas.org>",
80
 
                         "Jakub Steiner <jimmac@novell.com>" ])
81
 
 
82
 
    dialog.run()
83
 
    # Destroy the dialog
84
 
    dialog.destroy()
 
34
# Olive GTK UI version
 
35
__version__ = '0.11.0'
 
36
 
 
37
# Load the glade file
 
38
if sys.platform == 'win32':
 
39
    gladefile = os.path.dirname(sys.executable) + "/share/olive/olive.glade"
 
40
else:
 
41
    gladefile = "/usr/share/olive/olive.glade"
 
42
 
 
43
if not os.path.exists(gladefile):
 
44
    # Load from current directory if not installed
 
45
    gladefile = "olive.glade"
 
46
    # Check again
 
47
    if not os.path.exists(gladefile):
 
48
        # Fail
 
49
        print _('Glade file cannot be found.')
 
50
        sys.exit(1)
 
51
 
 
52
from dialog import error_dialog, info_dialog
85
53
 
86
54
class OliveGtk:
87
55
    """ The main Olive GTK frontend class. This is called when launching the
88
56
    program. """
89
57
    
90
58
    def __init__(self):
91
 
        self.window = OliveGui(calling_app = self)
92
 
        
93
 
        self.pref = Preferences()
94
 
        self.path = None
 
59
        self.toplevel = gtk.glade.XML(gladefile, 'window_main', 'olive-gtk')
 
60
        
 
61
        self.window = self.toplevel.get_widget('window_main')
 
62
        
 
63
        self.pref = OlivePreferences()
95
64
 
96
65
        # Initialize the statusbar
97
 
        self.context_id = self.window.statusbar.get_context_id('olive')
98
 
        
99
 
                # Get the TreeViews
100
 
        self.treeview_left = self.window.treeview_left
101
 
        self.treeview_right = self.window.treeview_right
102
 
        
 
66
        self.statusbar = self.toplevel.get_widget('statusbar')
 
67
        self.context_id = self.statusbar.get_context_id('olive')
 
68
        
 
69
        # Get the main window
 
70
        self.window_main = self.toplevel.get_widget('window_main')
 
71
        # Get the HPaned
 
72
        self.hpaned_main = self.toplevel.get_widget('hpaned_main')
 
73
        # Get the TreeViews
 
74
        self.treeview_left = self.toplevel.get_widget('treeview_left')
 
75
        self.treeview_right = self.toplevel.get_widget('treeview_right')
 
76
        # Get some important menu items
 
77
        self.menuitem_add_files = self.toplevel.get_widget('menuitem_add_files')
 
78
        self.menuitem_remove_files = self.toplevel.get_widget('menuitem_remove_file')
 
79
        self.menuitem_file_make_directory = self.toplevel.get_widget('menuitem_file_make_directory')
 
80
        self.menuitem_file_rename = self.toplevel.get_widget('menuitem_file_rename')
 
81
        self.menuitem_file_move = self.toplevel.get_widget('menuitem_file_move')
 
82
        self.menuitem_view_show_hidden_files = self.toplevel.get_widget('menuitem_view_show_hidden_files')
 
83
        self.menuitem_branch = self.toplevel.get_widget('menuitem_branch')
 
84
        self.menuitem_branch_init = self.toplevel.get_widget('menuitem_branch_initialize')
 
85
        self.menuitem_branch_get = self.toplevel.get_widget('menuitem_branch_get')
 
86
        self.menuitem_branch_checkout = self.toplevel.get_widget('menuitem_branch_checkout')
 
87
        self.menuitem_branch_pull = self.toplevel.get_widget('menuitem_branch_pull')
 
88
        self.menuitem_branch_push = self.toplevel.get_widget('menuitem_branch_push')
 
89
        self.menuitem_branch_commit = self.toplevel.get_widget('menuitem_branch_commit')
 
90
        self.menuitem_branch_status = self.toplevel.get_widget('menuitem_branch_status')
 
91
        self.menuitem_branch_missing = self.toplevel.get_widget('menuitem_branch_missing_revisions')
 
92
        self.menuitem_stats = self.toplevel.get_widget('menuitem_stats')
 
93
        self.menuitem_stats_diff = self.toplevel.get_widget('menuitem_stats_diff')
 
94
        self.menuitem_stats_log = self.toplevel.get_widget('menuitem_stats_log')
 
95
        # Get some toolbuttons
 
96
        #self.menutoolbutton_diff = self.toplevel.get_widget('menutoolbutton_diff')
 
97
        self.toolbutton_diff = self.toplevel.get_widget('toolbutton_diff')
 
98
        self.toolbutton_log = self.toplevel.get_widget('toolbutton_log')
 
99
        self.toolbutton_commit = self.toplevel.get_widget('toolbutton_commit')
 
100
        self.toolbutton_pull = self.toplevel.get_widget('toolbutton_pull')
 
101
        self.toolbutton_push = self.toplevel.get_widget('toolbutton_push')
103
102
        # Get the drive selector
104
103
        self.combobox_drive = gtk.combo_box_new_text()
105
104
        self.combobox_drive.connect("changed", self._refresh_drives)
106
105
        
107
 
        # Get the navigation widgets
108
 
        self.hbox_location = self.window.locationbar
109
 
        self.button_location_up = self.window.button_location_up
110
 
        self.button_location_jump = self.window.button_location_jump
111
 
        self.entry_location = self.window.entry_location
112
 
        self.image_location_error = self.window.image_location_error
113
 
        
114
 
        # Get the History widgets
115
 
        self.check_history = self.window.checkbutton_history
116
 
        self.entry_history = self.window.entry_history_revno
117
 
        self.button_history = self.window.button_history_browse
118
 
        
119
 
        self._just_started = True
 
106
        self.vbox_main_right = self.toplevel.get_widget('vbox_main_right')
 
107
 
 
108
        
 
109
        # Dictionary for signal_autoconnect
 
110
        dic = { "on_window_main_destroy": gtk.main_quit,
 
111
                "on_window_main_delete_event": self.on_window_main_delete_event,
 
112
                "on_quit_activate": self.on_window_main_delete_event,
 
113
                "on_about_activate": self.on_about_activate,
 
114
                "on_menuitem_add_files_activate": self.on_menuitem_add_files_activate,
 
115
                "on_menuitem_remove_file_activate": self.on_menuitem_remove_file_activate,
 
116
                "on_menuitem_file_make_directory_activate": self.on_menuitem_file_make_directory_activate,
 
117
                "on_menuitem_file_move_activate": self.on_menuitem_file_move_activate,
 
118
                "on_menuitem_file_rename_activate": self.on_menuitem_file_rename_activate,
 
119
                "on_menuitem_view_show_hidden_files_activate": self.on_menuitem_view_show_hidden_files_activate,
 
120
                "on_menuitem_view_refresh_activate": self.on_menuitem_view_refresh_activate,
 
121
                "on_menuitem_branch_initialize_activate": self.on_menuitem_branch_initialize_activate,
 
122
                "on_menuitem_branch_get_activate": self.on_menuitem_branch_get_activate,
 
123
                "on_menuitem_branch_checkout_activate": self.on_menuitem_branch_checkout_activate,
 
124
                "on_menuitem_branch_commit_activate": self.on_menuitem_branch_commit_activate,
 
125
                "on_menuitem_branch_push_activate": self.on_menuitem_branch_push_activate,
 
126
                "on_menuitem_branch_pull_activate": self.on_menuitem_branch_pull_activate,
 
127
                "on_menuitem_branch_status_activate": self.on_menuitem_branch_status_activate,
 
128
                "on_menuitem_branch_missing_revisions_activate": self.on_menuitem_branch_missing_revisions_activate,
 
129
                "on_menuitem_stats_diff_activate": self.on_menuitem_stats_diff_activate,
 
130
                "on_menuitem_stats_log_activate": self.on_menuitem_stats_log_activate,
 
131
                "on_menuitem_stats_infos_activate": self.on_menuitem_stats_infos_activate,
 
132
                "on_toolbutton_refresh_clicked": self.on_menuitem_view_refresh_activate,
 
133
                "on_toolbutton_log_clicked": self.on_menuitem_stats_log_activate,
 
134
                #"on_menutoolbutton_diff_clicked": self.on_menuitem_stats_diff_activate,
 
135
                "on_toolbutton_diff_clicked": self.on_menuitem_stats_diff_activate,
 
136
                "on_toolbutton_commit_clicked": self.on_menuitem_branch_commit_activate,
 
137
                "on_toolbutton_pull_clicked": self.on_menuitem_branch_pull_activate,
 
138
                "on_toolbutton_push_clicked": self.on_menuitem_branch_push_activate,
 
139
                "on_treeview_right_button_press_event": self.on_treeview_right_button_press_event,
 
140
                "on_treeview_right_row_activated": self.on_treeview_right_row_activated,
 
141
                "on_treeview_left_button_press_event": self.on_treeview_left_button_press_event,
 
142
                "on_treeview_left_row_activated": self.on_treeview_left_row_activated }
 
143
        
 
144
        # Connect the signals to the handlers
 
145
        self.toplevel.signal_autoconnect(dic)
120
146
        
121
147
        # Apply window size and position
122
148
        width = self.pref.get_preference('window_width', 'int')
127
153
        self.window.move(x, y)
128
154
        # Apply paned position
129
155
        pos = self.pref.get_preference('paned_position', 'int')
130
 
        self.window.hpaned_main.set_position(pos)
 
156
        self.hpaned_main.set_position(pos)
 
157
        
 
158
        # Apply menu to the toolbutton
 
159
        #menubutton = self.toplevel.get_widget('menutoolbutton_diff')
 
160
        #menubutton.set_menu(handler.menu.toolbar_diff)
131
161
        
132
162
        # Now we can show the window
133
163
        self.window.show()
134
164
        
135
165
        # Show drive selector if under Win32
136
166
        if sys.platform == 'win32':
137
 
            self.hbox_location.pack_start(self.combobox_drive, False, False, 0)
138
 
            self.hbox_location.reorder_child(self.combobox_drive, 1)
 
167
            self.vbox_main_right.pack_start(self.combobox_drive, False, True, 0)
 
168
            self.vbox_main_right.reorder_child(self.combobox_drive, 0)
139
169
            self.combobox_drive.show()
140
170
            self.gen_hard_selector()
141
171
        
142
 
        # Acceptable errors when loading files/folders in the treeviews
143
 
        self.acceptable_errors = (errno.ENOENT, errno.ELOOP)
144
 
        
145
172
        self._load_left()
146
173
 
147
174
        # Apply menu state
148
 
        self.window.mb_view_showhidden.set_active(self.pref.get_preference('dotted_files', 'bool'))
149
 
        self.window.mb_view_showignored.set_active(self.pref.get_preference('ignored_files', 'bool'))
 
175
        self.menuitem_view_show_hidden_files.set_active(self.pref.get_preference('dotted_files', 'bool'))
150
176
 
151
 
        # We're starting local
152
 
        self.remote = False
153
 
        self.remote_branch = None
154
 
        self.remote_path = None
155
 
        self.remote_revision = None
156
 
        
157
177
        self.set_path(os.getcwd())
158
178
        self._load_right()
159
 
        
160
 
        self._just_started = False
161
179
 
162
 
    def set_path(self, path, force_remote=False):
 
180
    def set_path(self, path):
 
181
        self.path = path
163
182
        self.notbranch = False
164
 
        
165
 
        if force_remote:
166
 
            # Forcing remote mode (reading data from inventory)
167
 
            self._show_stock_image(gtk.STOCK_DISCONNECT)
168
 
            try:
169
 
                br = Branch.open_containing(path)[0]
170
 
            except bzrerrors.NotBranchError:
171
 
                self._show_stock_image(gtk.STOCK_DIALOG_ERROR)
172
 
                self.check_history.set_active(False)
173
 
                self.check_history.set_sensitive(False)
174
 
                return False
175
 
            except bzrerrors.UnsupportedProtocol:
176
 
                self._show_stock_image(gtk.STOCK_DIALOG_ERROR)
177
 
                self.check_history.set_active(False)
178
 
                self.check_history.set_sensitive(False)
179
 
                return False
180
 
            
181
 
            self._show_stock_image(gtk.STOCK_CONNECT)
182
 
            
183
 
            self.remote = True
184
 
           
185
 
            # We're remote
186
 
            self.remote_branch, self.remote_path = Branch.open_containing(path)
187
 
            
188
 
            if self.remote_revision is None:
189
 
                self.remote_revision = self.remote_branch.last_revision()
190
 
            
191
 
            self.remote_entries = self.remote_branch.repository.get_inventory(self.remote_revision).entries()
192
 
            
193
 
            if len(self.remote_path) == 0:
194
 
                self.remote_parent = self.remote_branch.repository.get_inventory(self.remote_branch.last_revision()).iter_entries_by_dir().next()[1].file_id
195
 
            else:
196
 
                for (name, type) in self.remote_entries:
197
 
                    if name == self.remote_path:
198
 
                        self.remote_parent = type.file_id
199
 
                        break
200
 
            
201
 
            if not path.endswith('/'):
202
 
                path += '/'
203
 
            
204
 
            if self.remote_branch.base == path:
205
 
                self.button_location_up.set_sensitive(False)
206
 
            else:
207
 
                self.button_location_up.set_sensitive(True)
208
 
        else:
209
 
            if os.path.isdir(path):
210
 
                self.image_location_error.destroy()
211
 
                self.remote = False
212
 
                
213
 
                # We're local
214
 
                try:
215
 
                    self.wt, self.wtpath = WorkingTree.open_containing(path)
216
 
                except (bzrerrors.NotBranchError, bzrerrors.NoWorkingTree):
217
 
                    self.notbranch = True
218
 
                
219
 
                # If we're in the root, we cannot go up anymore
220
 
                if sys.platform == 'win32':
221
 
                    drive, tail = os.path.splitdrive(path)
222
 
                    if tail in ('', '/', '\\'):
223
 
                        self.button_location_up.set_sensitive(False)
224
 
                    else:
225
 
                        self.button_location_up.set_sensitive(True)
226
 
                else:
227
 
                    if self.path == '/':
228
 
                        self.button_location_up.set_sensitive(False)
229
 
                    else:
230
 
                        self.button_location_up.set_sensitive(True)
231
 
            elif not os.path.isfile(path):
232
 
                # Doesn't seem to be a file nor a directory, trying to open a
233
 
                # remote location
234
 
                self._show_stock_image(gtk.STOCK_DISCONNECT)
235
 
                try:
236
 
                    br = Branch.open_containing(path)[0]
237
 
                except bzrerrors.NotBranchError:
238
 
                    self._show_stock_image(gtk.STOCK_DIALOG_ERROR)
239
 
                    self.check_history.set_active(False)
240
 
                    self.check_history.set_sensitive(False)
241
 
                    return False
242
 
                except bzrerrors.UnsupportedProtocol:
243
 
                    self._show_stock_image(gtk.STOCK_DIALOG_ERROR)
244
 
                    self.check_history.set_active(False)
245
 
                    self.check_history.set_sensitive(False)
246
 
                    return False
247
 
                
248
 
                self._show_stock_image(gtk.STOCK_CONNECT)
249
 
                
250
 
                self.remote = True
251
 
               
252
 
                # We're remote
253
 
                self.remote_branch, self.remote_path = Branch.open_containing(path)
254
 
                
255
 
                if self.remote_revision is None:
256
 
                    self.remote_revision = self.remote_branch.last_revision()
257
 
                
258
 
                self.remote_entries = self.remote_branch.repository.get_inventory(self.remote_revision).entries()
259
 
                
260
 
                if len(self.remote_path) == 0:
261
 
                    self.remote_parent = self.remote_branch.repository.get_inventory(self.remote_branch.last_revision()).iter_entries_by_dir().next()[1].file_id
262
 
                else:
263
 
                    for (name, type) in self.remote_entries:
264
 
                        if name == self.remote_path:
265
 
                            self.remote_parent = type.file_id
266
 
                            break
267
 
                
268
 
                if not path.endswith('/'):
269
 
                    path += '/'
270
 
                
271
 
                if self.remote_branch.base == path:
272
 
                    self.button_location_up.set_sensitive(False)
273
 
                else:
274
 
                    self.button_location_up.set_sensitive(True)
275
 
        
276
 
        if self.notbranch:
277
 
            self.check_history.set_active(False)
278
 
            self.check_history.set_sensitive(False)
279
 
        else:
280
 
            self.check_history.set_sensitive(True)
281
 
        
282
 
        self.window.statusbar.push(self.context_id, path)
283
 
        self.entry_location.set_text(path)
284
 
        self.path = path
285
 
        return True
 
183
        try:
 
184
            self.wt, self.wtpath = WorkingTree.open_containing(self.path)
 
185
        except errors.NotBranchError:
 
186
            self.notbranch = True
286
187
 
287
188
    def get_path(self):
288
 
        if not self.remote:
289
 
            return self.path
290
 
        else:
291
 
            # Remote mode
292
 
            if len(self.remote_path) > 0:
293
 
                return self.remote_branch.base + self.remote_path + '/'
294
 
            else:
295
 
                return self.remote_branch.base
 
189
        return self.path
296
190
   
297
191
    def on_about_activate(self, widget):
 
192
        from dialog import about
298
193
        about()
299
 
    
300
 
    def on_button_history_browse_clicked(self, widget):
301
 
        """ Browse for revision button handler. """
302
 
        if self.remote:
303
 
            br = self.remote_branch
304
 
        else:
305
 
            br = self.wt.branch
306
 
            
307
 
        revb = RevisionBrowser(br, self.window)
308
 
        response = revb.run()
309
 
        if response != gtk.RESPONSE_NONE:
310
 
            revb.hide()
311
 
        
312
 
            if response == gtk.RESPONSE_OK:
313
 
                if revb.selected_revno is not None:
314
 
                    self.entry_history.set_text(revb.selected_revno)
315
 
                    self.on_entry_history_revno_activate()
316
 
            
317
 
            revb.destroy()
318
 
    
319
 
    def on_button_location_jump_clicked(self, widget):
320
 
        """ Location Jump button handler. """
321
 
        location = self.entry_location.get_text()
322
 
        
323
 
        if self.set_path(location):
324
 
            self.refresh_right()
325
 
    
326
 
    def on_button_location_up_clicked(self, widget):
327
 
        """ Location Up button handler. """
328
 
        if not self.remote:
329
 
            # Local mode
330
 
            self.set_path(os.path.split(self.get_path())[0])
331
 
        else:
332
 
            # Remote mode
333
 
            delim = '/'
334
 
            newpath = delim.join(self.get_path().split(delim)[:-2])
335
 
            newpath += '/'
336
 
            self.set_path(newpath)
337
 
 
338
 
        self.refresh_right()
339
 
    
340
 
    def on_checkbutton_history_toggled(self, widget):
341
 
        """ History Mode toggle handler. """
342
 
        if self.check_history.get_active():
343
 
            # History Mode activated
344
 
            self.entry_history.set_sensitive(True)
345
 
            self.button_history.set_sensitive(True)
346
 
            if self.entry_history.get_text() != "":
347
 
                self.on_entry_history_revno_activate()
348
 
        else:
349
 
            # History Mode deactivated
350
 
            self.entry_history.set_sensitive(False)
351
 
            self.button_history.set_sensitive(False)
352
 
            
353
 
            # Return right window to normal view by acting like we jump to it
354
 
            self.on_button_location_jump_clicked(widget)
355
 
    
356
 
    @show_bzr_error
357
 
    def on_entry_history_revno_activate(self, widget=None):
358
 
        """ Key pressed handler for the history entry. """
359
 
        path = self.get_path()
360
 
        if not self.remote:
361
 
            self.remote = True
362
 
            self.remote_branch = self.wt.branch
363
 
        
364
 
        revno = int(self.entry_history.get_text())
365
 
        self.remote_revision = self.remote_branch.get_rev_id(revno)
366
 
        if self.set_path(path, True):
367
 
            self.refresh_right()
368
 
 
 
194
        
369
195
    def on_menuitem_add_files_activate(self, widget):
370
196
        """ Add file(s)... menu handler. """
371
 
        from bzrlib.plugins.gtk.olive.add import AddDialog
372
 
        add = AddDialog(self.wt, self.wtpath, self.get_selected_right(), self.window)
373
 
        response = add.run()
374
 
        add.destroy()
375
 
        if response == gtk.RESPONSE_OK:
376
 
            self.refresh_right()
377
 
 
 
197
        from add import OliveAdd
 
198
        add = OliveAdd(self.wt, self.wtpath, self.get_selected_right())
 
199
        add.display()
 
200
    
378
201
    def on_menuitem_branch_get_activate(self, widget):
379
202
        """ Branch/Get... menu handler. """
380
 
        from bzrlib.plugins.gtk.branch import BranchDialog
381
 
        
382
 
        if self.remote:
383
 
            branch = BranchDialog(os.getcwd(), self.window, self.remote_branch.base)
384
 
        else:
385
 
            branch = BranchDialog(self.get_path(), self.window)
386
 
        response = branch.run()
387
 
        if response != gtk.RESPONSE_NONE:
388
 
            branch.hide()
389
 
            
390
 
            if response == gtk.RESPONSE_OK:
391
 
                self.refresh_right()
392
 
            
393
 
            branch.destroy()
 
203
        from branch import OliveBranch
 
204
        branch = OliveBranch()
 
205
        branch.display()
394
206
    
395
207
    def on_menuitem_branch_checkout_activate(self, widget):
396
208
        """ Branch/Checkout... menu handler. """
397
 
        from bzrlib.plugins.gtk.checkout import CheckoutDialog
398
 
        
399
 
        if self.remote:
400
 
            checkout = CheckoutDialog(os.getcwd(), self.window, self.remote_branch.base)
401
 
        else:
402
 
            checkout = CheckoutDialog(self.get_path(), self.window)
403
 
        response = checkout.run()
404
 
        if response != gtk.RESPONSE_NONE:
405
 
            checkout.hide()
406
 
        
407
 
            if response == gtk.RESPONSE_OK:
408
 
                self.refresh_right()
409
 
            
410
 
            checkout.destroy()
 
209
        from checkout import OliveCheckout
 
210
        checkout = OliveCheckout()
 
211
        checkout.display()
411
212
    
412
 
    @show_bzr_error
413
213
    def on_menuitem_branch_commit_activate(self, widget):
414
214
        """ Branch/Commit... menu handler. """
415
 
        selected = self.get_selected_right()
416
 
        if selected:
417
 
            selected = os.path.join(self.wtpath, selected)
418
 
        commit = CommitDialog(wt=self.wt,
419
 
                              parent=self.window,
420
 
                              selected=selected,
421
 
                             )
422
 
        response = commit.run()
423
 
        if response != gtk.RESPONSE_NONE:
424
 
            commit.hide()
425
 
        
426
 
            if response == gtk.RESPONSE_OK:
427
 
                self.refresh_right()
428
 
            
429
 
            commit.destroy()
430
 
    
431
 
    def on_menuitem_branch_conflicts_activate(self, widget):
432
 
        """ Branch/Conflicts... menu handler. """
433
 
        conflicts = ConflictsDialog(self.wt, self.window)
434
 
        response = conflicts.run()
435
 
        if response != gtk.RESPONSE_NONE:
436
 
            conflicts.destroy()
437
 
    
438
 
    def on_menuitem_branch_merge_activate(self, widget):
439
 
        """ Branch/Merge... menu handler. """
440
 
        from bzrlib.plugins.gtk.merge import MergeDialog
441
 
        
442
 
        if self.check_for_changes():
443
 
            error_dialog(_i18n('There are local changes in the branch'),
444
 
                         _i18n('Please commit or revert the changes before merging.'))
445
 
        else:
446
 
            parent_branch_path = self.wt.branch.get_parent()
447
 
            merge = MergeDialog(self.wt, self.wtpath, parent_branch_path, self.window)
448
 
            response = merge.run()
449
 
            merge.destroy()
450
 
            if response == gtk.RESPONSE_OK:
451
 
                self.refresh_right()
452
 
 
453
 
    @show_bzr_error
 
215
        from commit import OliveCommit
 
216
        commit = OliveCommit(self.wt, self.wtpath)
 
217
        commit.display()
 
218
    
454
219
    def on_menuitem_branch_missing_revisions_activate(self, widget):
455
220
        """ Branch/Missing revisions menu handler. """
456
 
        
457
 
        from bzrlib.missing import find_unmerged, iter_log_revisions
458
 
        
459
221
        local_branch = self.wt.branch
460
 
        parent_branch_path = local_branch.get_parent()
461
 
        if parent_branch_path is None:
462
 
            error_dialog(_i18n('Parent location is unknown'),
463
 
                         _i18n('Cannot determine missing revisions if no parent location is known.'))
 
222
        
 
223
        other_branch = local_branch.get_parent()
 
224
        if other_branch is None:
 
225
            error_dialog(_('Parent location is unknown'),
 
226
                                     _('Cannot determine missing revisions if no parent location is known.'))
464
227
            return
465
228
        
466
 
        parent_branch = Branch.open(parent_branch_path)
467
 
        
468
 
        if parent_branch.base == local_branch.base:
469
 
            parent_branch = local_branch
470
 
        
471
 
        local_extra, remote_extra = find_unmerged(local_branch,parent_branch)
472
 
 
473
 
        if local_extra or remote_extra:
474
 
            
475
 
            ## def log_revision_one_line_text(log_revision):
476
 
            ##    """ Generates one line description of log_revison ended with end of line."""
477
 
            ##    revision = log_revision.rev
478
 
            ##    txt =  "- %s (%s)\n" % (revision.get_summary(), revision.committer, )
479
 
            ##    txt = txt.replace("<"," ") # Seems < > chars are expected to be xml tags ...
480
 
            ##    txt = txt.replace(">"," ")
481
 
            ##    return txt
482
 
            
483
 
            dlg_txt = ""
484
 
            if local_extra:
485
 
                dlg_txt += _i18n('%d local extra revision(s). \n') % (len(local_extra),) 
486
 
                ## NOTE: We do not want such ugly info about missing revisions
487
 
                ##       Revision Browser should be used there
488
 
                ## max_revisions = 10
489
 
                ## for log_revision in iter_log_revisions(local_extra, local_branch.repository, verbose=1):
490
 
                ##    dlg_txt += log_revision_one_line_text(log_revision)
491
 
                ##    if max_revisions <= 0:
492
 
                ##        dlg_txt += _i18n("more ... \n")
493
 
                ##        break
494
 
                ## max_revisions -= 1
495
 
            ## dlg_txt += "\n"
496
 
            if remote_extra:
497
 
                dlg_txt += _i18n('%d local missing revision(s).\n') % (len(remote_extra),) 
498
 
                ## max_revisions = 10
499
 
                ## for log_revision in iter_log_revisions(remote_extra, parent_branch.repository, verbose=1):
500
 
                ##    dlg_txt += log_revision_one_line_text(log_revision)
501
 
                ##    if max_revisions <= 0:
502
 
                ##        dlg_txt += _i18n("more ... \n")
503
 
                ##        break
504
 
                ##    max_revisions -= 1
505
 
                
506
 
            info_dialog(_i18n('There are missing revisions'),
507
 
                        dlg_txt)
 
229
        remote_branch = Branch.open(other_branch)
 
230
        
 
231
        if remote_branch.base == local_branch.base:
 
232
            remote_branch = local_branch
 
233
 
 
234
        ret = len(local_branch.missing_revisions(remote_branch))
 
235
 
 
236
        if ret > 0:
 
237
            info_dialog(_('There are missing revisions'),
 
238
                                    _('%d revision(s) missing.') % ret)
508
239
        else:
509
 
            info_dialog(_i18n('Local branch up to date'),
510
 
                        _i18n('There are no missing revisions.'))
 
240
            info_dialog(_('Local branch up to date'),
 
241
                                    _('There are no missing revisions.'))
511
242
 
512
 
    @show_bzr_error
513
243
    def on_menuitem_branch_pull_activate(self, widget):
514
244
        """ Branch/Pull menu handler. """
515
245
        branch_to = self.wt.branch
516
246
 
517
247
        location = branch_to.get_parent()
518
248
        if location is None:
519
 
            error_dialog(_i18n('Parent location is unknown'),
520
 
                                     _i18n('Pulling is not possible until there is a parent location.'))
 
249
            error_dialog(_('Parent location is unknown'),
 
250
                                     _('Pulling is not possible until there is a parent location.'))
521
251
            return
522
252
 
523
 
        branch_from = Branch.open(location)
 
253
        try:
 
254
            branch_from = Branch.open(location)
 
255
        except errors.NotBranchError:
 
256
            error_dialog(_('Directory is not a branch'),
 
257
                                     _('You can perform this action only in a branch.'))
524
258
 
525
259
        if branch_to.get_parent() is None:
526
260
            branch_to.set_parent(branch_from.base)
527
261
 
528
 
        ret = branch_to.pull(branch_from)
529
 
        
530
 
        info_dialog(_i18n('Pull successful'), _i18n('%d revision(s) pulled.') % ret)
531
 
        
532
 
    @show_bzr_error
533
 
    def on_menuitem_branch_update_activate(self, widget):
534
 
        """ Brranch/checkout update menu handler. """
535
 
        
536
 
        ret = self.wt.update()
537
 
        conflicts = self.wt.conflicts()
538
 
        if conflicts:
539
 
            info_dialog(_i18n('Update successful but conflicts generated'), _i18n('Number of conflicts generated: %d.') % (len(conflicts),) )
540
 
        else:
541
 
            info_dialog(_i18n('Update successful'), _i18n('No conflicts generated.') )
 
262
        #old_rh = branch_to.revision_history()
 
263
        #if tree_to is not None:
 
264
        #    tree_to.pull(branch_from)
 
265
        #else:
 
266
        #    branch_to.pull(branch_from)
 
267
        branch_to.pull(branch_from)
 
268
        
 
269
        # TODO: get the number of pulled revisions
 
270
        ret = 0
 
271
        
 
272
        info_dialog(_('Pull successful'), _('%d revision(s) pulled.') % ret)
542
273
    
543
274
    def on_menuitem_branch_push_activate(self, widget):
544
275
        """ Branch/Push... menu handler. """
545
 
        push = PushDialog(repository=None,revid=None,branch=self.wt.branch, parent=self.window)
546
 
        response = push.run()
547
 
        if response != gtk.RESPONSE_NONE:
548
 
            push.destroy()
549
 
    
550
 
    @show_bzr_error
551
 
    def on_menuitem_branch_revert_activate(self, widget):
552
 
        """ Branch/Revert all changes menu handler. """
553
 
        ret = self.wt.revert(None)
554
 
        if ret:
555
 
            warning_dialog(_i18n('Conflicts detected'),
556
 
                           _i18n('Please have a look at the working tree before continuing.'))
557
 
        else:
558
 
            info_dialog(_i18n('Revert successful'),
559
 
                        _i18n('All files reverted to last revision.'))
560
 
        self.refresh_right()
 
276
        from push import OlivePush
 
277
        push = OlivePush(self.wt.branch)
 
278
        push.display()
561
279
    
562
280
    def on_menuitem_branch_status_activate(self, widget):
563
281
        """ Branch/Status... menu handler. """
564
 
        from bzrlib.plugins.gtk.status import StatusDialog
565
 
        status = StatusDialog(self.wt, self.wtpath)
566
 
        response = status.run()
567
 
        if response != gtk.RESPONSE_NONE:
568
 
            status.destroy()
 
282
        from status import OliveStatus
 
283
        status = OliveStatus(self.wt, self.wtpath)
 
284
        status.display()
569
285
    
570
286
    def on_menuitem_branch_initialize_activate(self, widget):
571
287
        """ Initialize current directory. """
572
 
        init = InitDialog(self.path, self.window)
573
 
        response = init.run()
574
 
        if response != gtk.RESPONSE_NONE:
575
 
            init.hide()
576
 
        
577
 
            if response == gtk.RESPONSE_OK:
578
 
                self.refresh_right()
579
 
            
580
 
            init.destroy()
581
 
        
582
 
    def on_menuitem_branch_tags_activate(self, widget):
583
 
        """ Branch/Tags... menu handler. """
584
 
        from bzrlib.plugins.gtk.tags import TagsWindow
585
 
        if not self.remote:
586
 
            window = TagsWindow(self.wt.branch, self.window)
587
 
        else:
588
 
            window = TagsWindow(self.remote_branch, self.window)
589
 
        window.show()
590
 
    
591
 
    def on_menuitem_file_annotate_activate(self, widget):
592
 
        """ File/Annotate... menu handler. """
593
 
        if self.get_selected_right() is None:
594
 
            error_dialog(_i18n('No file was selected'),
595
 
                         _i18n('Please select a file from the list.'))
596
 
            return
597
 
        
598
 
        branch = self.wt.branch
599
 
        file_id = self.wt.path2id(self.wt.relpath(os.path.join(self.path, self.get_selected_right())))
600
 
        
601
 
        window = GAnnotateWindow(all=False, plain=False, parent=self.window)
602
 
        window.set_title(os.path.join(self.path, self.get_selected_right()) + " - Annotate")
603
 
        config = GAnnotateConfig(window)
604
 
        window.show()
605
 
        branch.lock_read()
 
288
        import bzrlib.bzrdir as bzrdir
 
289
        
606
290
        try:
607
 
            window.annotate(self.wt, branch, file_id)
608
 
        finally:
609
 
            branch.unlock()
610
 
    
611
 
    def on_menuitem_file_bookmark_activate(self, widget):
612
 
        """ File/Bookmark current directory menu handler. """
613
 
        if self.pref.add_bookmark(self.path):
614
 
            info_dialog(_i18n('Bookmark successfully added'),
615
 
                        _i18n('The current directory was bookmarked. You can reach\nit by selecting it from the left panel.'))
616
 
            self.pref.write()
 
291
            if not os.path.exists(self.path):
 
292
                os.mkdir(self.path)
 
293
     
 
294
            try:
 
295
                existing_bzrdir = bzrdir.BzrDir.open(self.path)
 
296
            except errors.NotBranchError:
 
297
                bzrdir.BzrDir.create_branch_convenience(self.path)
 
298
            else:
 
299
                if existing_bzrdir.has_branch():
 
300
                    if existing_bzrdir.has_workingtree():
 
301
                        raise errors.AlreadyBranchError(self.path)
 
302
                    else:
 
303
                        raise errors.BranchExistsWithoutWorkingTree(self.path)
 
304
                else:
 
305
                    existing_bzrdir.create_branch()
 
306
                    existing_bzrdir.create_workingtree()
 
307
        except errors.AlreadyBranchError, errmsg:
 
308
            error_dialog(_('Directory is already a branch'),
 
309
                                     _('The current directory (%s) is already a branch.\nYou can start using it, or initialize another directory.') % errmsg)
 
310
        except errors.BranchExistsWithoutWorkingTree, errmsg:
 
311
            error_dialog(_('Branch without a working tree'),
 
312
                                     _('The current directory (%s)\nis a branch without a working tree.') % errmsg)
617
313
        else:
618
 
            warning_dialog(_i18n('Location already bookmarked'),
619
 
                           _i18n('The current directory is already bookmarked.\nSee the left panel for reference.'))
 
314
            info_dialog(_('Initialize successful'),
 
315
                                    _('Directory successfully initialized.'))
 
316
            self.refresh_right()
620
317
        
621
 
        self.refresh_left()
622
 
    
623
318
    def on_menuitem_file_make_directory_activate(self, widget):
624
319
        """ File/Make directory... menu handler. """
625
 
        from bzrlib.plugins.gtk.olive.mkdir import MkdirDialog
626
 
        mkdir = MkdirDialog(self.wt, self.wtpath, self.window)
627
 
        response = mkdir.run()
628
 
        mkdir.destroy()
629
 
        if response == gtk.RESPONSE_OK:
630
 
            self.refresh_right()
 
320
        from mkdir import OliveMkdir
 
321
        mkdir = OliveMkdir(self.wt, self.wtpath)
 
322
        mkdir.display()
631
323
    
632
324
    def on_menuitem_file_move_activate(self, widget):
633
325
        """ File/Move... menu handler. """
634
 
        from bzrlib.plugins.gtk.olive.move import MoveDialog
635
 
        move = MoveDialog(self.wt, self.wtpath, self.get_selected_right(), self.window)
636
 
        response = move.run()
637
 
        move.destroy()
638
 
        if response == gtk.RESPONSE_OK:
639
 
            self.refresh_right()
 
326
        from move import OliveMove
 
327
        move = OliveMove(self.wt, self.wtpath, self.get_selected_right())
 
328
        move.display()
640
329
    
641
330
    def on_menuitem_file_rename_activate(self, widget):
642
331
        """ File/Rename... menu handler. """
643
 
        from bzrlib.plugins.gtk.olive.rename import RenameDialog
644
 
        rename = RenameDialog(self.wt, self.wtpath, self.get_selected_right(), self.window)
645
 
        response = rename.run()
646
 
        rename.destroy()
647
 
        if response == gtk.RESPONSE_OK:
648
 
            self.refresh_right()
 
332
        from rename import OliveRename
 
333
        rename = OliveRename(self.wt, self.wtpath, self.get_selected_right())
 
334
        rename.display()
649
335
 
650
336
    def on_menuitem_remove_file_activate(self, widget):
651
337
        """ Remove (unversion) selected file. """
652
 
        from bzrlib.plugins.gtk.olive.remove import RemoveDialog
653
 
        remove = RemoveDialog(self.wt, self.wtpath,
654
 
                                   selected=self.get_selected_right(),
655
 
                                   parent=self.window)
656
 
        response = remove.run()
657
 
        
658
 
        if response != gtk.RESPONSE_NONE:
659
 
            remove.hide()
660
 
        
661
 
            if response == gtk.RESPONSE_OK:
662
 
                self.set_path(self.path)
663
 
                self.refresh_right()
664
 
            
665
 
            remove.destroy()
 
338
        from remove import OliveRemove
 
339
        remove = OliveRemove(self.wt, self.wtpath, self.get_selected_right())
 
340
        remove.display()
666
341
    
667
342
    def on_menuitem_stats_diff_activate(self, widget):
668
343
        """ Statistics/Differences... menu handler. """
669
 
        window = DiffWindow(parent=self.window)
 
344
        from bzrlib.plugins.gtk.viz.diffwin import DiffWindow
 
345
        window = DiffWindow()
670
346
        parent_tree = self.wt.branch.repository.revision_tree(self.wt.branch.last_revision())
671
347
        window.set_diff(self.wt.branch.nick, self.wt, parent_tree)
672
348
        window.show()
673
349
    
674
350
    def on_menuitem_stats_infos_activate(self, widget):
675
351
        """ Statistics/Informations... menu handler. """
676
 
        from bzrlib.plugins.gtk.olive.info import InfoDialog
677
 
        if self.remote:
678
 
            info = InfoDialog(self.remote_branch)
679
 
        else:
680
 
            info = InfoDialog(self.wt.branch)
 
352
        from info import OliveInfo
 
353
        info = OliveInfo(self.wt)
681
354
        info.display()
682
355
    
683
356
    def on_menuitem_stats_log_activate(self, widget):
684
357
        """ Statistics/Log... menu handler. """
685
 
 
686
 
        if not self.remote:
687
 
            branch = self.wt.branch
688
 
        else:
689
 
            branch = self.remote_branch
690
 
 
691
 
        window = branchwin.BranchWindow(branch, [branch.last_revision()], None, 
692
 
                                        parent=self.window)
 
358
        from bzrlib.plugins.gtk.viz.branchwin import BranchWindow
 
359
        window = BranchWindow()
 
360
        window.set_branch(self.wt.branch, self.wt.branch.last_revision(), None)
693
361
        window.show()
694
362
    
695
363
    def on_menuitem_view_refresh_activate(self, widget):
702
370
    def on_menuitem_view_show_hidden_files_activate(self, widget):
703
371
        """ View/Show hidden files menu handler. """
704
372
        self.pref.set_preference('dotted_files', widget.get_active())
705
 
        if self.path is not None:
706
 
            self.refresh_right()
707
373
 
708
 
    def on_menuitem_view_show_ignored_files_activate(self, widget):
709
 
        """ Hide/Show ignored files menu handler. """
710
 
        self.pref.set_preference('ignored_files', widget.get_active())
711
 
        if self.path is not None:
712
 
            self.refresh_right()
713
 
            
714
374
    def on_treeview_left_button_press_event(self, widget, event):
715
 
        """ Occurs when somebody clicks in the bookmark list. """
716
 
        treepathpos = widget.get_path_at_pos(int(event.x), int(event.y))
717
 
        treeselection = widget.get_selection()
718
 
        if treepathpos is not None:
719
 
            treeselection.select_path(treepathpos[0])
720
 
            if event.button == 1:
721
 
                newdir = self.get_selected_left()
722
 
                if newdir == None:
723
 
                    return
724
 
 
725
 
                if self.set_path(newdir):
726
 
                    self.refresh_right()
727
 
            elif event.button == 3:
728
 
                # Don't show context with nothing selected
729
 
                if self.get_selected_left() == None:
730
 
                    return
731
 
 
732
 
                # Create a menu
733
 
                from menu import OliveMenu
734
 
                menu = OliveMenu(path=self.get_path(),
735
 
                                 selected=self.get_selected_left(),
736
 
                                 app=self)
737
 
                
738
 
                menu.left_context_menu().popup(None, None, None, 0,
739
 
                                               event.time)
740
 
        else:
741
 
            if treeselection is not None:
742
 
                treeselection.unselect_all()
743
 
 
 
375
        """ Occurs when somebody right-clicks in the bookmark list. """
 
376
        if event.button == 3:
 
377
            # Don't show context with nothing selected
 
378
            if self.get_selected_left() == None:
 
379
                return
 
380
 
 
381
            # Create a menu
 
382
            from menu import OliveMenu
 
383
            menu = OliveMenu(self.get_path(), self.get_selected_left())
 
384
            
 
385
            menu.left_context_menu().popup(None, None, None, 0,
 
386
                                           event.time)
 
387
            
 
388
            # Bookmarks might have changed
 
389
            self.pref.read()
 
390
        
744
391
    def on_treeview_left_row_activated(self, treeview, path, view_column):
745
392
        """ Occurs when somebody double-clicks or enters an item in the
746
393
        bookmark list. """
749
396
        if newdir == None:
750
397
            return
751
398
 
752
 
        if self.set_path(newdir):
753
 
            self.refresh_right()
754
 
 
 
399
        self.set_path(newdir)
 
400
        self.refresh_right()
 
401
    
755
402
    def on_treeview_right_button_press_event(self, widget, event):
756
 
        """ Occurs when somebody clicks in the file list. """
757
 
        treepathpos = widget.get_path_at_pos(int(event.x), int(event.y))
758
 
        if event.button == 1:
759
 
            if treepathpos is None and widget.get_selection is not None:
760
 
                treeselection = widget.get_selection()
761
 
                treeselection.unselect_all()
762
 
        elif event.button == 3:
763
 
            treeselection = widget.get_selection()
764
 
            if treepathpos is not None:
765
 
                treeselection.select_path(treepathpos[0])
766
 
            else:
767
 
                if treeselection is not None:
768
 
                    treeselection.unselect_all()
 
403
        """ Occurs when somebody right-clicks in the file list. """
 
404
        if event.button == 3:
769
405
            # Create a menu
770
406
            from menu import OliveMenu
771
 
            menu = OliveMenu(path=self.get_path(),
772
 
                             selected=self.get_selected_right(),
773
 
                             app=self)
 
407
            menu = OliveMenu(self.get_path(), self.get_selected_right())
774
408
            # get the menu items
775
 
            m_open = menu.ui.get_widget('/context_right/open')
776
409
            m_add = menu.ui.get_widget('/context_right/add')
777
410
            m_remove = menu.ui.get_widget('/context_right/remove')
778
 
            m_remove_and_delete = menu.ui.get_widget('/context_right/remove_and_delete')
779
 
            m_rename = menu.ui.get_widget('/context_right/rename')
780
 
            m_revert = menu.ui.get_widget('/context_right/revert')
781
411
            m_commit = menu.ui.get_widget('/context_right/commit')
782
 
            m_annotate = menu.ui.get_widget('/context_right/annotate')
783
412
            m_diff = menu.ui.get_widget('/context_right/diff')
784
413
            # check if we're in a branch
785
414
            try:
786
415
                from bzrlib.branch import Branch
787
416
                Branch.open_containing(self.get_path())
788
 
                if self.remote:
789
 
                    m_open.set_sensitive(False)
790
 
                    m_add.set_sensitive(False)
791
 
                    m_remove.set_sensitive(False)
792
 
                    m_remove_and_delete.set_sensitive(False)
793
 
                    m_rename.set_sensitive(False)
794
 
                    m_revert.set_sensitive(False)
795
 
                    m_commit.set_sensitive(False)
796
 
                    m_annotate.set_sensitive(False)
797
 
                    m_diff.set_sensitive(False)
798
 
                else:
799
 
                    if treepathpos is None:
800
 
                        m_open.set_sensitive(False)
801
 
                        m_add.set_sensitive(False)
802
 
                        m_remove.set_sensitive(False)
803
 
                        m_remove_and_delete.set_sensitive(False)
804
 
                        m_rename.set_sensitive(False)
805
 
                        m_annotate.set_sensitive(False)
806
 
                        m_diff.set_sensitive(False)
807
 
                        m_revert.set_sensitive(False)
808
 
                    else:
809
 
                        m_open.set_sensitive(True)
810
 
                        m_add.set_sensitive(True)
811
 
                        m_remove.set_sensitive(True)
812
 
                        m_remove_and_delete.set_sensitive(True)
813
 
                        m_rename.set_sensitive(True)
814
 
                        m_annotate.set_sensitive(True)
815
 
                        m_diff.set_sensitive(True)
816
 
                        m_revert.set_sensitive(True)
817
 
                    m_commit.set_sensitive(True)
818
 
            except bzrerrors.NotBranchError:
819
 
                if treepathpos is None:
820
 
                    m_open.set_sensitive(False)
821
 
                else:
822
 
                    m_open.set_sensitive(True)
 
417
                m_add.set_sensitive(True)
 
418
                m_remove.set_sensitive(True)
 
419
                m_commit.set_sensitive(True)
 
420
                m_diff.set_sensitive(True)
 
421
            except errors.NotBranchError:
823
422
                m_add.set_sensitive(False)
824
423
                m_remove.set_sensitive(False)
825
 
                m_remove_and_delete.set_sensitive(False)
826
 
                m_rename.set_sensitive(False)
827
 
                m_revert.set_sensitive(False)
828
424
                m_commit.set_sensitive(False)
829
 
                m_annotate.set_sensitive(False)
830
425
                m_diff.set_sensitive(False)
831
 
 
832
 
            if not self.remote:
833
 
                menu.right_context_menu().popup(None, None, None, 0,
834
 
                                                event.time)
835
 
            else:
836
 
                menu.remote_context_menu().popup(None, None, None, 0,
837
 
                                                 event.time)
 
426
            menu.right_context_menu().popup(None, None, None, 0,
 
427
                                            event.time)
838
428
        
839
429
    def on_treeview_right_row_activated(self, treeview, path, view_column):
840
430
        """ Occurs when somebody double-clicks or enters an item in the
841
431
        file list. """
 
432
        import os.path
 
433
        
842
434
        from launch import launch
843
435
        
844
436
        newdir = self.get_selected_right()
845
437
        
846
 
        if not self.remote:
847
 
            # We're local
848
 
            if newdir == '..':
849
 
                self.set_path(os.path.split(self.get_path())[0])
 
438
        if newdir == '..':
 
439
            self.set_path(os.path.split(self.get_path())[0])
 
440
        else:
 
441
            fullpath = self.get_path() + os.sep + newdir
 
442
            if os.path.isdir(fullpath):
 
443
                # selected item is an existant directory
 
444
                self.set_path(fullpath)
850
445
            else:
851
 
                fullpath = os.path.join(self.get_path(), newdir)
852
 
                if os.path.isdir(fullpath):
853
 
                    # selected item is an existant directory
854
 
                    self.set_path(fullpath)
855
 
                else:
856
 
                    launch(fullpath)
857
 
        else:
858
 
            # We're remote
859
 
            if self._is_remote_dir(self.get_path() + newdir):
860
 
                self.set_path(self.get_path() + newdir)
 
446
                launch(fullpath) 
861
447
        
862
448
        self.refresh_right()
863
449
    
864
450
    def on_window_main_delete_event(self, widget, event=None):
865
451
        """ Do some stuff before exiting. """
866
 
        width, height = self.window.get_size()
 
452
        width, height = self.window_main.get_size()
867
453
        self.pref.set_preference('window_width', width)
868
454
        self.pref.set_preference('window_height', height)
869
 
        x, y = self.window.get_position()
 
455
        x, y = self.window_main.get_position()
870
456
        self.pref.set_preference('window_x', x)
871
457
        self.pref.set_preference('window_y', y)
872
458
        self.pref.set_preference('paned_position',
873
 
                                 self.window.hpaned_main.get_position())
 
459
                                      self.hpaned_main.get_position())
874
460
        
875
461
        self.pref.write()
876
 
        self.window.destroy()
 
462
        self.window_main.destroy()
877
463
        
878
464
    def _load_left(self):
879
465
        """ Load data into the left panel. (Bookmarks) """
884
470
        bookmarks = self.pref.get_bookmarks()
885
471
        
886
472
        # Add them to the TreeStore
887
 
        titer = treestore.append(None, [_i18n('Bookmarks'), None])
888
 
 
889
 
        # Get titles and sort by title
890
 
        bookmarks = [[self.pref.get_bookmark_title(item), item] for item in bookmarks]
891
 
        bookmarks.sort()
892
 
        for title_item in bookmarks:
893
 
            treestore.append(titer, title_item)
 
473
        titer = treestore.append(None, [_('Bookmarks'), None])
 
474
        for item in bookmarks:
 
475
            title = self.pref.get_bookmark_title(item)
 
476
            treestore.append(titer, [title, item])
894
477
        
895
478
        # Create the column and add it to the TreeView
896
479
        self.treeview_left.set_model(treestore)
897
 
        tvcolumn_bookmark = gtk.TreeViewColumn(_i18n('Bookmark'))
 
480
        tvcolumn_bookmark = gtk.TreeViewColumn(_('Bookmark'))
898
481
        self.treeview_left.append_column(tvcolumn_bookmark)
899
482
        
900
483
        # Set up the cells
908
491
    def _load_right(self):
909
492
        """ Load data into the right panel. (Filelist) """
910
493
        # Create ListStore
911
 
        # Model: [ icon, dir, name, status text, status, size (int), size (human), mtime (int), mtime (local), fileid ]
912
 
        liststore = gtk.ListStore(gobject.TYPE_STRING,
913
 
                                  gobject.TYPE_BOOLEAN,
914
 
                                  gobject.TYPE_STRING,
915
 
                                  gobject.TYPE_STRING,
916
 
                                  gobject.TYPE_STRING,
917
 
                                  gobject.TYPE_STRING,
918
 
                                  gobject.TYPE_STRING,
919
 
                                  gobject.TYPE_INT,
920
 
                                  gobject.TYPE_STRING,
921
 
                                  gobject.TYPE_STRING)
 
494
        liststore = gtk.ListStore(str, str, str)
922
495
        
923
 
        dirs = []
 
496
        dirs = ['..']
924
497
        files = []
925
498
        
926
499
        # Fill the appropriate lists
932
505
                dirs.append(item)
933
506
            else:
934
507
                files.append(item)
 
508
            
 
509
        # Sort'em
 
510
        dirs.sort()
 
511
        files.sort()
935
512
        
936
513
        if not self.notbranch:
937
514
            branch = self.wt.branch
940
517
            delta = self.wt.changes_from(tree2, want_unchanged=True)
941
518
        
942
519
        # Add'em to the ListStore
943
 
        for item in dirs:
944
 
            try:
945
 
                statinfo = os.stat(self.path + os.sep + item)
946
 
            except OSError, e:
947
 
                if e.errno in self.acceptable_errors:
948
 
                    continue
949
 
                else:
950
 
                    raise
951
 
            liststore.append([ gtk.STOCK_DIRECTORY,
952
 
                               True,
953
 
                               item,
954
 
                               '',
955
 
                               '',
956
 
                               "<DIR>",
957
 
                               "<DIR>",
958
 
                               statinfo.st_mtime,
959
 
                               self._format_date(statinfo.st_mtime),
960
 
                               ''])
 
520
        for item in dirs:    
 
521
            liststore.append([gtk.STOCK_DIRECTORY, item, ''])
961
522
        for item in files:
962
523
            status = 'unknown'
963
 
            fileid = ''
964
524
            if not self.notbranch:
965
525
                filename = self.wt.relpath(self.path + os.sep + item)
966
526
                
967
 
                try:
968
 
                    self.wt.lock_read()
969
 
                    
970
 
                    for rpath, rpathnew, id, kind, text_modified, meta_modified in delta.renamed:
971
 
                        if rpathnew == filename:
972
 
                            status = 'renamed'
973
 
                            fileid = id
974
 
                    for rpath, id, kind in delta.added:
975
 
                        if rpath == filename:
976
 
                            status = 'added'
977
 
                            fileid = id
978
 
                    for rpath, id, kind in delta.removed:
979
 
                        if rpath == filename:
980
 
                            status = 'removed'
981
 
                            fileid = id
982
 
                    for rpath, id, kind, text_modified, meta_modified in delta.modified:
983
 
                        if rpath == filename:
984
 
                            status = 'modified'
985
 
                            fileid = id
986
 
                    for rpath, id, kind in delta.unchanged:
987
 
                        if rpath == filename:
988
 
                            status = 'unchanged'
989
 
                            fileid = id
990
 
                    for rpath, file_class, kind, id, entry in self.wt.list_files():
991
 
                        if rpath == filename and file_class == 'I':
992
 
                            status = 'ignored'
993
 
                finally:
994
 
                    self.wt.unlock()
 
527
                for rpath, id, kind, text_modified, meta_modified in delta.renamed:
 
528
                    if rpath == filename:
 
529
                        status = 'renamed'
 
530
                for rpath, id, kind in delta.added:
 
531
                    if rpath == filename:
 
532
                        status = 'added'
 
533
                for rpath, id, kind in delta.removed:
 
534
                    if rpath == filename:
 
535
                        status = 'removed'
 
536
                for rpath, id, kind, text_modified, meta_modified in delta.modified:
 
537
                    if rpath == filename:
 
538
                        status = 'modified'
 
539
                for rpath, id, kind in delta.unchanged:
 
540
                    if rpath == filename:
 
541
                        status = 'unchanged'
 
542
            
 
543
            #try:
 
544
            #    status = fileops.status(path + os.sep + item)
 
545
            #except errors.PermissionDenied:
 
546
            #    continue
995
547
            
996
548
            if status == 'renamed':
997
 
                st = _i18n('renamed')
 
549
                st = _('renamed')
998
550
            elif status == 'removed':
999
 
                st = _i18n('removed')
 
551
                st = _('removed')
1000
552
            elif status == 'added':
1001
 
                st = _i18n('added')
 
553
                st = _('added')
1002
554
            elif status == 'modified':
1003
 
                st = _i18n('modified')
 
555
                st = _('modified')
1004
556
            elif status == 'unchanged':
1005
 
                st = _i18n('unchanged')
1006
 
            elif status == 'ignored':
1007
 
                st = _i18n('ignored')
 
557
                st = _('unchanged')
1008
558
            else:
1009
 
                st = _i18n('unknown')
1010
 
            
1011
 
            try:
1012
 
                statinfo = os.stat(self.path + os.sep + item)
1013
 
            except OSError, e:
1014
 
                if e.errno in self.acceptable_errors:
1015
 
                    continue
1016
 
                else:
1017
 
                    raise
1018
 
            liststore.append([gtk.STOCK_FILE,
1019
 
                              False,
1020
 
                              item,
1021
 
                              st,
1022
 
                              status,
1023
 
                              str(statinfo.st_size), # NOTE: if int used there it will fail for large files (size expressed as long int)
1024
 
                              self._format_size(statinfo.st_size),
1025
 
                              statinfo.st_mtime,
1026
 
                              self._format_date(statinfo.st_mtime),
1027
 
                              fileid])
 
559
                st = _('unknown')
 
560
            liststore.append([gtk.STOCK_FILE, item, st])
1028
561
        
1029
562
        # Create the columns and add them to the TreeView
1030
563
        self.treeview_right.set_model(liststore)
1031
 
        self._tvcolumn_filename = gtk.TreeViewColumn(_i18n('Filename'))
1032
 
        self._tvcolumn_status = gtk.TreeViewColumn(_i18n('Status'))
1033
 
        self._tvcolumn_size = gtk.TreeViewColumn(_i18n('Size'))
1034
 
        self._tvcolumn_mtime = gtk.TreeViewColumn(_i18n('Last modified'))
1035
 
        self.treeview_right.append_column(self._tvcolumn_filename)
1036
 
        self.treeview_right.append_column(self._tvcolumn_status)
1037
 
        self.treeview_right.append_column(self._tvcolumn_size)
1038
 
        self.treeview_right.append_column(self._tvcolumn_mtime)
 
564
        tvcolumn_filename = gtk.TreeViewColumn(_('Filename'))
 
565
        tvcolumn_status = gtk.TreeViewColumn(_('Status'))
 
566
        self.treeview_right.append_column(tvcolumn_filename)
 
567
        self.treeview_right.append_column(tvcolumn_status)
1039
568
        
1040
569
        # Set up the cells
1041
570
        cellpb = gtk.CellRendererPixbuf()
1042
571
        cell = gtk.CellRendererText()
1043
 
        self._tvcolumn_filename.pack_start(cellpb, False)
1044
 
        self._tvcolumn_filename.pack_start(cell, True)
1045
 
        self._tvcolumn_filename.set_attributes(cellpb, stock_id=0)
1046
 
        self._tvcolumn_filename.add_attribute(cell, 'text', 2)
1047
 
        self._tvcolumn_status.pack_start(cell, True)
1048
 
        self._tvcolumn_status.add_attribute(cell, 'text', 3)
1049
 
        self._tvcolumn_size.pack_start(cell, True)
1050
 
        self._tvcolumn_size.add_attribute(cell, 'text', 6)
1051
 
        self._tvcolumn_mtime.pack_start(cell, True)
1052
 
        self._tvcolumn_mtime.add_attribute(cell, 'text', 8)
1053
 
        
1054
 
        # Set up the properties of the TreeView
1055
 
        self.treeview_right.set_headers_visible(True)
1056
 
        self.treeview_right.set_headers_clickable(True)
1057
 
        self.treeview_right.set_search_column(1)
1058
 
        self._tvcolumn_filename.set_resizable(True)
1059
 
        self._tvcolumn_status.set_resizable(True)
1060
 
        self._tvcolumn_size.set_resizable(True)
1061
 
        self._tvcolumn_mtime.set_resizable(True)
1062
 
        # Set up sorting
1063
 
        liststore.set_sort_func(13, self._sort_filelist_callback, None)
1064
 
        liststore.set_sort_column_id(13, gtk.SORT_ASCENDING)
1065
 
        self._tvcolumn_filename.set_sort_column_id(13)
1066
 
        self._tvcolumn_status.set_sort_column_id(3)
1067
 
        self._tvcolumn_size.set_sort_column_id(5)
1068
 
        self._tvcolumn_mtime.set_sort_column_id(7)
1069
 
        
1070
 
        # Set sensitivity
1071
 
        self.set_sensitivity()
1072
 
        
1073
 
    def get_selected_fileid(self):
1074
 
        """ Get the file_id of the selected file. """
1075
 
        treeselection = self.treeview_right.get_selection()
1076
 
        (model, iter) = treeselection.get_selected()
1077
 
        
1078
 
        if iter is None:
1079
 
            return None
1080
 
        else:
1081
 
            return model.get_value(iter, 9)
1082
 
    
 
572
        tvcolumn_filename.pack_start(cellpb, False)
 
573
        tvcolumn_filename.pack_start(cell, True)
 
574
        tvcolumn_filename.set_attributes(cellpb, stock_id=0)
 
575
        tvcolumn_filename.add_attribute(cell, 'text', 1)
 
576
        tvcolumn_status.pack_start(cell, True)
 
577
        tvcolumn_status.add_attribute(cell, 'text', 2)
 
578
 
 
579
        self.menuitem_branch_init.set_sensitive(self.notbranch)
 
580
        # Check if current directory is a branch
 
581
        self.menuitem_branch_get.set_sensitive(not self.notbranch)
 
582
        self.menuitem_branch_checkout.set_sensitive(not self.notbranch)
 
583
        self.menuitem_branch_pull.set_sensitive(not self.notbranch)
 
584
        self.menuitem_branch_push.set_sensitive(not self.notbranch)
 
585
        self.menuitem_branch_commit.set_sensitive(not self.notbranch)
 
586
        self.menuitem_branch_status.set_sensitive(not self.notbranch)
 
587
        self.menuitem_branch_missing.set_sensitive(not self.notbranch)
 
588
        self.menuitem_stats.set_sensitive(not self.notbranch)
 
589
        self.menuitem_add_files.set_sensitive(not self.notbranch)
 
590
        self.menuitem_remove_files.set_sensitive(not self.notbranch)
 
591
        self.menuitem_file_make_directory.set_sensitive(not self.notbranch)
 
592
        self.menuitem_file_rename.set_sensitive(not self.notbranch)
 
593
        self.menuitem_file_move.set_sensitive(not self.notbranch)
 
594
        #self.menutoolbutton_diff.set_sensitive(True)
 
595
        self.toolbutton_diff.set_sensitive(not self.notbranch)
 
596
        self.toolbutton_log.set_sensitive(not self.notbranch)
 
597
        self.toolbutton_commit.set_sensitive(not self.notbranch)
 
598
        self.toolbutton_pull.set_sensitive(not self.notbranch)
 
599
        self.toolbutton_push.set_sensitive(not self.notbranch)
 
600
        
1083
601
    def get_selected_right(self):
1084
602
        """ Get the selected filename. """
1085
603
        treeselection = self.treeview_right.get_selection()
1088
606
        if iter is None:
1089
607
            return None
1090
608
        else:
1091
 
            return model.get_value(iter, 2)
 
609
            return model.get_value(iter, 1)
1092
610
    
1093
611
    def get_selected_left(self):
1094
612
        """ Get the selected bookmark. """
1102
620
 
1103
621
    def set_statusbar(self, message):
1104
622
        """ Set the statusbar message. """
1105
 
        self.window.statusbar.push(self.context_id, message)
 
623
        self.statusbar.push(self.context_id, message)
1106
624
    
1107
625
    def clear_statusbar(self):
1108
626
        """ Clean the last message from the statusbar. """
1109
 
        self.window.statusbar.pop(self.context_id)
1110
 
    
1111
 
    def set_sensitivity(self):
1112
 
        """ Set menu and toolbar sensitivity. """
1113
 
        if not self.remote:
1114
 
            self.window.set_view_to_localbranch(self.notbranch)
1115
 
        else:
1116
 
            self.window.set_view_to_remotebranch()
 
627
        self.statusbar.pop(self.context_id)
1117
628
    
1118
629
    def refresh_left(self):
1119
630
        """ Refresh the bookmark list. """
1122
633
        treestore = self.treeview_left.get_model()
1123
634
        treestore.clear()
1124
635
 
1125
 
        # Re-read preferences
1126
 
        self.pref.read()
1127
 
        
1128
636
        # Get bookmarks
1129
637
        bookmarks = self.pref.get_bookmarks()
1130
638
 
1131
639
        # Add them to the TreeStore
1132
 
        titer = treestore.append(None, [_i18n('Bookmarks'), None])
 
640
        titer = treestore.append(None, [_('Bookmarks'), None])
 
641
        for item in bookmarks:
 
642
            title = self.pref.get_bookmark_title(item)
 
643
            treestore.append(titer, [title, item])
1133
644
 
1134
 
        # Get titles and sort by title
1135
 
        bookmarks = [[self.pref.get_bookmark_title(item), item] for item in bookmarks]
1136
 
        bookmarks.sort()
1137
 
        for title_item in bookmarks:
1138
 
            treestore.append(titer, title_item)
1139
 
        
1140
645
        # Add the TreeStore to the TreeView
1141
646
        self.treeview_left.set_model(treestore)
1142
647
 
1145
650
 
1146
651
    def refresh_right(self, path=None):
1147
652
        """ Refresh the file list. """
1148
 
        if not self.remote:
1149
 
            # We're local
1150
 
            from bzrlib.workingtree import WorkingTree
1151
 
    
1152
 
            if path is None:
1153
 
                path = self.get_path()
1154
 
    
1155
 
            # A workaround for double-clicking Bookmarks
1156
 
            if not os.path.exists(path):
1157
 
                return
1158
 
    
1159
 
            # Get ListStore and clear it
1160
 
            liststore = self.treeview_right.get_model()
1161
 
            liststore.clear()
1162
 
            
1163
 
            # Show Status column
1164
 
            self._tvcolumn_status.set_visible(True)
1165
 
    
1166
 
            dirs = []
1167
 
            files = []
1168
 
    
1169
 
            # Fill the appropriate lists
1170
 
            dotted_files = self.pref.get_preference('dotted_files', 'bool')
1171
 
            ignored_files = self.pref.get_preference('ignored_files', 'bool')
1172
 
 
1173
 
            for item in os.listdir(path):
1174
 
                if not dotted_files and item[0] == '.':
1175
 
                    continue
1176
 
                if os.path.isdir(path + os.sep + item):
1177
 
                    dirs.append(item)
1178
 
                else:
1179
 
                    files.append(item)
1180
 
            
1181
 
            # Try to open the working tree
1182
 
            notbranch = False
1183
 
            try:
1184
 
                tree1 = WorkingTree.open_containing(path)[0]
1185
 
            except (bzrerrors.NotBranchError, bzrerrors.NoWorkingTree):
1186
 
                notbranch = True
1187
 
            
 
653
        from bzrlib.workingtree import WorkingTree
 
654
 
 
655
        if path is None:
 
656
            path = self.get_path()
 
657
 
 
658
        # A workaround for double-clicking Bookmarks
 
659
        if not os.path.exists(path):
 
660
            return
 
661
 
 
662
        # Get ListStore and clear it
 
663
        liststore = self.treeview_right.get_model()
 
664
        liststore.clear()
 
665
 
 
666
        dirs = ['..']
 
667
        files = []
 
668
 
 
669
        # Fill the appropriate lists
 
670
        dotted_files = self.pref.get_preference('dotted_files', 'bool')
 
671
        for item in os.listdir(path):
 
672
            if not dotted_files and item[0] == '.':
 
673
                continue
 
674
            if os.path.isdir(path + os.sep + item):
 
675
                dirs.append(item)
 
676
            else:
 
677
                files.append(item)
 
678
 
 
679
        # Sort'em
 
680
        dirs.sort()
 
681
        files.sort()
 
682
        
 
683
        # Try to open the working tree
 
684
        notbranch = False
 
685
        try:
 
686
            tree1 = WorkingTree.open_containing(path)[0]
 
687
        except errors.NotBranchError:
 
688
            notbranch = True
 
689
        except errors.PermissionDenied:
 
690
            print "DEBUG: permission denied."
 
691
        
 
692
        if not notbranch:
 
693
            branch = tree1.branch
 
694
            tree2 = tree1.branch.repository.revision_tree(branch.last_revision())
 
695
        
 
696
            delta = tree1.changes_from(tree2, want_unchanged=True)
 
697
 
 
698
        # Add'em to the ListStore
 
699
        for item in dirs:
 
700
            liststore.append([gtk.STOCK_DIRECTORY, item, ''])
 
701
        for item in files:
 
702
            status = 'unknown'
1188
703
            if not notbranch:
1189
 
                branch = tree1.branch
1190
 
                tree2 = tree1.branch.repository.revision_tree(branch.last_revision())
1191
 
            
1192
 
                delta = tree1.changes_from(tree2, want_unchanged=True)
1193
 
                
1194
 
            # Add'em to the ListStore
1195
 
            for item in dirs:
1196
 
                try:
1197
 
                    statinfo = os.stat(self.path + os.sep + item)
1198
 
                except OSError, e:
1199
 
                    if e.errno in self.acceptable_errors:
1200
 
                        continue
1201
 
                    else:
1202
 
                        raise
1203
 
                liststore.append([gtk.STOCK_DIRECTORY,
1204
 
                                  True,
1205
 
                                  item,
1206
 
                                  '',
1207
 
                                  '',
1208
 
                                  "<DIR>",
1209
 
                                  "<DIR>",
1210
 
                                  statinfo.st_mtime,
1211
 
                                  self._format_date(statinfo.st_mtime),
1212
 
                                  ''])
1213
 
            for item in files:
1214
 
                status = 'unknown'
1215
 
                fileid = ''
1216
 
                if not notbranch:
1217
 
                    filename = tree1.relpath(path + os.sep + item)
1218
 
                    
1219
 
                    try:
1220
 
                        self.wt.lock_read()
1221
 
                        
1222
 
                        for rpath, rpathnew, id, kind, text_modified, meta_modified in delta.renamed:
1223
 
                            if rpathnew == filename:
1224
 
                                status = 'renamed'
1225
 
                                fileid = id
1226
 
                        for rpath, id, kind in delta.added:
1227
 
                            if rpath == filename:
1228
 
                                status = 'added'
1229
 
                                fileid = id
1230
 
                        for rpath, id, kind in delta.removed:
1231
 
                            if rpath == filename:
1232
 
                                status = 'removed'
1233
 
                                fileid = id
1234
 
                        for rpath, id, kind, text_modified, meta_modified in delta.modified:
1235
 
                            if rpath == filename:
1236
 
                                status = 'modified'
1237
 
                                fileid = id
1238
 
                        for rpath, id, kind in delta.unchanged:
1239
 
                            if rpath == filename:
1240
 
                                status = 'unchanged'
1241
 
                                fileid = id
1242
 
                        for rpath, file_class, kind, id, entry in self.wt.list_files():
1243
 
                            if rpath == filename and file_class == 'I':
1244
 
                                status = 'ignored'
1245
 
                    finally:
1246
 
                        self.wt.unlock()
1247
 
                
1248
 
                if status == 'renamed':
1249
 
                    st = _i18n('renamed')
1250
 
                elif status == 'removed':
1251
 
                    st = _i18n('removed')
1252
 
                elif status == 'added':
1253
 
                    st = _i18n('added')
1254
 
                elif status == 'modified':
1255
 
                    st = _i18n('modified')
1256
 
                elif status == 'unchanged':
1257
 
                    st = _i18n('unchanged')
1258
 
                elif status == 'ignored':
1259
 
                    st = _i18n('ignored')
1260
 
                    if not ignored_files:
1261
 
                        continue
1262
 
                else:
1263
 
                    st = _i18n('unknown')
1264
 
                
1265
 
                try:
1266
 
                    statinfo = os.stat(self.path + os.sep + item)
1267
 
                except OSError, e:
1268
 
                    if e.errno in self.acceptable_errors:
1269
 
                        continue
1270
 
                    else:
1271
 
                        raise
1272
 
                liststore.append([gtk.STOCK_FILE,
1273
 
                                  False,
1274
 
                                  item,
1275
 
                                  st,
1276
 
                                  status,
1277
 
                                  str(statinfo.st_size),
1278
 
                                  self._format_size(statinfo.st_size),
1279
 
                                  statinfo.st_mtime,
1280
 
                                  self._format_date(statinfo.st_mtime),
1281
 
                                  fileid])
1282
 
        else:
1283
 
            # We're remote
1284
 
            
1285
 
            # Get ListStore and clear it
1286
 
            liststore = self.treeview_right.get_model()
1287
 
            liststore.clear()
1288
 
            
1289
 
            # Hide Status column
1290
 
            self._tvcolumn_status.set_visible(False)
1291
 
            
1292
 
            dirs = []
1293
 
            files = []
1294
 
            
1295
 
            self._show_stock_image(gtk.STOCK_REFRESH)
1296
 
            
1297
 
            for (name, type) in self.remote_entries:
1298
 
                if type.kind == 'directory':
1299
 
                    dirs.append(type)
1300
 
                elif type.kind == 'file':
1301
 
                    files.append(type)
1302
 
            
1303
 
            class HistoryCache:
1304
 
                """ Cache based on revision history. """
1305
 
                def __init__(self, history):
1306
 
                    self._history = history
1307
 
                
1308
 
                def _lookup_revision(self, revid):
1309
 
                    for r in self._history:
1310
 
                        if r.revision_id == revid:
1311
 
                            return r
1312
 
                    rev = repo.get_revision(revid)
1313
 
                    self._history.append(rev)
1314
 
                    return rev
1315
 
            
1316
 
            repo = self.remote_branch.repository
1317
 
            
1318
 
            revhistory = self.remote_branch.revision_history()
1319
 
            try:
1320
 
                revs = repo.get_revisions(revhistory)
1321
 
                cache = HistoryCache(revs)
1322
 
            except bzrerrors.InvalidHttpResponse:
1323
 
                # Fallback to dummy algorithm, because of LP: #115209
1324
 
                cache = HistoryCache([])
1325
 
            
1326
 
            for item in dirs:
1327
 
                if item.parent_id == self.remote_parent:
1328
 
                    rev = cache._lookup_revision(item.revision)
1329
 
                    liststore.append([ gtk.STOCK_DIRECTORY,
1330
 
                                       True,
1331
 
                                       item.name,
1332
 
                                       '',
1333
 
                                       '',
1334
 
                                       "<DIR>",
1335
 
                                       "<DIR>",
1336
 
                                       rev.timestamp,
1337
 
                                       self._format_date(rev.timestamp),
1338
 
                                       ''
1339
 
                                   ])
1340
 
                while gtk.events_pending():
1341
 
                    gtk.main_iteration()
1342
 
            
1343
 
            for item in files:
1344
 
                if item.parent_id == self.remote_parent:
1345
 
                    rev = cache._lookup_revision(item.revision)
1346
 
                    liststore.append([ gtk.STOCK_FILE,
1347
 
                                       False,
1348
 
                                       item.name,
1349
 
                                       '',
1350
 
                                       '',
1351
 
                                       str(item.text_size),
1352
 
                                       self._format_size(item.text_size),
1353
 
                                       rev.timestamp,
1354
 
                                       self._format_date(rev.timestamp),
1355
 
                                       item.file_id
1356
 
                                   ])
1357
 
                while gtk.events_pending():
1358
 
                    gtk.main_iteration()
1359
 
            
1360
 
            self.image_location_error.destroy()
1361
 
 
1362
 
        # Columns should auto-size
1363
 
        self.treeview_right.columns_autosize()
1364
 
        
1365
 
        # Set sensitivity
1366
 
        self.set_sensitivity()
 
704
                filename = tree1.relpath(path + os.sep + item)
 
705
                
 
706
                for rpath, id, kind, text_modified, meta_modified in delta.renamed:
 
707
                    if rpath == filename:
 
708
                        status = 'renamed'
 
709
                for rpath, id, kind in delta.added:
 
710
                    if rpath == filename:
 
711
                        status = 'added'
 
712
                for rpath, id, kind, text_modified, meta_modified in delta.removed:
 
713
                    if rpath == filename:
 
714
                        status = 'removed'
 
715
                for rpath, id, kind, text_modified, meta_modified in delta.modified:
 
716
                    if rpath == filename:
 
717
                        status = 'modified'
 
718
                for rpath, id, kind in delta.unchanged:
 
719
                    if rpath == filename:
 
720
                        status = 'unchanged'
 
721
            
 
722
            #try:
 
723
            #    status = fileops.status(path + os.sep + item)
 
724
            #except errors.PermissionDenied:
 
725
            #    continue
 
726
 
 
727
            if status == 'renamed':
 
728
                st = _('renamed')
 
729
            elif status == 'removed':
 
730
                st = _('removed')
 
731
            elif status == 'added':
 
732
                st = _('added')
 
733
            elif status == 'modified':
 
734
                st = _('modified')
 
735
            elif status == 'unchanged':
 
736
                st = _('unchanged')
 
737
            else:
 
738
                st = _('unknown')
 
739
            liststore.append([gtk.STOCK_FILE, item, st])
 
740
 
 
741
        # Add the ListStore to the TreeView
 
742
        self.treeview_right.set_model(liststore)
1367
743
 
1368
744
    def _harddisks(self):
1369
745
        """ Returns hard drive letters under Win32. """
1374
750
            if sys.platform == 'win32':
1375
751
                print "pyWin32 modules needed to run Olive on Win32."
1376
752
                sys.exit(1)
 
753
            else:
 
754
                pass
1377
755
        
1378
756
        driveletters = []
1379
757
        for drive in string.ascii_uppercase:
1380
 
            if win32file.GetDriveType(drive+':') == win32file.DRIVE_FIXED or\
1381
 
                win32file.GetDriveType(drive+':') == win32file.DRIVE_REMOTE:
 
758
            if win32file.GetDriveType(drive+':') == win32file.DRIVE_FIXED:
1382
759
                driveletters.append(drive+':')
1383
760
        return driveletters
1384
761
    
1387
764
        drives = self._harddisks()
1388
765
        for drive in drives:
1389
766
            self.combobox_drive.append_text(drive)
1390
 
        self.combobox_drive.set_active(drives.index(os.getcwd()[0:2]))
1391
767
    
1392
768
    def _refresh_drives(self, combobox):
1393
 
        if self._just_started:
1394
 
            return
1395
769
        model = combobox.get_model()
1396
770
        active = combobox.get_active()
1397
771
        if active >= 0:
1398
772
            drive = model[active][0]
1399
 
            self.set_path(drive + '\\')
1400
773
            self.refresh_right(drive + '\\')
1401
 
    
1402
 
    def check_for_changes(self):
1403
 
        """ Check whether there were changes in the current working tree. """
1404
 
        old_tree = self.wt.branch.repository.revision_tree(self.wt.branch.last_revision())
1405
 
        delta = self.wt.changes_from(old_tree)
1406
 
 
1407
 
        changes = False
1408
 
        
1409
 
        if len(delta.added) or len(delta.removed) or len(delta.renamed) or len(delta.modified):
1410
 
            changes = True
1411
 
        
1412
 
        return changes
1413
 
    
1414
 
    def _sort_filelist_callback(self, model, iter1, iter2, data):
1415
 
        """ The sort callback for the file list, return values:
1416
 
        -1: iter1 < iter2
1417
 
        0: iter1 = iter2
1418
 
        1: iter1 > iter2
1419
 
        """
1420
 
        name1 = model.get_value(iter1, 2)
1421
 
        name2 = model.get_value(iter2, 2)
1422
 
        
1423
 
        if model.get_value(iter1, 1):
1424
 
            # item1 is a directory
1425
 
            if not model.get_value(iter2, 1):
1426
 
                # item2 isn't
1427
 
                return -1
1428
 
            else:
1429
 
                # both of them are directories, we compare their names
1430
 
                if name1 < name2:
1431
 
                    return -1
1432
 
                elif name1 == name2:
1433
 
                    return 0
1434
 
                else:
1435
 
                    return 1
1436
 
        else:
1437
 
            # item1 is not a directory
1438
 
            if model.get_value(iter2, 1):
1439
 
                # item2 is
1440
 
                return 1
1441
 
            else:
1442
 
                # both of them are files, compare them
1443
 
                if name1 < name2:
1444
 
                    return -1
1445
 
                elif name1 == name2:
1446
 
                    return 0
1447
 
                else:
1448
 
                    return 1
1449
 
    
1450
 
    def _format_size(self, size):
1451
 
        """ Format size to a human readable format. """
1452
 
        if size < 1000:
1453
 
            return "%d[B]" % (size,)
1454
 
        size = size / 1000.0
1455
 
        
1456
 
        for metric in ["kB","MB","GB","TB"]:
1457
 
            if size < 1000:
1458
 
                break
1459
 
            size = size / 1000.0
1460
 
        return "%.1f[%s]" % (size,metric) 
1461
 
    
1462
 
    def _format_date(self, timestamp):
1463
 
        """ Format the time (given in secs) to a human readable format. """
1464
 
        return time.ctime(timestamp)
1465
 
    
1466
 
    def _is_remote_dir(self, location):
1467
 
        """ Determine whether the given location is a directory or not. """
1468
 
        if not self.remote:
1469
 
            # We're in local mode
1470
 
            return False
1471
 
        else:
1472
 
            branch, path = Branch.open_containing(location)
1473
 
            for (name, type) in self.remote_entries:
1474
 
                if name == path and type.kind == 'directory':
1475
 
                    # We got it
1476
 
                    return True
1477
 
            # Either it's not a directory or not in the inventory
1478
 
            return False
1479
 
    
1480
 
    def _show_stock_image(self, stock_id):
1481
 
        """ Show a stock image next to the location entry. """
1482
 
        self.image_location_error.destroy()
1483
 
        self.image_location_error = gtk.image_new_from_stock(stock_id, gtk.ICON_SIZE_BUTTON)
1484
 
        self.hbox_location.pack_start(self.image_location_error, False, False, 0)
1485
 
        if sys.platform == 'win32':
1486
 
            self.hbox_location.reorder_child(self.image_location_error, 2)
1487
 
        else:
1488
 
            self.hbox_location.reorder_child(self.image_location_error, 1)
1489
 
        self.image_location_error.show()
1490
 
        while gtk.events_pending():
1491
 
            gtk.main_iteration()
1492
774
 
1493
775
import ConfigParser
1494
776
 
1495
 
class Preferences:
 
777
class OlivePreferences:
1496
778
    """ A class which handles Olive's preferences. """
1497
 
    def __init__(self, path=None):
 
779
    def __init__(self):
1498
780
        """ Initialize the Preferences class. """
1499
781
        # Some default options
1500
782
        self.defaults = { 'strict_commit' : False,
1501
783
                          'dotted_files'  : False,
1502
 
                          'ignored_files' : True,
1503
784
                          'window_width'  : 700,
1504
785
                          'window_height' : 400,
1505
786
                          'window_x'      : 40,
1508
789
 
1509
790
        # Create a config parser object
1510
791
        self.config = ConfigParser.RawConfigParser()
1511
 
 
1512
 
        # Set filename
1513
 
        if path is None:
1514
 
            if sys.platform == 'win32':
1515
 
                # Windows - no dotted files
1516
 
                self._filename = os.path.expanduser('~/olive.conf')
1517
 
            else:
1518
 
                self._filename = os.path.expanduser('~/.olive.conf')
1519
 
        else:
1520
 
            self._filename = path
1521
792
        
1522
793
        # Load the configuration
1523
794
        self.read()
1540
811
 
1541
812
    def read(self):
1542
813
        """ Just read the configuration. """
1543
 
        # Re-initialize the config parser object to avoid some bugs
1544
 
        self.config = ConfigParser.RawConfigParser()
1545
 
        self.config.read([self._filename])
 
814
        if sys.platform == 'win32':
 
815
            # Windows - no dotted files
 
816
            self.config.read([os.path.expanduser('~/olive.conf')])
 
817
        else:
 
818
            self.config.read([os.path.expanduser('~/.olive.conf')])
1546
819
    
1547
820
    def write(self):
1548
821
        """ Write the configuration to the appropriate files. """
1549
 
        fp = open(self._filename, 'w')
1550
 
        self.config.write(fp)
1551
 
        fp.close()
 
822
        if sys.platform == 'win32':
 
823
            # Windows - no dotted files
 
824
            fp = open(os.path.expanduser('~/olive.conf'), 'w')
 
825
            self.config.write(fp)
 
826
            fp.close()
 
827
        else:
 
828
            fp = open(os.path.expanduser('~/.olive.conf'), 'w')
 
829
            self.config.write(fp)
 
830
            fp.close()
1552
831
 
1553
832
    def get_bookmarks(self):
1554
833
        """ Return the list of bookmarks. """
1577
856
    
1578
857
    def set_bookmark_title(self, path, title):
1579
858
        """ Set bookmark title. """
1580
 
        # FIXME: What if path isn't listed yet?
1581
 
        # FIXME: Canonicalize paths first?
1582
859
        self.config.set(path, 'title', title)
1583
860
    
1584
861
    def remove_bookmark(self, path):
1587
864
 
1588
865
    def set_preference(self, option, value):
1589
866
        """ Set the value of the given option. """
1590
 
        if value is True:
1591
 
            value = 'yes'
1592
 
        elif value is False:
1593
 
            value = 'no'
1594
 
        
1595
867
        if self.config.has_section('preferences'):
1596
868
            self.config.set('preferences', option, value)
1597
869
        else:
1605
877
        """
1606
878
        if self.config.has_option('preferences', option):
1607
879
            if kind == 'bool':
1608
 
                return self.config.getboolean('preferences', option)
 
880
                #return self.config.getboolean('preferences', option)
 
881
                return True
1609
882
            elif kind == 'int':
1610
883
                return self.config.getint('preferences', option)
1611
884
            elif kind == 'float':
1617
890
                return self._get_default(option)
1618
891
            except KeyError:
1619
892
                return None
 
893