Index: trac/Query.py
===================================================================
--- trac/Query.py	(revision 1014)
+++ trac/Query.py	(working copy)
@@ -111,32 +111,31 @@
             if check:
                 del constraints[field]
 
-        def add_db_options(field, constraints, prefix, cursor, sql):
+        def add_db_options(field, constraints, prefix, cursor, sql, withnull=0):
             cursor.execute(sql)
             options = []
+            if withnull: options.append({'name': '(empty)'})
             while 1:
                 row = cursor.fetchone()
                 if not row: break
                 if row[0]: options.append({'name': row[0]})
             add_options(field, constraints, prefix, options)
 
-        add_options('status', constraints, 'query.options.',
-                    [{'name': 'new'}, {'name': 'assigned'},
-                     {'name': 'reopened'}, {'name': 'closed'}])
-        add_options('resolution', constraints, 'query.options.',
-                    [{'name': 'fixed'}, {'name': 'invalid'}, {'name': 'wontfix'},
-                     {'name': 'duplicate'}, {'name': 'worksforme'}])
         cursor = self.db.cursor()
+        add_db_options('status', constraints, 'query.options.', cursor,
+                       'SELECT name FROM enum WHERE type=\'status\' ORDER BY value')
+        add_db_options('resolution', constraints, 'query.options.', cursor,
+                       'SELECT name FROM enum WHERE type=\'resolution\' ORDER BY value')
         add_db_options('component', constraints, 'query.options.', cursor,
-                       'SELECT name FROM component ORDER BY name', )
+                       'SELECT name FROM component ORDER BY name', 1)
         add_db_options('milestone', constraints, 'query.options.', cursor,
-                       'SELECT name FROM milestone ORDER BY name')
+                       'SELECT name FROM milestone ORDER BY name', 1)
         add_db_options('version', constraints, 'query.options.', cursor,
-                       'SELECT name FROM version ORDER BY name')
+                       'SELECT name FROM version ORDER BY name', 1)
         add_db_options('priority', constraints, 'query.options.', cursor,
-                       'SELECT name FROM enum WHERE type=\'priority\'')
+                       'SELECT name FROM enum WHERE type=\'priority\' ORDER BY value')
         add_db_options('severity', constraints, 'query.options.', cursor,
-                       'SELECT name FROM enum WHERE type=\'severity\'')
+                       'SELECT name FROM enum WHERE type=\'severity\' ORDER BY value')
 
         custom_fields = get_custom_fields(self.env)
         for custom in custom_fields:
@@ -147,6 +146,7 @@
                     options[i] = {'name': options[i]}
                     if check and (options[i]['name'] in constraints[custom['name']]):
                         options[i]['selected'] = 1
+                options.insert(0, {'name': '(empty)'})
                 custom['options'] = options
         util.add_to_hdf(custom_fields, self.req.hdf, 'query.custom')
 
@@ -182,7 +182,7 @@
         if [k for k in constraints.keys() if k in custom_fields]:
             sql += ", ticket_custom.name AS name, " \
                    "ticket_custom.value AS value " \
-                   "FROM ticket OUTER JOIN ticket_custom ON id = ticket"
+                   "FROM ticket LEFT OUTER JOIN ticket_custom ON id = ticket"
         else:
             sql += " FROM ticket"
         sql += " INNER JOIN (SELECT name AS priority_name, value AS priority_value " \
@@ -195,15 +195,24 @@
             col = k
             if not col in Ticket.std_fields:
                 col = 'value'
+            empty_custom = ''
+            if len(v) != 0 and v[0] == '(empty)':
+                clause.append("IFNULL(%s, '') = ''" % col)
+                v.pop(0)
+                empty_custom = " OR id NOT IN (SELECT ticket" \
+                                             " FROM ticket_custom" \
+                                             " WHERE name = '%s') " % k
             if len(v) > 1:
                 inlist = ["'" + util.sql_escape(item) + "'" for item in v]
                 clause.append("%s IN (%s)" % (col, ", ".join(inlist)))
-            elif k in ['keywords', 'cc']:
-                clause.append("%s LIKE '%%%s%%'" % (col, util.sql_escape(v[0])))
-            else:
-                clause.append("%s = '%s'" % (col, util.sql_escape(v[0])))
+            elif len(v) != 0:
+                if k in ['keywords', 'cc']:
+                    clause.append("%s LIKE '%%%s%%'" % (col, util.sql_escape(v[0])))
+                else:
+                    clause.append("%s = '%s'" % (col, util.sql_escape(v[0])))
             if not k in Ticket.std_fields:
-                clauses.append("(name='%s' AND (" % k + " OR ".join(clause) + "))")
+                clauses.append("(name='%s' AND (" % k + 
+                               " OR ".join(clause) + ")" + empty_custom + ")")
             else:
                 clauses.append(" OR ".join(clause))
         if clauses:

