/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: Szilveszter Farkas (Phanatic)
  • Date: 2007-05-16 08:17:55 UTC
  • mto: (195.1.7 trunk)
  • mto: This revision was merged to the branch mainline in revision 199.
  • Revision ID: szilveszter.farkas@gmail.com-20070516081755-8rok1lm91i3zv3oa
Added NEWS entry.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
 #!/usr/bin/python
2
 
 
3
1
# Copyright (C) 2006 by Szilveszter Farkas (Phanatic) <szilveszter.farkas@gmail.com>
4
2
#
5
3
# This program is free software; you can redistribute it and/or modify
38
36
from bzrlib.branch import Branch
39
37
import bzrlib.errors as bzrerrors
40
38
from bzrlib.lazy_import import lazy_import
41
 
from bzrlib.ui import ui_factory
42
39
from bzrlib.workingtree import WorkingTree
43
40
 
44
 
from bzrlib.plugins.gtk import _i18n
45
41
from bzrlib.plugins.gtk.dialog import error_dialog, info_dialog, warning_dialog
46
42
from bzrlib.plugins.gtk.errors import show_bzr_error
47
43
from guifiles import GLADEFILENAME
56
52
from bzrlib.plugins.gtk.conflicts import ConflictsDialog
57
53
from bzrlib.plugins.gtk.initialize import InitDialog
58
54
from bzrlib.plugins.gtk.push import PushDialog
59
 
from bzrlib.plugins.gtk.revbrowser import RevisionBrowser
60
 
 
61
 
def about():
62
 
    """ Display the AboutDialog. """
63
 
    from bzrlib.plugins.gtk import __version__
64
 
    from bzrlib.plugins.gtk.olive.guifiles import GLADEFILENAME
65
 
 
66
 
    # Load AboutDialog description
67
 
    dglade = gtk.glade.XML(GLADEFILENAME, 'aboutdialog')
68
 
    dialog = dglade.get_widget('aboutdialog')
69
 
 
70
 
    # Set version
71
 
    dialog.set_version(__version__)
72
 
    dialog.set_authors([ _i18n("Lead Developer:"),
73
 
                         "Szilveszter Farkas <szilveszter.farkas@gmail.com>",
74
 
                         _i18n("Contributors:"),
75
 
                         "Jelmer Vernooij <jelmer@samba.org>",
76
 
                         "Mateusz Korniak <mateusz.korniak@ant.gliwice.pl>",
77
 
                         "Gary van der Merwe <garyvdm@gmail.com>" ])
78
 
    dialog.set_artists([ "Simon Pascal Klein <klepas@klepas.org>",
79
 
                         "Jakub Steiner <jimmac@novell.com>" ])
80
 
 
81
 
    dialog.run()
82
 
    # Destroy the dialog
83
 
    dialog.destroy()
84
55
 
