Index: childtickets.py
===================================================================
--- childtickets.py	(revision 9850)
+++ childtickets.py	(working copy)
@@ -3,7 +3,7 @@
 import re
 
 from trac.core import *
-from trac.ticket.api import ITicketManipulator
+from trac.ticket.api import ITicketManipulator, ITicketChangeListener
 from trac.web.api import ITemplateStreamFilter, IRequestFilter
 from trac.perm import IPermissionRequestor
 from trac.ticket.model import Ticket
@@ -13,10 +13,66 @@
 from genshi.filters import Transformer
 
 class TracchildticketsModule(Component):
-    implements(ITicketManipulator, ITemplateStreamFilter, IRequestFilter)
+    implements(ITicketManipulator, ITicketChangeListener, ITemplateStreamFilter, IRequestFilter)
 
+    # ITicketChangeListener methods
+    def ticket_update_childreport(self,parent_id):
+        'Add a childreport if this ticket has children, otherwise make sure its blank'
+        # Create an instance of the parent ticket
+        pticket = Ticket(self.env, parent_id)
+        print "pticket is %s, %s" % (pticket,pticket.id,)
 
+        db = self.env.get_db_cnx()
+        cursor = db.cursor()
 
+        # If the ticket has children we add a template child report
+        cursor.execute("SELECT 1 FROM ticket_custom WHERE name='parent' AND value=%s", ('#%s' % pticket.id,))
+        if cursor.fetchone() is None: # We do not have children so don't show the field
+            childreport_template = ''
+        else: # Get the template from the config file or fallback to the plugin default
+            def legacy_table_headers(default):
+                table_headers = self.config.getlist('childtickets', 'parent.%s.table_headers' % pticket['type'], default = [])
+                if len(table_headers) == 0:
+                    return default
+                return '[[TicketQuery(format=table,parent=$TICKET,col=%s)]]' % str('|'.join(table_headers))
+            childreport_template = self.config.get(
+                  'childtickets', 'parent.%s.childreport' % pticket['type'], # define a per ticket type childreport
+                  default=legacy_table_headers( # Handle old style table_headers definitions
+                        default=self.config.get('childtickets', 'default_childreport',
+                              default='[[TicketQuery(format=table,parent=$TICKET)]]'
+                        )
+                  )
+            )
+ 
+            # The query must be filtered to only show tickets with this as a parent
+            if 'parent=$TICKET' not in childreport_template:
+                # TODO rewrite this with a regex. Administrator could put a space in between empty brackets
+                if 'TicketQuery()' in childreport_template:
+                    childreport_template = childreport_template.replace('TicketQuery()','TicketQuery(parent=$TICKET)')
+                else:
+                    childreport_template = childreport_template.replace('TicketQuery(','TicketQuery(parent=$TICKET,')
+
+        # Trac does not have a $TICKET parameter so we have to hard code it in each ticket
+        childreport_template = childreport_template.replace('$TICKET','#%s' % pticket.id)
+
+        cursor.execute("UPDATE ticket_custom SET value=%s WHERE name='childreport' AND ticket=%s", (childreport_template, pticket.id,))
+        db.commit()
+
+    def ticket_created(self,ticket):
+        if ticket.values.get('parent'):
+            print "Updating parent of new ticket"
+            return self.ticket_update_childreport(ticket.values.get('parent').lstrip('#'))
+
+    def ticket_changed(self,ticket,comment,author,old_values):
+        # If the parents changed then update the old parent
+        if old_values.get('parent'):
+            print "Updating old parent"
+            self.ticket_update_childreport(old_values.get('parent').lstrip('#'))
+        if ticket.values.get('parent'):
+            print "Updating current parent"
+            return self.ticket_update_childreport(ticket.values.get('parent').lstrip('#'))
+
+
     # IRequestFilter methods
     def pre_process_request(self, req, handler):
 
@@ -106,7 +162,6 @@
             # - If ticket has no child tickets and child tickets are NOT allowed then skip.
             # - If ticket has child tickets and child tickets are NOT allowed (ie. rules changed or ticket type changed after children were assigned),
             #   print list of tickets but do not allow any tickets to be created.
-            # - If child tickets are allowed then print list of child tickets or 'No Child Tickets' if non are currently assigned.
             # 
             if ticket and ticket.exists:
 
@@ -165,36 +220,7 @@
                 elif childtickets:
                     snippet.append(tag.div(tag.h3("Child Tickets",id="comment:child_tickets")))
 
-                # Test if the ticket has children: If so, then list in pretty table.
-                if childtickets:
-                    snippet.append(
-                            tag.div(
-                                tag.table(
-                                    tag.thead(
-                                        tag.tr(
-                                            tag.th("Ticket",class_="id"),
-                                            [ tag.th(s.title(),class_=s) for s in columns ])
-                                        ),
-                                    tag.tbody([ self._table_row(req,tkt,columns) for tkt in childtickets ]),
-                                    class_="listing tickets",
-                                    ),
-                                )
-                            )
-                elif self.config.getbool('childtickets', 'parent.%s.allow_child_tickets' % ticket['type']):
-                    snippet.append(tag.div(tag.p("NO SUB-TICKETS.")))
-
                 return stream | filter.append(snippet)
 
         return stream
 
-    def _table_row(self, req, ticket, columns):
-
-        # Is the ticket closed?
-        ticket_class = ''
-        if ticket['status'] == 'closed':
-            ticket_class = 'closed'
-
-        return tag.tr(
-                tag.td(tag.a("#%s" % ticket.id, href=req.href.ticket(ticket.id), title="Child ticket #%s" % ticket.id, class_=ticket_class), class_="id"),
-                [ tag.td(ticket[s], class_=s) for s in columns ],
-                )
