← Back to team overview

openerp-dev-web team mailing list archive

[Merge] lp:~openerp-dev/openobject-client-web/improved-custom-filters into lp:openobject-client-web

 

sma (Open ERP) has proposed merging lp:~openerp-dev/openobject-client-web/improved-custom-filters into lp:openobject-client-web.

Requested reviews:
  OpenERP SA's Web Client R&D (openerp-dev-web)


Custom Filters for search view are change now according to given link (Task 1).
http://piratepad.net/openerp-web-bugs

* Improve custom fiters, only one line: Columns, Custom Filter, Save filter, <select filter>, \h  fill Clear, Search (Fp confirm).

* If i click on  Custom filter it should display the box above like on http://trac.edgewall.org/query with 'and' and 'or'.


-- 
https://code.launchpad.net/~openerp-dev/openobject-client-web/improved-custom-filters/+merge/32975
Your team OpenERP SA's Web Client R&D is requested to review the proposed merge of lp:~openerp-dev/openobject-client-web/improved-custom-filters into lp:openobject-client-web.
=== modified file 'addons/openerp/controllers/search.py'
--- addons/openerp/controllers/search.py	2010-08-10 12:08:29 +0000
+++ addons/openerp/controllers/search.py	2010-08-18 10:51:43 +0000
@@ -184,42 +184,46 @@
 
         frm = {}
         error = ''
-        values = {}
-
-        for key, val in record.items():
-            for field in val:
-                fld = {}
-                datas = {}
-                res = proxy.fields_get(field)
-
-                fld['value'] = val[field]
-                fld['type'] = res[field].get('type')
-
-                data[field] = fld
-                try:
-                    frm = TinyForm(**data).to_python()
-                except Exception, e:
-                    error = ustr(e)
-                    error_field = ustr(e.field)
-                    return dict(error=error, error_field=error_field)
-
-                datas['rec'] = field
-
-                if fld['type'] == 'many2one':
-                    datas['rec_val'] = fld['value']
-                    frm[field] = 'many2one'
-                elif isinstance(frm[field], bool):
-                    if frm[field]:
-                        datas['rec_val'] = 1
+        All_values = {}
+        
+        for k, v in record.items():
+            values = {}
+            for key, val in v.items():                
+                for field in val:
+                    fld = {}
+                    datas = {}
+                    res = proxy.fields_get(field)
+    
+                    fld['value'] = val[field]
+                    fld['type'] = res[field].get('type')
+    
+                    data[field] = fld
+                    try:
+                        frm = TinyForm(**data).to_python()
+                    except Exception, e:
+                        error = ustr(e)
+                        error_field = ustr(e.field)
+                        return dict(error=error, error_field=error_field)
+    
+                    datas['rec'] = field
+    
+                    if fld['type'] == 'many2one':
+                        datas['rec_val'] = fld['value']
+                        frm[field] = 'many2one'
+                    elif isinstance(frm[field], bool):
+                        if frm[field]:
+                            datas['rec_val'] = 1
+                        else:
+                            datas['rec_val'] = 0
                     else:
-                        datas['rec_val'] = 0
-                else:
-                    datas['rec_val'] = frm[field]
-
-            datas['type'] = fld['type']
-            values[key] = datas
-
-        return dict(frm=values, error=error)
+                        datas['rec_val'] = frm[field]
+    
+                datas['type'] = fld['type']
+                values[key] = datas
+                
+            All_values[k] = values
+
+        return dict(frm=All_values, error=error)
 
     @expose('json')
     def eval_domain_filter(self, **kw):
@@ -275,28 +279,55 @@
                         search_data[field] = value
                     else:
                         search_data[field] = value.split('m2o_')[1]
+                        
+        def get_domain(x):
+            tempdomain = ""
+                        
+            if len(x)== 1:
+                if isinstance(x[0], (int, list)):                    
+                    tempdomain +=  ",'" + ustr(x[0]) + "',"
+                else:
+                    tempdomain +=  ",'" + x[0] + "',"
+
+            elif len(x) == 4:
+                if isinstance(x[3], (int, list)):                                    
+                    tempdomain += '[\'' + x[0] + '\', (\'' + x[1] + '\', \'' + x[2] + '\', ' + ustr(x[3]) + '\')]'                                                                
+                else:                                    
+                    tempdomain += '[\'' + x[0] + '\', (\'' + x[1] + '\', \'' + x[2] + '\', \'' + x[3] + '\')]'
+                                                
+            elif len(x) == 3:                               
+                if isinstance(x[2], (int, list)):
+                    tempdomain += '[(\'' + x[0] + '\', \'' + x[1] + '\', ' + ustr(x[2]) + ')]'
+                else:
+                    tempdomain += '[(\'' + x[0] + '\', \'' + x[1] + '\', \'' + x[2] + '\')]'
+            
+            return tempdomain
 
         inner_domain = []
         if custom_domains:
-            tmp_domain = ''
-
+            tmp_domain = ''            
             custom_domains = eval(custom_domains)
-            for inner in custom_domains:
-                if len(inner) == 4:
-                    if isinstance(inner[3], (int, list)):
-                        tmp_domain += '[\'' + inner[0] + '\', (\'' + inner[1] + '\', \'' + inner[2] + '\', ' + ustr(inner[3]) + ')]'
-                    else:
-                        tmp_domain += '[\'' + inner[0] + '\', (\'' + inner[1] + '\', \'' + inner[2] + '\', \'' + inner[3] + '\')]'
-                elif len(inner) == 3:
-                    if isinstance(inner[2], (int, list)):
-                        tmp_domain += '[(\'' + inner[0] + '\', \'' + inner[1] + '\', ' + ustr(inner[2]) + ')]'
-                    else:
-                        tmp_domain += '[(\'' + inner[0] + '\', \'' + inner[1] + '\', \'' + inner[2] + '\')]'
-
+            for i in custom_domains[:-1]:
+                if len(i):
+                    i.insert(0, '|')
+                 
+            for i in custom_domains:                
+                for inner in i:        
+                    if len(inner) == 1 and len([x for x in inner if isinstance(x, list)]) == 0:
+                        tmp_domain += ",'" + inner[0] +"',"
+                    elif len([x for x in inner if isinstance(x, list)]):
+                        for d in inner:
+                            tmp_domain += get_domain(d)                    
+                    else:
+                        tmp_domain += get_domain(inner)
+            
             if tmp_domain :
-                cust_domain = tmp_domain.replace('][', ', ')
+                cust_domain = tmp_domain                      
+                if cust_domain.find('|') != -1 or cust_domain.find('&') != -1:                
+                    tmp_domain = tmp_domain.lstrip(',')
+                    cust_domain = (tmp_domain).replace("][", ",").replace("[", "").replace("]", "")
+                                                   
                 inner_domain.extend(eval(cust_domain))
-
                 if len(inner_domain)>1 and inner_domain[-2] in ['&','|']:
                     if len(inner_domain) == 2:
                         inner_domain = [inner_domain[1]]

=== modified file 'addons/openerp/static/css/style.css'
--- addons/openerp/static/css/style.css	2010-08-18 08:49:56 +0000
+++ addons/openerp/static/css/style.css	2010-08-18 10:51:43 +0000
@@ -82,23 +82,22 @@
     width: 0%;
 }
 
-table#filter_table {
+table#filter_option_table {
     margin: 0;
 }
 
-table#filter_table td.filter_column {
-    text-align: left;
+table#filter_option_table td.filter_column {    
     padding: 0;
 }
 
-table#filter_table td.filter_column select {
+table#filter_option_table td.filter_column select {
     width: 80px;
 }
 
-table#filter_table td.filter_column input.qstring,
-table#filter_table td.filter_column select.filter_fields,
-table#filter_table td.filter_column select.expr,
-table#filter_table td.and_or select.select_andor {
+table#filter_option_table td.filter_column input.qstring,
+table#filter_option_table td.filter_column select.filter_fields,
+table#filter_option_table td.filter_column select.expr,
+table#filter_option_table td.and_or select.select_andor {
     width: 100px;
     -moz-border-radius: 3px 3px 3px 3px;
 	background: none repeat scroll 0 0 #FFFFFF;
@@ -106,19 +105,43 @@
 	vertical-align: middle;
 }
 
-#filter_table .image_col {
+#filter_option_table .image_col {
     padding-left: 0;
     padding-right: 2px;
     text-align: left;
 }
 
-table#filter_table td.and_or {
+table#filter_option_table label.and_or {
     padding-left: 5px;
     text-align: left;
 }
 
-table#filter_table td.and_or select {
-    width: 55px;
+#filter_option_table td .filter-lsep {
+	float:left;
+	line-height:50%;
+	width:47%;
+}
+
+#filter_option_table td .filter-msep {
+	float:left;
+	text-align:center;
+	width:5%;
+}
+
+#filter_option_table td .filter-rsep {
+	float:right;
+	line-height:50%;
+	width:47%;
+}
+
+#filter_option_table td .filter-hr{
+	background-color:#CCCCCC;
+	border:medium none;
+	color:#CCCCCC;
+	height:1px;
+	margin:5px 0 !important;
+	overflow:hidden;
+	padding:0;
 }
 
 /* ============== SEARCH FORM start ==============*/

=== modified file 'addons/openerp/static/javascript/search.js'
--- addons/openerp/static/javascript/search.js	2010-08-10 12:08:29 +0000
+++ addons/openerp/static/javascript/search.js	2010-08-18 10:51:43 +0000
@@ -10,7 +10,7 @@
 // It's based on Mozilla Public License Version (MPL) 1.1 with following 
 // restrictions:
 //
-// -   All names, links and logos of Tiny, OpenERP and Axelor must be 
+// -   All names, links and logos of Tiny, Open ERP and Axelor must be 
 //     kept as in original distribution without any changes in all software 
 //     screens, especially in start-up page and the software header, even if 
 //     the application source code has been changed or updated or code has been 
@@ -27,43 +27,243 @@
 //
 ////////////////////////////////////////////////////////////////////////////////
 
-function add_filter_row() {
+function add_filter_row(elem) {
+    
     var filter_table = jQuery('#filter_table');
-    var vals = ['AND', 'OR'];
+    var filter_opt_tbl = jQuery('#filter_option_table')
+    var $cls_tbody = jQuery(elem).closest("tbody")
 
-    if(filter_table.is(':hidden')) {
-        filter_table.show();
+    if (jQuery(filter_opt_tbl).find('tbody:visible').length == 1 && jQuery($cls_tbody).siblings().length == 1) {
+	    if(filter_table.is(':hidden')) {
+	        if (jQuery('label#filterlabel').text() == ''){
+	            jQuery('label#filterlabel').text(jQuery('select.filter_fields_and option:selected').text())
+	            jQuery('label#filterlabel').attr('value', jQuery(elem).val())
+	        }
+	        filter_table.show();
+	    }
     } else {
-        var old_tr = filter_table.find('tr:last');
-        old_tr.find('input.qstring').css('background', '#FFF');
+        var position_tr = jQuery($cls_tbody).find('tr:last').prev();
+
+        if (jQuery($cls_tbody).prev().attr('id') == 'filter_table') {
+            var position_tr = filter_table.find('tr:last');
+        }
+        
+        var old_tr = jQuery(filter_opt_tbl).find('tbody:first').find('tr.filter_row_class:first')            
+        old_tr.find('input.qstring').css('background', '#FFF');        
 
         var new_tr = old_tr.clone();
-
-        var qstring = new_tr.find('input.qstring').css('background', '#fff').val('');
-
-        var and_or = jQuery('<td>', {'class': 'and_or'}).appendTo(old_tr);
-
-        var select_andor = jQuery('<select>', {
-            'class': 'select_andor'
-        }).appendTo(and_or);
-        jQuery.each(vals, function (index, label) {
-            select_andor.append(jQuery('<option>').val(label).text(label));
+        new_tr.find('label#filterlabel').text(jQuery('select.filter_fields_and option:selected').text());
+        new_tr.find('label#filterlabel').attr('value', jQuery(elem).val());
+        new_tr.find('input.qstring').css('background', '#fff').val('');
+        if (new_tr.is(':hidden')) {
+            new_tr.show()
+        }
+        
+        var index_row;
+        var $curr_body = position_tr.closest('tbody')
+        $curr_body.find('label.filterlabel').each(function(i, v) {
+	        var theValue = jQuery(v).text();
+	        if (theValue == jQuery('select.filter_fields_and option:selected').text()){                          
+	            index_row = i
+	            new_tr.find('select.expr').hide()
+	            new_tr.find('label#filterlabel').hide()	           
+	            new_tr.find('label.and_or').remove()
+	            
+	            var select_andor = jQuery('<label>', {'class': 'and_or'}).text('OR');               
+	            select_andor.insertBefore(new_tr.find('input.qstring'));              
+	        }
         });
 
-        old_tr.after(new_tr);
+        if(index_row >= 0) {
+             position_tr = $curr_body.find('tr.filter_row_class')[index_row];                        
+        }
+
+        jQuery(position_tr).after(new_tr);
+    }
+    
+    if (!jQuery('select.filter_fields_or').closest("tbody").siblings().length) {
+        jQuery('select#filter_fields_or').attr('disabled', true);
+    }else{
+        jQuery('select#filter_fields_or').attr('disabled', false);
+    }
+}
+
+function addOrBlock(elem){
+    
+    var filter_option_table = jQuery('#filter_option_table');
+    var old_tr = jQuery('#filter_table').next('tbody.actions').find('tr.actions');    
+    var tbody = filter_option_table.find('tbody:last');
+   
+    var action_tr = old_tr.clone();
+    action_tr.find('select.filter_fields_or').parent().show();
+    action_tr.find('select.filter_fields_or').attr('disabled', false);        
+    if (action_tr.is(':hidden')) {
+        action_tr.show();
+    }
+    
+    var position_tr = filter_option_table.find('tr:last');
+    position_tr.find('select.filter_fields_or').parent().hide();    
+    
+    var newtbody = jQuery('<tbody>');    
+    var tr = jQuery('<tr id="or">');
+    var td = jQuery('<td>', {'colspan': '4'});
+    td.append(jQuery('<div class="filter-lsep">').append(jQuery('<hr class="filter-hr"/>')));
+    td.append(jQuery('<div class="filter-msep">Or</div>'));
+    td.append(jQuery('<div class="filter-rsep">').append(jQuery('<hr class="filter-hr"/>')));    
+    jQuery(tr).append(td)
+    jQuery(newtbody).append(tr)
+    
+    var oldTr = filter_option_table.find('tr:first');
+    var new_tr = oldTr.clone();
+    new_tr.find('label#filterlabel').text(jQuery('select.filter_fields_or option:selected').text());
+    new_tr.find('label#filterlabel').attr('value', jQuery(elem).val());    
+    new_tr.find('input.qstring').css('background', '#FFF').val('');
+    
+    jQuery(tr).after(new_tr);
+    jQuery(new_tr).after(action_tr);        
+    jQuery(tbody).after(newtbody);   
+}
+
+function switch_searchView(d) {
+    
+    var domain = eval(d)
+    var operators = [];
+    var tbodys = [];
+    var trs = 0;
+    var tbody = jQuery("<tbody/>");
+    var prev_row_field = '';
+    var old_tr = jQuery('#filter_option_table tbody:first').find('tr.filter_row_class:first');
+    var action_tbody = jQuery('#filter_option_table').find('tbody.actions');
+    var selection_options =  jQuery('tbody.actions tr.actions').find('select.filter_fields_and:first');
+    
+    jQuery('#filter_table').hide()   
+
+    for (i=0; i<domain.length; i++) {
+
+        var item = domain[i];
+        if (item.length==1) {
+            operators.push(item);            
+        }      
+        else {
+	        var new_tr = old_tr.clone();
+	        var txt =  jQuery(selection_options).find('option[value='+ item[0] + ']').text()
+	        new_tr.find('label#filterlabel').text(txt);
+	        new_tr.find('label#filterlabel').attr('value', item[0]);
+	        new_tr.find('select.expr').val(item[1]);
+	        old_tr.find('input.qstring').css('background', '#FFF').val('');
+	        new_tr.find('input.qstring').attr('value', item[2]);
+
+	        if (trs==0 || operators[operators.length-1]=='&') {
+                tbody.append(new_tr)
+                if (trs>0)
+                   operators.splice(operators.length-1, 1);
+            }
+            else if(prev_row_field!=item[0] && operators[operators.length-1]=='|') {
+                tbodys.push(tbody);
+                tbody = jQuery("<tbody/>");
+                tbody.append(new_tr);
+                trs = 1;
+                operators.splice(operators.length-1, 1);
+            }            
+            else if(prev_row_field==item[0] && operators[operators.length-1]=='|') {
+                new_tr.find('label#filterlabel').hide();
+                new_tr.find('select.expr').hide();
+                var select_andor = jQuery('<label>', {'class': 'and_or'}).text('OR');               
+                select_andor.insertBefore(new_tr.find('input.qstring'));
+                tbody.append(new_tr);
+                operators.splice(operators.length-1, 1);
+            }      
+            trs ++;            
+            prev_row_field = item[0];
+        }                
+    }
+
+    if (domain.length){
+        tbodys.push(tbody)
+        jQuery('#filters').toggleClass('group-expand group-collapse');
+        jQuery('#filter_option_table').toggle();
+        if (action_tbody.is(':visible')){ 
+            action_tbody.hide()
+        }
+    }
+
+    for (i=0; i<tbodys.length; i++) {	       
+
+        if (tbodys[i + 1]) {
+            var trOr = jQuery('<tr id="or">');
+		    var td = jQuery('<td>', {'colspan': '4'});
+		    td.append(jQuery('<div class="filter-lsep">').append(jQuery('<hr class="filter-hr"/>')));
+		    td.append(jQuery('<div class="filter-msep">Or</div>'));
+		    td.append(jQuery('<div class="filter-rsep">').append(jQuery('<hr class="filter-hr"/>')));    
+		    jQuery(trOr).append(td)
+		    tbodys[i + 1].prepend(trOr)		         
+        }
+        if (tbodys[i - 1]) {
+            tbodys[i - 1].find('tr.actions td.filter_column').hide()               
+        }
+
+        var actTr = action_tbody.find('tr.actions').clone(true);
+        actTr.find('select#filter_fields_or').attr('disabled', false);
+        jQuery(tbodys[i]).append(actTr)
+        $('#filter_option_table').append(tbodys[i])
     }
 }
 
 function remove_filter_row(element) {
+
     var node = jQuery(element).closest('tr');
+    var t = jQuery(node).closest('tbody')
+    var $paren = t.parent()
+    var prev_body = jQuery($paren.children('tbody')[t.index()-1])
+    var next_body = jQuery($paren.children('tbody')[t.index()+1])   
+
+    if (t.find('tr.filter_row_class').length <= 1 && t.attr('id')!='filter_table') {
+                
+        if (!(next_body.length >= 1) || !(prev_body.length >= 1)) {        
+            jQuery(prev_body.find('td.filter_column')).show();
+        }
+
+        jQuery(node).closest('tbody').remove();
+        
+        if (jQuery('#filter_option_table tbody:visible').length == 2 ) {            
+            var body_next = jQuery('#filter_option_table').find('tbody:first')
+            jQuery(body_next).find('#or').remove()
+        }        
+    }
+    
     if(node.is(':only-child')) {
+
+        if (jQuery('#filter_option_table tbody:visible').length >= 1 && node.closest("tbody").siblings().length > 1){            
+            jQuery('#filter_table').next().hide()
+            jQuery('#filter_option_table').find('tr#or:first').hide()
+        }
+
         node.find('input.qstring').css('background', '#FFF').val('');
-        jQuery('#filter_table').hide();
+        jQuery('label#filterlabel').text('')
+        jQuery('label#filterlabel').attr('value', '')
+        jQuery('select#filter_fields_or').attr('disabled', true)
+        jQuery('#filter_table').hide();        
+	    
     } else {
+
         if(node.is(':last-child')) {
             node.prev().find('.and_or').remove();
         }
-        node.remove();
+
+        if(node.next().find('label.and_or').is(':visible')){             
+             node.next().remove();
+        }
+        else{
+			if (jQuery('#filter_option_table tbody:visible').length == 0) {
+			    jQuery('tbody.actions').show()
+			    jQuery('tbody.actions').find('tr.actions').find('td.filter_column').show()                
+			}
+			
+			if (jQuery('#filter_option_table tbody:visible').length == 1){   
+	           jQuery('#filter_option_table').find('tr#or:first').hide()
+	        }
+	        node.remove();            
+        }
     }
 }
 
@@ -74,86 +274,141 @@
 function isOrderable(type) {
     return jQuery.inArray(type, ['integer', 'float', 'date', 'datetime', 'boolean']) != -1;
 }
-function display_Customfilters(all_domains, group_by_ctx) {
-    var record = {};
-
-    var children = jQuery('#filter_table tr.filter_row_class');
-    children.each(function () {
-        var $constraint_value = jQuery(this).find('input.qstring');
-        var $fieldname = jQuery(this).find('select.filter_fields');
-
-        var id = jQuery(this).parent().find('> .filter_row_class').index(this);
-
-        if($constraint_value.val()) {
-            var rec = {};
-            rec[$fieldname.val()] = $constraint_value.val();
-            record[id] = rec;
-        }
+
+/**
+ * To return the keys of an object. use jQuery.keys(obj).
+*/
+jQuery.extend({
+    keys: function(obj){
+        var a = [];
+        $.each(obj, function(k){ a.push(k) });
+        return a;
+    }
+})
+
+function display_Customfilters(all_domains, group_by_ctx) {    
+    var Allrecords = {};
+    var parent_tbody = jQuery('#filter_option_table > tbody')
+
+    parent_tbody.each(function () {
+	    var children = jQuery(this).find('> .filter_row_class');	    
+	    var record = {};
+	    var pid = jQuery(this).index()
+
+	    children.each(function () {
+	        var $constraint_value = jQuery(this).find('input.qstring');
+	        var $fieldname = jQuery(this).find('label.filterlabel');
+	        var id = jQuery(this).parent().find('> .filter_row_class').index(this);
+
+	        if($constraint_value.val()) {
+	            var rec = {};
+	            rec[$fieldname.attr('value')] = $constraint_value.val();
+	            record[id] = rec;
+	        }
+	    });
+
+	    if (jQuery.keys(record).length != 0){
+	       Allrecords[pid] = record;
+	    }
     });
-
+    
     openobject.http.postJSON('/openerp/search/get', {
-        record: serializeJSON(record),
+        record: serializeJSON(Allrecords),
         _terp_model: jQuery('#_terp_model').val()
     }).addCallback(function(obj) {
         var custom_domain = [];
         if(obj.error) {
+            var children = jQuery('#filter_option_table tbody').find('> .filter_row_class')
             children.each(function () {
-                if(jQuery(this).find('select.filter_fields').val() == obj['error_field']) {
+                if(jQuery(this).find('label.filterlabel').attr('value') == obj['error_field']) {
                     jQuery(this).find('input.qstring').css('background', '#f66').val(obj.error);
                 }
             });
         }
         var form_result = obj.frm;
+        var tbody_keys = jQuery.keys(form_result)
+
         if(form_result) {
             // By property, we get incorrect ordering
-            for(var index = 0; ; ++index) {
-                if(!(index in form_result)) { break; }
-
-                var return_record = form_result[index];
-                var temp_domain = [];
-
-                var $row = jQuery('tr.filter_row_class').eq(index);
-
-                var type = return_record.type;
-
-                var grouping = $row.find('select.select_andor').val();
-                if(grouping) {
-                    temp_domain.push(grouping == 'AND' ? '&' : '|');
-                }
-
-                var field = return_record['rec'];
-                var comparison = $row.find('select.expr').val();
-                var value = return_record['rec_val'];
-
-                switch (comparison) {
-                    case 'ilike':
-                    case 'not ilike':
-                        if(isOrderable(type)) {
-                            comparison = (comparison == 'ilike' ? '=' : '!=');
-                        }
-                        break;
-                    case '<':
-                    case '>':
-                        if(!isOrderable(type)) {
-                            comparison = '=';
-                        }
-                        break;
-                    case 'in':
-                    case 'not in':
-                        if(typeof value == 'string') {
-                            value = value.split(',');
-                        } else {
-                            /* very weird array-type construct
-                               looks a bit like [[6, 0, [list of ids here]]]
-                             */
-                            value = value[value.length - 1][value[value.length - 1].length - 1]
-                        }
-                        break;
-                }
-
-                temp_domain.push(field, comparison, value);
-                custom_domain.push(temp_domain);
-            }
+            for(var ind=0; ind<tbody_keys.length ;ind++){
+                var All_domain = [];
+                var group = []
+                var tbody_frm_ind = form_result[tbody_keys[ind]]; //tbody dictionary
+                var trs_keys = jQuery.unique(jQuery.keys(tbody_frm_ind)); //sort trs
+
+                for(index = 0; index<trs_keys.length ; index++) {
+	                var return_record = tbody_frm_ind[trs_keys[index]];
+	                var $curr_body = jQuery('#filter_option_table > tbody').eq(tbody_keys[ind]);              	                
+	                var $row = jQuery($curr_body.find('> .filter_row_class').eq(trs_keys[index]));                	                
+	                var $next_row = []
+
+	                if (jQuery($row.next('tr.filter_row_class')).find('input.qstring').val() != ''){
+	                       $next_row = jQuery($row.next());
+	                }
+
+	                var type = return_record.type;	                
+	                var temp_domain = [];
+	                var grouping = $next_row.length != 0 ? $next_row.find('label.and_or').text(): null;
+
+	                if (group.length==0) {
+                        var new_grp = $curr_body.find('tr.filter_row_class:gt('+trs_keys[index]+')')
+                        new_grp = new_grp.find('td.filter_column:not(:has(label))').find('input.qstring[value]')                        
+                        if (new_grp.length){
+                            group.push('&')
+                        }
+                    }
+                    if(grouping) {
+                        temp_domain.push(grouping == 'AND' ? '&' : '|');                        
+                    }
+
+	                var field = return_record['rec'];
+	                var comparison = $row.find('select.expr').val();	                
+	                var value = return_record['rec_val'];
+
+	                switch (comparison) {
+	                    case 'ilike':
+	                    case 'not ilike':
+	                        if(isOrderable(type)) {
+	                            comparison = (comparison == 'ilike' ? '=' : '!=');
+	                        }
+	                        break;
+	                    case '<':
+	                    case '>':
+	                        if(!isOrderable(type)) {
+	                            comparison = '=';
+	                        }
+	                        break;
+	                    case 'in':
+	                    case 'not in':
+	                        if(typeof value == 'string') {
+	                            value = value.split(',');
+	                        } else {
+	                            /* very weird array-type construct
+	                               looks a bit like [[6, 0, [list of ids here]]]
+	                             */
+	                            value = value[value.length - 1][value[value.length - 1].length - 1]
+	                        }
+	                        break;
+	                }
+	                
+	                if ($row.find('label.and_or').length>0 || grouping){                       
+                        temp_domain.push(field, comparison, value);
+                        group.push(temp_domain);
+                    }
+                    else{
+                        group.push(field, comparison, value)
+                    }
+
+                    if (!grouping) {             
+                        All_domain.push(group);                        
+                        group = [];
+                    }     	                
+	            }
+
+	            if (All_domain.length) {
+	               custom_domain.push(All_domain);
+	            }
+            };
         }
         final_search_domain(serializeJSON(custom_domain), all_domains, group_by_ctx);
     });
@@ -257,11 +512,9 @@
 
 function search_filter(src, id) {
     var all_domains = parse_filters(src, id);
-    var filters = jQuery('#filter_table');
-    if(filters.is(':visible') || jQuery('#_terp_filter_domain').val() != '[]') {
-        if (filters.is(':hidden')){
-            filters.show();
-        }
+    var filters = jQuery('#filter_table');    
+    
+    if(filters.is(':visible') || jQuery('#_terp_filter_domain').val() != '[]') {        
         display_Customfilters(all_domains, group_by);
     } else {
         var custom_domain = jQuery('#_terp_filter_domain').val() || '[]';

=== modified file 'addons/openerp/widgets/search.py'
--- addons/openerp/widgets/search.py	2010-08-10 12:08:29 +0000
+++ addons/openerp/widgets/search.py	2010-08-18 10:51:43 +0000
@@ -217,7 +217,7 @@
     template = "templates/search.mako"
     javascript = [JSLink("openerp", "javascript/search.js", location=locations.bodytop)]
 
-    params = ['fields_type', 'filters_list', 'operators_map', 'fields_list', 'filter_domain']
+    params = ['fields_type', 'filters_list', 'operators_map', 'fields_list', 'filter_domain', 'flt_domain']
     member_widgets = ['frame']
 
     _notebook = Notebook(name="search_notebook")
@@ -251,20 +251,13 @@
 
         if isinstance (self.search_view, basestring):
             self.search_view = eval(self.search_view)
-
+        
         if not self.search_view:
-            self.search_view = cache.fields_view_get(self.model, view_id, 'search', ctx, True)
-
+            self.search_view = cache.fields_view_get(self.model, view_id, 'search', ctx, True)            
+            
         self.fields_list = []
-        fields = self.search_view['fields']
-
-        for k,v in fields.items():
-            if v['type'] in ('many2one', 'char', 'float', 'integer', 'date',
-                             'datetime', 'selection', 'many2many', 'boolean',
-                             'one2many') and v.get('selectable',  False):
-                self.fields_list.append((k, v['string'], v['type']))
-        if self.fields_list:
-            self.fields_list.sort(lambda x, y: cmp(x[1], y[1]))
+        fields = self.search_view.get('fields')       
+        
         try:
             dom = xml.dom.minidom.parseString(self.search_view['arch'])
         except:
@@ -300,7 +293,15 @@
                                                 'translate': new_field['translate'],
                                                 'selectable': new_field['selectable']}
             self.fields.update(field_dict)
-
+           
+        for k,v in self.fields.items():
+            if v['type'] in ('many2one', 'char', 'float', 'integer', 'date',
+                             'datetime', 'selection', 'many2many', 'boolean',
+                             'one2many') and v.get('selectable',  False):
+                self.fields_list.append((k, v['string'], v['type']))
+        if self.fields_list:
+            self.fields_list.sort(lambda x, y: cmp(x[1], y[1]))
+        
         self.frame = self.parse(model, dom, self.fields, values)
         if self.frame:
             self.frame = self.frame[0]
@@ -320,11 +321,9 @@
             ('=', _('is equal to')), ('<>', _('is not equal to')),
             ('>', _('greater than')), ('<', _('less than')),
             ('in', _('in')), ('not in', _('not in'))]
-
-        if self.filter_domain == []:
-            self.filter_domain += [(self.fields_list[0][0], self.operators_map[0][0], '')]
-        else:
-            self.custom_filter_domain = self.filter_domain
+        
+        self.flt_domain = str(self.filter_domain).replace("(", "[").replace(')', ']')
+        self.custom_filter_domain = self.filter_domain
 
     def parse(self, model=None, root=None, fields=None, values={}):
 

=== modified file 'addons/openerp/widgets/templates/search.mako'
--- addons/openerp/widgets/templates/search.mako	2010-08-04 08:22:51 +0000
+++ addons/openerp/widgets/templates/search.mako	2010-08-18 10:51:43 +0000
@@ -2,41 +2,69 @@
 	% if frame:
 		${display_member(frame)}
 	% endif
-	<table id="filter_table" style="display: none;">
-		% for f,k in enumerate(filter_domain):
-			% if len(k) >1:
-			    <tr class="filter_row_class">
-                    <td class="image_col">
-                        <button onclick="remove_filter_row(this); return false;">
-                            <img alt="Remove filter row" src="/openerp/static/images/button-b-icons-remove.gif"/>
-                        </button>
-                    </td>
-					<td align="right" class="filter_column">
-						<select class="filter_fields">
-							% for field in fields_list:
-								<option kind="${field[2]}" value="${field[0]}" ${py.selector(field[0]==k[0])}>${field[1]}</option>
-							% endfor
-					       </select>
-						<select class="expr">
-							% for operator, description in operators_map:
-								<option value="${operator}" ${py.selector(operator==k[1])}>${description}</option>
-							% endfor
-						</select>
-					       <input type="text" class='qstring' value="${k[2] or ''}" />
-					</td>
-					% if len(filter_domain[f -1]) == 1:
-					<td class="and_or">
-						<select class="select_andor">
-						% if filter_domain[f-1] == '&':
-							<option value="AND">AND</option>
-						%else:
-							<option value="OR">OR</option>
-						% endif
-						</select>
-					</td>
-					% endif
-			    </tr>
-			% endif
-		% endfor
-	</table>
+	
+	<table>
+        <tr>
+           <td style="padding:4px; white-space:nowrap;">
+                <div id="filters" class="group-expand"><h2><span>Filters</span></h2></div>
+                <table id="filter_option_table" style="display:none;">
+	                <tbody id="filter_table" style="display:none;">					
+					    <tr class="filter_row_class">
+		                    <td class="image_col">
+		                        <button onclick="remove_filter_row(this); return false;">
+		                            <img alt="Remove filter row" src="/openerp/static/images/button-b-icons-remove.gif"/>
+		                        </button>
+		                    </td>
+		                    <td class="filterlabel">
+                                   <label id="filterlabel" value="" class="filterlabel"></label>
+                               </td>
+                               <td>
+                                <select class="expr">
+                                     % for operator, description in operators_map:
+                                         <option value="${operator}" >${description}</option>
+                                     % endfor
+                                </select>
+                               </td>
+							<td align="right" class="filter_column">
+							    <input type="text" class='qstring' value="" />
+							</td>
+					    </tr>
+					</tbody>
+					<tbody class="actions">
+						<tr class="actions">
+	                        <td style="white-space:nowrap;">
+	                            <label for="add_filter_and">And</label>
+	                            <select class="filter_fields_and" onchange="add_filter_row(this); return jQuery('select.filter_fields_and').val('');">
+	                               <option></option>
+	                               % for field in fields_list:
+	                                   <option kind="${field[2]}" value="${field[0]}">${field[1]}</option>
+	                               % endfor
+	                            </select>
+	                        </td>                       
+	                        <td class="filter_column" colspan="2" style="text-align:right; white-space:nowrap;">
+	                            <label for="add_filter_or">OR</label>
+	                            <select id="filter_fields_or" disabled="disabled" class="filter_fields_or" onchange="addOrBlock(this); return jQuery('select.filter_fields_or').val('');">
+	                                <option></option>
+	                                % for field in fields_list:
+	                                    <option kind="${field[2]}" value="${field[0]}">${field[1]}</option>
+	                                % endfor
+	                            </select>
+	                        </td>
+	                    </tr>
+	                </tbody>
+				</table>
+		   </td>
+	    </tr>
+    </table>
+    <script type="text/javascript">
+		jQuery('#filters').click(function() {
+		    jQuery(this).toggleClass('group-expand group-collapse');
+		    jQuery('#filter_option_table').toggle();		    
+		});
+		
+		jQuery(document).ready(function () {
+		    
+            switch_searchView("${flt_domain | n}");
+		});
+    </script>	
 </div>

=== modified file 'addons/openerp/widgets/templates/viewform.mako'
--- addons/openerp/widgets/templates/viewform.mako	2010-07-15 12:54:38 +0000
+++ addons/openerp/widgets/templates/viewform.mako	2010-08-18 10:51:43 +0000
@@ -25,19 +25,9 @@
             <td valign="top">${display_member(search)}</td>
         </tr>
         <tr>
-            <td class="view_form_options" align="left">
-                <div>
-                    <button onclick="add_filter_row(); return false;">
-                        <img src="/openerp/static/images/button-b-icons-add.gif" alt="Add custom filtering row">
-                    </button>
-                </div>
-                <div>
-                    <button title="${_('Filter records.')}" onclick="search_filter(); return false;"
-                            >${_("Filter")}</button>
-                    <button title="${_('Clear all .')}" id="clear_all_filters" class="${css_clear}"
-                            onclick="new ListView('_terp_list').clear(); return false;"
-                            >${_("Clear")}</button>
-                    <div class="custom-filter">
+            <td class="view_form_options" align="left">                
+                <div>                    
+                    
                         <button title="${_('Save Filter.')}"
                                 onclick="save_filter(); return false;"
                                 >${_("Save Filter")}</button>
@@ -50,7 +40,14 @@
                             <option value="${f[0]}">${f[1]}</option>
                             % endfor
                         </select>
-                    </div>
+                    
+                    <div align="right">
+	                    <button title="${_('Filter records.')}" onclick="search_filter(); return false;"
+	                            >${_("Search")}</button>
+	                    <button title="${_('Clear all .')}" id="clear_all_filters" class="${css_clear}"
+	                            onclick="new ListView('_terp_list').clear(); return false;"
+	                            >${_("Clear")}</button>
+	                </div>
                 </div>
             </td>
         </tr>


Follow ups