openerp-dev-web team mailing list archive
-
openerp-dev-web team
-
Mailing list archive
-
Message #05659
[Merge] lp:~openerp-dev/openobject-client/trunk-m2o_with_selection-rga into lp:openobject-client
Ravi Gadhia (OpenERP) has proposed merging lp:~openerp-dev/openobject-client/trunk-m2o_with_selection-rga into lp:openobject-client.
Requested reviews:
Naresh(OpenERP) (nch-openerp)
For more details, see:
https://code.launchpad.net/~openerp-dev/openobject-client/trunk-m2o_with_selection-rga/+merge/58245
Hello,
Improve selection field.
Now M2O field with widget="selection" no need to pre-load selection value (at time of fields_view_get) it's get value on popup by name_search and we can apply domain as like M2O field
related server branch:
https://code.launchpad.net/~openerp-dev/openobject-server/trunk-M2O_with_selection-rga
--
https://code.launchpad.net/~openerp-dev/openobject-client/trunk-m2o_with_selection-rga/+merge/58245
Your team OpenERP R&D Team is subscribed to branch lp:~openerp-dev/openobject-client/trunk-m2o_with_selection-rga.
=== modified file 'bin/widget/model/field.py'
--- bin/widget/model/field.py 2011-04-13 13:24:05 +0000
+++ bin/widget/model/field.py 2011-04-19 08:45:00 +0000
@@ -45,12 +45,31 @@
klass = TYPES.get(type, CharField)
return klass
+class M2O_SelectionField(dict):
+ def __init__(self ,*args, **kwargs):
+ self.swap = {}
+
+ def __setitem__(self, key, value):
+ self.swap[value] = key
+ super(M2O_SelectionField, self).__setitem__(key, value)
+
+ def update(self, *args, **kwargs):
+ for key, val in args[0].items():
+ self.swap[val] = key
+ super(M2O_SelectionField, self).update(args[0])
+
+ def get_value(self, key):
+ return self.get(key, '')
+
+ def get_key(self,value):
+ return self.swap.get(value, False)
class CharField(object):
def __init__(self, parent, attrs):
self.parent = parent
self.attrs = attrs
self.name = attrs['name']
+ self.selection = M2O_SelectionField()
self.internal = False
self.default_attrs = {}
@@ -104,12 +123,12 @@
return True
def get(self, model, check_load=True, readonly=True, modified=False):
- return model.value.get(self.name, False) or False
+ return model.value.get(self.name, False)
def set_client(self, model, value, test_state=True, force_change=False):
internal = model.value.get(self.name, False)
self.set(model, value, test_state)
- if (internal or False) != (model.value.get(self.name,False) or False):
+ if (internal or False) != (model.value.get(self.name, False) or False):
model.modified = True
model.modified_fields.setdefault(self.name)
self.sig_changed(model)
@@ -136,7 +155,7 @@
try:
attrs_changes = eval(self.attrs.get('attrs',"{}"))
except:
- attrs_changes = eval(self.attrs.get('attrs',"{}"),model.value)
+ attrs_changes = eval(self.attrs.get('attrs',"{}"), model.value)
for k,v in attrs_changes.items():
for i in range(0,len(v)):
if v[i][2]:
@@ -242,14 +261,24 @@
class SelectionField(CharField):
+
+ def get(self, model, check_load=True, readonly=True, modified=False):
+ return model.value.get(self.name, False)
+
def set(self, model, value, test_state=True, modified=False):
+ self.selection.update(dict(self.attrs.get('selection',[])))
+
+ if isinstance(value,(list,tuple)) and len(value):
+ self.selection[value[0]] = value[1]
+
+ if value and isinstance(value, (int, long)) and self.attrs.get('relation', False):
+ rpc2 = RPCProxy(self.attrs['relation'])
+ result = rpc2.name_get([value], rpc.session.context)
+ self.selection.update(dict(result))
+
value = isinstance(value,(list,tuple)) and len(value) and value[0] or value
-
- if not self.get_state_attrs(model).get('required', False) and value is None:
- super(SelectionField, self).set(model, value, test_state, modified)
-
- if value in [sel[0] for sel in self.attrs['selection']]:
- super(SelectionField, self).set(model, value, test_state, modified)
+
+ super(SelectionField, self).set(model, value, test_state, modified)
class FloatField(CharField):
def validate(self, model):
@@ -303,6 +332,7 @@
def get_client(self, model):
#model._check_load()
if model.value[self.name]:
+ self.selection.update(dict([model.value[self.name]]))
return model.value[self.name][1]
return False
=== modified file 'bin/widget/model/group.py'
--- bin/widget/model/group.py 2011-04-13 05:28:58 +0000
+++ bin/widget/model/group.py 2011-04-19 08:45:00 +0000
@@ -343,7 +343,10 @@
for f in fields.keys():
add_field = True
if f in models.fields:
- if fields[f].get('widget','') == models.fields[f].get('widget',''):
+ if fields[f].get('widget','') == models.fields[f].get('widget','') :
+ if fields[f].get('widget','') == 'selection' and models.mfields[f].selection:
+ selection = models.mfields[f].selection
+ fields[f]['selection'] = zip(selection.keys(),selection.values())
models.fields[f].update(fields[f])
add_field = False
if f in models.mfields and fields[f].get('type','') == 'one2many':
@@ -352,7 +355,6 @@
models.fields[f] = fields[f]
models.fields[f]['name'] = f
to_add.append(f)
-
self.mfields_load(to_add, models)
for fname in to_add:
for m in models.models:
=== modified file 'bin/widget/model/record.py'
--- bin/widget/model/record.py 2011-04-13 05:07:59 +0000
+++ bin/widget/model/record.py 2011-04-19 08:45:00 +0000
@@ -33,6 +33,7 @@
from gtk import glade
import tools
from field import O2MField
+from field import SelectionField
class EvalEnvironment(object):
def __init__(self, parent):
@@ -232,6 +233,9 @@
if self.mgroup.mfields[fieldname].attrs.get('on_change',False):
fields_with_on_change[fieldname] = value
else:
+ if self.mgroup.mfields[fieldname].attrs.get('widget') == 'selection' and value:
+ relation = self.mgroup.mfields[fieldname].attrs['relation']
+ value = rpc.session.rpc_exec_auth('/object', 'execute', relation, 'name_search', '', [('id','=',value)], 'ilike')[0]
self.mgroup.mfields[fieldname].set_default(self, value)
for field, value in fields_with_on_change.items():
self.mgroup.mfields[field].set_default(self, value)
=== modified file 'bin/widget/screen/screen.py'
--- bin/widget/screen/screen.py 2011-04-13 09:12:58 +0000
+++ bin/widget/screen/screen.py 2011-04-19 08:45:00 +0000
@@ -592,13 +592,6 @@
if attrs['widget']=='one2many_list':
attrs['widget']='one2many'
attrs['type'] = attrs['widget']
- if attrs.get('selection',[]):
- attrs['selection'] = eval(attrs['selection'])
- for att_key, att_val in attrs['selection'].items():
- for sel in fields[str(attrs['name'])]['selection']:
- if att_key == sel[0]:
- sel[1] = att_val
- attrs['selection'] = fields[str(attrs['name'])]['selection']
fields[unicode(attrs['name'])].update(attrs)
for node2 in node:
_parse_fields(node2, fields)
@@ -617,7 +610,6 @@
self.models.screen = self
self.models.add_fields(fields, self.models, context=context)
self.fields = self.models.fields
-
parser = widget_parse(parent=self.parent, window=self.window)
view = parser.parse(self, root_node, self.fields, toolbar=toolbar, submenu=submenu, help=help)
if view:
=== modified file 'bin/widget/view/form_gtk/selection.py'
--- bin/widget/view/form_gtk/selection.py 2010-07-16 05:41:32 +0000
+++ bin/widget/view/form_gtk/selection.py 2011-04-19 08:45:00 +0000
@@ -23,7 +23,7 @@
import interface
import gtk
import gobject
-
+import rpc
import gettext
class selection(interface.widget_interface):
@@ -31,109 +31,83 @@
interface.widget_interface.__init__(self, window, parent, model, attrs)
self.widget = gtk.HBox(spacing=3)
- self.entry = gtk.ComboBoxEntry()
+ self.name = attrs['name']
+ self.attrs = attrs
+ self.entry = gtk.combo_box_entry_new_text()
+ self.entry.connect('notify::popup-shown', self.popup_show)
self.child = self.entry.get_child()
+ self.relation_model = self.attrs.get('relation', '')
self.child.set_property('activates_default', True)
self.child.connect('changed', self.sig_changed)
self.child.connect('populate-popup', self._menu_open)
- self.child.connect('key_press_event', self.sig_key_press)
- self.child.connect('activate', self.sig_activate)
self.child.connect_after('focus-out-event', self.sig_activate)
- self.entry.set_size_request(int(attrs.get('size', -1)), -1)
self.widget.pack_start(self.entry, expand=True, fill=True)
# the dropdown button is not focusable by a tab
self.widget.set_focus_chain([self.child])
- self.ok = True
+ self.set_popdown(attrs.get('selection',[]))
self._selection={}
-
- self.set_popdown(attrs.get('selection', []))
+ self.entry_text = ""
+
+
+ def popup_show(self, combobox, popup_show):
+ text = self.child.get_text()
+# if self._view.modelfield.selection.get_key(text):
+# text = ""
+ if combobox.get_property('popup-shown') and self.attrs.get('widget','') == 'selection':
+ domain = self._view.modelfield.domain_get(self._view.model)
+ context = self._view.modelfield.context_get(self._view.model)
+ selection = rpc.session.rpc_exec_auth('/object', 'execute', self.relation_model, 'name_search', text , domain , 'ilike', context , False)
+ self.set_popdown(selection)
def set_popdown(self, selection):
- self.model = gtk.ListStore(gobject.TYPE_STRING)
+ self.model = self.entry.get_model()
+ self.model.clear()
self._selection={}
lst = []
- for (value, name) in selection:
- name = str(name)
+ if not selection:
+ selection = [(False, '')]
+ for (i,j) in selection:
+ name = str(j)
lst.append(name)
- self._selection[name] = value
- i = self.model.append()
- self.model.set(i, 0, name)
- self.entry.set_model(self.model)
- self.entry.set_text_column(0)
- return lst
+ self._selection[i]=name
+ self.entry.append_text(name)
def _readonly_set(self, value):
interface.widget_interface._readonly_set(self, value)
self.entry.set_sensitive(not value)
- def value_get(self):
- res = self.child.get_text()
- return self._selection.get(res, False)
-
- def sig_key_press(self, widget, event):
- # allow showing available entries by hitting "ctrl+space"
- completion=gtk.EntryCompletion()
- if hasattr(completion, 'set_inline_selection'):
- completion.set_inline_selection(True)
- if (event.type == gtk.gdk.KEY_PRESS) \
- and ((event.state & gtk.gdk.CONTROL_MASK) != 0) \
- and (event.keyval == gtk.keysyms.space):
- self.entry.popup()
- elif not (event.keyval == gtk.keysyms.Up or event.keyval == gtk.keysyms.Down):
- completion.set_match_func(self.match_func,widget)
- completion.set_model(self.model)
- widget.set_completion(completion)
- completion.set_text_column(0)
-
- def match_func(self, completion, key, iter, widget):
- model = completion.get_model()
- return model[iter][0].lower().find(widget.get_text().lower()) >= 0 and True or False
-
def sig_activate(self, *args):
text = self.child.get_text()
- value = False
- if text:
- for txt, val in self._selection.items():
- if not val:
- continue
- if txt[:len(text)].lower() == text.lower():
- value = val
- if len(txt) == len(text):
- break
+ value = self._view.modelfield.selection.get_key(text)
+ if not value:
+ self.entry_text = text
self._view.modelfield.set_client(self._view.model, value, force_change=True)
self.display(self._view.model, self._view.modelfield)
-
def set_value(self, model, model_field):
- model_field.set_client(model, self.value_get())
-
- def _menu_sig_default_set(self):
- self.set_value(self._view.model, self._view.modelfield)
- super(selection, self)._menu_sig_default_set()
+ model_field.selection.update(self._selection)
+ text = self.child.get_text()
+ value = False
+ if text:
+ model_field.selection.get_key(text)
+ value = model_field.selection.get_key(text)
+ model_field.set_client(model, value)
def display(self, model, model_field):
- self.ok = False
if not model_field:
self.child.set_text('')
- self.ok = True
- return False
+ return
+ model_field.selection.update(dict(self.attrs.get('selection',[])))
super(selection, self).display(model, model_field)
- value = model_field.get(model)
- if not value:
- self.child.set_text('')
- else:
- found = False
- for long_text, sel_value in self._selection.items():
- if sel_value == value:
- self.child.set_text(long_text)
- found = True
- break
- self.ok = True
+ key = model_field.get(model, False)
+# model_field.selection.update(self._selection)
+ text = model_field.selection.get_value(key)
+ self.child.set_text(self.entry_text or text)
+ self.entry_text = ""
- def sig_changed(self, *args):
- if self.ok:
- self._focus_out()
+ def sig_changed(self, combox):
+ self._focus_out()
def _color_widget(self):
return self.child
@@ -141,4 +115,3 @@
def grab_focus(self):
return self.entry.grab_focus()
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
-
=== modified file 'bin/widget/view/list.py'
--- bin/widget/view/list.py 2011-04-12 08:48:06 +0000
+++ bin/widget/view/list.py 2011-04-19 08:45:00 +0000
@@ -860,7 +860,7 @@
if col in self.widget_tree.handlers:
if self.widget_tree.handlers[col]:
renderer.disconnect(self.widget_tree.handlers[col])
- self.widget_tree.handlers[col] = renderer.connect_after('editing-started', send_keys, self.widget_tree)
+ self.widget_tree.handlers[col] = renderer.connect_after('editing-started', send_keys, self.widget_tree, col.name)
def set_invisible_attr(self):
=== modified file 'bin/widget/view/tree_gtk/editabletree.py'
--- bin/widget/view/tree_gtk/editabletree.py 2010-12-23 09:52:21 +0000
+++ bin/widget/view/tree_gtk/editabletree.py 2011-04-19 08:45:00 +0000
@@ -149,7 +149,12 @@
def get_cursor(self):
res = super(EditableTreeView, self).get_cursor()
return res
-
+
+ def get_current_model(self):
+ path, column = self.get_cursor()
+ store = self.get_model()
+ return store.get_value(store.get_iter(path), 0)
+
def set_value(self):
path, column = self.get_cursor()
store = self.get_model()
@@ -175,7 +180,7 @@
def on_keypressed(self, entry, event, cell_value):
path, column = self.get_cursor()
store = self.get_model()
- model = store.get_value(store.get_iter(path), 0)
+ model = self.get_current_model()
if event.keyval in self.leaving_events:
shift_pressed = bool(gtk.gdk.SHIFT_MASK & event.state)
if isinstance(entry, gtk.Entry):
=== modified file 'bin/widget/view/tree_gtk/parser.py'
--- bin/widget/view/tree_gtk/parser.py 2011-03-20 11:26:23 +0000
+++ bin/widget/view/tree_gtk/parser.py 2011-04-19 08:45:00 +0000
@@ -33,6 +33,7 @@
from editabletree import EditableTreeView
from widget.view import interface
from widget.view.list import group_record
+from widget.model.field import SelectionField, M2OField
import time
import date_renderer
@@ -47,13 +48,16 @@
import gobject
import pango
-def send_keys(renderer, entry, position, treeview):
- if entry:
+def send_keys(renderer, entry, position, treeview, col_name):
+ if entry:
entry.connect('key_press_event', treeview.on_keypressed, renderer.get_property('text'))
entry.set_data('renderer', renderer)
entry.editing_done_id = entry.connect('editing_done', treeview.on_editing_done)
if isinstance(entry, gtk.ComboBoxEntry):
entry.connect('changed', treeview.on_editing_done)
+ if isinstance(entry, gtk.ComboBoxEntry):
+ popup = treeview.cells[col_name].popup
+ entry.connect('notify::popup-shown', popup, treeview)
def sort_model(column, screen):
unsaved_model = [x for x in screen.models if x.id == None or x.modified]
@@ -107,10 +111,8 @@
treeview.sequence = False
treeview.connect("motion-notify-event", treeview.set_tooltip)
treeview.connect('key-press-event', treeview.on_tree_key_press)
-
for node in root_node:
node_attrs = tools.node_attributes(node)
-
if node.tag == 'button':
cell = Cell('button')(node_attrs['string'], treeview, node_attrs)
cell.name = node_attrs['name']
@@ -158,16 +160,17 @@
self.window)
treeview.cells[fname] = cell
renderer = cell.renderer
-
+ col = gtk.TreeViewColumn(None, renderer)
+ col.name = fname
write_enable = editable and not node_attrs.get('readonly', False)
if isinstance(renderer, gtk.CellRendererToggle):
renderer.set_property('activatable', write_enable)
elif isinstance(renderer, (gtk.CellRendererText, gtk.CellRendererCombo, date_renderer.DecoratorRenderer)):
renderer.set_property('editable', write_enable)
if write_enable:
- handler_id = renderer.connect_after('editing-started', send_keys, treeview)
-
- col = gtk.TreeViewColumn(None, renderer)
+ handler_id = renderer.connect_after('editing-started', send_keys, treeview, col.name)
+
+
treeview.handlers[col] = handler_id
col_label = gtk.Label('')
if fields[fname].get('required', False):
@@ -176,7 +179,7 @@
col_label.set_text(fields[fname]['string'])
col_label.show()
col.set_widget(col_label)
- col.name = fname
+
col._type = fields[fname]['type']
col.set_cell_data_func(renderer, cell.setter)
col.set_clickable(True)
@@ -549,6 +552,13 @@
return rpc.name_get([found[0]], context)[0]
else:
return False, None
+
+ def get_textual_value(self, model):
+ if isinstance(model[self.field_name], SelectionField):
+ key = model[self.field_name].get_client(model)
+ return model[self.field_name].selection.get_value(key)
+ return model[self.field_name].get_client(model) or ''
+
class O2M(Char):
@@ -609,29 +619,46 @@
def __init__(self, *args):
super(Selection, self).__init__(*args)
self.renderer = gtk.CellRendererCombo()
- selection_data = gtk.ListStore(object, str)
- for x in self.attrs.get('selection', []):
- selection_data.append(x)
- self.renderer.set_property('model', selection_data)
+ self.selection_data = gtk.ListStore(str, str)
+ selection = self.attrs.get('selection', [])
+ for x in selection:
+ self.selection_data.append(x)
+ if not selection:
+ self.selection_data.append([False, ''])
+ self.renderer.set_property('model', self.selection_data)
self.renderer.set_property('text-column', 1)
+ self.relation = self.attrs.get('relation')
def get_textual_value(self, model):
- selection = dict(self.attrs['selection'])
- selection_value = selection.get(model[self.field_name].get(model), '')
+ key = model[self.field_name].get(model)
+ selection_value = model[self.field_name].selection.get_value(key)
if isinstance(model, group_record):
return selection_value + model[self.field_name].count
return selection_value
+
+ def popup(self, combobox, para, treeview):
+ if combobox.get_property('popup-shown') and self.relation:
+ entry = combobox.get_child()
+ text = entry.get_property('text')
+ rpc = RPCProxy(self.relation)
+ model = treeview.get_current_model()
+ domain = model[self.field_name].domain_get(model)
+ context = model[self.field_name].context_get(model)
+ key = model[self.field_name].selection.get_key(text)
+ if key:
+ text = ''
+ selection = rpc.name_search(text, domain, 'ilike',context, False)
+ if selection:
+ self.selection_data.clear()
+ model = treeview.get_current_model()
+ model[self.field_name].selection.update(dict(selection))
+ for x in selection:
+ self.selection_data.append(x)
def value_from_text(self, model, text):
- selection = self.attrs['selection']
- text = tools.ustr(text)
- res = False
- for val, txt in selection:
- if txt[:len(text)].lower() == text.lower():
- if len(txt) == len(text):
- return val
- res = val
- return res
+ key = model[self.field_name].get(model)
+ selection_value = model[self.field_name].selection.get_value(key)
+ return model[self.field_name].selection.get_key(text)
class ProgressBar(object):
=== modified file 'bin/widget_search/selection.py'
--- bin/widget_search/selection.py 2011-04-04 11:19:53 +0000
+++ bin/widget_search/selection.py 2011-04-19 08:45:00 +0000
@@ -28,25 +28,37 @@
class selection(wid_int.wid_int):
def __init__(self, name, parent, attrs={}, model=None, screen=None):
wid_int.wid_int.__init__(self, name, parent, attrs, screen)
-
self.widget = gtk.combo_box_entry_new_text()
+ self.widget.connect('notify::popup-shown', self.popup_show)
+ self.context = screen.context
+ self.relation_model = self.attrs.get('relation', '')
self.widget.child.set_editable(True)
self.attrs = attrs
self._selection = {}
self.name = name
- self.val_id = False
- if 'selection' in attrs:
- self.set_popdown(attrs.get('selection',[]))
+ self.set_popdown(attrs.get('selection',[]))
if self.default_search:
if isinstance(self.default_search,list):
self.default_search = self.default_search[0]
if self.attrs['type'] == 'many2one':
- self._value_set(int(self.default_search))
+ sel = rpc.session.rpc_exec_auth('/object', 'execute', self.relation_model, 'name_search', '' , [('id','=',self.default_search)] , 'ilike', self.context, False)
+ self.set_popdown(sel)
+ self._value_set(int(self.default_search))
else:
self._value_set(str(self.default_search))
if self.widget.child.get_text() in self._selection.keys():
self.widget.set_active(self.indexes[self.widget.child.get_text()]-1)
+ def popup_show(self, combobox, popup_show):
+ search_text = self.widget.child.get_text()
+# if self._selection.get(search_text, False):
+# search_text =''
+ if combobox.get_property('popup-shown') and self.attrs['type'] == 'many2one':
+ selection = rpc.session.rpc_exec_auth('/object', 'execute', self.relation_model, 'name_search', search_text , [] , 'ilike', self.context, False)
+ self.set_popdown(selection)
+ if not selection:
+ self.widget.child.set_text('')
+
def set_popdown(self, selection):
self.model = self.widget.get_model()
self.model.clear()