/b-gtk/fix-viz

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

« back to all changes in this revision

Viewing changes to olive/__init__.py

  • Committer: Jelmer Vernooij
  • Date: 2008-08-04 18:08:20 UTC
  • Revision ID: jelmer@samba.org-20080804180820-24n5va8sr53wfdbc
ReleaseĀ 0.95.

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
19
17
import os
20
18
import sys
21
19
import time
 
20
import errno
22
21
 
23
22
# gettext support
24
23
import gettext
33
32
import gobject
34
33
import gtk
35
34
import gtk.gdk
36
 
import gtk.glade
37
35
 
38
36
from bzrlib.branch import Branch
39
37
import bzrlib.errors as bzrerrors
44
42
from bzrlib.plugins.gtk import _i18n
45
43
from bzrlib.plugins.gtk.dialog import error_dialog, info_dialog, warning_dialog
46
44
from bzrlib.plugins.gtk.errors import show_bzr_error
47
 
from guifiles import GLADEFILENAME
 
45
from bzrlib.plugins.gtk.olive.window import OliveGui
48
46
 
49
47
from bzrlib.plugins.gtk.diff import DiffWindow
50
48
lazy_import(globals(), """
60
58
 
61
59
def about():
62
60
    """ 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
 
61
    from bzrlib.plugins.gtk import __version__, icon_path
 
62
    
 
63
    iconpath = icon_path() + os.sep
 
64
    
 
65
    dialog = gtk.AboutDialog()
 
66
    dialog.set_name("Olive")
71
67
    dialog.set_version(__version__)
 
68
    dialog.set_copyright("Copyright (C) 2006 Szilveszter Farkas (Phanatic)")
 
69
    dialog.set_website("https://launchpad.net/products/olive")
 
70
    dialog.set_website_label("https://launchpad.net/products/olive")
 
71
    dialog.set_icon_from_file(iconpath+"oliveicon2.png")
 
72
    dialog.set_logo(gtk.gdk.pixbuf_new_from_file(iconpath+"oliveicon2.png"))
72
73
    dialog.set_authors([ _i18n("Lead Developer:"),
73
74
                         "Szilveszter Farkas <szilveszter.farkas@gmail.com>",
74
75
                         _i18n("Contributors:"),
87
88
    program. """
88
89
    
89
90
    def __init__(self):
90
 
        self.toplevel = gtk.glade.XML(GLADEFILENAME, 'window_main', 'olive-gtk')
91
 
        self.window = self.toplevel.get_widget('window_main')
 
91
        self.window = OliveGui(calling_app = self)
 
92
        
92
93
        self.pref = Preferences()
93
94
        self.path = None
94
95
 
95
96
        # Initialize the statusbar
96
 
        self.statusbar = self.toplevel.get_widget('statusbar')
97
 
        self.context_id = self.statusbar.get_context_id('olive')
 
97
        self.context_id = self.window.statusbar.get_context_id('olive')
98
98
        
99
 
        # Get the main window
100
 
        self.window_main = self.toplevel.get_widget('window_main')
101
 
        # Get the HPaned
102
 
        self.hpaned_main = self.toplevel.get_widget('hpaned_main')
103
 
        # Get the TreeViews
104
 
        self.treeview_left = self.toplevel.get_widget('treeview_left')
105
 
        self.treeview_right = self.toplevel.get_widget('treeview_right')
106
 
        # Get some important menu items
107
 
        self.menuitem_add_files = self.toplevel.get_widget('menuitem_add_files')
108
 
        self.menuitem_remove_files = self.toplevel.get_widget('menuitem_remove_file')
109
 
        self.menuitem_file_bookmark = self.toplevel.get_widget('menuitem_file_bookmark')
110
 
        self.menuitem_file_make_directory = self.toplevel.get_widget('menuitem_file_make_directory')
111
 
        self.menuitem_file_rename = self.toplevel.get_widget('menuitem_file_rename')
112
 
        self.menuitem_file_move = self.toplevel.get_widget('menuitem_file_move')
113
 
        self.menuitem_file_annotate = self.toplevel.get_widget('menuitem_file_annotate')
114
 
        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
 
        self.menuitem_branch = self.toplevel.get_widget('menuitem_branch')
117
 
        self.menuitem_branch_init = self.toplevel.get_widget('menuitem_branch_initialize')
118
 
        self.menuitem_branch_get = self.toplevel.get_widget('menuitem_branch_get')
119
 
        self.menuitem_branch_checkout = self.toplevel.get_widget('menuitem_branch_checkout')
120
 
        self.menuitem_branch_pull = self.toplevel.get_widget('menuitem_branch_pull')
121
 
        self.menuitem_branch_push = self.toplevel.get_widget('menuitem_branch_push')
122
 
        self.menuitem_branch_update = self.toplevel.get_widget('menuitem_branch_update')
123
 
        self.menuitem_branch_revert = self.toplevel.get_widget('menuitem_branch_revert')
124
 
        self.menuitem_branch_merge = self.toplevel.get_widget('menuitem_branch_merge')
125
 
        self.menuitem_branch_commit = self.toplevel.get_widget('menuitem_branch_commit')
126
 
        self.menuitem_branch_tags = self.toplevel.get_widget('menuitem_branch_tags')
127
 
        self.menuitem_branch_status = self.toplevel.get_widget('menuitem_branch_status')
128
 
        self.menuitem_branch_missing = self.toplevel.get_widget('menuitem_branch_missing_revisions')
129
 
        self.menuitem_branch_conflicts = self.toplevel.get_widget('menuitem_branch_conflicts')
130
 
        self.menuitem_stats = self.toplevel.get_widget('menuitem_stats')
131
 
        self.menuitem_stats_diff = self.toplevel.get_widget('menuitem_stats_diff')
132
 
        self.menuitem_stats_log = self.toplevel.get_widget('menuitem_stats_log')
133
 
        # Get some toolbuttons
134
 
        #self.menutoolbutton_diff = self.toplevel.get_widget('menutoolbutton_diff')
135
 
        self.toolbutton_diff = self.toplevel.get_widget('toolbutton_diff')
136
 
        self.toolbutton_log = self.toplevel.get_widget('toolbutton_log')
137
 
        self.toolbutton_commit = self.toplevel.get_widget('toolbutton_commit')
138
 
        self.toolbutton_pull = self.toplevel.get_widget('toolbutton_pull')
139
 
        self.toolbutton_push = self.toplevel.get_widget('toolbutton_push')
140
 
        self.toolbutton_update = self.toplevel.get_widget('toolbutton_update')
141
99
        # Get the drive selector
142
100
        self.combobox_drive = gtk.combo_box_new_text()
143
101
        self.combobox_drive.connect("changed", self._refresh_drives)
144
102
        
145
103
        # Get the navigation widgets
146
 
        self.hbox_location = self.toplevel.get_widget('hbox_location')
147
 
        self.button_location_up = self.toplevel.get_widget('button_location_up')
148
 
        self.button_location_jump = self.toplevel.get_widget('button_location_jump')
149
 
        self.entry_location = self.toplevel.get_widget('entry_location')
150
 
        self.image_location_error = self.toplevel.get_widget('image_location_error')
 
104
        self.hbox_location = self.window.locationbar
 
105
        self.button_location_up = self.window.button_location_up
 
106
        self.button_location_jump = self.window.button_location_jump
 
107
        self.entry_location = self.window.entry_location
151
108
        
152
109
        # 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
 
        self.vbox_main_right = self.toplevel.get_widget('vbox_main_right')
158
 
        
159
 
        # Dictionary for signal_autoconnect
160
 
        dic = { "on_window_main_destroy": gtk.main_quit,
161
 
                "on_window_main_delete_event": self.on_window_main_delete_event,
162
 
                "on_quit_activate": self.on_window_main_delete_event,
163
 
                "on_about_activate": self.on_about_activate,
164
 
                "on_menuitem_add_files_activate": self.on_menuitem_add_files_activate,
165
 
                "on_menuitem_remove_file_activate": self.on_menuitem_remove_file_activate,
166
 
                "on_menuitem_file_bookmark_activate": self.on_menuitem_file_bookmark_activate,
167
 
                "on_menuitem_file_make_directory_activate": self.on_menuitem_file_make_directory_activate,
168
 
                "on_menuitem_file_move_activate": self.on_menuitem_file_move_activate,
169
 
                "on_menuitem_file_rename_activate": self.on_menuitem_file_rename_activate,
170
 
                "on_menuitem_file_annotate_activate": self.on_menuitem_file_annotate_activate,
171
 
                "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
 
                "on_menuitem_view_refresh_activate": self.on_menuitem_view_refresh_activate,
174
 
                "on_menuitem_branch_initialize_activate": self.on_menuitem_branch_initialize_activate,
175
 
                "on_menuitem_branch_get_activate": self.on_menuitem_branch_get_activate,
176
 
                "on_menuitem_branch_checkout_activate": self.on_menuitem_branch_checkout_activate,
177
 
                "on_menuitem_branch_revert_activate": self.on_menuitem_branch_revert_activate,
178
 
                "on_menuitem_branch_merge_activate": self.on_menuitem_branch_merge_activate,
179
 
                "on_menuitem_branch_commit_activate": self.on_menuitem_branch_commit_activate,
180
 
                "on_menuitem_branch_push_activate": self.on_menuitem_branch_push_activate,
181
 
                "on_menuitem_branch_pull_activate": self.on_menuitem_branch_pull_activate,
182
 
                "on_menuitem_branch_update_activate": self.on_menuitem_branch_update_activate,                
183
 
                "on_menuitem_branch_tags_activate": self.on_menuitem_branch_tags_activate,
184
 
                "on_menuitem_branch_status_activate": self.on_menuitem_branch_status_activate,
185
 
                "on_menuitem_branch_missing_revisions_activate": self.on_menuitem_branch_missing_revisions_activate,
186
 
                "on_menuitem_branch_conflicts_activate": self.on_menuitem_branch_conflicts_activate,
187
 
                "on_menuitem_stats_diff_activate": self.on_menuitem_stats_diff_activate,
188
 
                "on_menuitem_stats_log_activate": self.on_menuitem_stats_log_activate,
189
 
                "on_menuitem_stats_infos_activate": self.on_menuitem_stats_infos_activate,
190
 
                "on_toolbutton_refresh_clicked": self.on_menuitem_view_refresh_activate,
191
 
                "on_toolbutton_log_clicked": self.on_menuitem_stats_log_activate,
192
 
                #"on_menutoolbutton_diff_clicked": self.on_menuitem_stats_diff_activate,
193
 
                "on_toolbutton_diff_clicked": self.on_menuitem_stats_diff_activate,
194
 
                "on_toolbutton_commit_clicked": self.on_menuitem_branch_commit_activate,
195
 
                "on_toolbutton_pull_clicked": self.on_menuitem_branch_pull_activate,
196
 
                "on_toolbutton_push_clicked": self.on_menuitem_branch_push_activate,
197
 
                "on_toolbutton_update_clicked": self.on_menuitem_branch_update_activate,
198
 
                "on_treeview_right_button_press_event": self.on_treeview_right_button_press_event,
199
 
                "on_treeview_right_row_activated": self.on_treeview_right_row_activated,
200
 
                "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
 
                "on_treeview_left_row_activated": self.on_treeview_left_row_activated,
203
 
                "on_button_location_up_clicked": self.on_button_location_up_clicked,
204
 
                "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
209
 
            }
210
 
        
211
 
        # Connect the signals to the handlers
212
 
        self.toplevel.signal_autoconnect(dic)
 
110
        self.check_history = self.window.checkbutton_history
 
111
        self.entry_history = self.window.entry_history_revno
 
112
        self.button_history = self.window.button_history_browse
213
113
        
214
114
        self._just_started = True
215
115
        
222
122
        self.window.move(x, y)
223
123
        # Apply paned position
224
124
        pos = self.pref.get_preference('paned_position', 'int')
225
 
        self.hpaned_main.set_position(pos)
226
 
        
227
 
        # Apply menu to the toolbutton
228
 
        #menubutton = self.toplevel.get_widget('menutoolbutton_diff')
229
 
        #menubutton.set_menu(handler.menu.toolbar_diff)
 
125
        self.window.hpaned_main.set_position(pos)
230
126
        
231
127
        # Now we can show the window
232
128
        self.window.show()
238
134
            self.combobox_drive.show()
239
135
            self.gen_hard_selector()
240
136
        
241
 
        self._load_left()
 
137
        # Acceptable errors when loading files/folders in the treeviews
 
138
        self.acceptable_errors = (errno.ENOENT, errno.ELOOP)
 
139
        
 
140
        self.refresh_left()
242
141
 
243
142
        # Apply menu state
244
 
        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'))
 
143
        self.window.mb_view_showhidden.set_active(self.pref.get_preference('dotted_files', 'bool'))
 
144
        self.window.mb_view_showignored.set_active(self.pref.get_preference('ignored_files', 'bool'))
246
145
 
247
146
        # We're starting local
248
147
        self.remote = False
251
150
        self.remote_revision = None
252
151
        
253
152
        self.set_path(os.getcwd())
254
 
        self._load_right()
 
153
        self.refresh_right()
255
154
        
256
155
        self._just_started = False
257
156
 
258
157
    def set_path(self, path, force_remote=False):
 
158
        self.window.location_status.destroy()
259
159
        self.notbranch = False
260
160
        
261
161
        if force_remote:
262
162
            # Forcing remote mode (reading data from inventory)
263
 
            self._show_stock_image(gtk.STOCK_DISCONNECT)
 
163
            self.window.set_location_status(gtk.STOCK_DISCONNECT)
264
164
            try:
265
165
                br = Branch.open_containing(path)[0]
266
166
            except bzrerrors.NotBranchError:
267
 
                self._show_stock_image(gtk.STOCK_DIALOG_ERROR)
 
167
                self.window.set_location_status(gtk.STOCK_DIALOG_ERROR)
268
168
                self.check_history.set_active(False)
269
169
                self.check_history.set_sensitive(False)
270
170
                return False
271
171
            except bzrerrors.UnsupportedProtocol:
272
 
                self._show_stock_image(gtk.STOCK_DIALOG_ERROR)
 
172
                self.window.set_location_status(gtk.STOCK_DIALOG_ERROR)
273
173
                self.check_history.set_active(False)
274
174
                self.check_history.set_sensitive(False)
275
175
                return False
276
176
            
277
 
            self._show_stock_image(gtk.STOCK_CONNECT)
 
177
            self.window.set_location_status(gtk.STOCK_CONNECT)
278
178
            
279
179
            self.remote = True
280
180
           
303
203
                self.button_location_up.set_sensitive(True)
304
204
        else:
305
205
            if os.path.isdir(path):
306
 
                self.image_location_error.destroy()
307
206
                self.remote = False
308
207
                
309
208
                # We're local
310
209
                try:
311
 
                    self.wt, self.wtpath = WorkingTree.open_containing(path)
 
210
                    self.wt, self.wtpath = WorkingTree.open_containing(os.path.realpath(path))
312
211
                except (bzrerrors.NotBranchError, bzrerrors.NoWorkingTree):
313
212
                    self.notbranch = True
 
213
                except bzrerrors.PermissionDenied:
 
214
                    self.window.set_location_status(gtk.STOCK_DIALOG_WARNING, allowPopup=True)
 
215
                    self.window.location_status.connect_object('clicked', warning_dialog, 
 
216
                                       *(_i18n('Branch information unreadable'),
 
217
                                                _i18n('The current folder is a branch but the .bzr folder is not readable')))
 
218
                    self.notbranch = True
314
219
                
315
220
                # If we're in the root, we cannot go up anymore
316
221
                if sys.platform == 'win32':
327
232
            elif not os.path.isfile(path):
328
233
                # Doesn't seem to be a file nor a directory, trying to open a
329
234
                # remote location
330
 
                self._show_stock_image(gtk.STOCK_DISCONNECT)
 
235
                self.window.set_location_status(gtk.STOCK_DISCONNECT)
331
236
                try:
332
237
                    br = Branch.open_containing(path)[0]
333
238
                except bzrerrors.NotBranchError:
334
 
                    self._show_stock_image(gtk.STOCK_DIALOG_ERROR)
 
239
                    self.window.set_location_status(gtk.STOCK_DIALOG_ERROR)
335
240
                    self.check_history.set_active(False)
336
241
                    self.check_history.set_sensitive(False)
337
242
                    return False
338
243
                except bzrerrors.UnsupportedProtocol:
339
 
                    self._show_stock_image(gtk.STOCK_DIALOG_ERROR)
 
244
                    self.window.set_location_status(gtk.STOCK_DIALOG_ERROR)
340
245
                    self.check_history.set_active(False)
341
246
                    self.check_history.set_sensitive(False)
342
247
                    return False
343
248
                
344
 
                self._show_stock_image(gtk.STOCK_CONNECT)
 
249
                self.window.set_location_status(gtk.STOCK_CONNECT)
345
250
                
346
251
                self.remote = True
347
252
               
375
280
        else:
376
281
            self.check_history.set_sensitive(True)
377
282
        
378
 
        self.statusbar.push(self.context_id, path)
 
283
        self.window.statusbar.push(self.context_id, path)
379
284
        self.entry_location.set_text(path)
380
285
        self.path = path
381
286
        return True
408
313
            if response == gtk.RESPONSE_OK:
409
314
                if revb.selected_revno is not None:
410
315
                    self.entry_history.set_text(revb.selected_revno)
 
316
                    self.on_entry_history_revno_activate()
411
317
            
412
318
            revb.destroy()
413
319
    
438
344
            # History Mode activated
439
345
            self.entry_history.set_sensitive(True)
440
346
            self.button_history.set_sensitive(True)
 
347
            if self.entry_history.get_text() != "":
 
348
                self.on_entry_history_revno_activate()
441
349
        else:
442
350
            # History Mode deactivated
443
351
            self.entry_history.set_sensitive(False)
444
352
            self.button_history.set_sensitive(False)
 
353
            
 
354
            # Return right window to normal view by acting like we jump to it
 
355
            self.on_button_location_jump_clicked(widget)
445
356
    
446
357
    @show_bzr_error
447
 
    def on_entry_history_revno_key_press_event(self, widget, event):
 
358
    def on_entry_history_revno_activate(self, widget=None):
448
359
        """ 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()
461
 
    
462
 
    def on_entry_location_key_press_event(self, widget, event):
463
 
        """ 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'):
465
 
            # Return was hit, so we have to jump
466
 
            self.on_button_location_jump_clicked(widget)
467
 
    
 
360
        path = self.get_path()
 
361
        if not self.remote:
 
362
            self.remote = True
 
363
            self.remote_branch = self.wt.branch
 
364
        
 
365
        revno = int(self.entry_history.get_text())
 
366
        self.remote_revision = self.remote_branch.get_rev_id(revno)
 
367
        if self.set_path(path, True):
 
368
            self.refresh_right()
 
369
 
468
370
    def on_menuitem_add_files_activate(self, widget):
469
371
        """ Add file(s)... menu handler. """
470
 
        from add import OliveAdd
471
 
        add = OliveAdd(self.wt, self.wtpath, self.get_selected_right())
472
 
        add.display()
473
 
    
 
372
        from bzrlib.plugins.gtk.olive.add import AddDialog
 
373
        add = AddDialog(self.wt, self.wtpath, self.get_selected_right(), self.window)
 
374
        response = add.run()
 
375
        add.destroy()
 
376
        if response == gtk.RESPONSE_OK:
 
377
            self.refresh_right()
 
378
 
474
379
    def on_menuitem_branch_get_activate(self, widget):
475
380
        """ Branch/Get... menu handler. """
476
381
        from bzrlib.plugins.gtk.branch import BranchDialog
508
413
    @show_bzr_error
509
414
    def on_menuitem_branch_commit_activate(self, widget):
510
415
        """ Branch/Commit... menu handler. """
511
 
#     def __init__(self, wt, wtpath, notbranch, selected=None, parent=None):
512
416
        selected = self.get_selected_right()
513
417
        if selected:
514
418
            selected = os.path.join(self.wtpath, selected)
541
445
                         _i18n('Please commit or revert the changes before merging.'))
542
446
        else:
543
447
            parent_branch_path = self.wt.branch.get_parent()
544
 
            merge = MergeDialog(self.wt, self.wtpath,default_branch_path=parent_branch_path )
545
 
            merge.display()
 
448
            merge = MergeDialog(self.wt, self.wtpath, parent_branch_path, self.window)
 
449
            response = merge.run()
 
450
            merge.destroy()
 
451
            if response == gtk.RESPONSE_OK:
 
452
                self.refresh_right()
546
453
 
547
454
    @show_bzr_error
548
455
    def on_menuitem_branch_missing_revisions_activate(self, widget):
644
551
    @show_bzr_error
645
552
    def on_menuitem_branch_revert_activate(self, widget):
646
553
        """ Branch/Revert all changes menu handler. """
647
 
        ret = self.wt.revert([])
 
554
        ret = self.wt.revert(None)
648
555
        if ret:
649
556
            warning_dialog(_i18n('Conflicts detected'),
650
557
                           _i18n('Please have a look at the working tree before continuing.'))
716
623
    
717
624
    def on_menuitem_file_make_directory_activate(self, widget):
718
625
        """ File/Make directory... menu handler. """
719
 
        from mkdir import OliveMkdir
720
 
        mkdir = OliveMkdir(self.wt, self.wtpath)
721
 
        mkdir.display()
 
626
        from bzrlib.plugins.gtk.olive.mkdir import MkdirDialog
 
627
        mkdir = MkdirDialog(self.wt, self.wtpath, self.window)
 
628
        response = mkdir.run()
 
629
        mkdir.destroy()
 
630
        if response == gtk.RESPONSE_OK:
 
631
            self.refresh_right()
722
632
    
723
633
    def on_menuitem_file_move_activate(self, widget):
724
634
        """ File/Move... menu handler. """
725
 
        from move import OliveMove
726
 
        move = OliveMove(self.wt, self.wtpath, self.get_selected_right())
727
 
        move.display()
 
635
        from bzrlib.plugins.gtk.olive.move import MoveDialog
 
636
        move = MoveDialog(self.wt, self.wtpath, self.get_selected_right(), self.window)
 
637
        response = move.run()
 
638
        move.destroy()
 
639
        if response == gtk.RESPONSE_OK:
 
640
            self.refresh_right()
728
641
    
729
642
    def on_menuitem_file_rename_activate(self, widget):
730
643
        """ File/Rename... menu handler. """
731
 
        from rename import OliveRename
732
 
        rename = OliveRename(self.wt, self.wtpath, self.get_selected_right())
733
 
        rename.display()
 
644
        from bzrlib.plugins.gtk.olive.rename import RenameDialog
 
645
        rename = RenameDialog(self.wt, self.wtpath, self.get_selected_right(), self.window)
 
646
        response = rename.run()
 
647
        rename.destroy()
 
648
        if response == gtk.RESPONSE_OK:
 
649
            self.refresh_right()
734
650
 
735
651
    def on_menuitem_remove_file_activate(self, widget):
736
652
        """ Remove (unversion) selected file. """
737
 
        from remove import OliveRemoveDialog
738
 
        remove = OliveRemoveDialog(self.wt, self.wtpath,
 
653
        from bzrlib.plugins.gtk.olive.remove import RemoveDialog
 
654
        remove = RemoveDialog(self.wt, self.wtpath,
739
655
                                   selected=self.get_selected_right(),
740
656
                                   parent=self.window)
741
657
        response = remove.run()
758
674
    
759
675
    def on_menuitem_stats_infos_activate(self, widget):
760
676
        """ Statistics/Informations... menu handler. """
761
 
        from info import OliveInfo
 
677
        from bzrlib.plugins.gtk.olive.info import InfoDialog
762
678
        if self.remote:
763
 
            info = OliveInfo(self.remote_branch)
 
679
            info = InfoDialog(self.remote_branch)
764
680
        else:
765
 
            info = OliveInfo(self.wt.branch)
 
681
            info = InfoDialog(self.wt.branch)
766
682
        info.display()
767
683
    
768
684
    def on_menuitem_stats_log_activate(self, widget):
773
689
        else:
774
690
            branch = self.remote_branch
775
691
 
776
 
        window = branchwin.BranchWindow(branch, branch.last_revision(), None, parent=self.window)
 
692
        window = branchwin.BranchWindow(branch, [branch.last_revision()], None, 
 
693
                                        parent=self.window)
777
694
        window.show()
778
695
    
779
696
    def on_menuitem_view_refresh_activate(self, widget):
796
713
            self.refresh_right()
797
714
            
798
715
    def on_treeview_left_button_press_event(self, widget, event):
799
 
        """ Occurs when somebody right-clicks in the bookmark list. """
800
 
        if event.button == 3:
801
 
            # Don't show context with nothing selected
802
 
            if self.get_selected_left() == None:
803
 
                return
804
 
 
805
 
            # Create a menu
806
 
            from menu import OliveMenu
807
 
            menu = OliveMenu(path=self.get_path(),
808
 
                             selected=self.get_selected_left(),
809
 
                             app=self)
810
 
            
811
 
            menu.left_context_menu().popup(None, None, None, 0,
812
 
                                           event.time)
813
 
 
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()
 
716
        """ Occurs when somebody clicks in the bookmark list. """
 
717
        treepathpos = widget.get_path_at_pos(int(event.x), int(event.y))
 
718
        treeselection = widget.get_selection()
 
719
        if treepathpos is not None:
 
720
            treeselection.select_path(treepathpos[0])
 
721
            if event.button == 1:
 
722
                newdir = self.get_selected_left()
 
723
                if newdir == None:
 
724
                    return
 
725
 
 
726
                if self.set_path(newdir):
 
727
                    self.refresh_right()
 
728
            elif event.button == 3:
 
729
                # Don't show context with nothing selected
 
730
                if self.get_selected_left() == None:
 
731
                    return
 
732
 
 
733
                # Create a menu
 
734
                from menu import OliveMenu
 
735
                menu = OliveMenu(path=self.get_path(),
 
736
                                 selected=self.get_selected_left(),
 
737
                                 app=self)
 
738
                
 
739
                menu.left_context_menu().popup(None, None, None, 0,
 
740
                                               event.time)
 
741
        else:
 
742
            if treeselection is not None:
 
743
                treeselection.unselect_all()
827
744
 
828
745
    def on_treeview_left_row_activated(self, treeview, path, view_column):
829
746
        """ Occurs when somebody double-clicks or enters an item in the
837
754
            self.refresh_right()
838
755
 
839
756
    def on_treeview_right_button_press_event(self, widget, event):
840
 
        """ Occurs when somebody right-clicks in the file list. """
841
 
        if event.button == 3:
 
757
        """ Occurs when somebody clicks in the file list. """
 
758
        treepathpos = widget.get_path_at_pos(int(event.x), int(event.y))
 
759
        if event.button == 1:
 
760
            if treepathpos is None and widget.get_selection is not None:
 
761
                treeselection = widget.get_selection()
 
762
                treeselection.unselect_all()
 
763
        elif event.button == 3:
 
764
            treeselection = widget.get_selection()
 
765
            if treepathpos is not None:
 
766
                treeselection.select_path(treepathpos[0])
 
767
            else:
 
768
                if treeselection is not None:
 
769
                    treeselection.unselect_all()
842
770
            # Create a menu
843
771
            from menu import OliveMenu
844
772
            menu = OliveMenu(path=self.get_path(),
848
776
            m_open = menu.ui.get_widget('/context_right/open')
849
777
            m_add = menu.ui.get_widget('/context_right/add')
850
778
            m_remove = menu.ui.get_widget('/context_right/remove')
 
779
            m_remove_and_delete = menu.ui.get_widget('/context_right/remove_and_delete')
851
780
            m_rename = menu.ui.get_widget('/context_right/rename')
852
781
            m_revert = menu.ui.get_widget('/context_right/revert')
853
782
            m_commit = menu.ui.get_widget('/context_right/commit')
861
790
                    m_open.set_sensitive(False)
862
791
                    m_add.set_sensitive(False)
863
792
                    m_remove.set_sensitive(False)
 
793
                    m_remove_and_delete.set_sensitive(False)
864
794
                    m_rename.set_sensitive(False)
865
795
                    m_revert.set_sensitive(False)
866
796
                    m_commit.set_sensitive(False)
867
797
                    m_annotate.set_sensitive(False)
868
798
                    m_diff.set_sensitive(False)
869
799
                else:
 
800
                    if treepathpos is None:
 
801
                        m_open.set_sensitive(False)
 
802
                        m_add.set_sensitive(False)
 
803
                        m_remove.set_sensitive(False)
 
804
                        m_remove_and_delete.set_sensitive(False)
 
805
                        m_rename.set_sensitive(False)
 
806
                        m_annotate.set_sensitive(False)
 
807
                        m_diff.set_sensitive(False)
 
808
                        m_revert.set_sensitive(False)
 
809
                    else:
 
810
                        m_open.set_sensitive(True)
 
811
                        m_add.set_sensitive(True)
 
812
                        m_remove.set_sensitive(True)
 
813
                        m_remove_and_delete.set_sensitive(True)
 
814
                        m_rename.set_sensitive(True)
 
815
                        m_annotate.set_sensitive(True)
 
816
                        m_diff.set_sensitive(True)
 
817
                        m_revert.set_sensitive(True)
 
818
                    m_commit.set_sensitive(True)
 
819
            except bzrerrors.NotBranchError:
 
820
                if treepathpos is None:
 
821
                    m_open.set_sensitive(False)
 
822
                else:
870
823
                    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)
878
 
            except bzrerrors.NotBranchError:
879
 
                m_open.set_sensitive(True)
880
824
                m_add.set_sensitive(False)
881
825
                m_remove.set_sensitive(False)
 
826
                m_remove_and_delete.set_sensitive(False)
882
827
                m_rename.set_sensitive(False)
883
828
                m_revert.set_sensitive(False)
884
829
                m_commit.set_sensitive(False)
919
864
    
920
865
    def on_window_main_delete_event(self, widget, event=None):
921
866
        """ Do some stuff before exiting. """
922
 
        width, height = self.window_main.get_size()
 
867
        width, height = self.window.get_size()
923
868
        self.pref.set_preference('window_width', width)
924
869
        self.pref.set_preference('window_height', height)
925
 
        x, y = self.window_main.get_position()
 
870
        x, y = self.window.get_position()
926
871
        self.pref.set_preference('window_x', x)
927
872
        self.pref.set_preference('window_y', y)
928
873
        self.pref.set_preference('paned_position',
929
 
                                 self.hpaned_main.get_position())
 
874
                                 self.window.hpaned_main.get_position())
930
875
        
931
876
        self.pref.write()
932
 
        self.window_main.destroy()
933
 
        
934
 
    def _load_left(self):
935
 
        """ Load data into the left panel. (Bookmarks) """
936
 
        # Create TreeStore
937
 
        treestore = gtk.TreeStore(str, str)
938
 
        
939
 
        # Get bookmarks
940
 
        bookmarks = self.pref.get_bookmarks()
941
 
        
942
 
        # Add them to the TreeStore
943
 
        titer = treestore.append(None, [_i18n('Bookmarks'), None])
944
 
        for item in bookmarks:
945
 
            title = self.pref.get_bookmark_title(item)
946
 
            treestore.append(titer, [title, item])
947
 
        
948
 
        # Create the column and add it to the TreeView
949
 
        self.treeview_left.set_model(treestore)
950
 
        tvcolumn_bookmark = gtk.TreeViewColumn(_i18n('Bookmark'))
951
 
        self.treeview_left.append_column(tvcolumn_bookmark)
952
 
        
953
 
        # Set up the cells
954
 
        cell = gtk.CellRendererText()
955
 
        tvcolumn_bookmark.pack_start(cell, True)
956
 
        tvcolumn_bookmark.add_attribute(cell, 'text', 0)
957
 
        
958
 
        # Expand the tree
959
 
        self.treeview_left.expand_all()
960
 
 
961
 
    def _load_right(self):
962
 
        """ Load data into the right panel. (Filelist) """
963
 
        # 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)
975
 
        
976
 
        dirs = []
977
 
        files = []
978
 
        
979
 
        # Fill the appropriate lists
980
 
        dotted_files = self.pref.get_preference('dotted_files', 'bool')
981
 
        for item in os.listdir(self.path):
982
 
            if not dotted_files and item[0] == '.':
983
 
                continue
984
 
            if os.path.isdir(self.path + os.sep + item):
985
 
                dirs.append(item)
986
 
            else:
987
 
                files.append(item)
988
 
        
989
 
        if not self.notbranch:
990
 
            branch = self.wt.branch
991
 
            tree2 = self.wt.branch.repository.revision_tree(branch.last_revision())
992
 
        
993
 
            delta = self.wt.changes_from(tree2, want_unchanged=True)
994
 
        
995
 
        # Add'em to the ListStore
996
 
        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
 
                               ''])
