/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-06-10 15:50:23 UTC
  • mfrom: (195.1.26 browse-remote-branches)
  • Revision ID: szilveszter.farkas@gmail.com-20070610155023-o3moy5a3wrp9o412
Merge browse-remote-branches branch (experimental).

Show diffs side-by-side

added added

removed removed

Lines of Context:
36
36
from bzrlib.branch import Branch
37
37
import bzrlib.errors as bzrerrors
38
38
from bzrlib.lazy_import import lazy_import
 
39
from bzrlib.ui import ui_factory
39
40
from bzrlib.workingtree import WorkingTree
40
41
 
41
42
from bzrlib.plugins.gtk.dialog import error_dialog, info_dialog, warning_dialog
52
53
from bzrlib.plugins.gtk.conflicts import ConflictsDialog
53
54
from bzrlib.plugins.gtk.initialize import InitDialog
54
55
from bzrlib.plugins.gtk.push import PushDialog
 
56
from bzrlib.plugins.gtk.revbrowser import RevisionBrowser
55
57
 
56
58
class OliveGtk:
57
59
    """ The main Olive GTK frontend class. This is called when launching the
116
118
        self.entry_location = self.toplevel.get_widget('entry_location')
117
119
        self.image_location_error = self.toplevel.get_widget('image_location_error')
118
120
        
 
121
        # Get the History widgets
 
122
        self.check_history = self.toplevel.get_widget('checkbutton_history')
 
123
        self.entry_history = self.toplevel.get_widget('entry_history_revno')
 
124
        self.button_history = self.toplevel.get_widget('button_history_browse')
 
125
        
119
126
        self.vbox_main_right = self.toplevel.get_widget('vbox_main_right')
120
127
        
121
128
        # Dictionary for signal_autoconnect
159
166
                "on_treeview_left_row_activated": self.on_treeview_left_row_activated,
160
167
                "on_button_location_up_clicked": self.on_button_location_up_clicked,
161
168
                "on_button_location_jump_clicked": self.on_button_location_jump_clicked,
162
 
                "on_entry_location_key_press_event": self.on_entry_location_key_press_event
 
169
                "on_entry_location_key_press_event": self.on_entry_location_key_press_event,
 
170
                "on_checkbutton_history_toggled": self.on_checkbutton_history_toggled,
 
171
                "on_entry_history_revno_key_press_event": self.on_entry_history_revno_key_press_event,
 
172
                "on_button_history_browse_clicked": self.on_button_history_browse_clicked
163
173
            }
164
174
        
165
175
        # Connect the signals to the handlers
197
207
        # Apply menu state
198
208
        self.menuitem_view_show_hidden_files.set_active(self.pref.get_preference('dotted_files', 'bool'))
199
209
 
 
210
        # We're starting local
 
211
        self.remote = False
 
212
        self.remote_branch = None
 
213
        self.remote_path = None
 
214
        self.remote_revision = None
 
215
        
200
216
        self.set_path(os.getcwd())
201
217
        self._load_right()
202
218
        
203
219
        self._just_started = False
204
220
 
205
 
    def set_path(self, path):
206
 
        self.path = path
 
221
    def set_path(self, path, force_remote=False):
207
222
        self.notbranch = False
208
223
        
209
 
        try:
210
 
            self.wt, self.wtpath = WorkingTree.open_containing(self.path)
211
 
        except (bzrerrors.NotBranchError, bzrerrors.NoWorkingTree):
212
 
            self.notbranch = True
 
224
        if force_remote:
 
225
            # Forcing remote mode (reading data from inventory)
 
226
            self._show_stock_image(gtk.STOCK_DISCONNECT)
 
227
            try:
 
228
                br = Branch.open_containing(path)[0]
 
229
            except bzrerrors.NotBranchError:
 
230
                self._show_stock_image(gtk.STOCK_DIALOG_ERROR)
 
231
                self.check_history.set_active(False)
 
232
                self.check_history.set_sensitive(False)
 
233
                return False
 
234
            except bzrerrors.UnsupportedProtocol:
 
235
                self._show_stock_image(gtk.STOCK_DIALOG_ERROR)
 
236
                self.check_history.set_active(False)
 
237
                self.check_history.set_sensitive(False)
 
238
                return False
 
239
            
 
240
            self._show_stock_image(gtk.STOCK_CONNECT)
 
241
            
 
242
            self.remote = True
 
243
           
 
244
            # We're remote
 
245
            self.remote_branch, self.remote_path = Branch.open_containing(path)
 
246
            
 
247
            if self.remote_revision is None:
 
248
                self.remote_revision = self.remote_branch.last_revision()
 
249
            
 
250
            self.remote_entries = self.remote_branch.repository.get_inventory(self.remote_revision).entries()
 
251
            
 
252
            if len(self.remote_path) == 0:
 
253
                self.remote_parent = self.remote_branch.repository.get_inventory(self.remote_branch.last_revision()).iter_entries_by_dir().next()[1].file_id
 
254
            else:
 
255
                for (name, type) in self.remote_entries:
 
256
                    if name == self.remote_path:
 
257
                        self.remote_parent = type.file_id
 
258
                        break
 
259
            
 
260
            if not path.endswith('/'):
 
261
                path += '/'
 
262
            
 
263
            if self.remote_branch.base == path:
 
264
                self.button_location_up.set_sensitive(False)
 
265
            else:
 
266
                self.button_location_up.set_sensitive(True)
 
267
        else:
 
268
            if os.path.isdir(path):
 
269
                self.image_location_error.destroy()
 
270
                self.remote = False
 
271
                
 
272
                # We're local
 
273
                try:
 
274
                    self.wt, self.wtpath = WorkingTree.open_containing(path)
 
275
                except (bzrerrors.NotBranchError, bzrerrors.NoWorkingTree):
 
276
                    self.notbranch = True
 
277
                
 
278
                # If we're in the root, we cannot go up anymore
 
279
                if sys.platform == 'win32':
 
280
                    drive, tail = os.path.splitdrive(path)
 
281
                    if tail in ('', '/', '\\'):
 
282
                        self.button_location_up.set_sensitive(False)
 
283
                    else:
 
284
                        self.button_location_up.set_sensitive(True)
 
285
                else:
 
286
                    if self.path == '/':
 
287
                        self.button_location_up.set_sensitive(False)
 
288
                    else:
 
289
                        self.button_location_up.set_sensitive(True)
 
290
            elif not os.path.isfile(path):
 
291
                # Doesn't seem to be a file nor a directory, trying to open a
 
292
                # remote location
 
293
                self._show_stock_image(gtk.STOCK_DISCONNECT)
 
294
                try:
 
295
                    br = Branch.open_containing(path)[0]
 
296
                except bzrerrors.NotBranchError:
 
297
                    self._show_stock_image(gtk.STOCK_DIALOG_ERROR)
 
298
                    self.check_history.set_active(False)
 
299
                    self.check_history.set_sensitive(False)
 
300
                    return False
 
301
                except bzrerrors.UnsupportedProtocol:
 
302
                    self._show_stock_image(gtk.STOCK_DIALOG_ERROR)
 
303
                    self.check_history.set_active(False)
 
304
                    self.check_history.set_sensitive(False)
 
305
                    return False
 
306
                
 
307
                self._show_stock_image(gtk.STOCK_CONNECT)
 
308
                
 
309
                self.remote = True
 
310
               
 
311
                # We're remote
 
312
                self.remote_branch, self.remote_path = Branch.open_containing(path)
 
313
                
 
314
                if self.remote_revision is None:
 
315
                    self.remote_revision = self.remote_branch.last_revision()
 
316
                
 
317
                self.remote_entries = self.remote_branch.repository.get_inventory(self.remote_revision).entries()
 
318
                
 
319
                if len(self.remote_path) == 0:
 
320
                    self.remote_parent = self.remote_branch.repository.get_inventory(self.remote_branch.last_revision()).iter_entries_by_dir().next()[1].file_id
 
321
                else:
 
322
                    for (name, type) in self.remote_entries:
 
323
                        if name == self.remote_path:
 
324
                            self.remote_parent = type.file_id
 
325
                            break
 
326
                
 
327
                if not path.endswith('/'):
 
328
                    path += '/'
 
329
                
 
330
                if self.remote_branch.base == path:
 
331
                    self.button_location_up.set_sensitive(False)
 
332
                else:
 
333
                    self.button_location_up.set_sensitive(True)
 
334
        
 
335
        if self.notbranch:
 
336
            self.check_history.set_active(False)
 
337
            self.check_history.set_sensitive(False)
 
338
        else:
 
339
            self.check_history.set_sensitive(True)
213
340
        
214
341
        self.statusbar.push(self.context_id, path)
215
342
        self.entry_location.set_text(path)
216
 
        
217
 
        # If we're in the root, we cannot go up anymore
218
 
        if sys.platform == 'win32':
219
 
            drive, tail = os.path.splitdrive(self.path)
220
 
            if tail in ('', '/', '\\'):
221
 
                self.button_location_up.set_sensitive(False)
222
 
            else:
223
 
                self.button_location_up.set_sensitive(True)
224
 
        else:
225
 
            if self.path == '/':
226
 
                self.button_location_up.set_sensitive(False)
227
 
            else:
228
 
                self.button_location_up.set_sensitive(True)
 
343
        self.path = path
 
344
        return True
229
345
 
230
346
    def get_path(self):
231
 
        return self.path
 
347
        if not self.remote:
 
348
            return self.path
 
349
        else:
 
350
            # Remote mode
 
351
            if len(self.remote_path) > 0:
 
352
                return self.remote_branch.base + self.remote_path + '/'
 
353
            else:
 
354
                return self.remote_branch.base
232
355
   
233
356
    def on_about_activate(self, widget):
234
357
        from bzrlib.plugins.gtk.dialog import about
235
358
        about()
236
359
        
237
 
    def on_button_location_up_clicked(self, widget):
238
 
        """ Location Up button handler. """
239
 
        self.set_path(os.path.split(self.get_path())[0])
240
 
        self.refresh_right()
 
360
    
 
361
    def on_button_history_browse_clicked(self, widget):
 
362
        """ Browse for revision button handler. """
 
363
        if self.remote:
 
364
            br = self.remote_branch
 
365
        else:
 
366
            br = self.wt.branch
 
367
            
 
368
        revb = RevisionBrowser(br, self.window)
 
369
        response = revb.run()
 
370
        if response != gtk.RESPONSE_NONE:
 
371
            revb.hide()
 
372
        
 
373
            if response == gtk.RESPONSE_OK:
 
374
                if revb.selected_revno is not None:
 
375
                    self.entry_history.set_text(revb.selected_revno)
 
376
            
 
377
            revb.destroy()
241
378
    
242
379
    def on_button_location_jump_clicked(self, widget):
243
380
        """ Location Jump button handler. """
244
381
        location = self.entry_location.get_text()
245
 
        if os.path.isdir(location):
246
 
            self.set_path(location)
 
382
        
 
383
        if self.set_path(location):
247
384
            self.refresh_right()
248
 
            self.image_location_error.hide()
249
 
        else:
250
 
            self.image_location_error.show()
 
385
    
 
386
    def on_button_location_up_clicked(self, widget):
 
387
        """ Location Up button handler. """
 
388
        if not self.remote:
 
389
            # Local mode
 
390
            self.set_path(os.path.split(self.get_path())[0])
 
391
        else:
 
392
            # Remote mode
 
393
            delim = '/'
 
394
            newpath = delim.join(self.get_path().split(delim)[:-2])
 
395
            newpath += '/'
 
396
            self.set_path(newpath)
 
397
 
 
398
        self.refresh_right()
 
399
    
 
400
    def on_checkbutton_history_toggled(self, widget):
 
401
        """ History Mode toggle handler. """
 
402
        if self.check_history.get_active():
 
403
            # History Mode activated
 
404
            self.entry_history.set_sensitive(True)
 
405
            self.button_history.set_sensitive(True)
 
406
        else:
 
407
            # History Mode deactivated
 
408
            self.entry_history.set_sensitive(False)
 
409
            self.button_history.set_sensitive(False)
 
410
    
 
411
    @show_bzr_error
 
412
    def on_entry_history_revno_key_press_event(self, widget, event):
 
413
        """ Key pressed handler for the history entry. """
 
414
        if event.keyval == 65293:
 
415
            # Return was hit, so we have to load that specific revision
 
416
            # Emulate being remote, so inventory should be used
 
417
            path = self.get_path()
 
418
            if not self.remote:
 
419
                self.remote = True
 
420
                self.remote_branch = self.wt.branch
 
421
            
 
422
            revno = int(self.entry_history.get_text())
 
423
            self.remote_revision = self.remote_branch.get_rev_id(revno)
 
424
            if self.set_path(path, True):
 
425
                self.refresh_right()
251
426
    
252
427
    def on_entry_location_key_press_event(self, widget, event):
253
428
        """ Key pressed handler for the location entry. """
264
439
    def on_menuitem_branch_get_activate(self, widget):
265
440
        """ Branch/Get... menu handler. """
266
441
        from bzrlib.plugins.gtk.branch import BranchDialog
267
 
        branch = BranchDialog(self.get_path(), self.window)
 
442
        
 
443
        if self.remote:
 
444
            branch = BranchDialog(os.getcwd(), self.window, self.remote_branch.base)
 
445
        else:
 
446
            branch = BranchDialog(self.get_path(), self.window)
268
447
        response = branch.run()
269
448
        if response != gtk.RESPONSE_NONE:
270
449
            branch.hide()
271
 
        
 
450
            
272
451
            if response == gtk.RESPONSE_OK:
273
452
                self.refresh_right()
274
453
            
277
456
    def on_menuitem_branch_checkout_activate(self, widget):
278
457
        """ Branch/Checkout... menu handler. """
279
458
        from bzrlib.plugins.gtk.checkout import CheckoutDialog
280
 
        checkout = CheckoutDialog(self.get_path(), self.window)
 
459
        
 
460
        if self.remote:
 
461
            checkout = CheckoutDialog(os.getcwd(), self.window, self.remote_branch.base)
 
462
        else:
 
463
            checkout = CheckoutDialog(self.get_path(), self.window)
281
464
        response = checkout.run()
282
465
        if response != gtk.RESPONSE_NONE:
283
466
            checkout.hide()
359
542
        if branch_to.get_parent() is None:
360
543
            branch_to.set_parent(branch_from.base)
361
544
 
362
 
        #old_rh = branch_to.revision_history()
363
 
        #if tree_to is not None:
364
 
        #    tree_to.pull(branch_from)
365
 
        #else:
366
 
        #    branch_to.pull(branch_from)
367
545
        ret = branch_to.pull(branch_from)
368
546
        
369
547
        info_dialog(_('Pull successful'), _('%d revision(s) pulled.') % ret)
410
588
    def on_menuitem_branch_tags_activate(self, widget):
411
589
        """ Branch/Tags... menu handler. """
412
590
        from bzrlib.plugins.gtk.tags import TagsWindow
413
 
        window = TagsWindow(self.wt.branch, self.window)
 
591
        if not self.remote:
 
592
            window = TagsWindow(self.wt.branch, self.window)
 
593
        else:
 
594
            window = TagsWindow(self.remote_branch, self.window)
414
595
        window.show()
415
596
    
416
597
    def on_menuitem_file_annotate_activate(self, widget):
478
659
    def on_menuitem_stats_infos_activate(self, widget):
479
660
        """ Statistics/Informations... menu handler. """
480
661
        from info import OliveInfo
481
 
        info = OliveInfo(self.wt)
 
662
        if self.remote:
 
663
            info = OliveInfo(self.remote_branch)
 
664
        else:
 
665
            info = OliveInfo(self.wt.branch)
482
666
        info.display()
483
667
    
484
668
    def on_menuitem_stats_log_activate(self, widget):
485
669
        """ Statistics/Log... menu handler. """
486
670
        window = branchwin.BranchWindow()
487
 
        window.set_branch(self.wt.branch, self.wt.branch.last_revision(), None)
 
671
        if not self.remote:
 
672
            window.set_branch(self.wt.branch, self.wt.branch.last_revision(), None)
 
673
        else:
 
674
            window.set_branch(self.remote_branch, self.remote_branch.last_revision(), None)
488
675
        window.show()
489
676
    
490
677
    def on_menuitem_view_refresh_activate(self, widget):
524
711
        if newdir == None:
525
712
            return
526
713
 
527
 
        self.set_path(newdir)
528
 
        self.refresh_right()
 
714
        if self.set_path(newdir):
 
715
            self.refresh_right()
529
716
 
530
717
    def on_treeview_right_button_press_event(self, widget, event):
531
718
        """ Occurs when somebody right-clicks in the file list. """
536
723
                             selected=self.get_selected_right(),
537
724
                             app=self)
538
725
            # get the menu items
 
726
            m_open = menu.ui.get_widget('/context_right/open')
539
727
            m_add = menu.ui.get_widget('/context_right/add')
540
728
            m_remove = menu.ui.get_widget('/context_right/remove')
541
729
            m_rename = menu.ui.get_widget('/context_right/rename')
542
730
            m_revert = menu.ui.get_widget('/context_right/revert')
543
731
            m_commit = menu.ui.get_widget('/context_right/commit')
 
732
            m_annotate = menu.ui.get_widget('/context_right/annotate')
544
733
            m_diff = menu.ui.get_widget('/context_right/diff')
545
734
            # check if we're in a branch
546
735
            try:
547
736
                from bzrlib.branch import Branch
548
737
                Branch.open_containing(self.get_path())
549
 
                m_add.set_sensitive(True)
550
 
                m_remove.set_sensitive(True)
551
 
                m_rename.set_sensitive(True)
552
 
                m_revert.set_sensitive(True)
553
 
                m_commit.set_sensitive(True)
554
 
                m_diff.set_sensitive(True)
 
738
                if self.remote:
 
739
                    m_open.set_sensitive(False)
 
740
                    m_add.set_sensitive(False)
 
741
                    m_remove.set_sensitive(False)
 
742
                    m_rename.set_sensitive(False)
 
743
                    m_revert.set_sensitive(False)
 
744
                    m_commit.set_sensitive(False)
 
745
                    m_annotate.set_sensitive(False)
 
746
                    m_diff.set_sensitive(False)
 
747
                else:
 
748
                    m_open.set_sensitive(True)
 
749
                    m_add.set_sensitive(True)
 
750
                    m_remove.set_sensitive(True)
 
751
                    m_rename.set_sensitive(True)
 
752
                    m_revert.set_sensitive(True)
 
753
                    m_commit.set_sensitive(True)
 
754
                    m_annotate.set_sensitive(True)
 
755
                    m_diff.set_sensitive(True)
555
756
            except bzrerrors.NotBranchError:
 
757
                m_open.set_sensitive(True)
556
758
                m_add.set_sensitive(False)
557
759
                m_remove.set_sensitive(False)
558
760
                m_rename.set_sensitive(False)
559
761
                m_revert.set_sensitive(False)
560
762
                m_commit.set_sensitive(False)
 
763
                m_annotate.set_sensitive(False)
561
764
                m_diff.set_sensitive(False)
562
765
 
563
 
            menu.right_context_menu().popup(None, None, None, 0,
564
 
                                            event.time)
 
766
            if not self.remote:
 
767
                menu.right_context_menu().popup(None, None, None, 0,
 
768
                                                event.time)
 
769
            else:
 
770
                menu.remote_context_menu().popup(None, None, None, 0,
 
771
                                                 event.time)
565
772
        
566
773
    def on_treeview_right_row_activated(self, treeview, path, view_column):
567
774
        """ Occurs when somebody double-clicks or enters an item in the
