Index: trac/ticket/query.py
===================================================================
--- trac/ticket/query.py	(revision 8678)
+++ trac/ticket/query.py	(working copy)
@@ -953,7 +953,7 @@
                         index = int(match.group(2))
                     remove_constraints[k[10:match.end(1)]] = index
             
-            # Get constraints from form fields, and add a coonstraint if
+            # Get constraints from form fields, and add a constraint if
             # requested for clients without JavaScript
             add_num = None
             constraints = {}
@@ -992,7 +992,8 @@
                     clause = constraints.setdefault(clause_num, {})
                     clause.setdefault(field, []).extend(vals)
             if add_num is not None:
-                field = req.args.get('add_filter_' + add_num)
+                field = req.args.get('add_filter_' + add_num,
+                                     req.args.get('add_clause_' + add_num))
                 if field:
                     clause = constraints.setdefault(int(add_num), {})
                     modes = Query.get_modes().get(fields[field]['type'])
@@ -1009,10 +1010,6 @@
                 clauses[-1].setdefault(field, []).append(val)
         clauses = filter(None, clauses)
         
-        # Add a new empty clause for non-JavaScript clients if requested
-        if req is not None and req.args.get('add_clause'):
-            clauses.append({})
-        
         return clauses
 
     def display_html(self, req, query):
Index: trac/ticket/templates/query.html
===================================================================
--- trac/ticket/templates/query.html	(revision 8678)
+++ trac/ticket/templates/query.html	(working copy)
@@ -122,7 +122,7 @@
                     </tr>
                   </tbody>
 
-                  <tbody py:with="last_clause = clause_num == len(clauses) - 1">
+                  <tbody py:with="last_clause = clause_num == (len(clauses) or 1) - 1">
                     <tr class="actions">
                       <td class="and" colspan="2">
                         &nbsp;<label for="add_filter_${clause_num}">And</label>&nbsp;
@@ -132,15 +132,22 @@
                                   value="$field_name"
                                   disabled="${(field.type in ('radio', 'checkbox', 'id') and
                                                field_name in constraints and
-                                               len(constraints[field_name])) or None}">${fields[field_name].label}</option>
+                                               len(constraints[field_name])) or None}">${field.label}</option>
                         </select>
                         <div class="inlinebuttons">
                           <input type="submit" name="add_${clause_num}" value="+" />
                         </div>
                       </td>
                       <td py:if="last_clause" class="or" colspan="2">
+                        <label for="add_clause">Or</label>&nbsp;
+                        <select name="add_clause_${clause_num + 1}" id="add_clause">
+                          <option></option>
+                          <option py:for="field_name in field_names" value="$field_name">
+                            ${fields[field_name].label}
+                          </option>
+                        </select>
                         <div class="inlinebuttons">
-                          <input type="submit" name="add_clause" id="add_clause" value="Or..." />
+                          <input type="submit" name="add_${clause_num + 1}" value="+" />
                         </div>
                       </td>
                     </tr>
Index: trac/htdocs/js/query.js
===================================================================
--- trac/htdocs/js/query.js	(revision 8678)
+++ trac/htdocs/js/query.js	(working copy)
@@ -33,6 +33,9 @@
         var ctbody = table.closest("tbody");
         if (table.children().length > 2 || !ctbody.siblings().length) {
           tbody.remove();
+          if (!ctbody.siblings().length && table.children().length == 1) {
+            $("#add_clause").attr("disabled", true);
+          }
         } else {
           var add_clause = $("#add_clause", ctbody);
           if (add_clause.length)
@@ -110,7 +113,7 @@
     $("#filters select[name^=add_filter_]").change(function() {
       if (this.selectedIndex < 1)
         return;
-      
+
       if (this.options[this.selectedIndex].disabled) {
         // IE doesn't support disabled options
         alert("A filter already exists for that property");
@@ -219,33 +222,43 @@
         this.options[this.selectedIndex].disabled = true;
       
       this.selectedIndex = 0;
+
+      // Enable the Or... button if it's been disabled
+      $("#add_clause").attr("disabled", false);
     }).next("div.inlinebuttons").remove();
     
     // Add a new empty clause at the end by cloning the current last clause
-    function addClause(button) {
-      var tbody = $(button).closest("tbody");
-      var clauseNum = parseInt($("select[name^=add_filter_]", tbody)
-                               .attr("name").split("_").pop()) + 1;
-      tbody = tbody.parents("tbody").eq(0);
+    function addClause(select) {
+      var tbody = $(select).closest("tbody");
+      var clauseNum = parseInt($(select).attr("name").split("_").pop());
+      var tbody = $(select).closest("tbody").parents("tbody").eq(0);
       var copy = tbody.clone(true);
-      $(button).closest("td").next().attr("colSpan", 4).end().remove();
-      $("td.trac-clause-sep", copy).parent().removeAttr("style");
+      $(select).closest("td").next().attr("colSpan", 4).end().remove();
+      $("tr:first", copy).removeAttr("style");
       $("tr tbody:not(:last)", copy).remove();
       var newId = "add_filter_" + clauseNum;
-      $("select", copy).attr("id", newId).attr("name", newId)
+      $("select[name^=add_filter_]", copy).attr("id", newId)
+        .attr("name", newId)
         .children().enable().end()
         .prev().attr("for", newId);
+      $("select[name^=add_clause_]", copy)
+        .attr("name", "add_clause_" + (clauseNum + 1));
       tbody.after(copy);
     }
     
-    // Make the button for adding a clause a client-side trigger
-    var add_clause = $("#filters input[name=add_clause]");
-    add_clause.replaceWith(
-      $($.template('<input type="button" id="add_clause" value="$1">', 
-                   add_clause.val())).click(function() {
+    var add_clause = $("#add_clause");
+    add_clause.change(function() {
+      // Add a new clause and fire a change event on the new clause's
+      // add_filter select.
+      var field = $(this).val();
       addClause(this);
-      return false;
-    }));
+      $("#add_clause").closest("tr").find("select[name^=add_filter_]")
+        .val(field).change();
+    }).next("div.inlinebuttons").remove();
+    if (!add_clause.closest("tbody").siblings().length) {
+      // That is, if there are no filters added to this clause
+      add_clause.attr("disabled", true);
+    }
   }
 
 })(jQuery);