85
56
class OliveGtk:
86
57
    """ The main Olive GTK frontend class. This is called when launching the
106
77
        # Get some important menu items
107
78
        self.menuitem_add_files = self.toplevel.get_widget('menuitem_add_files')
108
79
        self.menuitem_remove_files = self.toplevel.get_widget('menuitem_remove_file')
109
 
        self.menuitem_file_bookmark = self.toplevel.get_widget('menuitem_file_bookmark')
110
80
        self.menuitem_file_make_directory = self.toplevel.get_widget('menuitem_file_make_directory')
111
81
        self.menuitem_file_rename = self.toplevel.get_widget('menuitem_file_rename')
112
82
        self.menuitem_file_move = self.toplevel.get_widget('menuitem_file_move')
113
83
        self.menuitem_file_annotate = self.toplevel.get_widget('menuitem_file_annotate')
114
84
        self.menuitem_view_show_hidden_files = self.toplevel.get_widget('menuitem_view_show_hidden_files')
115
 
        self.menuitem_view_show_ignored_files = self.toplevel.get_widget('menuitem_view_show_ignored_files')
116
85
        self.menuitem_branch = self.toplevel.get_widget('menuitem_branch')
117
86
        self.menuitem_branch_init = self.toplevel.get_widget('menuitem_branch_initialize')
118
87
        self.menuitem_branch_get = self.toplevel.get_widget('menuitem_branch_get')
119
88
        self.menuitem_branch_checkout = self.toplevel.get_widget('menuitem_branch_checkout')
120
89
        self.menuitem_branch_pull = self.toplevel.get_widget('menuitem_branch_pull')
121
90
        self.menuitem_branch_push = self.toplevel.get_widget('menuitem_branch_push')
122
 
        self.menuitem_branch_update = self.toplevel.get_widget('menuitem_branch_update')
123
91
        self.menuitem_branch_revert = self.toplevel.get_widget('menuitem_branch_revert')
124
92
        self.menuitem_branch_merge = self.toplevel.get_widget('menuitem_branch_merge')
125
93
        self.menuitem_branch_commit = self.toplevel.get_widget('menuitem_branch_commit')
137
105
        self.toolbutton_commit = self.toplevel.get_widget('toolbutton_commit')
138
106
        self.toolbutton_pull = self.toplevel.get_widget('toolbutton_pull')
139
107
        self.toolbutton_push = self.toplevel.get_widget('toolbutton_push')
140
 
        self.toolbutton_update = self.toplevel.get_widget('toolbutton_update')
141
108
        # Get the drive selector
142
109
        self.combobox_drive = gtk.combo_box_new_text()
143
110
        self.combobox_drive.connect("changed", self._refresh_drives)
144
111
        
145
112
        # Get the navigation widgets
146
 
        self.hbox_location = self.toplevel.get_widget('hbox_location')
147
113
        self.button_location_up = self.toplevel.get_widget('button_location_up')
148
114
        self.button_location_jump = self.toplevel.get_widget('button_location_jump')
149
115
        self.entry_location = self.toplevel.get_widget('entry_location')
150
116
        self.image_location_error = self.toplevel.get_widget('image_location_error')
151
117
        
152
 
        # Get the History widgets
153
 
        self.check_history = self.toplevel.get_widget('checkbutton_history')
154
 
        self.entry_history = self.toplevel.get_widget('entry_history_revno')
155
 
        self.button_history = self.toplevel.get_widget('button_history_browse')
156
 
        
157
118
        self.vbox_main_right = self.toplevel.get_widget('vbox_main_right')
158
119
        
159
120
        # Dictionary for signal_autoconnect
163
124
                "on_about_activate": self.on_about_activate,
164
125
                "on_menuitem_add_files_activate": self.on_menuitem_add_files_activate,
165
126
                "on_menuitem_remove_file_activate": self.on_menuitem_remove_file_activate,
166
 
                "on_menuitem_file_bookmark_activate": self.on_menuitem_file_bookmark_activate,
167
127
                "on_menuitem_file_make_directory_activate": self.on_menuitem_file_make_directory_activate,
168
128
                "on_menuitem_file_move_activate": self.on_menuitem_file_move_activate,
169
129
                "on_menuitem_file_rename_activate": self.on_menuitem_file_rename_activate,
170
130
                "on_menuitem_file_annotate_activate": self.on_menuitem_file_annotate_activate,
171
131
                "on_menuitem_view_show_hidden_files_activate": self.on_menuitem_view_show_hidden_files_activate,
172
 
                "on_menuitem_view_show_ignored_files_activate": self.on_menuitem_view_show_ignored_files_activate,
173
132
                "on_menuitem_view_refresh_activate": self.on_menuitem_view_refresh_activate,
174
133
                "on_menuitem_branch_initialize_activate": self.on_menuitem_branch_initialize_activate,
175
134
                "on_menuitem_branch_get_activate": self.on_menuitem_branch_get_activate,
179
138
                "on_menuitem_branch_commit_activate": self.on_menuitem_branch_commit_activate,
180
139
                "on_menuitem_branch_push_activate": self.on_menuitem_branch_push_activate,
181
140
                "on_menuitem_branch_pull_activate": self.on_menuitem_branch_pull_activate,
182
 
                "on_menuitem_branch_update_activate": self.on_menuitem_branch_update_activate,                
183
141
                "on_menuitem_branch_tags_activate": self.on_menuitem_branch_tags_activate,
184
142
                "on_menuitem_branch_status_activate": self.on_menuitem_branch_status_activate,
185
143
                "on_menuitem_branch_missing_revisions_activate": self.on_menuitem_branch_missing_revisions_activate,
194
152
                "on_toolbutton_commit_clicked": self.on_menuitem_branch_commit_activate,
195
153
                "on_toolbutton_pull_clicked": self.on_menuitem_branch_pull_activate,
196
154
                "on_toolbutton_push_clicked": self.on_menuitem_branch_push_activate,
197
 
                "on_toolbutton_update_clicked": self.on_menuitem_branch_update_activate,
198
155
                "on_treeview_right_button_press_event": self.on_treeview_right_button_press_event,
199
156
                "on_treeview_right_row_activated": self.on_treeview_right_row_activated,
200
157
                "on_treeview_left_button_press_event": self.on_treeview_left_button_press_event,
201
 
                "on_treeview_left_button_release_event": self.on_treeview_left_button_release_event,
202
158
                "on_treeview_left_row_activated": self.on_treeview_left_row_activated,
203
159
                "on_button_location_up_clicked": self.on_button_location_up_clicked,
204
160
                "on_button_location_jump_clicked": self.on_button_location_jump_clicked,
205
 
                "on_entry_location_key_press_event": self.on_entry_location_key_press_event,
206
 
                "on_checkbutton_history_toggled": self.on_checkbutton_history_toggled,
207
 
                "on_entry_history_revno_key_press_event": self.on_entry_history_revno_key_press_event,
208
 
                "on_button_history_browse_clicked": self.on_button_history_browse_clicked
 
161
                "on_entry_location_key_press_event": self.on_entry_location_key_press_event
209
162
            }
210
163
        
211
164
        # Connect the signals to the handlers
233
186
        
234
187
        # Show drive selector if under Win32
235
188
        if sys.platform == 'win32':
236
 
            self.hbox_location.pack_start(self.combobox_drive, False, False, 0)
237
 
            self.hbox_location.reorder_child(self.combobox_drive, 1)
 
189
            self.vbox_main_right.pack_start(self.combobox_drive, False, True, 0)
 
190
            self.vbox_main_right.reorder_child(self.combobox_drive, 0)
238
191
            self.combobox_drive.show()
239
192
            self.gen_hard_selector()
240
193
        
242
195
 
243
196
        # Apply menu state
244
197
        self.menuitem_view_show_hidden_files.set_active(self.pref.get_preference('dotted_files', 'bool'))
245
 
        self.menuitem_view_show_ignored_files.set_active(self.pref.get_preference('ignored_files', 'bool'))
246
198
 
247
 
        # We're starting local
248
 
        self.remote = False
249
 
        self.remote_branch = None
250
 
        self.remote_path = None
251
 
        self.remote_revision = None
252
 
        
253
199
        self.set_path(os.getcwd())
254
200
        self._load_right()
255
201
        
256
202
        self._just_started = False
257
203
 
258
 
    def set_path(self, path, force_remote=False):
 
204
    def set_path(self, path):
 
205
        self.path = path
259
206
        self.notbranch = False
260
207
        
261
 
        if force_remote:
262
 
            # Forcing remote mode (reading data from inventory)
263
 
            self._show_stock_image(gtk.STOCK_DISCONNECT)
264
 
            try:
265
 
                br = Branch.open_containing(path)[0]
266
 
            except bzrerrors.NotBranchError:
267
 
                self._show_stock_image(gtk.STOCK_DIALOG_ERROR)
268
 
                self.check_history.set_active(False)
269
 
                self.check_history.set_sensitive(False)
270
 
                return False
271
 
            except bzrerrors.UnsupportedProtocol:
272
 
                self._show_stock_image(gtk.STOCK_DIALOG_ERROR)
273
 
                self.check_history.set_active(False)
274
 
                self.check_history.set_sensitive(False)
275
 
                return False
276
 
            
277
 
            self._show_stock_image(gtk.STOCK_CONNECT)
278
 
            
279
 
            self.remote = True
280
 
           
281
 
            # We're remote
282
 
            self.remote_branch, self.remote_path = Branch.open_containing(path)
283
 
            
284
 
            if self.remote_revision is None:
285
 
                self.remote_revision = self.remote_branch.last_revision()
286
 
            
287
 
            self.remote_entries = self.remote_branch.repository.get_inventory(self.remote_revision).entries()
288
 
            
289
 
            if len(self.remote_path) == 0:
290
 
                self.remote_parent = self.remote_branch.repository.get_inventory(self.remote_branch.last_revision()).iter_entries_by_dir().next()[1].file_id
291
 
            else:
292
 
                for (name, type) in self.remote_entries:
293
 
                    if name == self.remote_path:
294
 
                        self.remote_parent = type.file_id
295
 
                        break
296
 
            
297
 
            if not path.endswith('/'):
298
 
                path += '/'
299
 
            
300
 
            if self.remote_branch.base == path:
301
 
                self.button_location_up.set_sensitive(False)
302
 
            else:
303
 
                self.button_location_up.set_sensitive(True)
304
 
        else:
305
 
            if os.path.isdir(path):
306
 
                self.image_location_error.destroy()
307
 
                self.remote = False
308
 
                
309
 
                # We're local
310
 
                try:
311
 
                    self.wt, self.wtpath = WorkingTree.open_containing(path)
312
 
                except (bzrerrors.NotBranchError, bzrerrors.NoWorkingTree):
313
 
                    self.notbranch = True
314
 
                
315
 
                # If we're in the root, we cannot go up anymore
316
 
                if sys.platform == 'win32':
317
 
                    drive, tail = os.path.splitdrive(path)
318
 
                    if tail in ('', '/', '\\'):
319
 
                        self.button_location_up.set_sensitive(False)
320
 
                    else:
321
 
                        self.button_location_up.set_sensitive(True)
322
 
                else:
323
 
                    if self.path == '/':
324
 
                        self.button_location_up.set_sensitive(False)
325
 
                    else:
326
 
                        self.button_location_up.set_sensitive(True)
327
 
            elif not os.path.isfile(path):
328
 
                # Doesn't seem to be a file nor a directory, trying to open a
329
 
                # remote location
330
 
                self._show_stock_image(gtk.STOCK_DISCONNECT)
331
 
                try:
332
 
                    br = Branch.open_containing(path)[0]
333
 
                except bzrerrors.NotBranchError:
334
 
                    self._show_stock_image(gtk.STOCK_DIALOG_ERROR)
335
 
                    self.check_history.set_active(False)
336
 
                    self.check_history.set_sensitive(False)
337
 
                    return False
338
 
                except bzrerrors.UnsupportedProtocol:
339
 
                    self._show_stock_image(gtk.STOCK_DIALOG_ERROR)
340
 
                    self.check_history.set_active(False)
341
 
                    self.check_history.set_sensitive(False)
342
 
                    return False
343
 
                
344
 
                self._show_stock_image(gtk.STOCK_CONNECT)
345
 
                
346
 
                self.remote = True
347
 
               
348
 
                # We're remote
349
 
                self.remote_branch, self.remote_path = Branch.open_containing(path)
350
 
                
351
 
                if self.remote_revision is None:
352
 
                    self.remote_revision = self.remote_branch.last_revision()
353
 
                
354
 
                self.remote_entries = self.remote_branch.repository.get_inventory(self.remote_revision).entries()
355
 
                
356
 
                if len(self.remote_path) == 0:
357
 
                    self.remote_parent = self.remote_branch.repository.get_inventory(self.remote_branch.last_revision()).iter_entries_by_dir().next()[1].file_id
358
 
                else:
359
 
                    for (name, type) in self.remote_entries:
360
 
                        if name == self.remote_path:
361
 
                            self.remote_parent = type.file_id
362
 
                            break
363
 
                
364
 
                if not path.endswith('/'):
365
 
                    path += '/'
366
 
                
367
 
                if self.remote_branch.base == path:
368
 
                    self.button_location_up.set_sensitive(False)
369
 
                else:
370
 
                    self.button_location_up.set_sensitive(True)
371
 
        
372
 
        if self.notbranch:
373
 
            self.check_history.set_active(False)
374
 
            self.check_history.set_sensitive(False)
375
 
        else:
376
 
            self.check_history.set_sensitive(True)
 
208
        try:
 
209
            self.wt, self.wtpath = WorkingTree.open_containing(self.path)
 
210
        except (bzrerrors.NotBranchError, bzrerrors.NoWorkingTree):
 
211
            self.notbranch = True
377
212
        
378
213
        self.statusbar.push(self.context_id, path)
379
214
        self.entry_location.set_text(path)
380
 
        self.path = path
381
 
        return True
 
215
        
 
216
        # If we're in the root, we cannot go up anymore
 
217
        if sys.platform == 'win32':
 
218
            drive, tail = os.path.splitdrive(self.path)
 
219
            if tail in ('', '/', '\\'):
 
220
                self.button_location_up.set_sensitive(False)
 
221
            else:
 
222
                self.button_location_up.set_sensitive(True)
 
223
        else:
 
224
            if self.path == '/':
 
225
                self.button_location_up.set_sensitive(False)
 
226
            else:
 
227
                self.button_location_up.set_sensitive(True)
382
228
 
383
229
    def get_path(self):
384
 
        if not self.remote:
385
 
            return self.path
386
 
        else:
387
 
            # Remote mode
388
 
            if len(self.remote_path) > 0:
389
 
                return self.remote_branch.base + self.remote_path + '/'
390
 
            else:
391
 
                return self.remote_branch.base
 
230
        return self.path
392
231
   
393
232
    def on_about_activate(self, widget):
 
233
        from bzrlib.plugins.gtk.dialog import about
394
234
        about()
395
 
    
396
 
    def on_button_history_browse_clicked(self, widget):
397
 
        """ Browse for revision button handler. """
398
 
        if self.remote:
399
 
            br = self.remote_branch
400
 
        else:
401
 
            br = self.wt.branch
402
 
            
403
 
        revb = RevisionBrowser(br, self.window)
404
 
        response = revb.run()
405
 
        if response != gtk.RESPONSE_NONE:
406
 
            revb.hide()
407
235
        
408
 
            if response == gtk.RESPONSE_OK:
409
 
                if revb.selected_revno is not None:
410
 
                    self.entry_history.set_text(revb.selected_revno)
411
 
            
412
 
            revb.destroy()
 
236
    def on_button_location_up_clicked(self, widget):
 
237
        """ Location Up button handler. """
 
238
        self.set_path(os.path.split(self.get_path())[0])
 
239
        self.refresh_right()
413
240
    
414
241
    def on_button_location_jump_clicked(self, widget):
415
242
        """ Location Jump button handler. """
416
243
        location = self.entry_location.get_text()
417
 
        
418
 
        if self.set_path(location):
 
244
        if os.path.isdir(location):
 
245
            self.set_path(location)
419
246
            self.refresh_right()
420
 
    
421
 
    def on_button_location_up_clicked(self, widget):
422
 
        """ Location Up button handler. """
423
 
        if not self.remote:
424
 
            # Local mode
425
 
            self.set_path(os.path.split(self.get_path())[0])
426
 
        else:
427
 
            # Remote mode
428
 
            delim = '/'
429
 
            newpath = delim.join(self.get_path().split(delim)[:-2])
430
 
            newpath += '/'
431
 
            self.set_path(newpath)
432
 
 
433
 
        self.refresh_right()
434
 
    
435
 
    def on_checkbutton_history_toggled(self, widget):
436
 
        """ History Mode toggle handler. """
437
 
        if self.check_history.get_active():
438
 
            # History Mode activated
439
 
            self.entry_history.set_sensitive(True)
440
 
            self.button_history.set_sensitive(True)
441
 
        else:
442
 
            # History Mode deactivated
443
 
            self.entry_history.set_sensitive(False)
444
 
            self.button_history.set_sensitive(False)
445
 
    
446
 
    @show_bzr_error
447
 
    def on_entry_history_revno_key_press_event(self, widget, event):
448
 
        """ Key pressed handler for the history entry. """
449
 
        if event.keyval == gtk.gdk.keyval_from_name('Return') or event.keyval == gtk.gdk.keyval_from_name('KP_Enter'):
450
 
            # Return was hit, so we have to load that specific revision
451
 
            # Emulate being remote, so inventory should be used
452
 
            path = self.get_path()
453
 
            if not self.remote:
454
 
                self.remote = True
455
 
                self.remote_branch = self.wt.branch
456
 
            
457
 
            revno = int(self.entry_history.get_text())
458
 
            self.remote_revision = self.remote_branch.get_rev_id(revno)
459
 
            if self.set_path(path, True):
460
 
                self.refresh_right()
 
247
            self.image_location_error.hide()
 
248
        else:
 
249
            self.image_location_error.show()
461
250
    
462
251
    def on_entry_location_key_press_event(self, widget, event):
463
252
        """ Key pressed handler for the location entry. """
464
 
        if event.keyval == gtk.gdk.keyval_from_name('Return') or event.keyval == gtk.gdk.keyval_from_name('KP_Enter'):
 
253
        if event.keyval == 65293:
465
254
            # Return was hit, so we have to jump
466
255
            self.on_button_location_jump_clicked(widget)
467
256
    
474
263
    def on_menuitem_branch_get_activate(self, widget):
475
264
        """ Branch/Get... menu handler. """
476
265
        from bzrlib.plugins.gtk.branch import BranchDialog
477
 
        
478
 
        if self.remote:
479
 
            branch = BranchDialog(os.getcwd(), self.window, self.remote_branch.base)
480
 
        else:
481
 
            branch = BranchDialog(self.get_path(), self.window)
 
266
        branch = BranchDialog(self.get_path(), self.window)
482
267
        response = branch.run()
483
268
        if response != gtk.RESPONSE_NONE:
484
269
            branch.hide()
485
 
            
 
270
        
486
271
            if response == gtk.RESPONSE_OK:
487
272
                self.refresh_right()
488
273
            
491
276
    def on_menuitem_branch_checkout_activate(self, widget):
492
277
        """ Branch/Checkout... menu handler. """
493
278
        from bzrlib.plugins.gtk.checkout import CheckoutDialog
494
 
        
495
 
        if self.remote:
496
 
            checkout = CheckoutDialog(os.getcwd(), self.window, self.remote_branch.base)
497
 
        else:
498
 
            checkout = CheckoutDialog(self.get_path(), self.window)
 
279
        checkout = CheckoutDialog(self.get_path(), self.window)
499
280
        response = checkout.run()
500
281
        if response != gtk.RESPONSE_NONE:
501
282
            checkout.hide()
508
289
    @show_bzr_error
509
290
    def on_menuitem_branch_commit_activate(self, widget):
510
291
        """ Branch/Commit... menu handler. """
511
 
#     def __init__(self, wt, wtpath, notbranch, selected=None, parent=None):
512
 
        selected = self.get_selected_right()
513
 
        if selected:
514
 
            selected = os.path.join(self.wtpath, selected)
515
 
        commit = CommitDialog(wt=self.wt,
516
 
                              parent=self.window,
517
 
                              selected=selected,
518
 
                             )
 
292
        commit = CommitDialog(self.wt, self.wtpath, self.notbranch, self.get_selected_right(), self.window)
519
293
        response = commit.run()
520
294
        if response != gtk.RESPONSE_NONE:
521
295
            commit.hide()
537
311
        from bzrlib.plugins.gtk.merge import MergeDialog
538
312
        
539
313
        if self.check_for_changes():
540
 
            error_dialog(_i18n('There are local changes in the branch'),
541
 
                         _i18n('Please commit or revert the changes before merging.'))
 
314
            error_dialog(_('There are local changes in the branch'),
 
315
                         _('Please commit or revert the changes before merging.'))
542
316
        else:
543
 
            parent_branch_path = self.wt.branch.get_parent()
544
 
            merge = MergeDialog(self.wt, self.wtpath,default_branch_path=parent_branch_path )
 
317
            merge = MergeDialog(self.wt, self.wtpath)
545
318
            merge.display()
546
319
 
547
320
    @show_bzr_error
548
321
    def on_menuitem_branch_missing_revisions_activate(self, widget):
549
322
        """ Branch/Missing revisions menu handler. """
550
 
        
551
 
        from bzrlib.missing import find_unmerged, iter_log_revisions
552
 
        
553
323
        local_branch = self.wt.branch
554
 
        parent_branch_path = local_branch.get_parent()
555
 
        if parent_branch_path is None:
556
 
            error_dialog(_i18n('Parent location is unknown'),
557
 
                         _i18n('Cannot determine missing revisions if no parent location is known.'))
 
324
        
 
325
        other_branch = local_branch.get_parent()
 
326
        if other_branch is None:
 
327
            error_dialog(_('Parent location is unknown'),
 
328
                         _('Cannot determine missing revisions if no parent location is known.'))
558
329
            return
559
330
        
560
 
        parent_branch = Branch.open(parent_branch_path)
561
 
        
562
 
        if parent_branch.base == local_branch.base:
563
 
            parent_branch = local_branch
564
 
        
565
 
        local_extra, remote_extra = find_unmerged(local_branch,parent_branch)
566
 
 
567
 
        if local_extra or remote_extra:
568
 
            
569
 
            ## def log_revision_one_line_text(log_revision):
570
 
            ##    """ Generates one line description of log_revison ended with end of line."""
571
 
            ##    revision = log_revision.rev
572
 
            ##    txt =  "- %s (%s)\n" % (revision.get_summary(), revision.committer, )
573
 
            ##    txt = txt.replace("<"," ") # Seems < > chars are expected to be xml tags ...
574
 
            ##    txt = txt.replace(">"," ")
575
 
            ##    return txt
576
 
            
577
 
            dlg_txt = ""
578
 
            if local_extra:
579
 
                dlg_txt += _i18n('%d local extra revision(s). \n') % (len(local_extra),) 
580
 
                ## NOTE: We do not want such ugly info about missing revisions
581
 
                ##       Revision Browser should be used there
582
 
                ## max_revisions = 10
583
 
                ## for log_revision in iter_log_revisions(local_extra, local_branch.repository, verbose=1):
584
 
                ##    dlg_txt += log_revision_one_line_text(log_revision)
585
 
                ##    if max_revisions <= 0:
586
 
                ##        dlg_txt += _i18n("more ... \n")
587
 
                ##        break
588
 
                ## max_revisions -= 1
589
 
            ## dlg_txt += "\n"
590
 
            if remote_extra:
591
 
                dlg_txt += _i18n('%d local missing revision(s).\n') % (len(remote_extra),) 
592
 
                ## max_revisions = 10
593
 
                ## for log_revision in iter_log_revisions(remote_extra, parent_branch.repository, verbose=1):
594
 
                ##    dlg_txt += log_revision_one_line_text(log_revision)
595
 
                ##    if max_revisions <= 0:
596
 
                ##        dlg_txt += _i18n("more ... \n")
597
 
                ##        break
598
 
                ##    max_revisions -= 1
599
 
                
600
 
            info_dialog(_i18n('There are missing revisions'),
601
 
                        dlg_txt)
 
331
        remote_branch = Branch.open(other_branch)
 
332
        
 
333
        if remote_branch.base == local_branch.base:
 
334
            remote_branch = local_branch
 
335
 
 
336
        ret = len(local_branch.missing_revisions(remote_branch))
 
337
 
 
338
        if ret > 0:
 
339
            info_dialog(_('There are missing revisions'),
 
340
                        _('%d revision(s) missing.') % ret)
602
341
        else:
603
 
            info_dialog(_i18n('Local branch up to date'),
604
 
                        _i18n('There are no missing revisions.'))
 
342
            info_dialog(_('Local branch up to date'),
 
343
                        _('There are no missing revisions.'))
605
344
 
606
345
    @show_bzr_error
607
346
    def on_menuitem_branch_pull_activate(self, widget):
610
349
 
611
350
        location = branch_to.get_parent()
612
351
        if location is None:
613
 
            error_dialog(_i18n('Parent location is unknown'),
614
 
                                     _i18n('Pulling is not possible until there is a parent location.'))
 
352
            error_dialog(_('Parent location is unknown'),
 
353
                                     _('Pulling is not possible until there is a parent location.'))
615
354
            return
616
355
 
617
356
        branch_from = Branch.open(location)
619
358
        if branch_to.get_parent() is None:
620
359
            branch_to.set_parent(branch_from.base)
621
360
 
 
361
        #old_rh = branch_to.revision_history()
 
362
        #if tree_to is not None:
 
363
        #    tree_to.pull(branch_from)
 
364
        #else:
 
365
        #    branch_to.pull(branch_from)
622
366
        ret = branch_to.pull(branch_from)
623
367
        
624
 
        info_dialog(_i18n('Pull successful'), _i18n('%d revision(s) pulled.') % ret)
625
 
        
626
 
    @show_bzr_error
627
 
    def on_menuitem_branch_update_activate(self, widget):
628
 
        """ Brranch/checkout update menu handler. """
629
 
        
630
 
        ret = self.wt.update()
631
 
        conflicts = self.wt.conflicts()
632
 
        if conflicts:
633
 
            info_dialog(_i18n('Update successful but conflicts generated'), _i18n('Number of conflicts generated: %d.') % (len(conflicts),) )
634
 
        else:
635
 
            info_dialog(_i18n('Update successful'), _i18n('No conflicts generated.') )
 
368
        info_dialog(_('Pull successful'), _('%d revision(s) pulled.') % ret)
636
369
    
637
370
    def on_menuitem_branch_push_activate(self, widget):
638
371
        """ Branch/Push... menu handler. """
639
 
        push = PushDialog(repository=None,revid=None,branch=self.wt.branch, parent=self.window)
 
372
        push = PushDialog(self.wt.branch, self.window)
640
373
        response = push.run()
641
374
        if response != gtk.RESPONSE_NONE:
642
375
            push.destroy()
646
379
        """ Branch/Revert all changes menu handler. """
647
380
        ret = self.wt.revert([])
648
381
        if ret:
649
 
            warning_dialog(_i18n('Conflicts detected'),
650
 
                           _i18n('Please have a look at the working tree before continuing.'))
 
382
            warning_dialog(_('Conflicts detected'),
 
383
                           _('Please have a look at the working tree before continuing.'))
651
384
        else:
652
 
            info_dialog(_i18n('Revert successful'),
653
 
                        _i18n('All files reverted to last revision.'))
 
385
            info_dialog(_('Revert successful'),
 
386
                        _('All files reverted to last revision.'))
654
387
        self.refresh_right()
655
388
    
656
389
    def on_menuitem_branch_status_activate(self, widget):
676
409
    def on_menuitem_branch_tags_activate(self, widget):
677
410
        """ Branch/Tags... menu handler. """
678
411
        from bzrlib.plugins.gtk.tags import TagsWindow
679
 
        if not self.remote:
680
 
            window = TagsWindow(self.wt.branch, self.window)
681
 
        else:
682
 
            window = TagsWindow(self.remote_branch, self.window)
 
412
        window = TagsWindow(self.wt.branch, self.window)
683
413
        window.show()
684
414
    
685
415
    def on_menuitem_file_annotate_activate(self, widget):
686
416
        """ File/Annotate... menu handler. """
687
417
        if self.get_selected_right() is None:
688
 
            error_dialog(_i18n('No file was selected'),
689
 
                         _i18n('Please select a file from the list.'))
 
418
            error_dialog(_('No file was selected'),
 
419
                         _('Please select a file from the list.'))
690
420
            return
691
421
        
692
422
        branch = self.wt.branch
693
423
        file_id = self.wt.path2id(self.wt.relpath(os.path.join(self.path, self.get_selected_right())))
694
424
        
695
 
        window = GAnnotateWindow(all=False, plain=False, parent=self.window)
 
425
        window = GAnnotateWindow(all=False, plain=False)
696
426
        window.set_title(os.path.join(self.path, self.get_selected_right()) + " - Annotate")
697
427
        config = GAnnotateConfig(window)
698
428
        window.show()
702
432
        finally:
703
433
            branch.unlock()
704
434
    
705
 
    def on_menuitem_file_bookmark_activate(self, widget):
706
 
        """ File/Bookmark current directory menu handler. """
707
 
        if self.pref.add_bookmark(self.path):
708
 
            info_dialog(_i18n('Bookmark successfully added'),
709
 
                        _i18n('The current directory was bookmarked. You can reach\nit by selecting it from the left panel.'))
710
 
            self.pref.write()
711
 
        else:
712
 
            warning_dialog(_i18n('Location already bookmarked'),
713
 
                           _i18n('The current directory is already bookmarked.\nSee the left panel for reference.'))
714
 
        
715
 
        self.refresh_left()
716
 
    
717
435
    def on_menuitem_file_make_directory_activate(self, widget):
718
436
        """ File/Make directory... menu handler. """
719
437
        from mkdir import OliveMkdir
751
469
    
752
470
    def on_menuitem_stats_diff_activate(self, widget):
753
471
        """ Statistics/Differences... menu handler. """
754
 
        window = DiffWindow(parent=self.window)
 
472
        window = DiffWindow()
755
473
        parent_tree = self.wt.branch.repository.revision_tree(self.wt.branch.last_revision())
756
474
        window.set_diff(self.wt.branch.nick, self.wt, parent_tree)
757
475
        window.show()
759
477
    def on_menuitem_stats_infos_activate(self, widget):
760
478
        """ Statistics/Informations... menu handler. """
761
479
        from info import OliveInfo
762
 
        if self.remote:
763
 
            info = OliveInfo(self.remote_branch)
764
 
        else:
765
 
            info = OliveInfo(self.wt.branch)
 
480
        info = OliveInfo(self.wt)
766
481
        info.display()
767
482
    
768
483
    def on_menuitem_stats_log_activate(self, widget):
769
484
        """ Statistics/Log... menu handler. """
770
 
 
771
 
        if not self.remote:
772
 
            branch = self.wt.branch
773
 
        else:
774
 
            branch = self.remote_branch
775
 
 
776
 
        window = branchwin.BranchWindow(branch, branch.last_revision(), None, parent=self.window)
 
485
        window = branchwin.BranchWindow()
 
486
        window.set_branch(self.wt.branch, self.wt.branch.last_revision(), None)
777
487
        window.show()
778
488
    
779
489
    def on_menuitem_view_refresh_activate(self, widget):
789
499
        if self.path is not None:
790
500
            self.refresh_right()
791
501
 
792
 
    def on_menuitem_view_show_ignored_files_activate(self, widget):
793
 
        """ Hide/Show ignored files menu handler. """
794
 
        self.pref.set_preference('ignored_files', widget.get_active())
795
 
        if self.path is not None:
796
 
            self.refresh_right()
797
 
            
798
502
    def on_treeview_left_button_press_event(self, widget, event):
799
503
        """ Occurs when somebody right-clicks in the bookmark list. """
800
504
        if event.button == 3:
811
515
            menu.left_context_menu().popup(None, None, None, 0,
812
516
                                           event.time)
813
517
 
814
 
    def on_treeview_left_button_release_event(self, widget, event):
815
 
        """ Occurs when somebody just clicks a bookmark. """
816
 
        if event.button != 3:
817
 
            # Allow one-click bookmark opening
818
 
            if self.get_selected_left() == None:
819
 
                return
820
 
            
821
 
            newdir = self.get_selected_left()
822
 
            if newdir == None:
823
 
                return
824
 
 
825
 
            if self.set_path(newdir):
826
 
                self.refresh_right()
827
 
 
828
518
    def on_treeview_left_row_activated(self, treeview, path, view_column):
829
519
        """ Occurs when somebody double-clicks or enters an item in the
830
520
        bookmark list. """
833
523
        if newdir == None:
834
524
            return
835
525
 
836
 
        if self.set_path(newdir):
837
 
            self.refresh_right()
 
526
        self.set_path(newdir)
 
527
        self.refresh_right()
838
528
 
839
529
    def on_treeview_right_button_press_event(self, widget, event):
840
530
        """ Occurs when somebody right-clicks in the file list. """
845
535
                             selected=self.get_selected_right(),
846
536
                             app=self)
847
537
            # get the menu items
848
 
            m_open = menu.ui.get_widget('/context_right/open')
849
538
            m_add = menu.ui.get_widget('/context_right/add')
850
539
            m_remove = menu.ui.get_widget('/context_right/remove')
851
540
            m_rename = menu.ui.get_widget('/context_right/rename')
852
541
            m_revert = menu.ui.get_widget('/context_right/revert')
853
542
            m_commit = menu.ui.get_widget('/context_right/commit')
854
 
            m_annotate = menu.ui.get_widget('/context_right/annotate')
855
543
            m_diff = menu.ui.get_widget('/context_right/diff')
856
544
            # check if we're in a branch
857
545
            try:
858
546
                from bzrlib.branch import Branch
859
547
                Branch.open_containing(self.get_path())
860
 
                if self.remote:
861
 
                    m_open.set_sensitive(False)
862
 
                    m_add.set_sensitive(False)
863
 
                    m_remove.set_sensitive(False)
864
 
                    m_rename.set_sensitive(False)
865
 
                    m_revert.set_sensitive(False)
866
 
                    m_commit.set_sensitive(False)
867
 
                    m_annotate.set_sensitive(False)
868
 
                    m_diff.set_sensitive(False)
869
 
                else:
870
 
                    m_open.set_sensitive(True)
871
 
                    m_add.set_sensitive(True)
872
 
                    m_remove.set_sensitive(True)
873
 
                    m_rename.set_sensitive(True)
874
 
                    m_revert.set_sensitive(True)
875
 
                    m_commit.set_sensitive(True)
876
 
                    m_annotate.set_sensitive(True)
877
 
                    m_diff.set_sensitive(True)
 
548
                m_add.set_sensitive(True)
 
549
                m_remove.set_sensitive(True)
 
550
                m_rename.set_sensitive(True)
 
551
                m_revert.set_sensitive(True)
 
552
                m_commit.set_sensitive(True)
 
553
                m_diff.set_sensitive(True)
878
554
            except bzrerrors.NotBranchError:
879
 
                m_open.set_sensitive(True)
880
555
                m_add.set_sensitive(False)
881
556
                m_remove.set_sensitive(False)
882
557
                m_rename.set_sensitive(False)
883
558
                m_revert.set_sensitive(False)
884
559
                m_commit.set_sensitive(False)
885
 
                m_annotate.set_sensitive(False)
886
560
                m_diff.set_sensitive(False)
887
561
 
888
 
            if not self.remote:
889
 
                menu.right_context_menu().popup(None, None, None, 0,
890
 
                                                event.time)
891
 
            else:
892
 
                menu.remote_context_menu().popup(None, None, None, 0,
893
 
                                                 event.time)
 
562
            menu.right_context_menu().popup(None, None, None, 0,
 
563
                                            event.time)
894
564
        
895
565
    def on_treeview_right_row_activated(self, treeview, path, view_column):
896
566
        """ Occurs when somebody double-clicks or enters an item in the
899
569
        
900
570
        newdir = self.get_selected_right()
901
571
        
902
 
        if not self.remote:
903
 
            # We're local
904
 
            if newdir == '..':
905
 
                self.set_path(os.path.split(self.get_path())[0])
 
572
        if newdir == '..':
 
573
            self.set_path(os.path.split(self.get_path())[0])
 
574
        else:
 
575
            fullpath = os.path.join(self.get_path(), newdir)
 
576
            if os.path.isdir(fullpath):
 
577
                # selected item is an existant directory
 
578
                self.set_path(fullpath)
906
579
            else:
907
 
                fullpath = os.path.join(self.get_path(), newdir)
908
 
                if os.path.isdir(fullpath):
909
 
                    # selected item is an existant directory
910
 
                    self.set_path(fullpath)
911
 
                else:
912
 
                    launch(fullpath)
913
 
        else:
914
 
            # We're remote
915
 
            if self._is_remote_dir(self.get_path() + newdir):
916
 
                self.set_path(self.get_path() + newdir)
 
580
                launch(fullpath) 
917
581
        
918
582
        self.refresh_right()
919
583
    
940
604
        bookmarks = self.pref.get_bookmarks()
941
605
        
942
606
        # Add them to the TreeStore
943
 
        titer = treestore.append(None, [_i18n('Bookmarks'), None])
 
607
        titer = treestore.append(None, [_('Bookmarks'), None])
944
608
        for item in bookmarks:
945
609
            title = self.pref.get_bookmark_title(item)
946
610
            treestore.append(titer, [title, item])
947
611
        
948
612
        # Create the column and add it to the TreeView
949
613
        self.treeview_left.set_model(treestore)
950
 
        tvcolumn_bookmark = gtk.TreeViewColumn(_i18n('Bookmark'))
 
614
        tvcolumn_bookmark = gtk.TreeViewColumn(_('Bookmark'))
951
615
        self.treeview_left.append_column(tvcolumn_bookmark)
952
616
        
953
617
        # Set up the cells
961
625
    def _load_right(self):
962
626
        """ Load data into the right panel. (Filelist) """
963
627
        # Create ListStore
964
 
        # Model: [ icon, dir, name, status text, status, size (int), size (human), mtime (int), mtime (local), fileid ]
965
 
        liststore = gtk.ListStore(gobject.TYPE_STRING,
966
 
                                  gobject.TYPE_BOOLEAN,
967
 
                                  gobject.TYPE_STRING,
968
 
                                  gobject.TYPE_STRING,
969
 
                                  gobject.TYPE_STRING,
970
 
                                  gobject.TYPE_STRING,
971
 
                                  gobject.TYPE_STRING,
972
 
                                  gobject.TYPE_INT,
973
 
                                  gobject.TYPE_STRING,
974
 
                                  gobject.TYPE_STRING)
 
628
        # Model: [icon, dir, name, status text, status, size (int), size (human), mtime (int), mtime (local)]
 
629
        liststore = gtk.ListStore(str, gobject.TYPE_BOOLEAN, str, str, str, gobject.TYPE_INT, gobject.TYPE_STRING, gobject.TYPE_INT, gobject.TYPE_STRING)
975
630
        
976
631
        dirs = []
977
632
        files = []
994
649
        
995
650
        # Add'em to the ListStore
996
651
        for item in dirs:
997
 
            try:
998
 
                statinfo = os.stat(self.path + os.sep + item)
999
 
            except OSError, e:
1000
 
                if e.errno == 40:
1001
 
                    continue
1002
 
                else:
1003
 
                    raise
1004
 
            liststore.append([ gtk.STOCK_DIRECTORY,
1005
 
                               True,
1006
 
                               item,
1007
 
                               '',
1008
 
                               '',
1009
 
                               "<DIR>",
1010
 
                               "<DIR>",
1011
 
                               statinfo.st_mtime,
1012
 
                               self._format_date(statinfo.st_mtime),
1013
 
                               ''])
 
652
            statinfo = os.stat(self.path + os.sep + item)
 
653
            liststore.append([gtk.STOCK_DIRECTORY, True, item, '', '', statinfo.st_size, self._format_size(statinfo.st_size), statinfo.st_mtime, self._format_date(statinfo.st_mtime)])
1014
654
        for item in files:
1015
655
            status = 'unknown'
1016
 
            fileid = ''
1017
656
            if not self.notbranch:
1018
657
                filename = self.wt.relpath(self.path + os.sep + item)
1019
658
                
1023
662
                    for rpath, rpathnew, id, kind, text_modified, meta_modified in delta.renamed:
1024
663
                        if rpathnew == filename:
1025
664
                            status = 'renamed'
1026
 
                            fileid = id
1027
665
                    for rpath, id, kind in delta.added:
1028
666
                        if rpath == filename:
1029
667
                            status = 'added'
1030
 
                            fileid = id
1031
668
                    for rpath, id, kind in delta.removed:
1032
669
                        if rpath == filename:
1033
670
                            status = 'removed'
1034
 
                            fileid = id
1035
671
                    for rpath, id, kind, text_modified, meta_modified in delta.modified:
1036
672
                        if rpath == filename:
1037
673
                            status = 'modified'
1038
 
                            fileid = id
1039
674
                    for rpath, id, kind in delta.unchanged:
1040
675
                        if rpath == filename:
1041
676
                            status = 'unchanged'
1042
 
                            fileid = id
1043
677
                    for rpath, file_class, kind, id, entry in self.wt.list_files():
1044
678
                        if rpath == filename and file_class == 'I':
1045
679
                            status = 'ignored'
1046
680
                finally:
1047
681
                    self.wt.unlock()
1048
682
            
 
683
            #try:
 
684
            #    status = fileops.status(path + os.sep + item)
 
685
            #except errors.PermissionDenied:
 
686
            #    continue
 
687
            
1049
688
            if status == 'renamed':
1050
 
                st = _i18n('renamed')
 
689
                st = _('renamed')
1051
690
            elif status == 'removed':
1052
 
                st = _i18n('removed')
 
691
                st = _('removed')
1053
692
            elif status == 'added':
1054
 
                st = _i18n('added')
 
693
                st = _('added')
1055
694
            elif status == 'modified':
1056
 
                st = _i18n('modified')
 
695
                st = _('modified')
1057
696
            elif status == 'unchanged':
1058
 
                st = _i18n('unchanged')
 
697
                st = _('unchanged')
1059
698
            elif status == 'ignored':
1060
 
                st = _i18n('ignored')
 
699
                st = _('ignored')
1061
700
            else:
1062
 
                st = _i18n('unknown')
 
701
                st = _('unknown')
1063
702
            
1064
 
            try:
1065
 
                statinfo = os.stat(self.path + os.sep + item)
1066
 
            except OSError, e:
1067
 
                if e.errno == 40:
1068
 
                    continue
1069
 
                else:
1070
 
                    raise
1071
 
            liststore.append([gtk.STOCK_FILE,
1072
 
                              False,
1073
 
                              item,
1074
 
                              st,
1075
 
                              status,
1076
 
                              str(statinfo.st_size), # NOTE: if int used there it will fail for large files (size expressed as long int)
1077
 
                              self._format_size(statinfo.st_size),
1078
 
                              statinfo.st_mtime,
1079
 
                              self._format_date(statinfo.st_mtime),
1080
 
                              fileid])
 