570
777
        
571
778
        newdir = self.get_selected_right()
572
779
        
573
 
        if newdir == '..':
574
 
            self.set_path(os.path.split(self.get_path())[0])
 
780
        if not self.remote:
 
781
            # We're local
 
782
            if newdir == '..':
 
783
                self.set_path(os.path.split(self.get_path())[0])
 
784
            else:
 
785
                fullpath = os.path.join(self.get_path(), newdir)
 
786
                if os.path.isdir(fullpath):
 
787
                    # selected item is an existant directory
 
788
                    self.set_path(fullpath)
 
789
                else:
 
790
                    launch(fullpath)
575
791
        else:
576
 
            fullpath = os.path.join(self.get_path(), newdir)
577
 
            if os.path.isdir(fullpath):
578
 
                # selected item is an existant directory
579
 
                self.set_path(fullpath)
580
 
            else:
581
 
                launch(fullpath) 
 
792
            # We're remote
 
793
            if self._is_remote_dir(self.get_path() + newdir):
 
794
                self.set_path(self.get_path() + newdir)
582
795
        
583
796
        self.refresh_right()
584
797
    
626
839
    def _load_right(self):
627
840
        """ Load data into the right panel. (Filelist) """
628
841
        # Create ListStore
629
 
        # Model: [icon, dir, name, status text, status, size (int), size (human), mtime (int), mtime (local)]
