/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: Curtis Hovey
  • Date: 2012-03-11 18:24:06 UTC
  • mto: This revision was merged to the branch mainline in revision 785.
  • Revision ID: sinzui.is@verizon.net-20120311182406-f4jqpff65b30g3al
Create the mnemonic for the button label.

Show diffs side-by-side

added added

removed removed

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