703
            statinfo = os.stat(self.path + os.sep + item)
 
704
            liststore.append([gtk.STOCK_FILE, False, item, st, status, statinfo.st_size, self._format_size(statinfo.st_size), statinfo.st_mtime, self._format_date(statinfo.st_mtime)])
1081
705
        
1082
706
        # Create the columns and add them to the TreeView
1083
707
        self.treeview_right.set_model(liststore)
1084
 
        self._tvcolumn_filename = gtk.TreeViewColumn(_i18n('Filename'))
1085
 
        self._tvcolumn_status = gtk.TreeViewColumn(_i18n('Status'))
1086
 
        self._tvcolumn_size = gtk.TreeViewColumn(_i18n('Size'))
1087
 
        self._tvcolumn_mtime = gtk.TreeViewColumn(_i18n('Last modified'))
1088
 
        self.treeview_right.append_column(self._tvcolumn_filename)
1089
 
        self.treeview_right.append_column(self._tvcolumn_status)
1090
 
        self.treeview_right.append_column(self._tvcolumn_size)
1091
 
        self.treeview_right.append_column(self._tvcolumn_mtime)
 
708
        tvcolumn_filename = gtk.TreeViewColumn(_('Filename'))
 
709
        tvcolumn_status = gtk.TreeViewColumn(_('Status'))
 
710
        tvcolumn_size = gtk.TreeViewColumn(_('Size'))
 
711
        tvcolumn_mtime = gtk.TreeViewColumn(_('Last modified'))
 
712
        self.treeview_right.append_column(tvcolumn_filename)
 
713
        self.treeview_right.append_column(tvcolumn_status)
 
714
        self.treeview_right.append_column(tvcolumn_size)
 
715
        self.treeview_right.append_column(tvcolumn_mtime)
1092
716
        
1093
717
        # Set up the cells
1094
718
        cellpb = gtk.CellRendererPixbuf()
1095
719
        cell = gtk.CellRendererText()
1096
 
        self._tvcolumn_filename.pack_start(cellpb, False)
1097
 
        self._tvcolumn_filename.pack_start(cell, True)
1098
 
        self._tvcolumn_filename.set_attributes(cellpb, stock_id=0)
1099
 
        self._tvcolumn_filename.add_attribute(cell, 'text', 2)
1100
 
        self._tvcolumn_status.pack_start(cell, True)
1101
 
        self._tvcolumn_status.add_attribute(cell, 'text', 3)
1102
 
        self._tvcolumn_size.pack_start(cell, True)
1103
 
        self._tvcolumn_size.add_attribute(cell, 'text', 6)
1104
 
        self._tvcolumn_mtime.pack_start(cell, True)
1105
 
        self._tvcolumn_mtime.add_attribute(cell, 'text', 8)
 
720
        tvcolumn_filename.pack_start(cellpb, False)
 
721
        tvcolumn_filename.pack_start(cell, True)
 
722
        tvcolumn_filename.set_attributes(cellpb, stock_id=0)
 
723
        tvcolumn_filename.add_attribute(cell, 'text', 2)
 
724
        tvcolumn_status.pack_start(cell, True)
 
725
        tvcolumn_status.add_attribute(cell, 'text', 3)
 
726
        tvcolumn_size.pack_start(cell, True)
 
727
        tvcolumn_size.add_attribute(cell, 'text', 6)
 
728
        tvcolumn_mtime.pack_start(cell, True)
 
729
        tvcolumn_mtime.add_attribute(cell, 'text', 8)
1106
730
        
1107
731
        # Set up the properties of the TreeView
1108
732
        self.treeview_right.set_headers_visible(True)
1109
733
        self.treeview_right.set_headers_clickable(True)
1110
734
        self.treeview_right.set_search_column(1)
1111
 
        self._tvcolumn_filename.set_resizable(True)
1112
 
        self._tvcolumn_status.set_resizable(True)
1113
 
        self._tvcolumn_size.set_resizable(True)
1114
 
        self._tvcolumn_mtime.set_resizable(True)
 
735
        tvcolumn_filename.set_resizable(True)
1115
736
        # Set up sorting
1116
737
        liststore.set_sort_func(13, self._sort_filelist_callback, None)
1117
738
        liststore.set_sort_column_id(13, gtk.SORT_ASCENDING)
1118
 
        self._tvcolumn_filename.set_sort_column_id(13)
1119
 
        self._tvcolumn_status.set_sort_column_id(3)
1120
 
        self._tvcolumn_size.set_sort_column_id(5)
1121
 
        self._tvcolumn_mtime.set_sort_column_id(7)
 
739
        tvcolumn_filename.set_sort_column_id(13)
 
740
        tvcolumn_status.set_sort_column_id(3)
 
741
        tvcolumn_size.set_sort_column_id(5)
 
742
        tvcolumn_mtime.set_sort_column_id(7)
1122
743
        
1123
744
        # Set sensitivity
1124
745
        self.set_sensitivity()
1125
746
        
1126
 
    def get_selected_fileid(self):
1127
 
        """ Get the file_id of the selected file. """
1128
 
        treeselection = self.treeview_right.get_selection()
1129
 
        (model, iter) = treeselection.get_selected()
1130
 
        
1131
 
        if iter is None:
1132
 
            return None
1133
 
        else:
1134
 
            return model.get_value(iter, 9)
1135
 
    
1136
747
    def get_selected_right(self):
1137
748
        """ Get the selected filename. """
1138
749
        treeselection = self.treeview_right.get_selection()
1163
774
    
1164
775
    def set_sensitivity(self):
1165
776
        """ Set menu and toolbar sensitivity. """
1166
 
        if not self.remote:
1167
 
            # We're local
1168
 
            self.menuitem_branch_init.set_sensitive(self.notbranch)
1169
 
            self.menuitem_branch_get.set_sensitive(self.notbranch)
1170
 
            self.menuitem_branch_checkout.set_sensitive(self.notbranch)
1171
 
            self.menuitem_branch_pull.set_sensitive(not self.notbranch)
1172
 
            self.menuitem_branch_push.set_sensitive(not self.notbranch)
1173
 
            self.menuitem_branch_update.set_sensitive(not self.notbranch)
1174
 
            self.menuitem_branch_revert.set_sensitive(not self.notbranch)
1175
 
            self.menuitem_branch_merge.set_sensitive(not self.notbranch)
1176
 
            self.menuitem_branch_commit.set_sensitive(not self.notbranch)
1177
 
            self.menuitem_branch_tags.set_sensitive(not self.notbranch)
1178
 
            self.menuitem_branch_status.set_sensitive(not self.notbranch)
1179
 
            self.menuitem_branch_missing.set_sensitive(not self.notbranch)
1180
 
            self.menuitem_branch_conflicts.set_sensitive(not self.notbranch)
1181
 
            self.menuitem_stats.set_sensitive(not self.notbranch)
1182
 
            self.menuitem_stats_diff.set_sensitive(not self.notbranch)
1183
 
            self.menuitem_add_files.set_sensitive(not self.notbranch)
1184
 
            self.menuitem_remove_files.set_sensitive(not self.notbranch)
1185
 
            self.menuitem_file_make_directory.set_sensitive(not self.notbranch)
1186
 
            self.menuitem_file_rename.set_sensitive(not self.notbranch)
1187
 
            self.menuitem_file_move.set_sensitive(not self.notbranch)
1188
 
            self.menuitem_file_annotate.set_sensitive(not self.notbranch)
1189
 
            #self.menutoolbutton_diff.set_sensitive(True)
1190
 
            self.toolbutton_diff.set_sensitive(not self.notbranch)
1191
 
            self.toolbutton_log.set_sensitive(not self.notbranch)
1192
 
            self.toolbutton_commit.set_sensitive(not self.notbranch)
1193
 
            self.toolbutton_pull.set_sensitive(not self.notbranch)
1194
 
            self.toolbutton_push.set_sensitive(not self.notbranch)
1195
 
            self.toolbutton_update.set_sensitive(not self.notbranch)
1196
 
        else:
1197
 
            # We're remote
1198
 
            self.menuitem_branch_init.set_sensitive(False)
1199
 
            self.menuitem_branch_get.set_sensitive(True)
1200
 
            self.menuitem_branch_checkout.set_sensitive(True)
1201
 
            self.menuitem_branch_pull.set_sensitive(False)
1202
 
            self.menuitem_branch_push.set_sensitive(False)
1203
 
            self.menuitem_branch_update.set_sensitive(False)
1204
 
            self.menuitem_branch_revert.set_sensitive(False)
1205
 
            self.menuitem_branch_merge.set_sensitive(False)
1206
 
            self.menuitem_branch_commit.set_sensitive(False)
1207
 
            self.menuitem_branch_tags.set_sensitive(True)
1208
 
            self.menuitem_branch_status.set_sensitive(False)
1209
 
            self.menuitem_branch_missing.set_sensitive(False)
1210
 
            self.menuitem_branch_conflicts.set_sensitive(False)
1211
 
            self.menuitem_stats.set_sensitive(True)
1212
 
            self.menuitem_stats_diff.set_sensitive(False)
1213
 
            self.menuitem_add_files.set_sensitive(False)
1214
 
            self.menuitem_remove_files.set_sensitive(False)
1215
 
            self.menuitem_file_make_directory.set_sensitive(False)
1216
 
            self.menuitem_file_rename.set_sensitive(False)
1217
 
            self.menuitem_file_move.set_sensitive(False)
1218
 
            self.menuitem_file_annotate.set_sensitive(False)
1219
 
            #self.menutoolbutton_diff.set_sensitive(True)
1220
 
            self.toolbutton_diff.set_sensitive(False)
1221
 
            self.toolbutton_log.set_sensitive(True)
1222
 
            self.toolbutton_commit.set_sensitive(False)
1223
 
            self.toolbutton_pull.set_sensitive(False)
1224
 
            self.toolbutton_push.set_sensitive(False)
1225
 
            self.toolbutton_update.set_sensitive(False)
 
777
        self.menuitem_branch_init.set_sensitive(self.notbranch)
 
778
        self.menuitem_branch_get.set_sensitive(self.notbranch)
 
779
        self.menuitem_branch_checkout.set_sensitive(self.notbranch)
 
780
        self.menuitem_branch_pull.set_sensitive(not self.notbranch)
 
781
        self.menuitem_branch_push.set_sensitive(not self.notbranch)
 
782
        self.menuitem_branch_revert.set_sensitive(not self.notbranch)
 
783
        self.menuitem_branch_merge.set_sensitive(not self.notbranch)
 
784
        self.menuitem_branch_commit.set_sensitive(not self.notbranch)
 
785
        self.menuitem_branch_tags.set_sensitive(not self.notbranch)
 
786
        self.menuitem_branch_status.set_sensitive(not self.notbranch)
 
787
        self.menuitem_branch_missing.set_sensitive(not self.notbranch)
 
788
        self.menuitem_branch_conflicts.set_sensitive(not self.notbranch)
 
789
        self.menuitem_stats.set_sensitive(not self.notbranch)
 
790
        self.menuitem_add_files.set_sensitive(not self.notbranch)
 
791
        self.menuitem_remove_files.set_sensitive(not self.notbranch)
 
792
        self.menuitem_file_make_directory.set_sensitive(not self.notbranch)
 
793
        self.menuitem_file_rename.set_sensitive(not self.notbranch)
 
794
        self.menuitem_file_move.set_sensitive(not self.notbranch)
 
795
        self.menuitem_file_annotate.set_sensitive(not self.notbranch)
 
796
        #self.menutoolbutton_diff.set_sensitive(True)
 
797
        self.toolbutton_diff.set_sensitive(not self.notbranch)
 
798
        self.toolbutton_log.set_sensitive(not self.notbranch)
 
799
        self.toolbutton_commit.set_sensitive(not self.notbranch)
 
800
        self.toolbutton_pull.set_sensitive(not self.notbranch)
 
801
        self.toolbutton_push.set_sensitive(not self.notbranch)
1226
802
    
1227
803
    def refresh_left(self):
1228
804
        """ Refresh the bookmark list. """
1238
814
        bookmarks = self.pref.get_bookmarks()
1239
815
 
1240
816
        # Add them to the TreeStore
1241
 
        titer = treestore.append(None, [_i18n('Bookmarks'), None])
 
817
        titer = treestore.append(None, [_('Bookmarks'), None])
1242
818
        for item in bookmarks:
1243
819
            title = self.pref.get_bookmark_title(item)
1244
820
            treestore.append(titer, [title, item])
1251
827
 
1252
828
    def refresh_right(self, path=None):
1253
829
        """ Refresh the file list. """
1254
 
        if not self.remote:
1255
 
            # We're local
1256
 
            from bzrlib.workingtree import WorkingTree
1257
 
    
1258
 
            if path is None:
1259
 
                path = self.get_path()
1260
 
    
1261
 
            # A workaround for double-clicking Bookmarks
1262
 
            if not os.path.exists(path):
1263
 
                return
1264
 
    
1265
 
            # Get ListStore and clear it
1266
 
            liststore = self.treeview_right.get_model()
1267
 
            liststore.clear()
1268
 
            
1269
 
            # Show Status column
1270
 
            self._tvcolumn_status.set_visible(True)
1271
 
    
1272
 
            dirs = []
1273
 
            files = []
1274
 
    
1275
 
            # Fill the appropriate lists
1276
 
            dotted_files = self.pref.get_preference('dotted_files', 'bool')
1277
 
            ignored_files = self.pref.get_preference('ignored_files', 'bool')
1278
 
 
1279
 
            for item in os.listdir(path):
1280
 
                if not dotted_files and item[0] == '.':
1281
 
                    continue
1282
 
                if os.path.isdir(path + os.sep + item):
1283
 
                    dirs.append(item)
1284
 
                else:
1285
 
                    files.append(item)
1286
 
            
1287
 
            # Try to open the working tree
1288
 
            notbranch = False
1289
 
            try:
1290
 
                tree1 = WorkingTree.open_containing(path)[0]
1291
 
            except (bzrerrors.NotBranchError, bzrerrors.NoWorkingTree):
1292
 
                notbranch = True
1293
 
            
 
830
        from bzrlib.workingtree import WorkingTree
 
831
 
 
832
        if path is None:
 
833
            path = self.get_path()
 
834
 
 
835
        # A workaround for double-clicking Bookmarks
 
836
        if not os.path.exists(path):
 
837
            return
 
838
 
 
839
        # Get ListStore and clear it
 
840
        liststore = self.treeview_right.get_model()
 
841
        liststore.clear()
 
842
 
 
843
        dirs = []
 
844
        files = []
 
845
 
 
846
        # Fill the appropriate lists
 
847
        dotted_files = self.pref.get_preference('dotted_files', 'bool')
 
848
        for item in os.listdir(path):
 
849
            if not dotted_files and item[0] == '.':
 
850
                continue
 
851
            if os.path.isdir(path + os.sep + item):
 
852
                dirs.append(item)
 
853
            else:
 
854
                files.append(item)
 
855
        
 
856
        # Try to open the working tree
 
857
        notbranch = False
 
858
        try:
 
859
            tree1 = WorkingTree.open_containing(path)[0]
 
860
        except (bzrerrors.NotBranchError, bzrerrors.NoWorkingTree):
 
861
            notbranch = True
 
862
        
 
863
        if not notbranch:
 
864
            branch = tree1.branch
 
865
            tree2 = tree1.branch.repository.revision_tree(branch.last_revision())
 
866
        
 
867
            delta = tree1.changes_from(tree2, want_unchanged=True)
 
868
            
 
869
        # Add'em to the ListStore
 
870
        for item in dirs:
 
871
            statinfo = os.stat(self.path + os.sep + item)
 
872
            liststore.append([gtk.STOCK_DIRECTORY, True, item, '', '', statinfo.st_size, self._format_size(statinfo.st_size), statinfo.st_mtime, self._format_date(statinfo.st_mtime)])
 
873
        for item in files:
 
874
            status = 'unknown'
1294
875
            if not notbranch:
1295
 
                branch = tree1.branch
1296
 
                tree2 = tree1.branch.repository.revision_tree(branch.last_revision())
1297
 
            
1298
 
                delta = tree1.changes_from(tree2, want_unchanged=True)
 
876
                filename = tree1.relpath(path + os.sep + item)
1299
877
                
1300
 
            # Add'em to the ListStore
1301
 
            for item in dirs:
1302
878
                try:
1303
 
                    statinfo = os.stat(self.path + os.sep + item)
1304
 
                except OSError, e:
1305
 
                    if e.errno == 40:
1306
 
                        continue
1307
 
                    else:
1308
 
                        raise
1309
 
                liststore.append([gtk.STOCK_DIRECTORY,
1310
 
                                  True,
1311
 
                                  item,
1312
 
                                  '',
1313
 
                                  '',
1314
 
                                  "<DIR>",
1315
 
                                  "<DIR>",
1316
 
                                  statinfo.st_mtime,
1317
 
                                  self._format_date(statinfo.st_mtime),
1318
 
                                  ''])
1319
 
            for item in files:
1320
 
                status = 'unknown'
1321
 
                fileid = ''
1322
 
                if not notbranch:
1323
 
                    filename = tree1.relpath(path + os.sep + item)
 
879
                    self.wt.lock_read()
1324
880
                    
1325
 
                    try:
1326
 
                        self.wt.lock_read()
1327
 
                        
1328
 
                        for rpath, rpathnew, id, kind, text_modified, meta_modified in delta.renamed:
1329
 
                            if rpathnew == filename:
1330
 
                                status = 'renamed'
1331
 
                                fileid = id
1332
 
                        for rpath, id, kind in delta.added:
1333
 
                            if rpath == filename:
1334
 
                                status = 'added'
1335
 
                                fileid = id
1336
 
                        for rpath, id, kind in delta.removed:
1337
 
                            if rpath == filename:
1338
 
                                status = 'removed'
1339
 
                                fileid = id
1340
 
                        for rpath, id, kind, text_modified, meta_modified in delta.modified:
1341
 
                            if rpath == filename:
1342
 
                                status = 'modified'
1343
 
                                fileid = id
1344
 
                        for rpath, id, kind in delta.unchanged:
1345
 
                            if rpath == filename:
1346
 
                                status = 'unchanged'
1347
 
                                fileid = id