1014
 
        for item in files:
1015
 
            status = 'unknown'
1016
 
            fileid = ''
1017
 
            if not self.notbranch:
1018
 
                filename = self.wt.relpath(self.path + os.sep + item)
1019
 
                
1020
 
                try:
1021
 
                    self.wt.lock_read()
1022
 
                    
1023
 
                    for rpath, rpathnew, id, kind, text_modified, meta_modified in delta.renamed:
1024
 
                        if rpathnew == filename:
1025
 
                            status = 'renamed'
1026
 
                            fileid = id
1027
 
                    for rpath, id, kind in delta.added:
1028
 
                        if rpath == filename:
1029
 
                            status = 'added'
1030
 
                            fileid = id
1031
 
                    for rpath, id, kind in delta.removed:
1032
 
                        if rpath == filename:
1033
 
                            status = 'removed'
1034
 
                            fileid = id
1035
 
                    for rpath, id, kind, text_modified, meta_modified in delta.modified:
1036
 
                        if rpath == filename:
1037
 
                            status = 'modified'
1038
 
                            fileid = id
1039
 
                    for rpath, id, kind in delta.unchanged:
1040
 
                        if rpath == filename:
1041
 
                            status = 'unchanged'
1042
 
                            fileid = id
1043
 
                    for rpath, file_class, kind, id, entry in self.wt.list_files():
1044
 
                        if rpath == filename and file_class == 'I':
1045
 
                            status = 'ignored'
1046
 
                finally:
1047
 
                    self.wt.unlock()
1048
 
            
1049
 
            if status == 'renamed':
1050
 
                st = _i18n('renamed')
1051
 
            elif status == 'removed':
1052
 
                st = _i18n('removed')
1053
 
            elif status == 'added':
1054
 
                st = _i18n('added')
1055
 
            elif status == 'modified':
1056
 
                st = _i18n('modified')
1057
 
            elif status == 'unchanged':
1058
 
                st = _i18n('unchanged')
1059
 
            elif status == 'ignored':
1060
 
                st = _i18n('ignored')
1061
 
            else:
1062
 
                st = _i18n('unknown')
1063
 
            
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])
1081
 
        
1082
 
        # Create the columns and add them to the TreeView
1083
 
        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)
1092
 
        
1093
 
        # Set up the cells
1094
 
        cellpb = gtk.CellRendererPixbuf()
1095
 
        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)
1106
 
        
1107
 
        # Set up the properties of the TreeView
1108
 
        self.treeview_right.set_headers_visible(True)
1109
 
        self.treeview_right.set_headers_clickable(True)
1110
 
        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)
1115
 
        # Set up sorting
1116
 
        liststore.set_sort_func(13, self._sort_filelist_callback, None)
1117
 
        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)
1122
 
        
1123
 
        # Set sensitivity
1124
 
        self.set_sensitivity()
1125
 
        
 
877
        self.window.destroy()
 
878
    
1126
879
    def get_selected_fileid(self):
1127
880
        """ Get the file_id of the selected file. """
1128
 
        treeselection = self.treeview_right.get_selection()
 
881
        treeselection = self.window.treeview_right.get_selection()
1129
882
        (model, iter) = treeselection.get_selected()
1130
883
        
1131
884
        if iter is None:
1135
888
    
1136
889
    def get_selected_right(self):
1137
890
        """ Get the selected filename. """
1138
 
        treeselection = self.treeview_right.get_selection()
 
891
        treeselection = self.window.treeview_right.get_selection()
1139
892
        (model, iter) = treeselection.get_selected()
1140
893
        
1141
894
        if iter is None:
1145
898
    
1146
899
    def get_selected_left(self):
1147
900
        """ Get the selected bookmark. """
1148
 
        treeselection = self.treeview_left.get_selection()
 
901
        treeselection = self.window.treeview_left.get_selection()
1149
902
        (model, iter) = treeselection.get_selected()
1150
903
        
1151
904
        if iter is None:
1155
908
 
1156
909
    def set_statusbar(self, message):
1157
910
        """ Set the statusbar message. """
1158
 
        self.statusbar.push(self.context_id, message)
 
911
        self.window.statusbar.push(self.context_id, message)
1159
912
    
1160
913
    def clear_statusbar(self):
1161
914
        """ Clean the last message from the statusbar. """
1162
 
        self.statusbar.pop(self.context_id)
 
915
        self.window.statusbar.pop(self.context_id)
1163
916
    
1164
917
    def set_sensitivity(self):
1165
918
        """ Set menu and toolbar sensitivity. """
1166
919
        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)
 
920
            self.window.set_view_to_localbranch(self.notbranch)
1196
921
        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)
 
922
            self.window.set_view_to_remotebranch()
1226
923
    
1227
924
    def refresh_left(self):
1228
925
        """ Refresh the bookmark list. """
1229
926
        
1230
 
        # Get TreeStore and clear it
1231
 
        treestore = self.treeview_left.get_model()
1232
 
        treestore.clear()
 
927
        # Get ListStore and clear it
 
928
        liststore = self.window.bookmarklist
 
929
        liststore.clear()
1233
930
 
1234
931
        # Re-read preferences
1235
932
        self.pref.read()
1237
934
        # Get bookmarks
1238
935
        bookmarks = self.pref.get_bookmarks()
1239
936
 
1240
 
        # Add them to the TreeStore
1241
 
        titer = treestore.append(None, [_i18n('Bookmarks'), None])
1242
 
        for item in bookmarks:
1243
 
            title = self.pref.get_bookmark_title(item)
1244
 
            treestore.append(titer, [title, item])
1245
 
 
1246
 
        # Add the TreeStore to the TreeView
1247
 
        self.treeview_left.set_model(treestore)
1248
 
 
1249
 
        # Expand the tree
1250
 
        self.treeview_left.expand_all()
1251
 
 
1252
 
    def refresh_right(self, path=None):
 
937
        # Get titles and sort by title
 
938
        bookmarks = [[self.pref.get_bookmark_title(item), item, gtk.STOCK_DIRECTORY] for item in bookmarks]
 
939
        bookmarks.sort()
 
940
        for title_item in bookmarks:
 
941
            liststore.append(title_item)
 
942
        
 
943
        # Add the ListStore to the TreeView
 
944
        self.window.treeview_left.set_model(liststore)
 
945
 
 
946
    def refresh_right(self):
1253
947
        """ Refresh the file list. """
1254
948
        if not self.remote:
1255
949
            # We're local
1256
950
            from bzrlib.workingtree import WorkingTree
1257
951
    
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
 
    
 
952
            path = self.get_path()
 
953
            
1265
954
            # Get ListStore and clear it
1266
 
            liststore = self.treeview_right.get_model()
 
955
            liststore = self.window.filelist
1267
956
            liststore.clear()
1268
 
            
1269
 
            # Show Status column
1270
 
            self._tvcolumn_status.set_visible(True)
1271
957
    
1272
958
            dirs = []
1273
959
            files = []
1284
970
                else:
1285
971
                    files.append(item)
1286
972
            
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
 
            
1294
 
            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)
 
973
            self.window.col_status.set_visible(False)
 
974
            if not self.notbranch:
 
975
                try:
 
976
                    tree1 = WorkingTree.open_containing(os.path.realpath(path))[0]
 
977
                    branch = tree1.branch
 
978
                    tree2 = tree1.branch.repository.revision_tree(branch.last_revision())
1299
979
                
 
980
                    delta = tree1.changes_from(tree2, want_unchanged=True)
 
981
                    
 
982
                    # Show Status column
 
983
                    self.window.col_status.set_visible(True)
 
984
                except bzrerrors.LockContention:
 
985
                    self.window.set_location_status(gtk.STOCK_DIALOG_ERROR, allowPopup=True)
 
986
                    self.window.location_status.connect_object('clicked', error_dialog, 
 
987
                                       *(_i18n('Branch is locked'),
 
988
                                                _i18n('The branch in the current folder is locked by another Bazaar program')))
 
989
                    self.notbranch = True
 
990
                    self.window.set_view_to_localbranch(False) 
 
991
            
1300
992
            # Add'em to the ListStore
1301
993
            for item in dirs:
 
994
                status = ''
 
995
                st = ''
 
996
                fileid = ''
 
997
                if not self.notbranch:
 
998
                    filename = tree1.relpath(os.path.join(os.path.realpath(path), item))
 
999
                    
 
1000
                    st, status = self.statusmapper(filename, delta)
 
1001
                    if not ignored_files and status == 'ignored':
 
1002
                        continue
 
1003
                
1302
1004
                try:
1303
1005
                    statinfo = os.stat(self.path + os.sep + item)
1304
1006
                except OSError, e:
1305
 
                    if e.errno == 40:
 
1007
                    if e.errno in self.acceptable_errors:
1306
1008
                        continue
1307
1009
                    else:
1308
1010
                        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
 
                                  ''])
 
1011
                liststore.append([ gtk.STOCK_DIRECTORY,
 
1012
                                   True,
 
1013
                                   item,
 
1014
                                   st,
 
1015
                                   status,
 
1016
                                   "<DIR>",
 
1017
                                   "<DIR>",
 
1018
                                   statinfo.st_mtime,
 
1019
                                   self._format_date(statinfo.st_mtime),
 
1020
                                   ''])
1319
1021
            for item in files:
1320
 
                status = 'unknown'
 
1022
                status = ''
 
1023
                st = ''
1321
1024
                fileid = ''
1322
 
                if not notbranch:
1323
 
                    filename = tree1.relpath(path + os.sep + item)
 
1025
                if not self.notbranch:
 
1026
                    filename = tree1.relpath(os.path.join(os.path.realpath(path), item))
1324
1027
                    
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:
 
1028
                    st, status = self.statusmapper(filename, delta)
 
1029
                    if not ignored_files and status == 'ignored':
1367
1030
                        continue
1368
 
                else:
1369
 
                    st = _i18n('unknown')
1370
1031
                
1371
1032
                try:
1372
1033
                    statinfo = os.stat(self.path + os.sep + item)
1373
1034
                except OSError, e:
1374
 
                    if e.errno == 40:
 
1035
                    if e.errno in self.acceptable_errors:
1375
1036
                        continue
1376
1037
                    else:
1377
1038
                        raise
1389
1050
            # We're remote
1390
1051
            
1391
1052
            # Get ListStore and clear it
1392
 
            liststore = self.treeview_right.get_model()
 
1053
            liststore = self.window.filelist
1393
1054
            liststore.clear()
1394
1055
            
1395
1056
            # Hide Status column
1396
 
            self._tvcolumn_status.set_visible(False)
 
1057
            self.window.col_status.set_visible(False)
1397
1058
            
1398
1059
            dirs = []
1399
1060
            files = []
1400
1061
            
1401
 
            self._show_stock_image(gtk.STOCK_REFRESH)
 
1062
            self.window.set_location_status(gtk.STOCK_REFRESH)
1402
1063
            
1403
1064
            for (name, type) in self.remote_entries:
1404
1065
                if type.kind == 'directory':
1463
1124
                while gtk.events_pending():
1464
1125
                    gtk.main_iteration()
1465
1126
            
1466
 
            self.image_location_error.destroy()
 
1127
            self.window.location_status.destroy()
1467
1128
 
1468
1129
        # Columns should auto-size
1469
 
        self.treeview_right.columns_autosize()
 
1130
        self.window.treeview_right.columns_autosize()
1470
1131
        
1471
1132
        # Set sensitivity
1472
1133
        self.set_sensitivity()
 
1134
    
 
1135
    def statusmapper(self, filename, delta):
 
1136
        status = 'unknown'
 
1137
        try:
 
1138
            self.wt.lock_read()
 
1139
            
 
1140
            for rpath, rpathnew, id, kind, text_modified, meta_modified in delta.renamed:
 
1141
                if rpathnew == filename:
 
1142
                    status = 'renamed'
 
1143
                    fileid = id
 
1144
            for rpath, id, kind in delta.added:
 
1145
                if rpath == filename:
 
1146
                    status = 'added'
 
1147
                    fileid = id
 
1148
            for rpath, id, kind in delta.removed:
 
1149
                if rpath == filename:
 
1150
                    status = 'removed'
 
1151
                    fileid = id
 
1152
            for rpath, id, kind, text_modified, meta_modified in delta.modified:
 
1153
                if rpath == filename:
 
1154
                    status = 'modified'
 
1155
                    fileid = id
 
1156
            for rpath, id, kind in delta.unchanged:
 
1157
                if rpath == filename:
 
1158
                    status = 'unchanged'
 
1159
                    fileid = id
 
1160
            for rpath, file_class, kind, id, entry in self.wt.list_files():
 
1161
                if rpath == filename and file_class == 'I':
 
1162
                    status = 'ignored'
 
1163
        finally:
 
1164
            self.wt.unlock()
 
1165
    
 
1166
        if status == 'renamed':
 
1167
            st = _i18n('renamed')
 
1168
        elif status == 'removed':
 
1169
            st = _i18n('removed')
 
1170
        elif status == 'added':
 
1171
            st = _i18n('added')
 
1172
        elif status == 'modified':
 
1173
            st = _i18n('modified')
 
1174
        elif status == 'unchanged':
 
1175
            st = _i18n('unchanged')
 
1176
        elif status == 'ignored':
 
1177
            st = _i18n('ignored')
 
1178
        else:
 
1179
            st = _i18n('unknown')
 
1180
        return st, status
1473
1181
 
1474
1182
    def _harddisks(self):
1475
1183
        """ Returns hard drive letters under Win32. """
1480
1188
            if sys.platform == 'win32':
1481
1189
                print "pyWin32 modules needed to run Olive on Win32."
1482
1190
                sys.exit(1)
1483
 
            else:
1484
 
                pass
1485
1191
        
1486
1192
        driveletters = []
1487
1193
        for drive in string.ascii_uppercase:
1488
 
            if win32file.GetDriveType(drive+':') == win32file.DRIVE_FIXED:
 
1194
            if win32file.GetDriveType(drive+':') == win32file.DRIVE_FIXED or\
 
1195
                win32file.GetDriveType(drive+':') == win32file.DRIVE_REMOTE or\
 
1196
                win32file.GetDriveType(drive+':') == win32file.DRIVE_REMOVABLE:
1489
1197
                driveletters.append(drive+':')
1490
1198
        return driveletters
1491
1199
    
1504
1212
        if active >= 0:
1505
1213
            drive = model[active][0]
1506
1214
            self.set_path(drive + '\\')
1507
 
            self.refresh_right(drive + '\\')
 
1215
            self.refresh_right()
1508
1216
    
1509
1217
    def check_for_changes(self):
1510
1218
        """ Check whether there were changes in the current working tree. """
1583
1291
                    return True
1584
1292
            # Either it's not a directory or not in the inventory
1585
1293
            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
1294
 
1600
1295
import ConfigParser
1601
1296
 
1724
1419
                return self._get_default(option)
1725
1420
            except KeyError:
1726
1421
                return None
1727