Index: tractags/api.py
===================================================================
--- tractags/api.py	(revision 1464)
+++ tractags/api.py	(revision 1869)
@@ -86,7 +86,8 @@
         args = [self.realm]
         sql = 'SELECT DISTINCT name FROM tags WHERE tagspace=%s'
         if tags:
-            sql += ' AND tags.tag IN (%s)' % ', '.join(['%s' for t in tags])
+            # 2008-12-02 george modified -- add LOWER() to ignore case
+            sql += ' AND LOWER(tags.tag) IN (%s)' % ', '.join(['LOWER(%s)' for t in tags])
             args += tags
         sql += ' ORDER by name'
         cursor.execute(sql, args)
@@ -99,7 +100,6 @@
 
         if not resources:
           return
-
         args = [self.realm] + list(resources)
         # XXX Is this going to be excruciatingly slow?
         sql = 'SELECT DISTINCT name, tag FROM tags WHERE tagspace=%%s AND ' \
@@ -192,10 +192,12 @@
         query = Query(query, attribute_handlers=all_attribute_handlers)
 
         query_tags = set(query.terms())
+#        add_warning(req, '[george is debugging] %s' % (query_tags))
         for provider in self.tag_providers:
             for resource, tags in provider.get_tagged_resources(req, query_tags):
                 if query(tags, context=resource):
                     yield resource, tags
+#                    add_warning(req, '[george is debugging] %s %s' % (resource, tags))
 
     def get_tags(self, req, resource):
         """Get tags for resource."""
Index: tractags/ticket.py
===================================================================
--- tractags/ticket.py	(revision 1464)
+++ tractags/ticket.py	(revision 1869)
@@ -14,6 +14,7 @@
 from trac.util.compat import set, sorted
 from trac.config import *
 from trac.resource import Resource
+from trac.web.chrome import add_warning
 
 
 class TicketTagProvider(Component):
@@ -39,7 +40,16 @@
     def get_tagged_resources(self, req, tags):
         if 'TICKET_VIEW' not in req.perm:
             return
-
+        # 2008-12-02 added by george, start to deal with custom fields
+        standard_fields = ['keywords','component','type','version','milestone','status','resolution','priority','severity']
+        s_fields = []
+        c_fields = []
+        for field in self.fields:
+            if field in standard_fields:
+                s_fields.append(field)
+            else:
+                c_fields.append(field)
+        # now custom field seperated with standard fields
         split_into_tags = TagSystem(self.env).split_into_tags
         db = self.env.get_db_cnx()
         cursor = db.cursor()
@@ -47,21 +57,57 @@
         ignore = ''
         if self.ignore_closed_tickets:
             ignore = " WHERE status != 'closed'"
