#454: save previous content of comments after comment edition, and show last comment edition information.

diff --git a/trac/htdocs/css/ticket.css b/trac/htdocs/css/ticket.css
--- a/trac/htdocs/css/ticket.css
+++ b/trac/htdocs/css/ticket.css
@@ -90,6 +90,12 @@
  margin-left: 0.2em;
 }
 .threading { font-size: 85%; }
+#changelog .trac-lastedit {
+ margin-left: 2.5em;
+ color: #999;
+ font-size: 80%;
+}
+#changelog .trac-lastedit :link, #changelog .trac-lastedit :visited { color: inherit }
 
 #preview .changes, #changelog .changes { list-style: square; margin-left: 2em; padding: 0 }
 #preview .comment, #changelog .comment { margin-left: 2em }
diff --git a/trac/ticket/model.py b/trac/ticket/model.py
--- a/trac/ticket/model.py
+++ b/trac/ticket/model.py
@@ -367,15 +367,33 @@
         for listener in TicketSystem(self.env).change_listeners:
             listener.ticket_deleted(self)
 
-    def modify_comment(self, cnum, comment, db=None):
+    def modify_comment(self, cnum, author, comment, when=None, db=None):
+        scnum = str(cnum)
+        if when is None:
+            when = datetime.now(utc)
+        when_ts = to_timestamp(when)
+        
         db, handle_ta = self._get_db_for_write(db)
+        like = db.like()
         cursor = db.cursor()
-        cursor.execute("UPDATE ticket_change SET newvalue=%%s "
+        cursor.execute("SELECT time,newvalue FROM ticket_change "
                        "WHERE ticket=%%s AND field='comment' "
-                       "  AND (oldvalue=%%s OR oldvalue %s)"
-                       % db.like(),
-                       (comment, self.id, str(cnum),
-                        '%.' + db.like_escape(str(cnum))))
+                       "  AND (oldvalue=%%s OR oldvalue %s)" % like,
+                       (self.id, scnum, '%.' + db.like_escape(scnum)))
+        for (ts, old_comment) in cursor:
+            cursor.execute("SELECT COUNT(ticket) FROM ticket_change "
+                           "WHERE ticket=%%s AND time=%%s AND field %s" % like,
+                           (self.id, ts, db.like_escape('_comment') + '%'))
+            rev = cursor.fetchone()[0]
+            cursor.execute("INSERT INTO ticket_change "
+                           "(ticket,time,author,field,oldvalue,newvalue) "
+                           "VALUES (%s,%s,%s,%s,%s,%s)",
+                           (self.id, ts, author, '_comment%d' % rev,
+                            old_comment, str(when_ts)))
+            cursor.execute("UPDATE ticket_change SET newvalue=%s "
+                           "WHERE ticket=%s AND time=%s AND field='comment'",
+                           (comment, self.id, ts))
+            break
         if handle_ta:
             db.commit()  
 
diff --git a/trac/ticket/templates/ticket.html b/trac/ticket/templates/ticket.html
--- a/trac/ticket/templates/ticket.html
+++ b/trac/ticket/templates/ticket.html
@@ -217,7 +217,8 @@
           <h2>Change History</h2>
           <div id="changelog">
             <py:for each="change in changes">
-              <div class="change" py:with="comment_is_edited = str(change.cnum) == cnum_edit">
+              <div class="change" py:with="comment_is_edited = str(change.cnum) == cnum_edit;
+                                           show_editor = can_edit_comment and comment_is_edited">
                 <h3 class="change">
                   <span class="threading" py:if="'cnum' in change"
                         py:with="change_replies = replies.get(str(change.cnum), [])">
@@ -235,7 +236,7 @@
                   </span>
                   <i18n:msg params="date, author">Changed ${dateinfo(change.date)} ago by ${authorinfo(change.author)}</i18n:msg>
                 </h3>
-                <div py:if="not (can_edit_comment and comment_is_edited)" class="inlinebuttons">
+                <div py:if="not show_editor" class="inlinebuttons">
                   <form py:if="'cnum' in change and can_append" 
                         method="get" action="#comment" class="inlinebuttons">
                     <div>
@@ -252,7 +253,11 @@
                   </form>              
                 </div>
                 ${display_change(change)}
-                <form id="trac-comment-editor" py:if="can_edit_comment and comment_is_edited" method="post" action="#comment:${change.cnum}">
+                <div py:if="not show_editor and change.last_edit.rev >= 0" i18n:msg="date, author" class="trac-lastedit">
+                  Last edited ${dateinfo(change.last_edit.date)} ago by ${authorinfo(change.last_edit.author)}
+                  (<a href="">diff</a>)
+                </div>
+                <form id="trac-comment-editor" py:if="show_editor" method="post" action="#comment:${change.cnum}">
                   <div>
                     <textarea name="edited_comment" class="wikitext" rows="10" cols="78">
 ${[edited_comment, change.comment][edited_comment is None]}</textarea>
diff --git a/trac/ticket/web_ui.py b/trac/ticket/web_ui.py
--- a/trac/ticket/web_ui.py
+++ b/trac/ticket/web_ui.py
@@ -492,7 +492,7 @@
                 req.perm(ticket.resource).require('TICKET_EDIT_COMMENT')
                 comment = req.args.get('edited_comment')
                 cnum = req.args.get('cnum_edit')
-                ticket.modify_comment(cnum, comment)
+                ticket.modify_comment(cnum, req.authname, comment)
                 req.redirect(req.href.ticket(ticket.id))
 
             # Do any action on the ticket?
@@ -1468,7 +1468,8 @@
                     yield current
                 last_uid = uid
                 current = {'date': date, 'author': author, 'fields': {},
-                           'permanent': permanent, 'comment': ''}
+                           'permanent': permanent, 'comment': '',
+                           'last_edit': {'rev': -1}}
                 if permanent and not when:
                     autonum += 1
                     current['cnum'] = autonum
@@ -1482,6 +1483,12 @@
                     else:
                         this_num = old
                     current['cnum'] = int(this_num)
+            elif field.startswith('_comment'):      # Comment edits
+                rev = int(field[8:])
+                if rev > current['last_edit']['rev']:
+                    last_edit = datetime.fromtimestamp(int(new), utc)
+                    current['last_edit'] = {'rev': rev, 'author': author,
+                                            'date': last_edit}
             elif old or new:
                 current['fields'][field] = {'old': old, 'new': new}
         if current:

