/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 diff.py

Add options to viz treeview to not show the line graph, and to only show the main line.
Set the revision browser to use these options.

Show diffs side-by-side

added added

removed removed

Lines of Context:
30
30
except ImportError:
31
31
    have_gconf = False
32
32
 
33
 
from bzrlib import (
34
 
    merge as _mod_merge,
35
 
    osutils,
36
 
    progress,
37
 
    urlutils,
38
 
    workingtree,
39
 
)
 
33
from bzrlib import osutils
40
34
from bzrlib.diff import show_diff_trees, internal_diff
41
35
from bzrlib.errors import NoSuchFile
42
 
from bzrlib.patches import parse_patches
43
36
from bzrlib.trace import warning
44
 
from bzrlib.plugins.gtk import _i18n
45
37
from bzrlib.plugins.gtk.window import Window
46
 
from dialog import error_dialog, info_dialog, warning_dialog
47
 
 
48
 
 
49
 
class SelectCancelled(Exception):
50
 
 
51
 
    pass
52
 
 
53
 
 
54
 
class DiffFileView(gtk.ScrolledWindow):
55
 
    """Window for displaying diffs from a diff file"""
 
38
 
 
39
 
 
40
class DiffView(gtk.ScrolledWindow):
 
41
    """This is the soft and chewy filling for a DiffWindow."""
56
42
 
57
43
    def __init__(self):
58
44
        gtk.ScrolledWindow.__init__(self)
 
45
 
59
46
        self.construct()
60
 
        self._diffs = {}
 
47
        self.rev_tree = None
 
48
        self.parent_tree = None
61
49
 
62
50
    def construct(self):
63
51
        self.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
146
134
 
147
135
            lang.set_tag_style(tag_id, style)
148
136
 
149
 
    @classmethod
150
 
    def apply_colordiff_colors(klass, lang):
 
137
    @staticmethod
 
138
    def apply_colordiff_colors(lang):
151
139
        """Set style colors for lang using the colordiff configuration file.
152
140
 
153
141
        Both ~/.colordiffrc and ~/.colordiffrc.bzr-gtk are read.
164
152
                except IOError, e:
165
153
                    warning('could not open file %s: %s' % (f, str(e)))
166
154
                else:
167
 
                    colors.update(klass.parse_colordiffrc(f))
 
155
                    colors.update(DiffView.parse_colordiffrc(f))
168
156
                    f.close()
169
157
 
170
158
        if not colors:
228
216
#        self.parent_tree.lock_read()
229
217
#        self.rev_tree.lock_read()
230
218
#        try:
231
 
#            self.delta = iter_changes_to_status(self.parent_tree, self.rev_tree)
 
219
#            self.delta = _iter_changes_to_status(self.parent_tree, self.rev_tree)
232
220
#            self.path_to_status = {}
233
221
#            self.path_to_diff = {}
234
222
#            source_inv = self.parent_tree.inventory
249
237
#            self.parent_tree.unlock()
250
238
 
251
239
    def show_diff(self, specific_files):
252
 
        sections = []
253
 
        if specific_files is None:
254
 
            self.buffer.set_text(self._diffs[None])
255
 
        else:
256
 
            for specific_file in specific_files:
257
 
                sections.append(self._diffs[specific_file])
258
 
            self.buffer.set_text(''.join(sections))
259
 
 
260
 
 
261
 
class DiffView(DiffFileView):
262
 
    """This is the soft and chewy filling for a DiffWindow."""
263
 
 
264
 
    def __init__(self):
265
 
        DiffFileView.__init__(self)
266
 
        self.rev_tree = None
267
 
        self.parent_tree = None
268
 
 
269
 
    def show_diff(self, specific_files):
270
 
        """Show the diff for the specified files"""
271
240
        s = StringIO()
272
241
        show_diff_trees(self.parent_tree, self.rev_tree, s, specific_files,
273
242
                        old_label='', new_label='',
321
290
        column.add_attribute(cell, "text", 0)
322
291
        self.treeview.append_column(column)
323
292
 
324
 
    def set_diff_text(self, lines):
325
 
        """Set the current diff from a list of lines
326
 
 
327
 
        :param lines: The diff to show, in unified diff format
328
 
        """
329
293
        # The diffs of the  selected file: a scrollable source or
330
294
        # text view
331
 
 
332
 
    def set_diff_text_sections(self, sections):
333
 
        self.diff_view = DiffFileView()
 
295
        self.diff_view = DiffView()
 
296
        self.pack2(self.diff_view)
334
297
        self.diff_view.show()
335
 
        self.pack2(self.diff_view)
336
 
        for oldname, newname, patch in sections:
337
 
            self.diff_view._diffs[newname] = str(patch)
338
 
            if newname is None:
339
 
                newname = ''
340
 
            self.model.append(None, [oldname, newname])
341
 
        self.diff_view.show_diff(None)
342
298
 
343
299
    def set_diff(self, rev_tree, parent_tree):
344
300
        """Set the differences showed by this window.
346
302
        Compares the two trees and populates the window with the
347
303
        differences.
348
304
        """
349
 
        self.diff_view = DiffView()
350
 
        self.pack2(self.diff_view)
351
 
        self.diff_view.show()
352
305
        self.diff_view.set_trees(rev_tree, parent_tree)
353
306
        self.rev_tree = rev_tree
354
307
        self.parent_tree = parent_tree
382
335
        self.treeview.expand_all()
383
336
 
384
337
    def set_file(self, file_path):
385
 
        """Select the current file to display"""
386
338
        tv_path = None
387
339
        for data in self.model:
388
340
            for child in data.iterchildren():
413
365
    differences between two revisions on a branch.
414
366
    """
415
367
 
416
 
    def __init__(self, parent=None, operations=None):
 
368
    def __init__(self, parent=None):
417
369
        Window.__init__(self, parent)
418
370
        self.set_border_width(0)
419
371
        self.set_title("bzrk diff")
424
376
        width = int(monitor.width * 0.66)
425
377
        height = int(monitor.height * 0.66)
426
378
        self.set_default_size(width, height)
427
 
        self.construct(operations)
428
 
 
429
 
    def construct(self, operations):
 
379
 
 
380
        self.construct()
 
381
 
 
382
    def construct(self):
430
383
        """Construct the window contents."""
431
 
        self.vbox = gtk.VBox()
432
 
        self.add(self.vbox)
433
 
        self.vbox.show()
434
 
        hbox = self._get_button_bar(operations)
435
 
        if hbox is not None:
436
 
            self.vbox.pack_start(hbox, expand=False, fill=True)
437
384
        self.diff = DiffWidget()
438
 
        self.vbox.add(self.diff)
 
385
        self.add(self.diff)
439
386
        self.diff.show_all()
440
387
 
441
 
    def _get_button_bar(self, operations):
442
 
        """Return a button bar to use.
443
 
 
444
 
        :return: None, meaning that no button bar will be used.
445
 
        """
446
 
        if operations is None:
447
 
            return None
448
 
        hbox = gtk.HButtonBox()
449
 
        hbox.set_layout(gtk.BUTTONBOX_START)
450
 
        for title, method in operations:
451
 
            merge_button = gtk.Button(title)
452
 
            merge_button.show()
453
 
            merge_button.set_relief(gtk.RELIEF_NONE)
454
 
            merge_button.connect("clicked", method)
455
 
            hbox.pack_start(merge_button, expand=False, fill=True)
456
 
        hbox.show()
457
 
        return hbox
458
 
 
459
 
    def _get_merge_target(self):
460
 
        d = gtk.FileChooserDialog('Merge branch', self,
461
 
                                  gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER,
462
 
                                  buttons=(gtk.STOCK_OK, gtk.RESPONSE_OK,
463
 
                                           gtk.STOCK_CANCEL,
464
 
                                           gtk.RESPONSE_CANCEL,))
465
 
        try:
466
 
            result = d.run()
467
 
            if result != gtk.RESPONSE_OK:
468
 
                raise SelectCancelled()
469
 
            return d.get_current_folder_uri()
470
 
        finally:
471
 
            d.destroy()
472
 
 
473
 
    def _merge_successful(self):
474
 
        # No conflicts found.
475
 
        info_dialog(_i18n('Merge successful'),
476
 
                    _i18n('All changes applied successfully.'))
477
 
 
478
 
    def _conflicts(self):
479
 
        warning_dialog(_i18n('Conflicts encountered'),
480
 
                       _i18n('Please resolve the conflicts manually'
481
 
                             ' before committing.'))
482
 
 
483
 
    def _handle_error(self, e):
484
 
        error_dialog('Error', str(e))
485
 
 
486
 
    def _get_save_path(self, basename):
487
 
        d = gtk.FileChooserDialog('Save As', self,
488
 
                                  gtk.FILE_CHOOSER_ACTION_SAVE,
489
 
                                  buttons=(gtk.STOCK_OK, gtk.RESPONSE_OK,
490
 
                                           gtk.STOCK_CANCEL,
491
 
                                           gtk.RESPONSE_CANCEL,))
492
 
        d.set_current_name(basename)
493
 
        try:
494
 
            result = d.run()
495
 
            if result != gtk.RESPONSE_OK:
496
 
                raise SelectCancelled()
497
 
            return urlutils.local_path_from_url(d.get_uri())
498
 
        finally:
499
 
            d.destroy()
500
 
 
501
388
    def set_diff(self, description, rev_tree, parent_tree):
502
389
        """Set the differences showed by this window.
503
390
 
511
398
        self.diff.set_file(file_path)
512
399
 
513
400
 
514
 
class DiffController(object):
515
 
 
516
 
    def __init__(self, path, patch, window=None):
517
 
        self.path = path
518
 
        self.patch = patch
519
 
        if window is None:
520
 
            window = DiffWindow(operations=self._provide_operations())
521
 
            self.initialize_window(window)
522
 
        self.window = window
523
 
 
524
 
    def initialize_window(self, window):
525
 
        window.diff.set_diff_text_sections(self.get_diff_sections())
526
 
        window.set_title(self.path + " - diff")
527
 
 
528
 
    def get_diff_sections(self):
529
 
        yield "Complete Diff", None, ''.join(self.patch)
530
 
        for patch in parse_patches(self.patch):
531
 
            oldname = patch.oldname.split('\t')[0]
532
 
            newname = patch.newname.split('\t')[0]
533
 
            yield oldname, newname, str(patch)
534
 
 
535
 
    def perform_save(self, window):
536
 
        try:
537
 
            save_path = self.window._get_save_path(osutils.basename(self.path))
538
 
        except SelectCancelled:
539
 
            return
540
 
        source = open(self.path, 'rb')
541
 
        try:
542
 
            target = open(save_path, 'wb')
543
 
            try:
544
 
                osutils.pumpfile(source, target)
545
 
            finally:
546
 
                target.close()
547
 
        finally:
548
 
            source.close()
549
 
 
550
 
    def _provide_operations(self):
551
 
        return [('Save', self.perform_save)]
552
 
 
553
 
 
554
 
class MergeDirectiveController(DiffController):
555
 
 
556
 
    def __init__(self, path, directive, window=None):
557
 
        DiffController.__init__(self, path, directive.patch.splitlines(True),
558
 
                                window)
559
 
        self.directive = directive
560
 
        self.merge_target = None
561
 
 
562
 
    def _provide_operations(self):
563
 
        return [('Merge', self.perform_merge), ('Save', self.perform_save)]
564
 
 
565
 
    def perform_merge(self, window):
566
 
        if self.merge_target is None:
567
 
            try:
568
 
                self.merge_target = self.window._get_merge_target()
569
 
            except SelectCancelled:
570
 
                return
571
 
        tree = workingtree.WorkingTree.open(self.merge_target)
572
 
        tree.lock_write()
573
 
        try:
574
 
            try:
575
 
                merger, verified = _mod_merge.Merger.from_mergeable(tree,
576
 
                    self.directive, progress.DummyProgress())
577
 
                merger.check_basis(True)
578
 
                merger.merge_type = _mod_merge.Merge3Merger
579
 
                conflict_count = merger.do_merge()
580
 
                merger.set_pending()
581
 
                if conflict_count == 0:
582
 
                    self.window._merge_successful()
583
 
                else:
584
 
                    self.window._conflicts()
585
 
                    # There are conflicts to be resolved.
586
 
                self.window.destroy()
587
 
            except Exception, e:
588
 
                self.window._handle_error(e)
589
 
        finally:
590
 
            tree.unlock()
591
 
 
592
 
 
593
 
def iter_changes_to_status(source, target):
 
401
def _iter_changes_to_status(source, target):
594
402
    """Determine the differences between trees.
595
403
 
596
 
    This is a wrapper around iter_changes which just yields more
 
404
    This is a wrapper around _iter_changes which just yields more
597
405
    understandable results.
598
406
 
599
407
    :param source: The source tree (basis tree)
615
423
        source.lock_read()
616
424
        try:
617
425
            for (file_id, paths, changed_content, versioned, parent_ids, names,
618
 
                 kinds, executables) in target.iter_changes(source):
 
426
                 kinds, executables) in target._iter_changes(source):
619
427
 
620
428
                # Skip the root entry if it isn't very interesting
621
429
                if parent_ids == (None, None):