/b-gtk/fix-viz

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

« back to all changes in this revision

Viewing changes to olive/__init__.py

  • Committer: Szilveszter Farkas (Phanatic)
  • Date: 2006-09-25 01:58:44 UTC
  • mto: (0.14.1 main)
  • mto: This revision was merged to the branch mainline in revision 83.
  • Revision ID: Szilveszter.Farkas@gmail.com-20060925015844-12e9eec2d5f41420
Huge cleanup after removing backend codebase.

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 ConfigParser
 
18
import os
 
19
import os.path
 
20
import sys
 
21
 
 
22
try:
 
23
    import pygtk
 
24
    pygtk.require("2.0")
 
25
except:
 
26
    pass
 
27
try:
 
28
    import gtk
 
29
    import gtk.gdk
 
30
    import gtk.glade
 
31
except:
 
32
    sys.exit(1)
 
33
 
 
34
from handler import OliveHandler
 
35
import bzrlib.errors as errors
 
36
 
 
37
# Olive GTK UI version
 
38
__version__ = '0.11.0'
 
39
 
 
40
class OliveGtk:
 
41
    """ The main Olive GTK frontend class. This is called when launching the
 
42
    program. """
 
43
    
 
44
    def __init__(self):
 
45
        # Load the glade file
 
46
        if sys.platform == 'win32':
 
47
            self.gladefile = os.path.dirname(sys.executable) + "/share/olive/olive.glade"
 
48
        else:
 
49
            self.gladefile = "/usr/share/olive/olive.glade"
 
50
 
 
51
        if not os.path.exists(self.gladefile):
 
52
            # Load from current directory if not installed
 
53
            self.gladefile = "olive.glade"
 
54
            # Check again
 
55
            if not os.path.exists(self.gladefile):
 
56
                # Fail
 
57
                print _('Glade file cannot be found.')
 
58
                sys.exit(1)
 
59
 
 
60
        self.toplevel = gtk.glade.XML(self.gladefile, 'window_main', 'olive-gtk')
 
61
        
 
62
        self.window = self.toplevel.get_widget('window_main')
 
63
        
 
64
        self.pref = OlivePreferences()
 
65
        self.comm = OliveCommunicator(self.toplevel, self.pref)
 
66
        handler = OliveHandler(self.gladefile, self.comm)
 
67
        
 
68
        # Dictionary for signal_autoconnect
 
69
        dic = { "on_window_main_destroy": gtk.main_quit,
 
70
                "on_window_main_delete_event": handler.on_window_main_delete_event,
 
71
                "on_quit_activate": handler.on_window_main_delete_event,
 
72
                "on_about_activate": handler.on_about_activate,
 
73
                "on_menuitem_add_files_activate": handler.on_menuitem_add_files_activate,
 
74
                "on_menuitem_remove_file_activate": handler.on_menuitem_remove_file_activate,
 
75
                "on_menuitem_file_make_directory_activate": handler.on_menuitem_file_make_directory_activate,
 
76
                "on_menuitem_file_move_activate": handler.on_menuitem_file_move_activate,
 
77
                "on_menuitem_file_rename_activate": handler.on_menuitem_file_rename_activate,
 
78
                "on_menuitem_view_show_hidden_files_activate": handler.on_menuitem_view_show_hidden_files_activate,
 
79
                "on_menuitem_view_refresh_activate": handler.on_menuitem_view_refresh_activate,
 
80
                "on_menuitem_branch_initialize_activate": handler.on_menuitem_branch_initialize_activate,
 
81
                "on_menuitem_branch_get_activate": handler.on_menuitem_branch_get_activate,
 
82
                "on_menuitem_branch_checkout_activate": handler.on_menuitem_branch_checkout_activate,
 
83
                "on_menuitem_branch_commit_activate": handler.on_menuitem_branch_commit_activate,
 
84
                "on_menuitem_branch_push_activate": handler.on_menuitem_branch_push_activate,
 
85
                "on_menuitem_branch_pull_activate": handler.on_menuitem_branch_pull_activate,
 
86
                "on_menuitem_branch_status_activate": handler.on_menuitem_branch_status_activate,
 
87
                "on_menuitem_branch_missing_revisions_activate": handler.on_menuitem_branch_missing_revisions_activate,
 
88
                "on_menuitem_stats_diff_activate": handler.on_menuitem_stats_diff_activate,
 
89
                "on_menuitem_stats_log_activate": handler.on_menuitem_stats_log_activate,
 
90
                "on_menuitem_stats_infos_activate": handler.on_menuitem_stats_infos_activate,
 
91
                "on_toolbutton_refresh_clicked": handler.on_menuitem_view_refresh_activate,
 
92
                "on_toolbutton_log_clicked": handler.on_menuitem_stats_log_activate,
 
93
                #"on_menutoolbutton_diff_clicked": handler.on_menuitem_stats_diff_activate,
 
94
                "on_toolbutton_diff_clicked": handler.on_menuitem_stats_diff_activate,
 
95
                "on_toolbutton_commit_clicked": handler.on_menuitem_branch_commit_activate,
 
96
                "on_toolbutton_pull_clicked": handler.on_menuitem_branch_pull_activate,
 
97
                "on_toolbutton_push_clicked": handler.on_menuitem_branch_push_activate,
 
98
                "on_treeview_right_button_press_event": handler.on_treeview_right_button_press_event,
 
99
                "on_treeview_right_row_activated": handler.on_treeview_right_row_activated,
 
100
                "on_treeview_left_button_press_event": handler.on_treeview_left_button_press_event,
 
101
                "on_treeview_left_row_activated": handler.on_treeview_left_row_activated }
 
102
        
 
103
        # Connect the signals to the handlers
 
104
        self.toplevel.signal_autoconnect(dic)
 
105
        
 
106
        # Apply window size and position
 
107
        width = self.pref.get_preference('window_width', 'int')
 
108
        height = self.pref.get_preference('window_height', 'int')
 
109
        self.window.resize(width, height)
 
110
        x = self.pref.get_preference('window_x', 'int')
 
111
        y = self.pref.get_preference('window_y', 'int')
 
112
        self.window.move(x, y)
 
113
        # Apply paned position
 
114
        pos = self.pref.get_preference('paned_position', 'int')
 
115
        self.comm.hpaned_main.set_position(pos)
 
116
        
 
117
        # Apply menu to the toolbutton
 
118
        #menubutton = self.toplevel.get_widget('menutoolbutton_diff')
 
119
        #menubutton.set_menu(handler.menu.toolbar_diff)
 
120
        
 
121
        # Now we can show the window
 
122
        self.window.show()
 
123
        
 
124
        # Show drive selector if under Win32
 
125
        if sys.platform == 'win32':
 
126
            self.comm.vbox_main_right.pack_start(self.comm.combobox_drive, False, True, 0)
 
127
            self.comm.vbox_main_right.reorder_child(self.comm.combobox_drive, 0)
 
128
            self.comm.combobox_drive.show()
 
129
            self.comm.gen_hard_selector()
 
130
        
 
131
        # Load default data into the panels
 
132
        self.treeview_left = self.toplevel.get_widget('treeview_left')
 
133
        self.treeview_right = self.toplevel.get_widget('treeview_right')
 
134
        self._load_left()
 
135
        self._load_right()
 
136
 
 
137
        # Apply menu state
 
138
        self.comm.menuitem_view_show_hidden_files.set_active(self.pref.get_preference('dotted_files', 'bool'))
 
139
        
 
140
    def _load_left(self):
 
141
        """ Load data into the left panel. (Bookmarks) """
 
142
        # set cursor to busy
 
143
        self.comm.set_busy(self.treeview_left)
 
144
        
 
145
        # Create TreeStore
 
146
        treestore = gtk.TreeStore(str, str)
 
147
        
 
148
        # Get bookmarks
 
149
        bookmarks = self.comm.pref.get_bookmarks()
 
150
        
 
151
        # Add them to the TreeStore
 
152
        titer = treestore.append(None, [_('Bookmarks'), None])
 
153
        for item in bookmarks:
 
154
            title = self.comm.pref.get_bookmark_title(item)
 
155
            treestore.append(titer, [title, item])
 
156
        
 
157
        # Create the column and add it to the TreeView
 
158
        self.treeview_left.set_model(treestore)
 
159
        tvcolumn_bookmark = gtk.TreeViewColumn(_('Bookmark'))
 
160
        self.treeview_left.append_column(tvcolumn_bookmark)
 
161
        
 
162
        # Set up the cells
 
163
        cell = gtk.CellRendererText()
 
164
        tvcolumn_bookmark.pack_start(cell, True)
 
165
        tvcolumn_bookmark.add_attribute(cell, 'text', 0)
 
166
        
 
167
        # Expand the tree
 