630
 
        liststore = gtk.ListStore(str, gobject.TYPE_BOOLEAN, str, str, str, gobject.TYPE_INT, gobject.TYPE_STRING, gobject.TYPE_INT, gobject.TYPE_STRING)
 
842
        # Model: [ icon, dir, name, status text, status, size (int), size (human), mtime (int), mtime (local), fileid]
 
843
        liststore = gtk.ListStore(gobject.TYPE_STRING,
 
844
                                  gobject.TYPE_BOOLEAN,
 
845
                                  gobject.TYPE_STRING,
 
846
                                  gobject.TYPE_STRING,
 
847
                                  gobject.TYPE_STRING,
 
848
                                  gobject.TYPE_INT,
 
849
                                  gobject.TYPE_STRING,
 
850
                                  gobject.TYPE_INT,
 
851
                                  gobject.TYPE_STRING,
 
852
                                  gobject.TYPE_STRING)
631
853
        
632
854
        dirs = []
633
855
        files = []
651
873
        # Add'em to the ListStore
652
874
        for item in dirs:
653
875
            statinfo = os.stat(self.path + os.sep + item)
654
 
            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)])
 
876
            liststore.append([ gtk.STOCK_DIRECTORY,
 
877
                               True,
 
878
                               item,
 
879
                               '',
 
880
                               '',
 
881
                               statinfo.st_size,
 
882
                               self._format_size(statinfo.st_size),
 
883
                               statinfo.st_mtime,
 
884
                               self._format_date(statinfo.st_mtime),
 
885
                               ''])
655
886
        for item in files:
656
887
            status = 'unknown'
 
888
            fileid = ''
657
889
            if not self.notbranch:
658
890
                filename = self.wt.relpath(self.path + os.sep + item)
659
891
                
663
895
                    for rpath, rpathnew, id, kind, text_modified, meta_modified in delta.renamed:
664
896
                        if rpathnew == filename:
665
897
                            status = 'renamed'
 
898
                            fileid = id
666
899
                    for rpath, id, kind in delta.added:
667
900
                        if rpath == filename:
668
901
                            status = 'added'
 
902
                            fileid = id
669
903
                    for rpath, id, kind in delta.removed:
670
904
                        if rpath == filename:
671
905
                            status = 'removed'
 
906
                            fileid = id
672
907
                    for rpath, id, kind, text_modified, meta_modified in delta.modified:
673
908
                        if rpath == filename:
674
909
                            status = 'modified'
 
910
                            fileid = id
675
911
                    for rpath, id, kind in delta.unchanged:
676
912
                        if rpath == filename:
677
913
                            status = 'unchanged'
 
914
                            fileid = id
678
915
                    for rpath, file_class, kind, id, entry in self.wt.list_files():
679
916
                        if rpath == filename and file_class == 'I':
680
917
                            status = 'ignored'
681
918
                finally:
682
919
                    self.wt.unlock()
683
920
            
684
 
            #try:
685
 
            #    status = fileops.status(path + os.sep + item)
686
 
            #except errors.PermissionDenied:
687
 
            #    continue
688
 
            
689
921
            if status == 'renamed':
690
922
                st = _('renamed')
691
923
            elif status == 'removed':
702
934
                st = _('unknown')
703
935
            
704
936
            statinfo = os.stat(self.path + os.sep + item)
705
 
            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)])
 
937
            liststore.append([gtk.STOCK_FILE,
 
938
                              False,
 
939
                              item,
 
940
                              st,
 
941
                              status,
 
942
                              statinfo.st_size,
 
943
                              self._format_size(statinfo.st_size),
 
944
                              statinfo.st_mtime,
 
945
                              self._format_date(statinfo.st_mtime),
 
946
                              fileid])