1348
 
                        for rpath, file_class, kind, id, entry in self.wt.list_files():
1349
 
                            if rpath == filename and file_class == 'I':
1350
 
                                status = 'ignored'
1351
 
                    finally:
1352
 
                        self.wt.unlock()
1353
 
                
1354
 
                if status == 'renamed':
1355
 
                    st = _i18n('renamed')
1356
 
                elif status == 'removed':
1357
 
                    st = _i18n('removed')
1358
 
                elif status == 'added':
1359
 
                    st = _i18n('added')
1360
 
                elif status == 'modified':
1361
 
                    st = _i18n('modified')
1362
 
                elif status == 'unchanged':
1363
 
                    st = _i18n('unchanged')
1364
 
                elif status == 'ignored':
1365
 
                    st = _i18n('ignored')
1366
 
                    if not ignored_files:
1367
 
                        continue
1368
 
                else:
1369
 
                    st = _i18n('unknown')
1370
 
                
1371
 
                try:
1372
 
                    statinfo = os.stat(self.path + os.sep + item)
1373
 
                except OSError, e:
1374
 
                    if e.errno == 40:
1375
 
                        continue
1376
 
                    else:
1377
 
                        raise
1378
 
                liststore.append([gtk.STOCK_FILE,
1379
 
                                  False,
1380
 
                                  item,
1381
 
                                  st,
1382
 
                                  status,
1383
 
                                  str(statinfo.st_size),
1384
 
                                  self._format_size(statinfo.st_size),
1385
 
                                  statinfo.st_mtime,
1386
 
                                  self._format_date(statinfo.st_mtime),
1387
 
                                  fileid])
1388
 
        else:
1389
 
            # We're remote
1390
 
            
1391
 
            # Get ListStore and clear it
1392
 
            liststore = self.treeview_right.get_model()
1393
 
            liststore.clear()
1394
 
            
1395
 
            # Hide Status column
1396
 
            self._tvcolumn_status.set_visible(False)
1397
 
            
1398
 
            dirs = []
1399
 
            files = []
1400
 
            
1401
 
            self._show_stock_image(gtk.STOCK_REFRESH)
1402
 
            
1403
 
            for (name, type) in self.remote_entries:
1404
 
                if type.kind == 'directory':
1405
 
                    dirs.append(type)
1406
 
                elif type.kind == 'file':
1407
 
                    files.append(type)
1408
 
            
1409
 
            class HistoryCache:
1410
 
                """ Cache based on revision history. """
1411
 
                def __init__(self, history):
1412
 
                    self._history = history
1413
 
                
1414
 
                def _lookup_revision(self, revid):
1415
 
                    for r in self._history:
1416
 
                        if r.revision_id == revid:
1417
 
                            return r
1418
 
                    rev = repo.get_revision(revid)
1419
 
                    self._history.append(rev)
1420
 
                    return rev
1421
 
            
1422
 
            repo = self.remote_branch.repository
1423
 
            
1424
 
            revhistory = self.remote_branch.revision_history()
1425
 
            try:
1426
 
                revs = repo.get_revisions(revhistory)
1427
 
                cache = HistoryCache(revs)
1428
 
            except bzrerrors.InvalidHttpResponse:
1429
 
                # Fallback to dummy algorithm, because of LP: #115209
1430
 
                cache = HistoryCache([])
1431
 
            
1432
 
            for item in dirs:
1433
 
                if item.parent_id == self.remote_parent:
1434
 
                    rev = cache._lookup_revision(item.revision)
1435
 
                    liststore.append([ gtk.STOCK_DIRECTORY,
1436
 
                                       True,
1437
 
                                       item.name,
1438
 
                                       '',
1439
 
                                       '',
1440
 
                                       "<DIR>",
1441
 
                                       "<DIR>",
1442
 
                                       rev.timestamp,
1443
 
                                       self._format_date(rev.timestamp),
1444
 
                                       ''
1445
 
                                   ])
1446
 
                while gtk.events_pending():
1447
 
                    gtk.main_iteration()
1448
 
            
1449
 
            for item in files:
1450
 
                if item.parent_id == self.remote_parent:
1451
 
                    rev = cache._lookup_revision(item.revision)
1452
 
                    liststore.append([ gtk.STOCK_FILE,
1453
 
                                       False,
1454
 
                                       item.name,
1455
 
                                       '',
1456
 
                                       '',
1457
 
                                       str(item.text_size),
1458
 
                                       self._format_size(item.text_size),
1459
 
                                       rev.timestamp,
1460
 
                                       self._format_date(rev.timestamp),
1461
 
                                       item.file_id
1462
 
                                   ])
1463
 
                while gtk.events_pending():
1464
 
                    gtk.main_iteration()
1465
 
            
1466
 
            self.image_location_error.destroy()
1467
 
 
1468
 
        # Columns should auto-size
 
881
                    for rpath, rpathnew, id, kind, text_modified, meta_modified in delta.renamed:
 
882
                        if rpathnew == filename:
 
883
                            status = 'renamed'
 
884
                    for rpath, id, kind in delta.added:
 
885
                        if rpath == filename:
 
886
                            status = 'added'                
 
887
                    for rpath, id, kind in delta.removed:
 
888
                        if rpath == filename:
 
889
                            status = 'removed'
 
890
                    for rpath, id, kind, text_modified, meta_modified in delta.modified:
 
891
                        if rpath == filename:
 
892
                            status = 'modified'
 
893
                    for rpath, id, kind in delta.unchanged:
 
894
                        if rpath == filename:
 
895
                            status = 'unchanged'
 
896
                    for rpath, file_class, kind, id, entry in self.wt.list_files():
 
897
                        if rpath == filename and file_class == 'I':
 
898
                            status = 'ignored'
 
899
                finally:
 
900
                    self.wt.unlock()
 
901
            
 
902
            #try:
 
903
            #    status = fileops.status(path + os.sep + item)
 
904
            #except errors.PermissionDenied:
 
905
            #    continue
 
906
 
 
907
            if status == 'renamed':
 
908
                st = _('renamed')
 
909
            elif status == 'removed':
 
910
                st = _('removed')
 
911
            elif status == 'added':
 
912
                st = _('added')
 
913
            elif status == 'modified':
 
914
                st = _('modified')
 
915
            elif status == 'unchanged':
 
916
                st = _('unchanged')
 
917
            elif status == 'ignored':
 
918
                st = _('ignored')
 
919
            else:
 
920
                st = _('unknown')
 
921
            
 
922
            statinfo = os.stat(self.path + os.sep + item)
 
923
            liststore.append([gtk.STOCK_FILE, False, item, st, status, statinfo.st_size, self._format_size(statinfo.st_size), statinfo.st_mtime, self._format_date(statinfo.st_mtime)])
 
924
 
 
925
        # Add the ListStore to the TreeView
 
926
        self.treeview_right.set_model(liststore)
1469
927
        self.treeview_right.columns_autosize()
1470
928
        
1471
929
        # Set sensitivity
1556
1014
    
1557
1015
    def _format_size(self, size):
1558
1016
        """ Format size to a human readable format. """
1559
 
        if size < 1000:
1560
 
            return "%d[B]" % (size,)
1561
 
        size = size / 1000.0
1562
 
        
1563
 
        for metric in ["kB","MB","GB","TB"]:
1564
 
            if size < 1000:
1565
 
                break
1566
 
            size = size / 1000.0
1567
 
        return "%.1f[%s]" % (size,metric) 
 
1017
        return size
1568
1018
    
1569
1019
    def _format_date(self, timestamp):
1570
1020
        """ Format the time (given in secs) to a human readable format. """
1571
1021
        return time.ctime(timestamp)
1572
 
    
1573
 
    def _is_remote_dir(self, location):
1574
 
        """ Determine whether the given location is a directory or not. """
1575
 
        if not self.remote:
1576
 
            # We're in local mode
1577
 
            return False
1578
 
        else:
1579
 
            branch, path = Branch.open_containing(location)
1580
 
            for (name, type) in self.remote_entries:
1581
 
                if name == path and type.kind == 'directory':
1582
 
                    # We got it
1583
 
                    return True
1584
 
            # Either it's not a directory or not in the inventory
1585
 
            return False
1586
 
    
1587
 
    def _show_stock_image(self, stock_id):
1588
 
        """ Show a stock image next to the location entry. """
1589
 
        self.image_location_error.destroy()
1590
 
        self.image_location_error = gtk.image_new_from_stock(stock_id, gtk.ICON_SIZE_BUTTON)
1591
 
        self.hbox_location.pack_start(self.image_location_error, False, False, 0)
1592
 
        if sys.platform == 'win32':
1593
 
            self.hbox_location.reorder_child(self.image_location_error, 2)
1594
 
        else:
1595
 
            self.hbox_location.reorder_child(self.image_location_error, 1)
1596
 
        self.image_location_error.show()
1597
 
        while gtk.events_pending():
1598
 
            gtk.main_iteration()
1599
1022
 
1600
1023
import ConfigParser
1601
1024
 
1606
1029
        # Some default options
1607
1030
        self.defaults = { 'strict_commit' : False,
1608
1031
                          'dotted_files'  : False,
1609
 
                          'ignored_files' : True,
1610
1032
                          'window_width'  : 700,
1611
1033
                          'window_height' : 400,
1612
1034
                          'window_x'      : 40,