168
        self.treeview_left.expand_all()
 
169
 
 
170
        self.comm.set_busy(self.treeview_left, False)
 
171
        
 
172
    def _load_right(self):
 
173
        """ Load data into the right panel. (Filelist) """
 
174
        from bzrlib.workingtree import WorkingTree
 
175
        
 
176
        # set cursor to busy
 
177
        self.comm.set_busy(self.treeview_right)
 
178
        
 
179
        # Create ListStore
 
180
        liststore = gtk.ListStore(str, str, str)
 
181
        
 
182
        dirs = ['..']
 
183
        files = []
 
184
        
 
185
        # Fill the appropriate lists
 
186
        path = self.comm.get_path()
 
187
        dotted_files = self.pref.get_preference('dotted_files', 'bool')
 
188
        for item in os.listdir(path):
 
189
            if not dotted_files and item[0] == '.':
 
190
                continue
 
191
            if os.path.isdir(path + os.sep + item):
 
192
                dirs.append(item)
 
193
            else:
 
194
                files.append(item)
 
195
            
 
196
        # Sort'em
 
197
        dirs.sort()
 
198
        files.sort()
 
199
        
 
200
        # Try to open the working tree
 
201
        notbranch = False
 
202
        try:
 
203
            tree1 = WorkingTree.open_containing(path)[0]
 
204
        except errors.NotBranchError:
 
205
            notbranch = True
 
206
        except errors.PermissionDenied:
 
207
            print "DEBUG: permission denied."
 
208
        
 
209
        if not notbranch:
 
210
            branch = tree1.branch
 
211
            tree2 = tree1.branch.repository.revision_tree(branch.last_revision())
 
212
        
 
213
            delta = tree1.changes_from(tree2, want_unchanged=True)
 
214
        
 
215
        # Add'em to the ListStore
 
216
        for item in dirs:    
 
217
            liststore.append([gtk.STOCK_DIRECTORY, item, ''])
 
218
        for item in files:
 
219
            status = 'unknown'
 
220
            if not notbranch:
 
221
                filename = tree1.relpath(path + os.sep + item)
 
222
                
 
223
                for rpath, id, kind, text_modified, meta_modified in delta.renamed:
 
224
                    if rpath == filename:
 
225
                        status = 'renamed'
 
226
                for rpath, id, kind in delta.added:
 
227
                    if rpath == filename:
 
228
                        status = 'added'
 
229
                for rpath, id, kind, text_modified, meta_modified in delta.removed:
 
230
                    if rpath == filename:
 
231
                        status = 'removed'
 
232
                for rpath, id, kind, text_modified, meta_modified in delta.modified:
 
233
                    if rpath == filename:
 
234
                        status = 'modified'
 
235
                for rpath, id, kind in delta.unchanged:
 
236
                    if rpath == filename:
 
237
                        status = 'unchanged'
 
238
            
 
239
            #try:
 
240
            #    status = fileops.status(path + os.sep + item)
 
241
            #except errors.PermissionDenied:
 
242
            #    continue
 
243
            
 
244
            if status == 'renamed':
 
245
                st = _('renamed')
 
246
            elif status == 'removed':
 
247
                st = _('removed')
 
248
            elif status == 'added':
 
249
                st = _('added')
 
250
            elif status == 'modified':
 
251
                st = _('modified')
 
252
            elif status == 'unchanged':
 
253
                st = _('unchanged')
 
254
            else:
 
255
                st = _('unknown')
 
256
            liststore.append([gtk.STOCK_FILE, item, st])
 
257
        
 
258
        # Create the columns and add them to the TreeView
 
259
        self.treeview_right.set_model(liststore)
 
260
        tvcolumn_filename = gtk.TreeViewColumn(_('Filename'))
 
261
        tvcolumn_status = gtk.TreeViewColumn(_('Status'))
 
262
        self.treeview_right.append_column(tvcolumn_filename)
 
263
        self.treeview_right.append_column(tvcolumn_status)
 
264
        
 
265
        # Set up the cells
 
266
        cellpb = gtk.CellRendererPixbuf()
 
267
        cell = gtk.CellRendererText()
 
268
        tvcolumn_filename.pack_start(cellpb, False)
 
269
        tvcolumn_filename.pack_start(cell, True)
 
270
        tvcolumn_filename.set_attributes(cellpb, stock_id=0)
 
271
        tvcolumn_filename.add_attribute(cell, 'text', 1)
 
272
        tvcolumn_status.pack_start(cell, True)
 
273
        tvcolumn_status.add_attribute(cell, 'text', 2)
 
274
        
 
275
        # Check if current directory is a branch
 
276
        if not notbranch:
 
277
            # Activate some items
 
278
            self.comm.menuitem_branch_init.set_sensitive(False)
 
279
            self.comm.menuitem_branch_get.set_sensitive(True)
 
280
            self.comm.menuitem_branch_checkout.set_sensitive(True)
 
281
            self.comm.menuitem_branch_pull.set_sensitive(True)
 
282
            self.comm.menuitem_branch_push.set_sensitive(True)
 
283
            self.comm.menuitem_branch_commit.set_sensitive(True)
 
284
            self.comm.menuitem_branch_status.set_sensitive(True)
 
285
            self.comm.menuitem_branch_missing.set_sensitive(True)
 
286
            self.comm.menuitem_stats.set_sensitive(True)
 
287
            self.comm.menuitem_add_files.set_sensitive(True)
 
288
            self.comm.menuitem_remove_files.set_sensitive(True)
 
289
            self.comm.menuitem_file_make_directory.set_sensitive(True)
 
290
            self.comm.menuitem_file_rename.set_sensitive(True)
 
291
            self.comm.menuitem_file_move.set_sensitive(True)
 
292
            #self.comm.menutoolbutton_diff.set_sensitive(True)
 
293
            self.comm.toolbutton_diff.set_sensitive(True)
 
294
            self.comm.toolbutton_log.set_sensitive(True)
 
295
            self.comm.toolbutton_commit.set_sensitive(True)
 
296
            self.comm.toolbutton_pull.set_sensitive(True)
 
297
            self.comm.toolbutton_push.set_sensitive(True)
 
298
        else:
 
299
            # Deactivate some items
 
300
            self.comm.menuitem_branch_init.set_sensitive(True)
 
301
            self.comm.menuitem_branch_get.set_sensitive(False)
 
302
            self.comm.menuitem_branch_checkout.set_sensitive(False)
 
303
            self.comm.menuitem_branch_pull.set_sensitive(False)
 
304
            self.comm.menuitem_branch_push.set_sensitive(False)
 
305
            self.comm.menuitem_branch_commit.set_sensitive(False)
 
306
            self.comm.menuitem_branch_status.set_sensitive(False)
 
307
            self.comm.menuitem_branch_missing.set_sensitive(False)
 
308
            self.comm.menuitem_stats.set_sensitive(False)
 
309
            self.comm.menuitem_add_files.set_sensitive(False)
 
310
            self.comm.menuitem_remove_files.set_sensitive(False)
 
311
            self.comm.menuitem_file_make_directory.set_sensitive(False)
 
312
            self.comm.menuitem_file_rename.set_sensitive(False)
 
313
            self.comm.menuitem_file_move.set_sensitive(False)
 
314
            #self.comm.menutoolbutton_diff.set_sensitive(False)
 
315
            self.comm.toolbutton_diff.set_sensitive(False)
 
316
            self.comm.toolbutton_log.set_sensitive(False)
 
317
            self.comm.toolbutton_commit.set_sensitive(False)
 
318
            self.comm.toolbutton_pull.set_sensitive(False)
 
319
            self.comm.toolbutton_push.set_sensitive(False)
 
320
        
 
321
        # set cursor to default
 
322
        self.comm.set_busy(self.treeview_right, False)
 
323
 
 
324
class OliveCommunicator:
 
325
    """ This class is responsible for the communication between the different
 
326
    modules. """
 
327
    def __init__(self, toplevel, pref):
 
328
        # Get glade main component
 
329
        self.toplevel = toplevel
 
330
        # Preferences object
 
331
        self.pref = pref
 
332
        # Default path
 
333
        self._path = os.getcwd()
 
334
 
 
335
        # Initialize the statusbar
 
336
        self.statusbar = self.toplevel.get_widget('statusbar')
 
337
        self.context_id = self.statusbar.get_context_id('olive')
 
338
        
 
339
        # Get the main window
 
340
        self.window_main = self.toplevel.get_widget('window_main')
 
341
        # Get the HPaned
 
342
        self.hpaned_main = self.toplevel.get_widget('hpaned_main')
 
343
        # Get the TreeViews
 
344
        self.treeview_left = self.toplevel.get_widget('treeview_left')
 
345
        self.treeview_right = self.toplevel.get_widget('treeview_right')
 
346
        # Get some important menu items
 
347
        self.menuitem_add_files = self.toplevel.get_widget('menuitem_add_files')
 
348
        self.menuitem_remove_files = self.toplevel.get_widget('menuitem_remove_file')
 
349
        self.menuitem_file_make_directory = self.toplevel.get_widget('menuitem_file_make_directory')
 
350
        self.menuitem_file_rename = self.toplevel.get_widget('menuitem_file_rename')
 
351
        self.menuitem_file_move = self.toplevel.get_widget('menuitem_file_move')
 
352
        self.menuitem_view_show_hidden_files = self.toplevel.get_widget('menuitem_view_show_hidden_files')
 
353
        self.menuitem_branch = self.toplevel.get_widget('menuitem_branch')
 
354
        self.menuitem_branch_init = self.toplevel.get_widget('menuitem_branch_initialize')
 
355
        self.menuitem_branch_get = self.toplevel.get_widget('menuitem_branch_get')
 
356
        self.menuitem_branch_checkout = self.toplevel.get_widget('menuitem_branch_checkout')
 
357
        self.menuitem_branch_pull = self.toplevel.get_widget('menuitem_branch_pull')
 
358
        self.menuitem_branch_push = self.toplevel.get_widget('menuitem_branch_push')
 
359
        self.menuitem_branch_commit = self.toplevel.get_widget('menuitem_branch_commit')
 
360
        self.menuitem_branch_status = self.toplevel.get_widget('menuitem_branch_status')
 
361
        self.menuitem_branch_missing = self.toplevel.get_widget('menuitem_branch_missing_revisions')
 
362
        self.menuitem_stats = self.toplevel.get_widget('menuitem_stats')
 
363
        self.menuitem_stats_diff = self.toplevel.get_widget('menuitem_stats_diff')
 
364
        self.menuitem_stats_log = self.toplevel.get_widget('menuitem_stats_log')
 
365
        # Get some toolbuttons
 
366
        #self.menutoolbutton_diff = self.toplevel.get_widget('menutoolbutton_diff')
 
367
        self.toolbutton_diff = self.toplevel.get_widget('toolbutton_diff')
 
368
        self.toolbutton_log = self.toplevel.get_widget('toolbutton_log')
 
369
        self.toolbutton_commit = self.toplevel.get_widget('toolbutton_commit')
 
370
        self.toolbutton_pull = self.toplevel.get_widget('toolbutton_pull')
 
371
        self.toolbutton_push = self.toplevel.get_widget('toolbutton_push')
 
372
        # Get the drive selector
 
373
        self.combobox_drive = gtk.combo_box_new_text()
 
374
        self.combobox_drive.connect("changed", self._refresh_drives)
 
375
        
 
376
        self.vbox_main_right = self.toplevel.get_widget('vbox_main_right')
 
377
    
 
378
    def set_path(self, path):
 
379
        """ Set the current path while browsing the directories. """
 
380
        self._path = path
 
381
    
 
382
    def get_path(self):
 
383
        """ Get the current path. """
 
384
        return self._path
 
385
    
 
386
    def get_selected_right(self):
 
387
        """ Get the selected filename. """
 
388
        treeselection = self.treeview_right.get_selection()
 
389
        (model, iter) = treeselection.get_selected()
 
390
        
 
391
        if iter is None:
 
392
            return None
 
393
        else:
 
394
            return model.get_value(iter, 1)
 
395
    
 
396
    def get_selected_left(self):
 
397
        """ Get the selected bookmark. """
 
398
        treeselection = self.treeview_left.get_selection()
 
399
        (model, iter) = treeselection.get_selected()
 
400
        
 
401
        if iter is None:
 
402
            return None
 
403
        else:
 
404
            return model.get_value(iter, 1)
 
405
 
 
406
    def set_statusbar(self, message):
 
407
        """ Set the statusbar message. """
 
408
        self.statusbar.push(self.context_id, message)
 
409
    
 
410
    def clear_statusbar(self):
 
411
        """ Clean the last message from the statusbar. """
 
412
        self.statusbar.pop(self.context_id)
 
413
    
 
414
    def refresh_left(self):
 
415
        """ Refresh the bookmark list. """
 
416
        # set cursor to busy
 
417
        self.set_busy(self.treeview_left)
 
418
        
 
419
        # Get TreeStore and clear it
 
420
        treestore = self.treeview_left.get_model()
 
421
        treestore.clear()
 
422
 
 
423
        # Get bookmarks
 
424
        bookmarks = self.pref.get_bookmarks()
 
425
 
 
426
        # Add them to the TreeStore
 
427
        titer = treestore.append(None, [_('Bookmarks'), None])
 
428
        for item in bookmarks:
 
429
            title = self.pref.get_bookmark_title(item)
 
430
            treestore.append(titer, [title, item])
 
431
 
 
432
        # Add the TreeStore to the TreeView
 
433
        self.treeview_left.set_model(treestore)
 
434
 
 
435
        # Expand the tree
 
436
        self.treeview_left.expand_all()
 
437
 
 
438
        self.set_busy(self.treeview_left, False)
 
439
 
 
440
    def refresh_right(self, path=None):
 
441
        """ Refresh the file list. """
 
442
        from bzrlib.workingtree import WorkingTree
 
443
 
 
444
        self.set_busy(self.treeview_right)
 
445
 
 
446
        if path is None:
 
447
            path = self.get_path()
 
448
 
 
449
        # A workaround for double-clicking Bookmarks
 
450
        if not os.path.exists(path):
 
451
            self.set_busy(self.treeview_right, False)
 
452
            return
 
453
 
 
454
        # Get ListStore and clear it
 
455
        liststore = self.treeview_right.get_model()
 
456
        liststore.clear()
 
457
 
 
458
        dirs = ['..']
 
459
        files = []
 
460
 
 
461
        # Fill the appropriate lists
 
462
        dotted_files = self.pref.get_preference('dotted_files', 'bool')
 
463
        for item in os.listdir(path):
 
464
            if not dotted_files and item[0] == '.':
 
465
                continue
 
466
            if os.path.isdir(path + os.sep + item):
 
467
                dirs.append(item)
 
468
            else:
 
469
                files.append(item)
 
470
 
 
471
        # Sort'em
 
472
        dirs.sort()
 
473
        files.sort()
 
474
        
 
475
        # Try to open the working tree
 
476
        notbranch = False
 
477
        try:
 
478
            tree1 = WorkingTree.open_containing(path)[0]
 
479
        except errors.NotBranchError:
 
480
            notbranch = True
 
481
        except errors.PermissionDenied:
 
482
            print "DEBUG: permission denied."
 
483
        
 
484
        if not notbranch:
 
485
            branch = tree1.branch
 
486
            tree2 = tree1.branch.repository.revision_tree(branch.last_revision())
 
487
        
 
488
            delta = tree1.changes_from(tree2, want_unchanged=True)
 
489
 
 
490
        # Add'em to the ListStore
 
491
        for item in dirs:
 
492
            liststore.append([gtk.STOCK_DIRECTORY, item, ''])
 
493
        for item in files:
 
494
            status = 'unknown'
 
495
            if not notbranch:
 
496
                filename = tree1.relpath(path + os.sep + item)
 
497
                
 
498
                for rpath, id, kind, text_modified, meta_modified in delta.renamed:
 
499
                    if rpath == filename:
 
500
                        status = 'renamed'
 
501
                for rpath, id, kind in delta.added:
 
502
                    if rpath == filename:
 
503
                        status = 'added'
 
504
                for rpath, id, kind, text_modified, meta_modified in delta.removed:
 
505
                    if rpath == filename:
 
506
                        status = 'removed'
 
507
                for rpath, id, kind, text_modified, meta_modified in delta.modified:
 
508
                    if rpath == filename:
 
509
                        status = 'modified'
 
510
                for rpath, id, kind in delta.unchanged:
 
511
                    if rpath == filename:
 
512
                        status = 'unchanged'
 
513
            
 
514
            #try:
 
515
            #    status = fileops.status(path + os.sep + item)
 
516
            #except errors.PermissionDenied:
 
517
            #    continue
 
518
 
 
519
            if status == 'renamed':
 
520
                st = _('renamed')
 
521
            elif status == 'removed':
 
522
                st = _('removed')
 
523
            elif status == 'added':
 
524
                st = _('added')
 
525
            elif status == 'modified':
 
526
                st = _('modified')
 
527
            elif status == 'unchanged':
 
528
                st = _('unchanged')
 
529
            else:
 
530
                st = _('unknown')
 
531
            liststore.append([gtk.STOCK_FILE, item, st])
 
532
 
 
533
        # Add the ListStore to the TreeView
 
534
        self.treeview_right.set_model(liststore)
 
535
 
 
536
        # Check if current directory is a branch
 
537
        if not notbranch:
 
538
            # Activate some items
 
539
            self.menuitem_branch_init.set_sensitive(False)
 
540
            self.menuitem_branch_get.set_sensitive(True)
 
541
            self.menuitem_branch_checkout.set_sensitive(True)
 
542
            self.menuitem_branch_pull.set_sensitive(True)
 
543
            self.menuitem_branch_push.set_sensitive(True)
 
544
            self.menuitem_branch_commit.set_sensitive(True)
 
545
            self.menuitem_branch_status.set_sensitive(True)
 
546
            self.menuitem_branch_missing.set_sensitive(True)
 
547
            self.menuitem_stats.set_sensitive(True)
 
548
            self.menuitem_add_files.set_sensitive(True)
 
549
            self.menuitem_remove_files.set_sensitive(True)
 
550
            self.menuitem_file_make_directory.set_sensitive(True)
 
551
            self.menuitem_file_rename.set_sensitive(True)
 
552
            self.menuitem_file_move.set_sensitive(True)
 
553
            #self.menutoolbutton_diff.set_sensitive(True)
 
554
            self.toolbutton_diff.set_sensitive(True)
 
555
            self.toolbutton_log.set_sensitive(True)
 
556
            self.toolbutton_commit.set_sensitive(True)
 
557
            self.toolbutton_pull.set_sensitive(True)
 
558
            self.toolbutton_push.set_sensitive(True)
 
559
        else:
 
560
            # Deactivate some items
 
561
            self.menuitem_branch_init.set_sensitive(True)
 
562
            self.menuitem_branch_get.set_sensitive(False)
 
563
            self.menuitem_branch_checkout.set_sensitive(False)
 
564
            self.menuitem_branch_pull.set_sensitive(False)
 
565
            self.menuitem_branch_push.set_sensitive(False)
 
566
            self.menuitem_branch_commit.set_sensitive(False)
 
567
            self.menuitem_branch_status.set_sensitive(False)
 
568
            self.menuitem_branch_missing.set_sensitive(False)
 
569
            self.menuitem_stats.set_sensitive(False)
 
570
            self.menuitem_add_files.set_sensitive(False)
 
571
            self.menuitem_remove_files.set_sensitive(False)
 
572
            self.menuitem_file_make_directory.set_sensitive(False)
 
573
            self.menuitem_file_rename.set_sensitive(False)
 
574
            self.menuitem_file_move.set_sensitive(False)
 
575
            #self.menutoolbutton_diff.set_sensitive(False)
 
576
            self.toolbutton_diff.set_sensitive(False)
 
577
            self.toolbutton_log.set_sensitive(False)
 
578
            self.toolbutton_commit.set_sensitive(False)
 
579
            self.toolbutton_pull.set_sensitive(False)
 
580
            self.toolbutton_push.set_sensitive(False)
 
581
 
 
582
        self.set_busy(self.treeview_right, False)
 
583
 
 
584
    def set_busy(self, widget, busy=True):
 
585
        if busy:
 
586
            widget.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.WATCH))
 
587
        else:
 
588
            widget.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.LEFT_PTR))
 
589
 
 
590
        gtk.main_iteration(0)
 
591
 
 
592
    def _harddisks(self):
 
593
        """ Returns hard drive letters under Win32. """
 
594
        try:
 
595
            import win32file
 
596
            import string
 
597
        except ImportError:
 
598
            if sys.platform == 'win32':
 
599
                print "pyWin32 modules needed to run Olive on Win32."
 
600
                sys.exit(1)
 
601
            else:
 
602
                pass
 
603
        
 
604
        driveletters = []
 
605
        for drive in string.ascii_uppercase:
 
606
            if win32file.GetDriveType(drive+':') == win32file.DRIVE_FIXED:
 
607
                driveletters.append(drive+':')
 
608
        return driveletters
 
609
    
 
610
    def gen_hard_selector(self):
 
611
        """ Generate the hard drive selector under Win32. """
 
612
        drives = self._harddisks()
 
613
        for drive in drives:
 
614
            self.combobox_drive.append_text(drive)
 
615
    
 
616
    def _refresh_drives(self, combobox):
 
617
        model = combobox.get_model()
 
618
        active = combobox.get_active()
 
619
        if active >= 0:
 
620
            drive = model[active][0]
 
621
            self.refresh_right(drive + '\\')
 
622
 
 
623
class OlivePreferences:
 
624
    """ A class which handles Olive's preferences. """
 
625
    def __init__(self):
 
626
        """ Initialize the Preferences class. """
 
627
        # Some default options
 
628
        self.defaults = { 'strict_commit' : False,
 
629
                          'dotted_files'  : False,
 
630
                          'window_width'  : 700,
 
631
                          'window_height' : 400,
 
632
                          'window_x'      : 40,
 
633
                          'window_y'      : 40,
 
634
                          'paned_position': 200 }
 
635
 
 
636
        # Create a config parser object
 
637
        self.config = ConfigParser.RawConfigParser()
 
638
        
 
639
        # Load the configuration
 
640
        if sys.platform == 'win32':
 
641
            # Windows - no dotted files
 
642
            self.config.read([os.path.expanduser('~/olive.conf')])
 
643
        else:
 
644
            self.config.read([os.path.expanduser('~/.olive.conf')])
 
645
        
 
646
    def _get_default(self, option):
 
647
        """ Get the default option for a preference. """
 
648
        try:
 
649
            ret = self.defaults[option]
 
650
        except KeyError:
 
651
            return None
 
652
        else:
 
653
            return ret
 
654
 
 
655
    def refresh(self):
 
656
        """ Refresh the configuration. """
 
657
        # First write out the changes
 
658
        self.write()
 
659
        # Then load the configuration again
 
660
        if sys.platform == 'win32':
 
661
            # Windows - no dotted files
 
662
            self.config.read([os.path.expanduser('~/olive.conf')])
 
663
        else:
 
664
            self.config.read([os.path.expanduser('~/.olive.conf')])
 
665
 
 
666
    def write(self):
 
667
        """ Write the configuration to the appropriate files. """
 
668
        if sys.platform == 'win32':
 
669
            # Windows - no dotted files
 
670
            fp = open(os.path.expanduser('~/olive.conf'), 'w')
 
671
            self.config.write(fp)
 
672
            fp.close()
 
673
        else:
 
674
            fp = open(os.path.expanduser('~/.olive.conf'), 'w')
 
675
            self.config.write(fp)
 
676
            fp.close()
 
677
 
 
678
    def get_preference(self, option, kind='str'):
 
679
        """ Get the value of the given option.
 
680
        
 
681
        :param kind: str/bool/int/float. default: str
 
682
        """
 
683
        if self.config.has_option('preferences', option):
 
684
            if kind == 'bool':
 
685
                return self.config.getboolean('preferences', option)
 
686
            elif kind == 'int':
 
687
                return self.config.getint('preferences', option)
 
688
            elif kind == 'float':
 
689
                return self.config.getfloat('preferences', option)
 
690
            else:
 
691
                return self.config.get('preferences', option)
 
692
        else:
 
693
            try:
 
694
                return self._get_default(option)
 
695
            except KeyError:
 
696
                return None
 
697
    
 
698
    def set_preference(self, option, value):
 
699
        """ Set the value of the given option. """
 
700
        if self.config.has_section('preferences'):
 
701
            self.config.set('preferences', option, value)
 
702
        else:
 
703
            self.config.add_section('preferences')
 
704
            self.config.set('preferences', option, value)
 
705
    
 
706
    def get_bookmarks(self):
 
707
        """ Return the list of bookmarks. """
 
708
        bookmarks = self.config.sections()
 
709
        if self.config.has_section('preferences'):
 
710
            bookmarks.remove('preferences')
 
711
        return bookmarks
 
712
 
 
713
    def add_bookmark(self, path):
 
714
        """ Add bookmark. """
 
715
        try:
 
716
            self.config.add_section(path)
 
717
        except ConfigParser.DuplicateSectionError:
 
718
            return False
 
719
        else:
 
720
            return True
 
721
 
 
722
    def get_bookmark_title(self, path):
 
723
        """ Get bookmark title. """
 
724
        try:
 
725
            ret = self.config.get(path, 'title')
 
726
        except ConfigParser.NoOptionError:
 
727
            ret = path
 
728
        
 
729
        return ret
 
730
    
 
731
    def set_bookmark_title(self, path, title):
 
732
        """ Set bookmark title. """
 
733
        self.config.set(path, 'title', title)
 
734
    
 
735
    def remove_bookmark(self, path):
 
736
        """ Remove bookmark. """
 
737
        return self.config.remove_section(path)