Index: trac/ticket/web_ui.py
===================================================================
--- trac/ticket/web_ui.py       (revision 217)
+++ trac/ticket/web_ui.py       (working copy)
@@ -257,25 +257,12 @@

         if req.method == 'POST':
             if not req.args.has_key('preview'):
-                self._do_save(req, db, ticket)
+                return self._do_save(req, db, ticket)
             else:
                 # Use user supplied values
                 ticket.populate(req.args)
                 self._validate_ticket(req, ticket)
-
-                req.hdf['ticket.action'] = action
-                req.hdf['ticket.ts'] = req.args.get('ts')
-                req.hdf['ticket.reassign_owner'] = req.args.get('reassign_owner') \
-                                                   or req.authname
-                req.hdf['ticket.resolve_resolution'] = req.args.get('resolve_resolution')
-                reporter_id = req.args.get('author')
-                comment = req.args.get('comment')
-                if comment:
-                    req.hdf['ticket.comment'] = comment
-                    # Wiki format a preview of comment
-                    req.hdf['ticket.comment_preview'] = wiki_to_html(comment,
-                                                                     self.env,
-                                                                     req, db)
+                self._populate_misc(req, db)
         else:
             req.hdf['ticket.reassign_owner'] = req.authname
             # Store a timestamp in order to detect "mid air collisions"
@@ -492,9 +479,15 @@

         # Mid air collision?
         if int(req.args.get('ts')) != ticket.time_changed:
-            raise TracError("Sorry, can not save your changes. "
-                            "This ticket has been modified by someone else "
-                            "since you started", 'Mid Air Collision')
+            self._insert_ticket_data(req, None, ticket,
+                                     req.args.get('author'))
+            self._populate_misc(req, db)
+            req.hdf.hdf.copy('newticket', req.hdf.hdf.getObj('ticket'))
+            ticket = Ticket(self.env, ticket.id, db=db)
+            self._insert_ticket_data(req, None, ticket,
+                                     req.args.get('author'))
+            self._populate_misc(req, db)
+            return 'ticket_error_midair.cs', None

         self._validate_ticket(req, ticket)

@@ -598,3 +591,18 @@
         actions = TicketSystem(self.env).get_available_actions(ticket, req.perm)
         for action in actions:
             req.hdf['ticket.actions.' + action] = '1'
+
+    def _populate_misc(self, req, db):
+        req.hdf['ticket.action'] = req.args.get('action', 'view')
+        req.hdf['ticket.ts'] = req.args.get('ts')
+        req.hdf['ticket.reassign_owner'] = req.args.get('reassign_owner') \
+                                           or req.authname
+        req.hdf['ticket.resolve_resolution'] = req.args.get('resolve_resolution')
+        reporter_id = req.args.get('author')
+        comment = req.args.get('comment')
+        if comment:
+            req.hdf['ticket.comment'] = comment
+            # Wiki format a preview of comment
+            req.hdf['ticket.comment_preview'] = wiki_to_html(
+                comment, self.env, req, db)
+
Index: templates/ticket_error_midair.cs
===================================================================
--- templates/ticket_error_midair.cs    (revision 0)
+++ templates/ticket_error_midair.cs    (revision 0)
@@ -0,0 +1,61 @@
+<?cs include "header.cs"?>
+
+<div id="ctxtnav" class="nav"></div>
+
+<div id="content" class="error">
+ <h1>Mid Air Collision</h1>
+  <div class="message">
+   <strong>Sorry, can not save your changes.</strong>
+   <p>This ticket has been modified by someone else since you started.</p>
+  </div>
+
+ <script type="text/javascript">
+   function setField(name, selector) {
+     if (selector == "") { // we want the merge field, so no need to update
+       return;
+     }
+     var key = selector + "_" + name;
+     document.getElementById(name).value = document.getElementById(key).value;
+   }
+ </script>
+ <form action="<?cs var:ticket.href ?>#preview" method="post">
+ <input type="hidden" name="author" value="<?cs var:ticket.reporter_id ?>" />
+ <table cellspacing="0" border="1">
+  <tr>
+   <th>&nbsp;</th>
+   <th colspan="2">Committed</th>
+   <th colspan="2">Yours</th>
+   <th colspan="2">Merged</th>
+  </tr><?cs
+  each:field = ticket.fields ?><?cs
+   if:ticket[name(field)] == newticket[name(field)] ?>
+   <input type="hidden" name="<?cs var:name(field) ?>" value="<?cs var:newticket[name(field)] ?>" /><?cs
+   else ?>
+    <tr>
+     <th><?cs var:name(field) ?></th>
+     <td><input type="radio" name="sel_<?cs var:name(field) ?>" id="sel_<?cs var:name(field) ?>_old" onclick="setField('<?cs var:name(field) ?>', 'old');" /></td>
+     <td><label for="sel_<?cs var:name(field) ?>_old"><?cs var:text_html(ticket[name(field)]) ?></label></td>
+     <td><input type="radio" name="sel_<?cs var:name(field) ?>" id="sel_<?cs var:name(field) ?>_new" checked="checked" onclick="setField('<?cs var:name(field)?>', 'new');" /></td>
+     <td><label for="sel_<?cs var:name(field) ?>_new"><?cs var:text_html(newticket[name(field)]) ?></label></td>
+     <td><input type="radio" name="sel_<?cs var:name(field) ?>" id="sel_<?cs var:name(field) ?>" onclick="setField('<?cs var:name(field) ?>', '');" /></td>
+     <td>
+      <input type="hidden" id="old_<?cs var:name(field) ?>" value="<?cs var:ticket[name(field)] ?>" />
+      <input type="hidden" id="new_<?cs var:name(field) ?>" value="<?cs var:newticket[name(field)] ?>" />
+      <input type="text" name="<?cs var:name(field) ?>" id="<?cs var:name(field) ?>" value="<?cs var:newticket[name(field)] ?>" onchange="document.getElementById('sel_<?cs var:name(field) ?>').checked=true;" />
+     </td>
+    </tr><?cs
+   /if ?><?cs
+  /each ?>
+  <input type="hidden" name="reassign_owner" value="<?cs var:ticket.reassign_owner ?>" />
+  <input type="hidden" name="action" value="<?cs var:ticket.action ?>" />
+  <input type="hidden" name="ts" value="<?cs var:ticket.ts ?>" />
+  <input type="hidden" name="comment" value="<?cs var:ticket.comment ?>" />
+ </table>
+
+  <div class="buttons">
+   <input type="submit" name="preview" value="Retry"  />&nbsp;
+  </div>
+ </form>
+</div>
+
+<?cs include "footer.cs"?>