706
947
        
707
948
        # Create the columns and add them to the TreeView
708
949
        self.treeview_right.set_model(liststore)
709
 
        tvcolumn_filename = gtk.TreeViewColumn(_('Filename'))
710
 
        tvcolumn_status = gtk.TreeViewColumn(_('Status'))
711
 
        tvcolumn_size = gtk.TreeViewColumn(_('Size'))
712
 
        tvcolumn_mtime = gtk.TreeViewColumn(_('Last modified'))
713
 
        self.treeview_right.append_column(tvcolumn_filename)
714
 
        self.treeview_right.append_column(tvcolumn_status)
715
 
        self.treeview_right.append_column(tvcolumn_size)
716
 
        self.treeview_right.append_column(tvcolumn_mtime)
 
950
        self._tvcolumn_filename = gtk.TreeViewColumn(_('Filename'))
 
951
        self._tvcolumn_status = gtk.TreeViewColumn(_('Status'))
 
952
        self._tvcolumn_size = gtk.TreeViewColumn(_('Size'))
 
953
        self._tvcolumn_mtime = gtk.TreeViewColumn(_('Last modified'))
 
954
        self.treeview_right.append_column(self._tvcolumn_filename)
 
955
        self.treeview_right.append_column(self._tvcolumn_status)
 
956
        self.treeview_right.append_column(self._tvcolumn_size)
 
957
        self.treeview_right.append_column(self._tvcolumn_mtime)
717
958
        
718
959
        # Set up the cells
719
960
        cellpb = gtk.CellRendererPixbuf()
720
961
        cell = gtk.CellRendererText()
721
 
        tvcolumn_filename.pack_start(cellpb, False)
722
 
        tvcolumn_filename.pack_start(cell, True)
723
 
        tvcolumn_filename.set_attributes(cellpb, stock_id=0)
724
 
        tvcolumn_filename.add_attribute(cell, 'text', 2)
725
 
        tvcolumn_status.pack_start(cell, True)
726
 
        tvcolumn_status.add_attribute(cell, 'text', 3)
727
 
        tvcolumn_size.pack_start(cell, True)
728
 
        tvcolumn_size.add_attribute(cell, 'text', 6)
729
 
        tvcolumn_mtime.pack_start(cell, True)
730
 
        tvcolumn_mtime.add_attribute(cell, 'text', 8)
 
962
        self._tvcolumn_filename.pack_start(cellpb, False)
 
963
        self._tvcolumn_filename.pack_start(cell, True)
 
964
        self._tvcolumn_filename.set_attributes(cellpb, stock_id=0)
 
965
        self._tvcolumn_filename.add_attribute(cell, 'text', 2)
 
966
        self._tvcolumn_status.pack_start(cell, True)
 
967
        self._tvcolumn_status.add_attribute(cell, 'text', 3)
 
968
        self._tvcolumn_size.pack_start(cell, True)
 
969
        self._tvcolumn_size.add_attribute(cell, 'text', 6)
 
970
        self._tvcolumn_mtime.pack_start(cell, True)
 
971
        self._tvcolumn_mtime.add_attribute(cell, 'text', 8)
731
972
        
732
973
        # Set up the properties of the TreeView
733
974
        self.treeview_right.set_headers_visible(True)
734
975
        self.treeview_right.set_headers_clickable(True)
735
976
        self.treeview_right.set_search_column(1)
736
 
        tvcolumn_filename.set_resizable(True)
 
977
        self._tvcolumn_filename.set_resizable(True)
 
978
        self._tvcolumn_status.set_resizable(True)
 
979
        self._tvcolumn_size.set_resizable(True)
 
980
        self._tvcolumn_mtime.set_resizable(True)
737
981
        # Set up sorting
738
982
        liststore.set_sort_func(13, self._sort_filelist_callback, None)
739
983
        liststore.set_sort_column_id(13, gtk.SORT_ASCENDING)
740
 
        tvcolumn_filename.set_sort_column_id(13)
741
 
        tvcolumn_status.set_sort_column_id(3)
742
 
        tvcolumn_size.set_sort_column_id(5)
743
 
        tvcolumn_mtime.set_sort_column_id(7)
 
984
        self._tvcolumn_filename.set_sort_column_id(13)
 
985
        self._tvcolumn_status.set_sort_column_id(3)
 
986
        self._tvcolumn_size.set_sort_column_id(5)
 
987
        self._tvcolumn_mtime.set_sort_column_id(7)
744
988
        
745
989
        # Set sensitivity
746
990
        self.set_sensitivity()
747
991
        
 
992
    def get_selected_fileid(self):
 
993
        """ Get the file_id of the selected file. """
 
994
        treeselection = self.treeview_right.get_selection()
 
995
        (model, iter) = treeselection.get_selected()
 
996
        
 
997
        if iter is None:
 
998
            return None
 
999
        else:
 
1000
            return model.get_value(iter, 9)
 
1001
    
748
1002
    def get_selected_right(self):
749
1003
        """ Get the selected filename. """
750
1004
        treeselection = self.treeview_right.get_selection()
775
1029
    
776
1030
    def set_sensitivity(self):
777
1031
        """ Set menu and toolbar sensitivity. """
778
 
        self.menuitem_branch_init.set_sensitive(self.notbranch)
779
 
        self.menuitem_branch_get.set_sensitive(self.notbranch)
780
 
        self.menuitem_branch_checkout.set_sensitive(self.notbranch)
781
 
        self.menuitem_branch_pull.set_sensitive(not self.notbranch)
782
 
        self.menuitem_branch_push.set_sensitive(not self.notbranch)
783
 
        self.menuitem_branch_revert.set_sensitive(not self.notbranch)
784
 
        self.menuitem_branch_merge.set_sensitive(not self.notbranch)
785
 
        self.menuitem_branch_commit.set_sensitive(not self.notbranch)
786
 
        self.menuitem_branch_tags.set_sensitive(not self.notbranch)
787
 
        self.menuitem_branch_status.set_sensitive(not self.notbranch)
788
 
        self.menuitem_branch_missing.set_sensitive(not self.notbranch)
789
 
        self.menuitem_branch_conflicts.set_sensitive(not self.notbranch)
790
 
        self.menuitem_stats.set_sensitive(not self.notbranch)
791
 
        self.menuitem_add_files.set_sensitive(not self.notbranch)
792
 
        self.menuitem_remove_files.set_sensitive(not self.notbranch)
793
 
        self.menuitem_file_make_directory.set_sensitive(not self.notbranch)
794
 
        self.menuitem_file_rename.set_sensitive(not self.notbranch)
795
 
        self.menuitem_file_move.set_sensitive(not self.notbranch)
796
 
        self.menuitem_file_annotate.set_sensitive(not self.notbranch)
797
 
        #self.menutoolbutton_diff.set_sensitive(True)
798
 
        self.toolbutton_diff.set_sensitive(not self.notbranch)
799
 
        self.toolbutton_log.set_sensitive(not self.notbranch)
800
 
        self.toolbutton_commit.set_sensitive(not self.notbranch)
801
 
        self.toolbutton_pull.set_sensitive(not self.notbranch)
802
 
        self.toolbutton_push.set_sensitive(not self.notbranch)
 
1032
        if not self.remote:
 
1033
            # We're local
 
1034
            self.menuitem_branch_init.set_sensitive(self.notbranch)
 
1035
            self.menuitem_branch_get.set_sensitive(self.notbranch)
 
1036
            self.menuitem_branch_checkout.set_sensitive(self.notbranch)
 
1037
            self.menuitem_branch_pull.set_sensitive(not self.notbranch)
 
1038
            self.menuitem_branch_push.set_sensitive(not self.notbranch)
 
1039
            self.menuitem_branch_revert.set_sensitive(not self.notbranch)
 
1040
            self.menuitem_branch_merge.set_sensitive(not self.notbranch)
 
1041
            self.menuitem_branch_commit.set_sensitive(not self.notbranch)
 
1042
            self.menuitem_branch_tags.set_sensitive(not self.notbranch)
 
1043
            self.menuitem_branch_status.set_sensitive(not self.notbranch)
 
1044
            self.menuitem_branch_missing.set_sensitive(not self.notbranch)
 
1045
            self.menuitem_branch_conflicts.set_sensitive(not self.notbranch)
 
1046
            self.menuitem_stats.set_sensitive(not self.notbranch)
 
1047
            self.menuitem_stats_diff.set_sensitive(not self.notbranch)
 
1048
            self.menuitem_add_files.set_sensitive(not self.notbranch)
 
1049
            self.menuitem_remove_files.set_sensitive(not self.notbranch)
 
1050
            self.menuitem_file_make_directory.set_sensitive(not self.notbranch)
 
1051
            self.menuitem_file_rename.set_sensitive(not self.notbranch)
 
1052
            self.menuitem_file_move.set_sensitive(not self.notbranch)
 
1053
            self.menuitem_file_annotate.set_sensitive(not self.notbranch)
 
1054
            #self.menutoolbutton_diff.set_sensitive(True)
 
1055
            self.toolbutton_diff.set_sensitive(not self.notbranch)
 
1056
            self.toolbutton_log.set_sensitive(not self.notbranch)
 
1057
            self.toolbutton_commit.set_sensitive(not self.notbranch)
 
1058
            self.toolbutton_pull.set_sensitive(not self.notbranch)
 
1059
            self.toolbutton_push.set_sensitive(not self.notbranch)
 
1060
        else:
 
1061
            # We're remote
 
1062
            self.menuitem_branch_init.set_sensitive(False)
 
1063
            self.menuitem_branch_get.set_sensitive(True)
 
1064
            self.menuitem_branch_checkout.set_sensitive(True)
 
1065
            self.menuitem_branch_pull.set_sensitive(False)
 
1066
            self.menuitem_branch_push.set_sensitive(False)
 
1067
            self.menuitem_branch_revert.set_sensitive(False)
 
1068
            self.menuitem_branch_merge.set_sensitive(False)
 
1069
            self.menuitem_branch_commit.set_sensitive(False)
 
1070
            self.menuitem_branch_tags.set_sensitive(True)
 
1071
            self.menuitem_branch_status.set_sensitive(False)
 
1072
            self.menuitem_branch_missing.set_sensitive(False)
 
1073
            self.menuitem_branch_conflicts.set_sensitive(False)
 
1074
            self.menuitem_stats.set_sensitive(True)
 
1075
            self.menuitem_stats_diff.set_sensitive(False)
 
1076
            self.menuitem_add_files.set_sensitive(False)
 
1077
            self.menuitem_remove_files.set_sensitive(False)
 
1078
            self.menuitem_file_make_directory.set_sensitive(False)
 
1079
            self.menuitem_file_rename.set_sensitive(False)
 
1080
            self.menuitem_file_move.set_sensitive(False)
 
1081
            self.menuitem_file_annotate.set_sensitive(False)
 
1082
            #self.menutoolbutton_diff.set_sensitive(True)
 
1083
            self.toolbutton_diff.set_sensitive(False)
 
1084
            self.toolbutton_log.set_sensitive(True)
 
1085
            self.toolbutton_commit.set_sensitive(False)
 
1086
            self.toolbutton_pull.set_sensitive(False)
 
1087
            self.toolbutton_push.set_sensitive(False)
803
1088
    
804
1089
    def refresh_left(self):
805
1090
        """ Refresh the bookmark list. """
828
1113
 
829
1114
    def refresh_right(self, path=None):
830
1115
        """ Refresh the file list. """
831
 
        from bzrlib.workingtree import WorkingTree
832
 
 
833
 
        if path is None:
834
 
            path = self.get_path()
835
 
 
836
 
        # A workaround for double-clicking Bookmarks
837
 
        if not os.path.exists(path):
838
 
            return
839
 
 
840
 
        # Get ListStore and clear it
841
 
        liststore = self.treeview_right.get_model()
842
 
        liststore.clear()
843
 
 
844
 
        dirs = []
845
 
        files = []
846
 
 
847
 
        # Fill the appropriate lists
848
 
        dotted_files = self.pref.get_preference('dotted_files', 'bool')
849
 
        for item in os.listdir(path):
850
 
            if not dotted_files and item[0] == '.':
851
 
                continue
852
 
            if os.path.isdir(path + os.sep + item):
853
 
                dirs.append(item)
854
 
            else:
855
 
                files.append(item)
856
 
        
857
 
        # Try to open the working tree
858
 
        notbranch = False
859
 
        try:
860
 
            tree1 = WorkingTree.open_containing(path)[0]
861
 
        except (bzrerrors.NotBranchError, bzrerrors.NoWorkingTree):
862
 
            notbranch = True
863
 
        
864
 
        if not notbranch:
865
 
            branch = tree1.branch
866
 
            tree2 = tree1.branch.repository.revision_tree(branch.last_revision())
867
 
        
868
 
            delta = tree1.changes_from(tree2, want_unchanged=True)
869
 
            
870
 
        # Add'em to the ListStore
871
 
        for item in dirs:
872
 
            statinfo = os.stat(self.path + os.sep + item)
873
 
            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)])
874
 
        for item in files:
875
 
            status = 'unknown'
 
1116
        if not self.remote:
 
1117
            # We're local
 
1118
            from bzrlib.workingtree import WorkingTree
 
1119
    
 
1120
            if path is None:
 
1121
                path = self.get_path()
 
1122
    
 
1123
            # A workaround for double-clicking Bookmarks
 
1124
            if not os.path.exists(path):
 
1125
                return
 
1126
    
 
1127
            # Get ListStore and clear it
 
1128
            liststore = self.treeview_right.get_model()
 
1129
            liststore.clear()
 
1130
            
 
1131
            # Show Status column
 
1132
            self._tvcolumn_status.set_visible(True)
 
1133
    
 
1134
            dirs = []
 
1135
            files = []
 
1136
    
 
1137
            # Fill the appropriate lists
 
1138
            dotted_files = self.pref.get_preference('dotted_files', 'bool')
 
1139
            for item in os.listdir(path):
 
1140
                if not dotted_files and item[0] == '.':
 
1141
                    continue
 
1142
                if os.path.isdir(path + os.sep + item):
 
1143
                    dirs.append(item)
 
1144
                else:
 
1145
                    files.append(item)
 
1146
            
 
1147
            # Try to open the working tree
 
1148
            notbranch = False
 
1149
            try:
 
1150
                tree1 = WorkingTree.open_containing(path)[0]
 
1151
            except (bzrerrors.NotBranchError, bzrerrors.NoWorkingTree):
 
1152
                notbranch = True
 
1153
            
876
1154
            if not notbranch:
877
 
                filename = tree1.relpath(path + os.sep + item)
 
1155
                branch = tree1.branch
 
1156
                tree2 = tree1.branch.repository.revision_tree(branch.last_revision())
 
1157
            
 
1158
                delta = tree1.changes_from(tree2, want_unchanged=True)
878
1159
                
879
 
                try:
880
 
                    self.wt.lock_read()
 
1160
            # Add'em to the ListStore
 
1161
            for item in dirs:
 
1162
                statinfo = os.stat(self.path + os.sep + item)
 
1163
                liststore.append([gtk.STOCK_DIRECTORY,
 
1164
                                  True,
 
1165
                                  item,
 
1166
                                  '',
 
1167
                                  '',
 
1168
                                  statinfo.st_size,
 
1169
                                  self._format_size(statinfo.st_size),
 
1170
                                  statinfo.st_mtime,
 
1171
                                  self._format_date(statinfo.st_mtime),
 
1172
                                  ''])
 
1173
            for item in files:
 
1174
                status = 'unknown'
 
1175
                fileid = ''
 
1176
                if not notbranch:
 
1177
                    filename = tree1.relpath(path + os.sep + item)
881
1178
                    
882
 
                    for rpath, rpathnew, id, kind, text_modified, meta_modified in delta.renamed:
883
 
                        if rpathnew == filename:
884
 
                            status = 'renamed'
885
 
                    for rpath, id, kind in delta.added:
886
 
                        if rpath == filename:
887
 
                            status = 'added'                
888
 
                    for rpath, id, kind in delta.removed:
889
 
                        if rpath == filename:
890
 
                            status = 'removed'
891
 
                    for rpath, id, kind, text_modified, meta_modified in delta.modified:
892
 
                        if rpath == filename:
893
 
                            status = 'modified'
894
 
                    for rpath, id, kind in delta.unchanged:
895
 
                        if rpath == filename:
896
 
                            status = 'unchanged'
897
 
                    for rpath, file_class, kind, id, entry in self.wt.list_files():
898
 
                        if rpath == filename and file_class == 'I':
899
 
                            status = 'ignored'
900
 
                finally:
901
 
                    self.wt.unlock()
902
 
            
903
 
            #try:
904
 
            #    status = fileops.status(path + os.sep + item)
905
 
            #except errors.PermissionDenied:
906
 
            #    continue
907
 
 
908
 
            if status == 'renamed':
909
 
                st = _('renamed')
910
 
            elif status == 'removed':
911
 
                st = _('removed')
912
 
            elif status == 'added':
913
 
                st = _('added')
914
 
            elif status == 'modified':
915
 
                st = _('modified')
916
 
            elif status == 'unchanged':
917
 
                st = _('unchanged')
918
 
            elif status == 'ignored':
919
 
                st = _('ignored')
920
 
            else:
921
 
                st = _('unknown')
922
 
            
923
 
            statinfo = os.stat(self.path + os.sep + item)
924
 
            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)])
925
 
 
926
 
        # Add the ListStore to the TreeView
927
 
        self.treeview_right.set_model(liststore)
 
1179
                    try:
 
1180
                        self.wt.lock_read()
 
1181
                        
 
1182
                        for rpath, rpathnew, id, kind, text_modified, meta_modified in delta.renamed:
 
1183
                            if rpathnew == filename:
 
1184
                                status = 'renamed'
 
1185
                                fileid = id
 
1186
                        for rpath, id, kind in delta.added:
 
1187
                            if rpath == filename:
 
1188
                                status = 'added'
 
1189
                                fileid = id
 
1190
                        for rpath, id, kind in delta.removed:
 
1191
                            if rpath == filename:
 
1192
                                status = 'removed'
 
1193
                                fileid = id
 
1194
                        for rpath, id, kind, text_modified, meta_modified in delta.modified:
 
1195
                            if rpath == filename:
 
1196
                                status = 'modified'
 
1197
                                fileid = id
 
1198
                        for rpath, id, kind in delta.unchanged:
 
1199
                            if rpath == filename:
 
1200
                                status = 'unchanged'
 
1201
                                fileid = id
 
1202
                        for rpath, file_class, kind, id, entry in self.wt.list_files():
 
1203
                            if rpath == filename and file_class == 'I':
 
1204
                                status = 'ignored'
 
1205
                    finally:
 
1206
                        self.wt.unlock()
 
1207
                
 
1208
                if status == 'renamed':
 
1209
                    st = _('renamed')
 
1210
                elif status == 'removed':
 
1211
                    st = _('removed')
 
1212
                elif status == 'added':
 
1213
                    st = _('added')
 
1214
                elif status == 'modified':
 
1215
                    st = _('modified')
 
1216
                elif status == 'unchanged':
 
1217
                    st = _('unchanged')
 
1218
                elif status == 'ignored':
 
1219
                    st = _('ignored')
 
1220
                else:
 
1221
                    st = _('unknown')
 
1222
                
 
1223
                statinfo = os.stat(self.path + os.sep + item)
 
1224
                liststore.append([gtk.STOCK_FILE,
 
1225
                                  False,
 
1226
                                  item,
 
1227
                                  st,
 
1228
                                  status,
 
1229
                                  statinfo.st_size,
 
1230
                                  self._format_size(statinfo.st_size),
 
1231
                                  statinfo.st_mtime,
 
1232
                                  self._format_date(statinfo.st_mtime),
 
1233
                                  fileid])
 
1234
        else:
 
1235
            # We're remote
 
1236
            
 
1237
            # Get ListStore and clear it
 
1238
            liststore = self.treeview_right.get_model()
 
1239
            liststore.clear()
 
1240
            
 
1241
            # Hide Status column
 
1242
            self._tvcolumn_status.set_visible(False)
 
1243
            
 
1244
            dirs = []
 
1245
            files = []
 
1246
            
 
1247
            self._show_stock_image(gtk.STOCK_REFRESH)
 
1248
            
 
1249
            for (name, type) in self.remote_entries:
 
1250
                if type.kind == 'directory':
 
1251
                    dirs.append(type)
 
1252
                elif type.kind == 'file':
 
1253
                    files.append(type)
 
1254
            
 
1255
            class HistoryCache:
 
1256
                """ Cache based on revision history. """
 
1257
                def __init__(self, history):
 
1258
                    self._history = history
 
1259
                
 
1260
                def _lookup_revision(self, revid):
 
1261
                    for r in self._history:
 
1262
                        if r.revision_id == revid:
 
1263
                            return r
 
1264
                    rev = repo.get_revision(revid)
 
1265
                    self._history.append(rev)
 
1266
                    return rev
 
1267
            
 
1268
            repo = self.remote_branch.repository
 
1269
            
 
1270
            revhistory = self.remote_branch.revision_history()
 
1271
            try:
 
1272
                revs = repo.get_revisions(revhistory)
 
1273
                cache = HistoryCache(revs)
 
1274
            except bzrerrors.InvalidHttpResponse:
 
1275
                # Fallback to dummy algorithm, because of LP: #115209
 
1276
                cache = HistoryCache([])
 
1277
            
 
1278
            for item in dirs:
 
1279
                if item.parent_id == self.remote_parent:
 
1280
                    rev = cache._lookup_revision(item.revision)
 
1281
                    liststore.append([ gtk.STOCK_DIRECTORY,
 
1282
                                       True,
 
1283
                                       item.name,
 
1284
                                       '',
 
1285
                                       '',
 
1286
                                       0,
 
1287
                                       self._format_size(0),
 
1288
                                       rev.timestamp,
 
1289
                                       self._format_date(rev.timestamp),
 
1290
                                       ''
 
1291
                                   ])
 
1292
                while gtk.events_pending():
 
1293
                    gtk.main_iteration()
 
1294
            
 
1295
            for item in files:
 
1296
                if item.parent_id == self.remote_parent:
 
1297
                    rev = cache._lookup_revision(item.revision)
 
1298
                    liststore.append([ gtk.STOCK_FILE,
 
1299
                                       False,
 
1300
                                       item.name,
 
1301
                                       '',
 
1302
                                       '',
 
1303
                                       item.text_size,
 
1304
                                       self._format_size(item.text_size),
 
1305
                                       rev.timestamp,
 
1306
                                       self._format_date(rev.timestamp),
 
1307
                                       item.file_id
 
1308
                                   ])
 
1309
                while gtk.events_pending():
 
1310
                    gtk.main_iteration()
 
1311
            
 
1312
            self.image_location_error.destroy()
 
1313
 
 
1314
        # Columns should auto-size
928
1315
        self.treeview_right.columns_autosize()
929
1316
        
930
1317
        # Set sensitivity
1020
1407
    def _format_date(self, timestamp):
1021
1408
        """ Format the time (given in secs) to a human readable format. """
1022
1409
        return time.ctime(timestamp)
 
1410
    
 
1411
    def _is_remote_dir(self, location):
 
1412
        """ Determine whether the given location is a directory or not. """
 
1413
        if not self.remote:
 
1414
            # We're in local mode
 
1415
            return False
 
1416
        else:
 
1417
            branch, path = Branch.open_containing(location)
 
1418
            for (name, type) in self.remote_entries:
 
1419
                if name == path and type.kind == 'directory':
 
1420
                    # We got it
 
1421
                    return True
 
1422
            # Either it's not a directory or not in the inventory
 
1423
            return False
 
1424
    
 
1425
    def _show_stock_image(self, stock_id):
 
1426
        """ Show a stock image next to the location entry. """
 
1427
        self.image_location_error.destroy()
 
1428
        self.image_location_error = gtk.image_new_from_stock(stock_id, gtk.ICON_SIZE_BUTTON)
 
1429
        self.hbox_location.pack_start(self.image_location_error, False, False, 0)
 
1430
        if sys.platform == 'win32':
 
1431
            self.hbox_location.reorder_child(self.image_location_error, 2)
 
1432
        else:
 
1433
            self.hbox_location.reorder_child(self.image_location_error, 1)
 
1434
        self.image_location_error.show()
 
1435
        while gtk.events_pending():
 
1436
            gtk.main_iteration()
1023
1437
 
1024
1438
import ConfigParser
1025
1439