-        sql = "SELECT * FROM (SELECT id, %s, %s AS fields FROM ticket%s) s" % (
-            ','.join(self.fields),
-            '||'.join(["COALESCE(%s, '')" % f for f in self.fields]),
+        # prepare clause for custom fields
+        left_join_clause = ''
+        field_join_clause = ''
+        for field in c_fields:
+            left_join_clause += " LEFT OUTER JOIN ticket_custom %s ON (t.id = %s.ticket AND %s.name = \'%s\') " % (field, field, field, field)
+            field_join_clause += ", %s.value " % (field)
+#            field_join_clause += ", %s.value as %s " % (field, field)
+#        add_warning(req, left_join_clause)
+#        add_warning(req, field_join_clause)
+        if s_fields:
+            comma_connector = ','
+        else:
+            comma_connector = ''
+        if s_fields and c_fields:
+            or_connector = '||'
+        else:
+            or_connector = ''
+#        sql = "SELECT * FROM (SELECT id, %s %s ,%s AS s_fields, %s AS c_fields FROM ticket t %s %s) s" % (
+        if self.fields:
+            as_fields_clause = ',%s %s %s AS fields' % (
+                '||'.join(["COALESCE(%s, '')" % f for f in s_fields]), or_connector,
+                '||'.join(["COALESCE(%s.value, '')" % f for f in c_fields]))
+        else:
+            as_fields_clause = ''
+                
+        sql = "SELECT * FROM (SELECT id %s %s %s %s FROM ticket t %s %s) s" % (
+            comma_connector, ','.join(s_fields), field_join_clause, as_fields_clause,
+#            '||'.join(["COALESCE(%s, '')" % f for f in self.fields]),
+            left_join_clause,
             ignore)
         constraints = []
         if tags:
-            constraints.append(
-                "(" + ' OR '.join(["fields LIKE %s" for t in tags]) + ")")
-            args += ['%' + t + '%' for t in tags]
-        else:
+            if s_fields and c_fields:
+                or_connector = ' OR '
+            else:
+                or_connector = ''
+            if self.fields:
+                constraints.append(
+                    "(" + ' OR '.join(["fields LIKE %s" for tt in tags]) + ")")
+#                    "(" + ' OR '.join(["s_fields LIKE %s" for tt in tags]) + ")")
+#                    "(" + ' OR '.join(["s_fields LIKE %s" for tt in tags]) + or_connector + ' OR '.join(["c_fields LIKE %s" for t in tags]) + ")")
+                args += ['%' + t + '%' for t in tags]
+        elif self.fields:
             constraints.append("fields != ''")
-
+#        add_warning(req, '%s' % sql)
         if constraints:
             sql += " WHERE " + " AND ".join(constraints)
+#        raise TracError(constraints)
         sql += " ORDER BY id"
+#        raise TracError(args)
+#        add_warning(req, '%s' % sql)
         self.env.log.debug(sql)
         cursor.execute(sql, args)
         for row in cursor:
@@ -70,9 +116,14 @@
             if 'TICKET_VIEW' not in perm or 'TAGS_VIEW' not in perm:
                 continue
             ticket_tags = split_into_tags(ttags)
-            tags = set([to_unicode(x) for x in tags])
-            if (not tags or ticket_tags.intersection(tags)):
+#            add_warning(req, '[george in debugging] %s %s' % (id, ticket_tags))
+# 2008-12-02 george modified to ignore case in query
+            temp_ticket_tags = set([to_unicode(x.lower()) for x in ticket_tags])
+            tags = set([to_unicode(x.lower()) for x in tags])
+#            if (not tags or ticket_tags.intersection(tags)):
+            if (not tags or temp_ticket_tags.intersection(tags)):
                 yield Resource('ticket', id), ticket_tags
+#                add_warning(req, '[george in debugging] %s' % ticket_tags)
 
 
     def get_resource_tags(self, req, resource):
Index: tractags/wiki.py
===================================================================
--- tractags/wiki.py	(revision 1464)
+++ tractags/wiki.py	(revision 1869)
@@ -18,7 +18,6 @@
 from genshi.builder import tag
 from genshi.filters.transform import Transformer
 
-
 class WikiTagProvider(DefaultTagProvider):
     """Tag provider for the Wiki."""
     realm = 'wiki'
@@ -51,10 +50,15 @@
     def validate_wiki_page(self, req, page):
         if req and 'TAGS_MODIFY' in req.perm(page.resource) \
                 and req.path_info.startswith('/wiki') and 'save' in req.args:
-            if self._update_tags(req, page) and \
-                    page.text == page.old_text and \
-                    page.readonly == int('readonly' in req.args):
-                req.redirect(get_resource_url(self.env, page.resource, req.href, version=None))
+# modified by george at 2008-11-25 to fix the problem of modifying page content and tag at same submit
+# not sure why the original author add so complicated judgement
+# I guess the author might try to avoid warning message of "Page not modified, showing latest version."
+# but it will confuse the user more than the warning
+#            if self._update_tags(req, page) and \
+#                    page.text == page.old_text and \
+#                    page.readonly == int('readonly' in req.args):
+#                req.redirect(get_resource_url(self.env, page.resource, req.href, version=None))        
+            self._update_tags(req, page)
         return []
 
     # IWikiChangeListener methods
Index: tractags/query.py
===================================================================
--- tractags/query.py	(revision 1464)
+++ tractags/query.py	(revision 1869)
@@ -272,7 +272,11 @@
             if not node or node.type == node.NULL:
                 return True
             elif node.type == node.TERM:
-                return node.value in terms
+            # 2008-12-02 george modified -- to ignore case in query
+                for term in terms:
+                    if node.value.lower() == term.lower():
+                        return True
+                return False
             elif node.type == node.AND:
                 return _match(node.left) and _match(node.right)
             elif node.type == node.OR:
