← Back to team overview

openerp-dev-web team mailing list archive

[Merge] lp:~openerp-dev-web/openobject-client-web/group_by into lp:~openerp-dev/openobject-client-web/trunk-dev-web

 

vda(Open ERP) has proposed merging lp:~openerp-dev-web/openobject-client-web/group_by into lp:~openerp-dev/openobject-client-web/trunk-dev-web.

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


Improved Group-by
(multiple group-by)
-- 
https://code.launchpad.net/~openerp-dev-web/openobject-client-web/group_by/+merge/25140
Your team OpenERP SA's Web Client R&D is requested to review the proposed merge of lp:~openerp-dev-web/openobject-client-web/group_by into lp:~openerp-dev/openobject-client-web/trunk-dev-web.
=== modified file 'addons/openerp/controllers/listgrid.py'
--- addons/openerp/controllers/listgrid.py	2010-05-10 12:50:52 +0000
+++ addons/openerp/controllers/listgrid.py	2010-05-12 11:20:48 +0000
@@ -28,7 +28,7 @@
 ###############################################################################
 import cherrypy
 from openerp.controllers import SecuredController
-from openerp.utils import rpc, TinyDict, TinyForm, TinyFormError, context_with_concurrency_info
+from openerp.utils import rpc, TinyDict, TinyForm, TinyFormError, context_with_concurrency_info, cache
 from openerp.widgets import listgrid
 
 import form
@@ -126,7 +126,22 @@
                 error = ustr(e)
                 
         return dict(error=error)
-
+    
+    @expose()
+    def multiple_groupby(self, model, name, grp_domain, group_by, view_id, view_type, parent, padding, groups):
+        grp_domain = ast.literal_eval(grp_domain)
+        view = cache.fields_view_get(model, view_id, view_type, rpc.session.context.copy(), True, True)
+        group_by = ast.literal_eval(group_by)
+        domain = grp_domain
+        padding = ast.literal_eval(padding)
+        groups = ast.literal_eval(groups)
+        context = {'group_by_no_leaf': False, 'group_by': group_by, '__domain': domain}
+        args = {'editable': True, 'view_mode': ['tree', 'form', 'calendar', 'graph'], 'nolinks': 1, 'group_by_ctx': group_by, 'selectable': 2, 'multiple_group_by': True}
+        
+        from openerp import widgets as tw
+        listgrp = tw.listgroup.MultipleGroup(name, model, view, ids=None, domain= domain, parent=parent, padding=padding, groups=groups, context=context, **args)
+        return listgrp.render()
+    
     @expose('json')
     def get(self, **kw):
         params, data = TinyDict.split(kw)

=== modified file 'addons/openerp/static/javascript/listgrid.js'
--- addons/openerp/static/javascript/listgrid.js	2010-05-06 06:24:46 +0000
+++ addons/openerp/static/javascript/listgrid.js	2010-05-12 11:20:48 +0000
@@ -308,6 +308,46 @@
         	this.sort_key_order = order;
         }
     },
+    
+    group_by: function(id, record, group) {
+    	var group_by_context = jQuery('[records="'+record+'"]').attr('grp_context');
+    	var domain = jQuery('[records="'+record+'"]').attr('grp_domain');
+    	var group_id = jQuery(group).attr('id').split('img_')[1];
+    	var total_groups = jQuery('table[id="'+this.name+'"]').attr('groups')
+    	
+    	if(group_by_context == '[]') {
+    		
+    		if(jQuery('[records="'+record+'"]').attr('parent')) {
+    			jQuery('[parent_grp_id="'+id+'"][id$="'+record+'"]').toggle()
+    		}
+    		else {
+    			jQuery('[parent_grp_id="'+id+'"][id$="'+record+'"]').toggle()
+    		}
+    		
+    		jQuery(group).toggleClass('group_collapse',200)
+    	}
+    	else {
+    		if(jQuery(group).attr('class').indexOf('collapse') < 0) {
+    			
+    			jQuery.ajax({
+						url: '/listgrid/multiple_groupby',
+						type: 'POST',
+						data : {'model': this.model, 'name': this.name, 'grp_domain': domain, 'group_by': group_by_context, 'view_id': jQuery('#_terp_view_id').val(), 'view_type': jQuery('#_terp_view_type').val(), 'parent': record, 'padding': jQuery(group).parent().index()+1, 'groups': total_groups},
+						dataType: 'html',
+						success: function(xmlHttp) {
+							jQuery('[records="'+record+'"]').after(xmlHttp);
+						}
+					})
+    			
+				jQuery(group).toggleClass('group_collapse',200)
+    		}
+    		else {
+    			jQuery('[parent="'+record+'"]').remove()
+    			jQuery(group).toggleClass('group_collapse',200)
+    		}
+    	}
+    	
+	},
 
     groupbyDrag: function(drag, drop) {
         var view = jQuery('table.grid[id$=grid]').attr('id').split("_grid")[0];

=== modified file 'addons/openerp/static/javascript/search.js'
--- addons/openerp/static/javascript/search.js	2010-04-27 07:19:17 +0000
+++ addons/openerp/static/javascript/search.js	2010-05-12 11:20:48 +0000
@@ -256,6 +256,8 @@
 	});	
 }
 
+var group_by = new Array();
+
 var search_filter = function(src, id) {
 	var all_domains = {};
 	var check_domain = 'None';
@@ -269,10 +271,16 @@
 		if(src.checked==false) {
 			src.checked = true
 			id.className = 'active_filter';
+			if(jQuery(src).attr('group_by_ctx')) {
+				group_by.push(jQuery(src).attr('group_by_ctx'))
+			}
 		}
 		else {
 			src.checked = false
 			id.className = 'inactive_filter';
+			group_by = jQuery.grep(group_by, function(grp) {
+				return grp != jQuery(src).attr('group_by_ctx');
+			})
 		}
 	}
 	var filter_table = $('filter_table');
@@ -304,13 +312,13 @@
 		if (box.id && box.checked && box.value != '[]') {
 			all_boxes = all_boxes.concat(box.value);
 		}
-		if (box.id && box.checked && getNodeAttribute(box, 'group_by_ctx').length > 0) {
-    		group = getNodeAttribute(box, 'group_by_ctx');
-    		group_by_ctx = group_by_ctx.concat(group);
-		}
+//		if (box.id && box.checked && getNodeAttribute(box, 'group_by_ctx').length > 0) {
+//    		group = getNodeAttribute(box, 'group_by_ctx');
+//    		group_by_ctx = group_by_ctx.concat(group);
+//		}
 	});
 	
-	openobject.dom.get('_terp_group_by_ctx').value = group_by_ctx;
+	openobject.dom.get('_terp_group_by_ctx').value = group_by;
 	
 	checked_button = all_boxes.toString();
 	check_domain = checked_button.length > 0? checked_button.replace(/(]\,\[)/g, ', ') : 'None';
@@ -327,11 +335,11 @@
 		if (filter_table.style.display == 'none'){
 			filter_table.style.display = '';
 		}		
-		display_Customfilters(all_domains, group_by_ctx);
+		display_Customfilters(all_domains, group_by);
 	}
 	else {
 		custom_domain = fil_dom ? fil_dom.value : '[]';		
-		final_search_domain(custom_domain, all_domains, group_by_ctx);	
+		final_search_domain(custom_domain, all_domains, group_by);	
 	}
 }
 

=== modified file 'addons/openerp/widgets/form/_form.py'
--- addons/openerp/widgets/form/_form.py	2010-04-21 14:22:43 +0000
+++ addons/openerp/widgets/form/_form.py	2010-05-12 11:20:48 +0000
@@ -644,7 +644,7 @@
 
     def __init__(self, **attrs):
         super(Group, self).__init__(**attrs)
-        self.default = False
+        self.default = attrs.get('expand', False)
         self.frame = Frame(**attrs)
         self.nolabel = True
         self.view_type = cherrypy.request.terp_params.get('_terp_view_type')

=== modified file 'addons/openerp/widgets/listgrid.py'
--- addons/openerp/widgets/listgrid.py	2010-05-10 09:05:26 +0000
+++ addons/openerp/widgets/listgrid.py	2010-05-12 11:20:48 +0000
@@ -82,8 +82,8 @@
         self.context = context or {}
         self.domain = domain or []
         
-        custom_search_domain = cherrypy.request.custom_search_domain
-        custom_filter_domain = cherrypy.request.custom_filter_domain
+        custom_search_domain = getattr(cherrypy.request, 'custom_search_domain', [])
+        custom_filter_domain = getattr(cherrypy.request, 'custom_filter_domain', [])
         
         if name.endswith('/'):
             self._name = name[:-1]

=== modified file 'addons/openerp/widgets/listgroup.py'
--- addons/openerp/widgets/listgroup.py	2010-05-06 13:14:37 +0000
+++ addons/openerp/widgets/listgroup.py	2010-05-12 11:20:48 +0000
@@ -33,6 +33,78 @@
 
 from listgrid import List, CELLTYPES
 
+def parse(group_by, hiddens, headers, padding, groups):
+    
+    for grp in range(len(group_by)):
+        if 'group_' in group_by[grp]:
+            group_by[grp] = group_by[grp].split("group_")[-1]
+            
+    new_hidden = ()
+    for grp_by in groups:
+        for hidden in hiddens:
+            if grp_by == hidden[0]:
+                hiden = {}
+                for h in hidden[1]:
+                    if h != 'invisible':
+                        hiden[h] = hidden[1].get(h)
+                new_hidden = (grp_by, hiden)
+                if padding is None:
+                    headers.insert(groups.index(grp_by), new_hidden)
+                else:
+                    headers.insert(groups.index(grp_by), new_hidden)
+                    
+    if not new_hidden:
+        for grp_by in groups:
+            for cnt, header in enumerate(headers):
+                if header[0] == grp_by:
+                    head = header
+                    headers.pop(cnt)
+                    if padding is None:
+                        headers.insert(groups.index(grp_by), head)
+                    else:
+                        headers.insert(groups.index(grp_by), head)
+    
+    return group_by, hiddens, headers
+
+def parse_groups(group_by, grp_records, headers, ids, model,  offset, limit, context, data):
+    proxy = rpc.RPCProxy(model)
+    grouped = []
+    grp_ids = []
+    for grp in grp_records:
+        inner = {}
+        for key, head in headers:
+            if not isinstance(head, int):
+                kind = head.get('type')
+                if kind == 'progressbar':
+                    inner[key] = CELLTYPES[kind](value=grp.get(key), **head)
+        grouped.append(inner)
+        
+    if len(group_by)  > 1:
+        child = False
+    else:
+        child = True
+        
+    if grp_records:
+        for rec in grp_records:
+            for grp_by in group_by:
+                if not rec.get(grp_by):
+                    rec[grp_by] = ''
+
+            rec_dom =  rec.get('__domain')
+            dom = [('id', 'in', ids), rec_dom[0]]
+            ch_ids = []
+            if child:
+                grp_ids = proxy.search(dom, offset, limit, 0, context)
+                for id in grp_ids:
+                    for d in data:
+                        if d.get('id') == id:
+                            ch_ids.append(d)
+            rec['child_rec'] = ch_ids
+            rec['group_id'] = 'group_' + str(random.randrange(1, 10000))
+            rec['group_by_id'] = group_by[0]+'_'+str(grp_records.index(rec))
+            
+    return grouped, grp_ids
+
 
 class ListGroup(List):
 
@@ -52,7 +124,7 @@
         self.limit = kw.get('limit', 0)
         self.count = kw.get('count', 0)
         self.link = kw.get('nolinks')
-
+        
         proxy = rpc.RPCProxy(model)
 
         if ids == None:
@@ -77,88 +149,88 @@
 
         if not isinstance(self.group_by_ctx, list):
             self.group_by_ctx = [self.group_by_ctx]
-
+        
         fields = view['fields']
 
         self.grp_records = []
         group_field = None
-
+        
         self.context.update(rpc.session.context.copy())
-        grp = self.context.get('group_by', False)
-        self.no_leaf = self.context.get('group_by_no_leaf', False)
-        if self.no_leaf:
-            self.editable = False
             
         super(ListGroup, self).__init__(
             name=name, model=model, view=view, ids=self.ids, domain=self.domain,
             context=self.context, limit=self.limit, count=self.count,
             offset=self.offset, editable=self.editable,
             selectable=self.selectable)
-
-        if self.group_by_ctx:
-            t = []
-            if self.group_by_ctx and isinstance(self.group_by_ctx[0], basestring):
-                self.group_by_ctx = self.group_by_ctx[0].split(',')
-            
-            for i in self.group_by_ctx:
-                if 'group_' in i:
-                    t.append((i.split('group_'))[1])
-                else:
-                    t.append(i)
-                    
-            gb = t[0]
-            self.group_by_ctx = gb
-
-            new_hidden = ()
-            for hidden in self.hiddens:
-                if gb == hidden[0]:
-                    hiden = {}
-                    for h in hidden[1]:
-                        if h != 'invisible':
-                            hiden[h] = hidden[1].get(h)
-                    new_hidden = (gb, hiden)
-                    self.headers.insert(0, new_hidden)
-            if not new_hidden:
-                for cnt, header in enumerate(self.headers):
-                    head = header
-                    if header[0] == gb:
-                        self.headers.pop(cnt)
-                        self.headers.insert(0, head)
-
-            self.grp_records = proxy.read_group(self.context.get('__domain', []) + (self.domain or []),
-                                                fields.keys(), gb, 0, False, self.context)    
-        
-        self.grouped = []
-        
-        for grp in self.grp_records:
-            inner = {}
-            for key, head in self.headers:
-                if not isinstance(head, int):
-                    kind = head.get('type')
-                    if kind == 'progressbar':
-                        inner[key] = CELLTYPES[kind](value=grp.get(key), **head)
-            self.grouped.append(inner)
+        
+        self.group_by_ctx, self.hiddens, self.headers = parse(self.group_by_ctx, self.hiddens, self.headers, None, self.group_by_ctx)
+                            
+        self.context['group_by'] = self.group_by_ctx
+        
+        
+        self.grp_records = proxy.read_group(self.context.get('__domain', []) + (self.domain or []),
+                                                fields.keys(), self.group_by_ctx, 0, False, self.context)   
+        
+        self.grouped, grp_ids = parse_groups(self.group_by_ctx, self.grp_records, self.headers, self.ids, model,  self.offset, self.limit, self.context, self.data)
+
                 
-        grp_ids = []
+class MultipleGroup(List):
+    
+    template = "templates/multiple_group.mako"
+    params = ['grp_records', 'group_by_ctx', 'grouped', 'parent', 'padding']
+    
+    def __init__(self, name, model, view, ids=[], domain=[], parent=None, padding=0, groups = [], context={}, **kw):
+        self.context = context or {}
+        self.domain = domain or []
+
+        self.selectable = kw.get('selectable', 0)
+        self.editable = kw.get('editable', False)
+        self.pageable = kw.get('pageable', True)
+
+        self.offset = kw.get('offset', 0)
+        self.limit = kw.get('limit', 80)
+        self.count = kw.get('count', 0)
+        self.link = kw.get('nolinks')
+        self.parent = parent or None
+        self.padding = padding or 0
         
-        if self.grp_records:
-            for rec in self.grp_records:
-                child = True
-                if not rec.get(self.group_by_ctx):
-                    rec[self.group_by_ctx] = ''
-
-                rec_dom =  rec.get('__domain')
-                dom = [('id', 'in', self.ids), rec_dom[0]]
-                inner_gb = self.context.get('group_by', [])
-                if self.no_leaf and not len(inner_gb):
-                    child = False
-                ch_ids = []
-                if child:
-                    grp_ids = proxy.search(dom, self.offset, self.limit, 0, self.context)
-                    for id in grp_ids:
-                        for d in self.data:
-                            if d.get('id') == id:
-                                ch_ids.append(d)
-                rec['child_rec'] = ch_ids
-                rec['group_id'] = 'group_' + str(random.randrange(1, 10000))
+        proxy = rpc.RPCProxy(model)
+        if ids == None:
+            if self.limit > 0:
+                ids = proxy.search(self.domain, self.offset, self.limit, 0, rpc.session.context.copy())
+            else:
+                ids = proxy.search(self.domain, 0, 0, 0, rpc.session.context.copy())
+            
+            if len(ids) < self.limit:
+                self.count = len(ids)
+            else:
+                self.count = proxy.search_count(domain, rpc.session.context.copy())
+
+        if ids and not isinstance(ids, list):
+            ids = [ids]
+
+        self.ids = ids
+
+        self.concurrency_info = None
+
+        self.group_by_ctx = kw.get('group_by_ctx', [])
+
+        if not isinstance(self.group_by_ctx, list):
+            self.group_by_ctx = [self.group_by_ctx]
+
+        fields = view['fields']
+
+        self.grp_records = []
+        group_field = None
+        super(MultipleGroup, self).__init__(
+            name=name, model=model, view=view, ids=self.ids, domain=self.domain,
+            parent=parent, padding=padding, groups=groups, context=self.context, limit=self.limit, 
+            count=self.count,offset=self.offset, editable=self.editable,
+            selectable=self.selectable)
+        self.group_by_ctx, self.hiddens, self.headers = parse(self.group_by_ctx, self.hiddens, self.headers, self.padding, groups)
+                                         
+        self.grp_records = proxy.read_group(self.context.get('__domain', []),
+                                                fields.keys(), self.group_by_ctx, 0, False, self.context)   
+
+        self.grouped, grp_ids = parse_groups(self.group_by_ctx, self.grp_records, self.headers, self.ids, model,  self.offset, self.limit, rpc.session.context.copy(), self.data)                            
                 
\ No newline at end of file

=== modified file 'addons/openerp/widgets/templates/listgroup.mako'
--- addons/openerp/widgets/templates/listgroup.mako	2010-04-09 13:06:28 +0000
+++ addons/openerp/widgets/templates/listgroup.mako	2010-05-12 11:20:48 +0000
@@ -3,7 +3,7 @@
 background = '#DEDEDE'
 %>
 
-<table id="${name}" class="gridview" width="100%" cellspacing="0" cellpadding="0">
+<table id="${name}" groups="${group_by_ctx}" class="gridview" width="100%" cellspacing="0" cellpadding="0">
     % if pageable:
     <tr class="pagerbar">
         <td colspan="2" class="pagerbar-cell" align="right">${pager.display()}</td>
@@ -33,10 +33,10 @@
 
                 <tbody>
 					% for j, grp_row in enumerate(grp_records):
-					<tr class="grid-row-group" records="${grp_row.get('group_id')}" style="cursor: pointer;" ch_records="${map(lambda x: x['id'],grp_row['child_rec'])}" grp_domain="${grp_row['__domain']}">
+					<tr class="grid-row-group" grp_by_id="${grp_row.get('group_by_id')}" records="${grp_row.get('group_id')}" style="cursor: pointer;" ch_records="${map(lambda x: x['id'],grp_row['child_rec'])}" grp_domain="${grp_row['__domain']}" grp_context="${grp_row['__context']['group_by']}">
                         % if editable:
                             <td class="grid-cell" style="background-color: ${background};">
-                                <img id="img_${grp_row.get('group_id')}" src="/openerp/static/images/treegrid/expand.gif" onclick="toggle_group_data('${grp_row.get('group_id')}');"></img>
+                                <img id="img_${grp_row.get('group_id')}" class="group_expand" onclick="new ListView('${name}').group_by('${grp_row.get('group_by_id')}', '${grp_row.get('group_id')}', this)"></img>
                             </td>
                         % endif
 
@@ -65,7 +65,7 @@
                     </tr>
 
                     % for ch in grp_row.get('child_rec'):
-                    <tr class="grid-row-group" id="grid-row ${grp_row.get('group_id')}" record="${ch.get('id')}"
+                    <tr class="grid-row-group" id="grid-row ${grp_row.get('group_id')}" parent_grp_id="${grp_row.get('group_by_id')}" record="${ch.get('id')}"
                         style="cursor: pointer; display: none;">
                         % if editable:
                             <td class="grid-cell">

=== added file 'addons/openerp/widgets/templates/multiple_group.mako'
--- addons/openerp/widgets/templates/multiple_group.mako	1970-01-01 00:00:00 +0000
+++ addons/openerp/widgets/templates/multiple_group.mako	2010-05-12 11:20:48 +0000
@@ -0,0 +1,67 @@
+<%!
+import itertools
+background = '#DEDEDE'
+%>
+% for j, grp_row in enumerate(grp_records):
+	<tr class="grid-row-group" parent="${parent}" grp_by_id="${grp_row.get('group_by_id')}" records="${grp_row.get('group_id')}" style="cursor: pointer;" ch_records="${map(lambda x: x['id'],grp_row['child_rec'])}" grp_domain="${grp_row['__domain']}" grp_context="${grp_row['__context']['group_by']}">
+		% if editable:
+			<td class="grid-cell" style="background-color: ${background};">
+			</td>
+		% endif
+		% for i, (field, field_attrs) in enumerate(headers):
+			% if field != 'button':
+				<td class="grid-cell ${field_attrs.get('type', 'char')}"
+					style="background-color: ${background};">
+					% if field_attrs.get('type') == 'progressbar':
+						<span>${grouped[j][field].display()}</span>
+					% else:
+						% if i  == padding-1:
+							<img id="img_${grp_row.get('group_id')}" class="group_expand" onclick="new ListView('${name}').group_by('${grp_row.get('group_by_id')}', '${grp_row.get('group_id')}', this)"></img>
+						% else:
+							<span>${grp_row.get(field)}</span>
+						% endif
+					% endif
+				</td>
+			% else:
+				<td class="grid-cell button" nowrap="nowrap" style="background-color: ${background};">
+					<span></span>
+				</td>
+			% endif
+		% endfor
+		% if editable:
+			<td class="grid-cell selector" style="background-color: ${background};">
+				<div style="width: 0px;"></div>
+			</td>
+		% endif
+	</tr>
+	% for ch in grp_row.get('child_rec'):
+		<tr class="grid-row-group" id="grid-row ${grp_row.get('group_id')}" parent="${parent}" parent_grp_id="${grp_row.get('group_by_id')}" record="${ch.get('id')}"
+			style="cursor: pointer; display:none;">
+			% if editable:
+				<td class="grid-cell">
+					<img src="/openerp/static/images/listgrid/edit_inline.gif" class="listImage" border="0"
+						title="${_('Edit')}" onclick="editRecord(${ch.get('id')}, '${source}')"/>
+				</td>
+			% endif
+			% for i, (field, field_attrs) in enumerate(headers):
+				% if field != 'button':
+					<td class="grid-cell ${field_attrs.get('type', 'char')}"
+						style="padding-left: 15px; ${(ch.get(field).color or None) and 'color: ' + ch.get(field).color};"
+						sortable_value="${ch.get(field).get_sortable_text()}">
+							<span>${ch[field].display()}</span>
+					</td>
+				% else:
+					<td class="grid-cell button" nowrap="nowrap">
+						${buttons[field_attrs-1].display(parent_grid=name, **buttons[field_attrs-1].params_from(ch))}
+					</td>
+				% endif
+			% endfor
+			% if editable:
+				<td class="grid-cell selector">
+					<img src="/openerp/static/images/listgrid/delete_inline.gif" class="listImage" border="0"
+						title="${_('Delete')}" onclick="new ListView('${name}').remove(${ch.get('id')})"/>
+				</td>
+			% endif
+		</tr>
+	% endfor
+% endfor
\ No newline at end of file


Follow ups