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

  • Committer: Szilveszter Farkas (Phanatic)
  • Date: 2007-01-29 20:59:09 UTC
  • mfrom: (126.1.3 bzr-gtk)
  • Revision ID: szilveszter.farkas@gmail.com-20070129205909-edmvt8lqfoa04pm9
Merge from integration branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
319
319
 
320
320
    def close(self, widget=None):
321
321
        self.window.destroy()
 
322
 
 
323
class CommitDialogNew(gtk.Dialog):
 
324
    """ New implementation of the Commit dialog. """
 
325
    def __init__(self, wt, wtpath, notbranch, selected=None, parent=None):
 
326
        """ Initialize the Commit Dialog. """
 
327
        gtk.Dialog.__init__(self, title="Commit - Olive",
 
328
                                  parent=parent,
 
329
                                  flags=0,
 
330
                                  buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
 
331
        
 
332
        # Get arguments
 
333
        self.wt = wt
 
334
        self.wtpath = wtpath
 
335
        self.notbranch = notbranch
 
336
        self.selected = selected
 
337
        
 
338
        # Set the delta
 
339
        self.old_tree = self.wt.branch.repository.revision_tree(self.wt.branch.last_revision())
 
340
        self.delta = self.wt.changes_from(self.old_tree)
 
341
        
 
342
        # Get pending merges
 
343
        self.pending = self._pending_merges(self.wt)
 
344
        
 
345
        # Do some preliminary checks
 
346
        self._is_checkout = False
 
347
        self._is_pending = False
 
348
        if self.wt is None and not self.notbranch:
 
349
            error_dialog(_('Directory does not have a working tree'),
 
350
                         _('Operation aborted.'))
 
351
            self.close()
 
352
            return
 
353
 
 
354
        if self.notbranch:
 
355
            error_dialog(_('Directory is not a branch'),
 
356
                         _('You can perform this action only in a branch.'))
 
357
            self.close()
 
358
            return
 
359
        else:
 
360
            if self.wt.branch.get_bound_location() is not None:
 
361
                # we have a checkout, so the local commit checkbox must appear
 
362
                self._is_checkout = True
 
363
            
 
364
            if self.pending:
 
365
                # There are pending merges, file selection not supported
 
366
                self._is_pending = True
 
367
        
 
368
        # Create the widgets
 
369
        self._button_commit = gtk.Button(_("Comm_it"), use_underline=True)
 
370
        if self._is_checkout:
 
371
            self._check_local = gtk.CheckButton(_("_Local only commit (works in checkouts)"),
 
372
                                                use_underline=True)
 
373
        self._check_strict = gtk.CheckButton(_("_Strict commit (fails if unknown files are present)"),
 
374
                                             use_underline=True)
 
375
        self._expander_files = gtk.Expander(_("Please select the file(s) to commit"))
 
376
        self._vpaned_main = gtk.VPaned()
 
377
        self._scrolledwindow_files = gtk.ScrolledWindow()
 
378
        self._scrolledwindow_message = gtk.ScrolledWindow()
 
379
        self._treeview_files = gtk.TreeView()
 
380
        self._vbox_message = gtk.VBox()
 
381
        self._label_message = gtk.Label(_("Please specify a commit message:"))
 
382
        self._textview_message = gtk.TextView()
 
383
        
 
384
        if self._is_pending:
 
385
            self._expander_merges = gtk.Expander(_("Pending merges"))
 
386
            self._vpaned_list = gtk.VPaned()
 
387
            self._scrolledwindow_merges = gtk.ScrolledWindow()
 
388
            self._treeview_merges = gtk.TreeView()
 
389
 
 
390
        # Set callbacks
 
391
        self._button_commit.connect('clicked', self._on_commit_clicked)
 
392
        self._treeview_files.connect('row_activated', self._on_treeview_files_row_activated)
 
393
        
 
394
        # Set properties
 
395
        self._scrolledwindow_files.set_policy(gtk.POLICY_AUTOMATIC,
 
396
                                              gtk.POLICY_AUTOMATIC)
 
397
        self._scrolledwindow_message.set_policy(gtk.POLICY_AUTOMATIC,
 
398
                                                gtk.POLICY_AUTOMATIC)
 
399
        self._textview_message.modify_font(pango.FontDescription("Monospace"))
 
400
        self.set_default_size(500, 500)
 
401
        self._vpaned_main.set_position(200)
 
402
 
 
403
        if self._is_pending:
 
404
            self._scrolledwindow_merges.set_policy(gtk.POLICY_AUTOMATIC,
 
405
                                                   gtk.POLICY_AUTOMATIC)
 
406
            self._treeview_files.set_sensitive(False)
 
407
        
 
408
        # Construct the dialog
 
409
        self.action_area.pack_end(self._button_commit)
 
410
        
 
411
        self._scrolledwindow_files.add(self._treeview_files)
 
412
        self._scrolledwindow_message.add(self._textview_message)
 
413
        
 
414
        self._expander_files.add(self._scrolledwindow_files)
 
415
        
 
416
        self._vbox_message.pack_start(self._label_message, False, False)
 
417
        self._vbox_message.pack_start(self._scrolledwindow_message, True, True)
 
418
        
 
419
        if self._is_pending:        
 
420
            self._expander_merges.add(self._scrolledwindow_merges)
 
421
            self._scrolledwindow_merges.add(self._treeview_merges)
 
422
            self._vpaned_list.add1(self._expander_files)
 
423
            self._vpaned_list.add2(self._expander_merges)
 
424
            self._vpaned_main.add1(self._vpaned_list)
 
425
        else:
 
426
            self._vpaned_main.add1(self._expander_files)
 
427
 
 
428
        self._vpaned_main.add2(self._vbox_message)
 
429
        
 
430
        self.vbox.pack_start(self._vpaned_main, True, True)
 
431
        if self._is_checkout:
 
432
            self.vbox.pack_start(self._check_local, False, False)
 
433
        self.vbox.pack_start(self._check_strict, False, False)
 
434
        
 
435
        # Create the file list
 
436
        self._create_file_view()
 
437
        # Create the pending merges
 
438
        self._create_pending_merges()
 
439
        
 
440
        # Expand the corresponding expander
 
441
        if self._is_pending:
 
442
            self._expander_merges.set_expanded(True)
 
443
        else:
 
444
            self._expander_files.set_expanded(True)
 
445
        
 
446
        # Display dialog
 
447
        self.vbox.show_all()
 
448
    
 
449
    def _on_treeview_files_row_activated(self, treeview, path, view_column):
 
450
        # FIXME: the diff window freezes for some reason
 
451
        treeselection = treeview.get_selection()
 
452
        (model, iter) = treeselection.get_selected()
 
453
        
 
454
        if iter is not None:
 
455
            from olive import DiffWindow
 
456
            
 
457
            _selected = model.get_value(iter, 1)
 
458
            
 
459
            diff = DiffWindow()
 
460
            parent_tree = self.wt.branch.repository.revision_tree(self.wt.branch.last_revision())
 
461
            diff.set_diff(self.wt.branch.nick, self.wt, parent_tree)
 
462
            try:
 
463
                diff.set_file(_selected)
 
464
            except errors.NoSuchFile:
 
465
                pass
 
466
            diff.show()
 
467
    
 
468
    def _on_commit_clicked(self, button):
 
469
        """ Commit button clicked handler. """
 
470
        textbuffer = self._textview_message.get_buffer()
 
471
        start, end = textbuffer.get_bounds()
 
472
        message = textbuffer.get_text(start, end).decode('utf-8')
 
473
        
 
474
        if not self.pending:
 
475
            specific_files = self._get_specific_files()
 
476
        else:
 
477
            specific_files = None
 
478
 
 
479
        if message == '':
 
480
            response = question_dialog(_('Commit with an empty message?'),
 
481
                                       _('You can describe your commit intent in the message.'))
 
482
            if response == gtk.RESPONSE_NO:
 
483
                # Kindly give focus to message area
 
484
                self._textview_message.grab_focus()
 
485
                return
 
486
 
 
487
        if self._is_checkout:
 
488
            local = self._check_local.get_active()
 
489
        else:
 
490
            local = False
 
491
        
 
492
        try:
 
493
            self.wt.commit(message,
 
494
                           allow_pointless=False,
 
495
                           strict=self._check_strict.get_active(),
 
496
                           local=local,
 
497
                           specific_files=specific_files)
 
498
        except errors.NotBranchError:
 
499
            error_dialog(_('Directory is not a branch'),
 
500
                         _('You can perform this action only in a branch.'))
 
501
            return
 
502
        except errors.LocalRequiresBoundBranch:
 
503
            error_dialog(_('Directory is not a checkout'),
 
504
                         _('You can perform local commit only on checkouts.'))
 
505
            return
 
506
        except errors.ConflictsInTree:
 
507
            error_dialog(_('Conflicts in tree'),
 
508
                         _('You need to resolve the conflicts before committing.'))
 
509
            return
 
510
        except errors.StrictCommitFailed:
 
511
            error_dialog(_('Strict commit failed'),
 
512
                         _('There are unknown files in the working tree.\nPlease add or delete them.'))
 
513
            return
 
514
        except errors.BoundBranchOutOfDate, errmsg:
 
515
            error_dialog(_('Bound branch is out of date'),
 
516
                         _('%s') % errmsg)
 
517
            return
 
518
        except errors.PointlessCommit:
 
519
            response = question_dialog(_('Commit with no changes?'),
 
520
                                       _('There are no changes in the working tree.'))
 
521
            if response == gtk.RESPONSE_YES:
 
522
                # Try to commit again
 
523
                try:
 
524
                    self.wt.commit(message,
 
525
                                   allow_pointless=True,
 
526
                                   strict=self._check_strict.get_active(),
 
527
                                   local=local,
 
528
                                   specific_files=specific_files)
 
529
                except errors.BzrError, msg:
 
530
                    error_dialog(_('Unknown bzr error'), str(msg))
 
531
                    return
 
532
                except Exception, msg:
 
533
                    error_dialog(_('Unknown error'), str(msg))
 
534
                    return
 
535
        except errors.BzrError, msg:
 
536
            error_dialog(_('Unknown bzr error'), str(msg))
 
537
            return
 
538
        except Exception, msg:
 
539
            error_dialog(_('Unknown error'), str(msg))
 
540
            return
 
541
        
 
542
        self.response(gtk.RESPONSE_OK)
 
543
 
 
544
    def _pending_merges(self, wt):
 
545
        """ Return a list of pending merges or None if there are none of them. """
 
546
        parents = wt.get_parent_ids()
 
547
        if len(parents) < 2:
 
548
            return None
 
549
        
 
550
        import re
 
551
        from bzrlib.osutils import format_date
 
552
        
 
553
        pending = parents[1:]
 
554
        branch = wt.branch
 
555
        last_revision = parents[0]
 
556
        
 
557
        if last_revision is not None:
 
558
            try:
 
559
                ignore = set(branch.repository.get_ancestry(last_revision))
 
560
            except errors.NoSuchRevision:
 
561
                # the last revision is a ghost : assume everything is new 
 
562
                # except for it
 
563
                ignore = set([None, last_revision])
 
564
        else:
 
565
            ignore = set([None])
 
566
        
 
567
        pm = []
 
568
        for merge in pending:
 
569
            ignore.add(merge)
 
570
            try:
 
571
                m_revision = branch.repository.get_revision(merge)
 
572
                
 
573
                rev = {}
 
574
                rev['committer'] = re.sub('<.*@.*>', '', m_revision.committer).strip(' ')
 
575
                rev['summary'] = m_revision.get_summary()
 
576
                rev['date'] = format_date(m_revision.timestamp,
 
577
                                          m_revision.timezone or 0, 
 
578
                                          'original', date_fmt="%Y-%m-%d",
 
579
                                          show_offset=False)
 
580
                
 
581
                pm.append(rev)
 
582
                
 
583
                inner_merges = branch.repository.get_ancestry(merge)
 
584
                assert inner_merges[0] is None
 
585
                inner_merges.pop(0)
 
586
                inner_merges.reverse()
 
587
                for mmerge in inner_merges:
 
588
                    if mmerge in ignore:
 
589
                        continue
 
590
                    mm_revision = branch.repository.get_revision(mmerge)
 
591
                    
 
592
                    rev = {}
 
593
                    rev['committer'] = re.sub('<.*@.*>', '', mm_revision.committer).strip(' ')
 
594
                    rev['summary'] = mm_revision.get_summary()
 
595
                    rev['date'] = format_date(mm_revision.timestamp,
 
596
                                              mm_revision.timezone or 0, 
 
597
                                              'original', date_fmt="%Y-%m-%d",
 
598
                                              show_offset=False)
 
599
                
 
600
                    pm.append(rev)
 
601
                    
 
602
                    ignore.add(mmerge)
 
603
            except errors.NoSuchRevision:
 
604
                print "DEBUG: NoSuchRevision:", merge
 
605
        
 
606
        return pm
 
607
 
 
608
    def _create_file_view(self):
 
609
        self._file_store = gtk.ListStore(gobject.TYPE_BOOLEAN,   # [0] checkbox
 
610
                                         gobject.TYPE_STRING,    # [1] path to display
 
611
                                         gobject.TYPE_STRING,    # [2] changes type
 
612
                                         gobject.TYPE_STRING)    # [3] real path
 
613
        self._treeview_files.set_model(self._file_store)
 
614
        crt = gtk.CellRendererToggle()
 
615
        crt.set_property("activatable", True)
 
616
        crt.connect("toggled", self._toggle_commit, self._file_store)
 
617
        self._treeview_files.append_column(gtk.TreeViewColumn(_('Commit'),
 
618
                                     crt, active=0))
 
619
        self._treeview_files.append_column(gtk.TreeViewColumn(_('Path'),
 
620
                                     gtk.CellRendererText(), text=1))
 
621
        self._treeview_files.append_column(gtk.TreeViewColumn(_('Type'),
 
622
                                     gtk.CellRendererText(), text=2))
 
623
 
 
624
        for path, id, kind in self.delta.added:
 
625
            marker = osutils.kind_marker(kind)
 
626
            self._file_store.append([ True, path+marker, _('added'), path ])
 
627
 
 
628
        for path, id, kind in self.delta.removed:
 
629
            marker = osutils.kind_marker(kind)
 
630
            self._file_store.append([ True, path+marker, _('removed'), path ])
 
631
 
 
632
        for oldpath, newpath, id, kind, text_modified, meta_modified in self.delta.renamed:
 
633
            marker = osutils.kind_marker(kind)
 
634
            if text_modified or meta_modified:
 
635
                changes = _('renamed and modified')
 
636
            else:
 
637
                changes = _('renamed')
 
638
            self._file_store.append([ True,
 
639
                                      oldpath+marker + '  =>  ' + newpath+marker,
 
640
                                      changes,
 
641
                                      newpath
 
642
                                    ])
 
643
 
 
644
        for path, id, kind, text_modified, meta_modified in self.delta.modified:
 
645
            marker = osutils.kind_marker(kind)
 
646
            self._file_store.append([ True, path+marker, _('modified'), path ])
 
647
    
 
648
    def _create_pending_merges(self):
 
649
        if not self.pending:
 
650
            return
 
651
        
 
652
        liststore = gtk.ListStore(gobject.TYPE_STRING,
 
653
                                  gobject.TYPE_STRING,
 
654
                                  gobject.TYPE_STRING)
 
655
        self._treeview_merges.set_model(liststore)
 
656
        
 
657
        self._treeview_merges.append_column(gtk.TreeViewColumn(_('Date'),
 
658
                                            gtk.CellRendererText(), text=0))
 
659
        self._treeview_merges.append_column(gtk.TreeViewColumn(_('Committer'),
 
660
                                            gtk.CellRendererText(), text=1))
 
661
        self._treeview_merges.append_column(gtk.TreeViewColumn(_('Summary'),
 
662
                                            gtk.CellRendererText(), text=2))
 
663
        
 
664
        for item in self.pending:
 
665
            liststore.append([ item['date'],
 
666
                               item['committer'],
 
667
                               item['summary'] ])
 
668
    
 
669
    def _get_specific_files(self):
 
670
        ret = []
 
671
        it = self._file_store.get_iter_first()
 
672
        while it:
 
673
            if self._file_store.get_value(it, 0):
 
674
                # get real path from hidden column 3
 
675
                ret.append(self._file_store.get_value(it, 3))
 
676
            it = self._file_store.iter_next(it)
 
677
 
 
678
        return ret
 
679
    
 
680
    def _toggle_commit(self, cell, path, model):
 
681
        model[path][0] = not model[path][0]
 
682
        return