Merge lp:~openerp-dev/openobject-client/trunk-m2o_with_selection-rga into lp:openobject-client
- trunk-m2o_with_selection-rga
- Merge into trunk
Status: | Rejected |
---|---|
Rejected by: | Naresh(OpenERP) |
Proposed branch: | lp:~openerp-dev/openobject-client/trunk-m2o_with_selection-rga |
Merge into: | lp:openobject-client |
Diff against target: |
579 lines (+169/-124) 9 files modified
bin/widget/model/field.py (+39/-9) bin/widget/model/group.py (+4/-2) bin/widget/model/record.py (+4/-0) bin/widget/screen/screen.py (+0/-8) bin/widget/view/form_gtk/selection.py (+46/-73) bin/widget/view/list.py (+1/-1) bin/widget/view/tree_gtk/editabletree.py (+7/-2) bin/widget/view/tree_gtk/parser.py (+51/-24) bin/widget_search/selection.py (+17/-5) |
To merge this branch: | bzr merge lp:~openerp-dev/openobject-client/trunk-m2o_with_selection-rga |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Naresh(OpenERP) | Pending | ||
Review via email: mp+58245@code.launchpad.net |
This proposal supersedes a proposal from 2011-03-15.
Commit message
Description of the change
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:/
Naresh(OpenERP) (nch-openerp) wrote : Posted in a previous version of this proposal | # |
Naresh(OpenERP) (nch-openerp) wrote : | # |
will have to implement it with new spec like web(proto)
Unmerged revisions
- 1842. By Ravi Gadhia (OpenERP)
-
Merge with trunk client
- 1841. By Ravi Gadhia (OpenERP)
-
[IMP] search text should not clear even it's in selection list(model)
- 1840. By Ravi Gadhia (OpenERP)
-
[IMP] If selection field has not key:val then get it by rpc call
- 1839. By Ravi Gadhia (OpenERP)
-
[FIX] when widget=selection on one2many field's form view (where each time new modelfield created whid dialog box popup)
- 1838. By Ravi Gadhia (OpenERP)
-
[Fix] Search view: set default value on (M2O) widget=selection field
- 1837. By Ravi Gadhia (OpenERP)
-
Remove un-used variable
- 1836. By Ravi Gadhia (OpenERP)
-
[IMP] Editable list view: add context, domain on selection field
- 1835. By Ravi Gadhia (OpenERP)
-
[IMP] Editable list view: M2O field with selection make rpc call at the time of popup (no preloded selection data)
- 1834. By Ravi Gadhia (OpenERP)
-
[IMP]Form view: add context, domain on selection field + usability imrovement
- 1833. By Ravi Gadhia (OpenERP)
-
[IMP] Form view: m20 with selection widget make rpc call when combobox popup
Preview Diff
1 | === modified file 'bin/widget/model/field.py' | |||
2 | --- bin/widget/model/field.py 2011-04-13 13:24:05 +0000 | |||
3 | +++ bin/widget/model/field.py 2011-04-19 08:45:00 +0000 | |||
4 | @@ -45,12 +45,31 @@ | |||
5 | 45 | klass = TYPES.get(type, CharField) | 45 | klass = TYPES.get(type, CharField) |
6 | 46 | return klass | 46 | return klass |
7 | 47 | 47 | ||
8 | 48 | class M2O_SelectionField(dict): | ||
9 | 49 | def __init__(self ,*args, **kwargs): | ||
10 | 50 | self.swap = {} | ||
11 | 51 | |||
12 | 52 | def __setitem__(self, key, value): | ||
13 | 53 | self.swap[value] = key | ||
14 | 54 | super(M2O_SelectionField, self).__setitem__(key, value) | ||
15 | 55 | |||
16 | 56 | def update(self, *args, **kwargs): | ||
17 | 57 | for key, val in args[0].items(): | ||
18 | 58 | self.swap[val] = key | ||
19 | 59 | super(M2O_SelectionField, self).update(args[0]) | ||
20 | 60 | |||
21 | 61 | def get_value(self, key): | ||
22 | 62 | return self.get(key, '') | ||
23 | 63 | |||
24 | 64 | def get_key(self,value): | ||
25 | 65 | return self.swap.get(value, False) | ||
26 | 48 | 66 | ||
27 | 49 | class CharField(object): | 67 | class CharField(object): |
28 | 50 | def __init__(self, parent, attrs): | 68 | def __init__(self, parent, attrs): |
29 | 51 | self.parent = parent | 69 | self.parent = parent |
30 | 52 | self.attrs = attrs | 70 | self.attrs = attrs |
31 | 53 | self.name = attrs['name'] | 71 | self.name = attrs['name'] |
32 | 72 | self.selection = M2O_SelectionField() | ||
33 | 54 | self.internal = False | 73 | self.internal = False |
34 | 55 | self.default_attrs = {} | 74 | self.default_attrs = {} |
35 | 56 | 75 | ||
36 | @@ -104,12 +123,12 @@ | |||
37 | 104 | return True | 123 | return True |
38 | 105 | 124 | ||
39 | 106 | def get(self, model, check_load=True, readonly=True, modified=False): | 125 | def get(self, model, check_load=True, readonly=True, modified=False): |
41 | 107 | return model.value.get(self.name, False) or False | 126 | return model.value.get(self.name, False) |
42 | 108 | 127 | ||
43 | 109 | def set_client(self, model, value, test_state=True, force_change=False): | 128 | def set_client(self, model, value, test_state=True, force_change=False): |
44 | 110 | internal = model.value.get(self.name, False) | 129 | internal = model.value.get(self.name, False) |
45 | 111 | self.set(model, value, test_state) | 130 | self.set(model, value, test_state) |
47 | 112 | if (internal or False) != (model.value.get(self.name,False) or False): | 131 | if (internal or False) != (model.value.get(self.name, False) or False): |
48 | 113 | model.modified = True | 132 | model.modified = True |
49 | 114 | model.modified_fields.setdefault(self.name) | 133 | model.modified_fields.setdefault(self.name) |
50 | 115 | self.sig_changed(model) | 134 | self.sig_changed(model) |
51 | @@ -136,7 +155,7 @@ | |||
52 | 136 | try: | 155 | try: |
53 | 137 | attrs_changes = eval(self.attrs.get('attrs',"{}")) | 156 | attrs_changes = eval(self.attrs.get('attrs',"{}")) |
54 | 138 | except: | 157 | except: |
56 | 139 | attrs_changes = eval(self.attrs.get('attrs',"{}"),model.value) | 158 | attrs_changes = eval(self.attrs.get('attrs',"{}"), model.value) |
57 | 140 | for k,v in attrs_changes.items(): | 159 | for k,v in attrs_changes.items(): |
58 | 141 | for i in range(0,len(v)): | 160 | for i in range(0,len(v)): |
59 | 142 | if v[i][2]: | 161 | if v[i][2]: |
60 | @@ -242,14 +261,24 @@ | |||
61 | 242 | 261 | ||
62 | 243 | 262 | ||
63 | 244 | class SelectionField(CharField): | 263 | class SelectionField(CharField): |
64 | 264 | |||
65 | 265 | def get(self, model, check_load=True, readonly=True, modified=False): | ||
66 | 266 | return model.value.get(self.name, False) | ||
67 | 267 | |||
68 | 245 | def set(self, model, value, test_state=True, modified=False): | 268 | def set(self, model, value, test_state=True, modified=False): |
69 | 269 | self.selection.update(dict(self.attrs.get('selection',[]))) | ||
70 | 270 | |||
71 | 271 | if isinstance(value,(list,tuple)) and len(value): | ||
72 | 272 | self.selection[value[0]] = value[1] | ||
73 | 273 | |||
74 | 274 | if value and isinstance(value, (int, long)) and self.attrs.get('relation', False): | ||
75 | 275 | rpc2 = RPCProxy(self.attrs['relation']) | ||
76 | 276 | result = rpc2.name_get([value], rpc.session.context) | ||
77 | 277 | self.selection.update(dict(result)) | ||
78 | 278 | |||
79 | 246 | value = isinstance(value,(list,tuple)) and len(value) and value[0] or value | 279 | value = isinstance(value,(list,tuple)) and len(value) and value[0] or value |
86 | 247 | 280 | ||
87 | 248 | if not self.get_state_attrs(model).get('required', False) and value is None: | 281 | super(SelectionField, self).set(model, value, test_state, modified) |
82 | 249 | super(SelectionField, self).set(model, value, test_state, modified) | ||
83 | 250 | |||
84 | 251 | if value in [sel[0] for sel in self.attrs['selection']]: | ||
85 | 252 | super(SelectionField, self).set(model, value, test_state, modified) | ||
88 | 253 | 282 | ||
89 | 254 | class FloatField(CharField): | 283 | class FloatField(CharField): |
90 | 255 | def validate(self, model): | 284 | def validate(self, model): |
91 | @@ -303,6 +332,7 @@ | |||
92 | 303 | def get_client(self, model): | 332 | def get_client(self, model): |
93 | 304 | #model._check_load() | 333 | #model._check_load() |
94 | 305 | if model.value[self.name]: | 334 | if model.value[self.name]: |
95 | 335 | self.selection.update(dict([model.value[self.name]])) | ||
96 | 306 | return model.value[self.name][1] | 336 | return model.value[self.name][1] |
97 | 307 | return False | 337 | return False |
98 | 308 | 338 | ||
99 | 309 | 339 | ||
100 | === modified file 'bin/widget/model/group.py' | |||
101 | --- bin/widget/model/group.py 2011-04-13 05:28:58 +0000 | |||
102 | +++ bin/widget/model/group.py 2011-04-19 08:45:00 +0000 | |||
103 | @@ -343,7 +343,10 @@ | |||
104 | 343 | for f in fields.keys(): | 343 | for f in fields.keys(): |
105 | 344 | add_field = True | 344 | add_field = True |
106 | 345 | if f in models.fields: | 345 | if f in models.fields: |
108 | 346 | if fields[f].get('widget','') == models.fields[f].get('widget',''): | 346 | if fields[f].get('widget','') == models.fields[f].get('widget','') : |
109 | 347 | if fields[f].get('widget','') == 'selection' and models.mfields[f].selection: | ||
110 | 348 | selection = models.mfields[f].selection | ||
111 | 349 | fields[f]['selection'] = zip(selection.keys(),selection.values()) | ||
112 | 347 | models.fields[f].update(fields[f]) | 350 | models.fields[f].update(fields[f]) |
113 | 348 | add_field = False | 351 | add_field = False |
114 | 349 | if f in models.mfields and fields[f].get('type','') == 'one2many': | 352 | if f in models.mfields and fields[f].get('type','') == 'one2many': |
115 | @@ -352,7 +355,6 @@ | |||
116 | 352 | models.fields[f] = fields[f] | 355 | models.fields[f] = fields[f] |
117 | 353 | models.fields[f]['name'] = f | 356 | models.fields[f]['name'] = f |
118 | 354 | to_add.append(f) | 357 | to_add.append(f) |
119 | 355 | |||
120 | 356 | self.mfields_load(to_add, models) | 358 | self.mfields_load(to_add, models) |
121 | 357 | for fname in to_add: | 359 | for fname in to_add: |
122 | 358 | for m in models.models: | 360 | for m in models.models: |
123 | 359 | 361 | ||
124 | === modified file 'bin/widget/model/record.py' | |||
125 | --- bin/widget/model/record.py 2011-04-13 05:07:59 +0000 | |||
126 | +++ bin/widget/model/record.py 2011-04-19 08:45:00 +0000 | |||
127 | @@ -33,6 +33,7 @@ | |||
128 | 33 | from gtk import glade | 33 | from gtk import glade |
129 | 34 | import tools | 34 | import tools |
130 | 35 | from field import O2MField | 35 | from field import O2MField |
131 | 36 | from field import SelectionField | ||
132 | 36 | 37 | ||
133 | 37 | class EvalEnvironment(object): | 38 | class EvalEnvironment(object): |
134 | 38 | def __init__(self, parent): | 39 | def __init__(self, parent): |
135 | @@ -232,6 +233,9 @@ | |||
136 | 232 | if self.mgroup.mfields[fieldname].attrs.get('on_change',False): | 233 | if self.mgroup.mfields[fieldname].attrs.get('on_change',False): |
137 | 233 | fields_with_on_change[fieldname] = value | 234 | fields_with_on_change[fieldname] = value |
138 | 234 | else: | 235 | else: |
139 | 236 | if self.mgroup.mfields[fieldname].attrs.get('widget') == 'selection' and value: | ||
140 | 237 | relation = self.mgroup.mfields[fieldname].attrs['relation'] | ||
141 | 238 | value = rpc.session.rpc_exec_auth('/object', 'execute', relation, 'name_search', '', [('id','=',value)], 'ilike')[0] | ||
142 | 235 | self.mgroup.mfields[fieldname].set_default(self, value) | 239 | self.mgroup.mfields[fieldname].set_default(self, value) |
143 | 236 | for field, value in fields_with_on_change.items(): | 240 | for field, value in fields_with_on_change.items(): |
144 | 237 | self.mgroup.mfields[field].set_default(self, value) | 241 | self.mgroup.mfields[field].set_default(self, value) |
145 | 238 | 242 | ||
146 | === modified file 'bin/widget/screen/screen.py' | |||
147 | --- bin/widget/screen/screen.py 2011-04-13 09:12:58 +0000 | |||
148 | +++ bin/widget/screen/screen.py 2011-04-19 08:45:00 +0000 | |||
149 | @@ -592,13 +592,6 @@ | |||
150 | 592 | if attrs['widget']=='one2many_list': | 592 | if attrs['widget']=='one2many_list': |
151 | 593 | attrs['widget']='one2many' | 593 | attrs['widget']='one2many' |
152 | 594 | attrs['type'] = attrs['widget'] | 594 | attrs['type'] = attrs['widget'] |
153 | 595 | if attrs.get('selection',[]): | ||
154 | 596 | attrs['selection'] = eval(attrs['selection']) | ||
155 | 597 | for att_key, att_val in attrs['selection'].items(): | ||
156 | 598 | for sel in fields[str(attrs['name'])]['selection']: | ||
157 | 599 | if att_key == sel[0]: | ||
158 | 600 | sel[1] = att_val | ||
159 | 601 | attrs['selection'] = fields[str(attrs['name'])]['selection'] | ||
160 | 602 | fields[unicode(attrs['name'])].update(attrs) | 595 | fields[unicode(attrs['name'])].update(attrs) |
161 | 603 | for node2 in node: | 596 | for node2 in node: |
162 | 604 | _parse_fields(node2, fields) | 597 | _parse_fields(node2, fields) |
163 | @@ -617,7 +610,6 @@ | |||
164 | 617 | self.models.screen = self | 610 | self.models.screen = self |
165 | 618 | self.models.add_fields(fields, self.models, context=context) | 611 | self.models.add_fields(fields, self.models, context=context) |
166 | 619 | self.fields = self.models.fields | 612 | self.fields = self.models.fields |
167 | 620 | |||
168 | 621 | parser = widget_parse(parent=self.parent, window=self.window) | 613 | parser = widget_parse(parent=self.parent, window=self.window) |
169 | 622 | view = parser.parse(self, root_node, self.fields, toolbar=toolbar, submenu=submenu, help=help) | 614 | view = parser.parse(self, root_node, self.fields, toolbar=toolbar, submenu=submenu, help=help) |
170 | 623 | if view: | 615 | if view: |
171 | 624 | 616 | ||
172 | === modified file 'bin/widget/view/form_gtk/selection.py' | |||
173 | --- bin/widget/view/form_gtk/selection.py 2010-07-16 05:41:32 +0000 | |||
174 | +++ bin/widget/view/form_gtk/selection.py 2011-04-19 08:45:00 +0000 | |||
175 | @@ -23,7 +23,7 @@ | |||
176 | 23 | import interface | 23 | import interface |
177 | 24 | import gtk | 24 | import gtk |
178 | 25 | import gobject | 25 | import gobject |
180 | 26 | 26 | import rpc | |
181 | 27 | import gettext | 27 | import gettext |
182 | 28 | 28 | ||
183 | 29 | class selection(interface.widget_interface): | 29 | class selection(interface.widget_interface): |
184 | @@ -31,109 +31,83 @@ | |||
185 | 31 | interface.widget_interface.__init__(self, window, parent, model, attrs) | 31 | interface.widget_interface.__init__(self, window, parent, model, attrs) |
186 | 32 | 32 | ||
187 | 33 | self.widget = gtk.HBox(spacing=3) | 33 | self.widget = gtk.HBox(spacing=3) |
189 | 34 | self.entry = gtk.ComboBoxEntry() | 34 | self.name = attrs['name'] |
190 | 35 | self.attrs = attrs | ||
191 | 36 | self.entry = gtk.combo_box_entry_new_text() | ||
192 | 37 | self.entry.connect('notify::popup-shown', self.popup_show) | ||
193 | 35 | self.child = self.entry.get_child() | 38 | self.child = self.entry.get_child() |
194 | 39 | self.relation_model = self.attrs.get('relation', '') | ||
195 | 36 | self.child.set_property('activates_default', True) | 40 | self.child.set_property('activates_default', True) |
196 | 37 | self.child.connect('changed', self.sig_changed) | 41 | self.child.connect('changed', self.sig_changed) |
197 | 38 | self.child.connect('populate-popup', self._menu_open) | 42 | self.child.connect('populate-popup', self._menu_open) |
198 | 39 | self.child.connect('key_press_event', self.sig_key_press) | ||
199 | 40 | self.child.connect('activate', self.sig_activate) | ||
200 | 41 | self.child.connect_after('focus-out-event', self.sig_activate) | 43 | self.child.connect_after('focus-out-event', self.sig_activate) |
201 | 42 | self.entry.set_size_request(int(attrs.get('size', -1)), -1) | ||
202 | 43 | self.widget.pack_start(self.entry, expand=True, fill=True) | 44 | self.widget.pack_start(self.entry, expand=True, fill=True) |
203 | 44 | 45 | ||
204 | 45 | # the dropdown button is not focusable by a tab | 46 | # the dropdown button is not focusable by a tab |
205 | 46 | self.widget.set_focus_chain([self.child]) | 47 | self.widget.set_focus_chain([self.child]) |
207 | 47 | self.ok = True | 48 | self.set_popdown(attrs.get('selection',[])) |
208 | 48 | self._selection={} | 49 | self._selection={} |
211 | 49 | 50 | self.entry_text = "" | |
212 | 50 | self.set_popdown(attrs.get('selection', [])) | 51 | |
213 | 52 | |||
214 | 53 | def popup_show(self, combobox, popup_show): | ||
215 | 54 | text = self.child.get_text() | ||
216 | 55 | # if self._view.modelfield.selection.get_key(text): | ||
217 | 56 | # text = "" | ||
218 | 57 | if combobox.get_property('popup-shown') and self.attrs.get('widget','') == 'selection': | ||
219 | 58 | domain = self._view.modelfield.domain_get(self._view.model) | ||
220 | 59 | context = self._view.modelfield.context_get(self._view.model) | ||
221 | 60 | selection = rpc.session.rpc_exec_auth('/object', 'execute', self.relation_model, 'name_search', text , domain , 'ilike', context , False) | ||
222 | 61 | self.set_popdown(selection) | ||
223 | 51 | 62 | ||
224 | 52 | def set_popdown(self, selection): | 63 | def set_popdown(self, selection): |
226 | 53 | self.model = gtk.ListStore(gobject.TYPE_STRING) | 64 | self.model = self.entry.get_model() |
227 | 65 | self.model.clear() | ||
228 | 54 | self._selection={} | 66 | self._selection={} |
229 | 55 | lst = [] | 67 | lst = [] |
232 | 56 | for (value, name) in selection: | 68 | if not selection: |
233 | 57 | name = str(name) | 69 | selection = [(False, '')] |
234 | 70 | for (i,j) in selection: | ||
235 | 71 | name = str(j) | ||
236 | 58 | lst.append(name) | 72 | lst.append(name) |
243 | 59 | self._selection[name] = value | 73 | self._selection[i]=name |
244 | 60 | i = self.model.append() | 74 | self.entry.append_text(name) |
239 | 61 | self.model.set(i, 0, name) | ||
240 | 62 | self.entry.set_model(self.model) | ||
241 | 63 | self.entry.set_text_column(0) | ||
242 | 64 | return lst | ||
245 | 65 | 75 | ||
246 | 66 | def _readonly_set(self, value): | 76 | def _readonly_set(self, value): |
247 | 67 | interface.widget_interface._readonly_set(self, value) | 77 | interface.widget_interface._readonly_set(self, value) |
248 | 68 | self.entry.set_sensitive(not value) | 78 | self.entry.set_sensitive(not value) |
249 | 69 | 79 | ||
250 | 70 | def value_get(self): | ||
251 | 71 | res = self.child.get_text() | ||
252 | 72 | return self._selection.get(res, False) | ||
253 | 73 | |||
254 | 74 | def sig_key_press(self, widget, event): | ||
255 | 75 | # allow showing available entries by hitting "ctrl+space" | ||
256 | 76 | completion=gtk.EntryCompletion() | ||
257 | 77 | if hasattr(completion, 'set_inline_selection'): | ||
258 | 78 | completion.set_inline_selection(True) | ||
259 | 79 | if (event.type == gtk.gdk.KEY_PRESS) \ | ||
260 | 80 | and ((event.state & gtk.gdk.CONTROL_MASK) != 0) \ | ||
261 | 81 | and (event.keyval == gtk.keysyms.space): | ||
262 | 82 | self.entry.popup() | ||
263 | 83 | elif not (event.keyval == gtk.keysyms.Up or event.keyval == gtk.keysyms.Down): | ||
264 | 84 | completion.set_match_func(self.match_func,widget) | ||
265 | 85 | completion.set_model(self.model) | ||
266 | 86 | widget.set_completion(completion) | ||
267 | 87 | completion.set_text_column(0) | ||
268 | 88 | |||
269 | 89 | def match_func(self, completion, key, iter, widget): | ||
270 | 90 | model = completion.get_model() | ||
271 | 91 | return model[iter][0].lower().find(widget.get_text().lower()) >= 0 and True or False | ||
272 | 92 | |||
273 | 93 | def sig_activate(self, *args): | 80 | def sig_activate(self, *args): |
274 | 94 | text = self.child.get_text() | 81 | text = self.child.get_text() |
284 | 95 | value = False | 82 | value = self._view.modelfield.selection.get_key(text) |
285 | 96 | if text: | 83 | if not value: |
286 | 97 | for txt, val in self._selection.items(): | 84 | self.entry_text = text |
278 | 98 | if not val: | ||
279 | 99 | continue | ||
280 | 100 | if txt[:len(text)].lower() == text.lower(): | ||
281 | 101 | value = val | ||
282 | 102 | if len(txt) == len(text): | ||
283 | 103 | break | ||
287 | 104 | self._view.modelfield.set_client(self._view.model, value, force_change=True) | 85 | self._view.modelfield.set_client(self._view.model, value, force_change=True) |
288 | 105 | self.display(self._view.model, self._view.modelfield) | 86 | self.display(self._view.model, self._view.modelfield) |
289 | 106 | 87 | ||
290 | 107 | |||
291 | 108 | def set_value(self, model, model_field): | 88 | def set_value(self, model, model_field): |
297 | 109 | model_field.set_client(model, self.value_get()) | 89 | model_field.selection.update(self._selection) |
298 | 110 | 90 | text = self.child.get_text() | |
299 | 111 | def _menu_sig_default_set(self): | 91 | value = False |
300 | 112 | self.set_value(self._view.model, self._view.modelfield) | 92 | if text: |
301 | 113 | super(selection, self)._menu_sig_default_set() | 93 | model_field.selection.get_key(text) |
302 | 94 | value = model_field.selection.get_key(text) | ||
303 | 95 | model_field.set_client(model, value) | ||
304 | 114 | 96 | ||
305 | 115 | def display(self, model, model_field): | 97 | def display(self, model, model_field): |
306 | 116 | self.ok = False | ||
307 | 117 | if not model_field: | 98 | if not model_field: |
308 | 118 | self.child.set_text('') | 99 | self.child.set_text('') |
311 | 119 | self.ok = True | 100 | return |
312 | 120 | return False | 101 | model_field.selection.update(dict(self.attrs.get('selection',[]))) |
313 | 121 | super(selection, self).display(model, model_field) | 102 | super(selection, self).display(model, model_field) |
325 | 122 | value = model_field.get(model) | 103 | key = model_field.get(model, False) |
326 | 123 | if not value: | 104 | # model_field.selection.update(self._selection) |
327 | 124 | self.child.set_text('') | 105 | text = model_field.selection.get_value(key) |
328 | 125 | else: | 106 | self.child.set_text(self.entry_text or text) |
329 | 126 | found = False | 107 | self.entry_text = "" |
319 | 127 | for long_text, sel_value in self._selection.items(): | ||
320 | 128 | if sel_value == value: | ||
321 | 129 | self.child.set_text(long_text) | ||
322 | 130 | found = True | ||
323 | 131 | break | ||
324 | 132 | self.ok = True | ||
330 | 133 | 108 | ||
334 | 134 | def sig_changed(self, *args): | 109 | def sig_changed(self, combox): |
335 | 135 | if self.ok: | 110 | self._focus_out() |
333 | 136 | self._focus_out() | ||
336 | 137 | 111 | ||
337 | 138 | def _color_widget(self): | 112 | def _color_widget(self): |
338 | 139 | return self.child | 113 | return self.child |
339 | @@ -141,4 +115,3 @@ | |||
340 | 141 | def grab_focus(self): | 115 | def grab_focus(self): |
341 | 142 | return self.entry.grab_focus() | 116 | return self.entry.grab_focus() |
342 | 143 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: | 117 | # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: |
343 | 144 | |||
344 | 145 | 118 | ||
345 | === modified file 'bin/widget/view/list.py' | |||
346 | --- bin/widget/view/list.py 2011-04-12 08:48:06 +0000 | |||
347 | +++ bin/widget/view/list.py 2011-04-19 08:45:00 +0000 | |||
348 | @@ -860,7 +860,7 @@ | |||
349 | 860 | if col in self.widget_tree.handlers: | 860 | if col in self.widget_tree.handlers: |
350 | 861 | if self.widget_tree.handlers[col]: | 861 | if self.widget_tree.handlers[col]: |
351 | 862 | renderer.disconnect(self.widget_tree.handlers[col]) | 862 | renderer.disconnect(self.widget_tree.handlers[col]) |
353 | 863 | self.widget_tree.handlers[col] = renderer.connect_after('editing-started', send_keys, self.widget_tree) | 863 | self.widget_tree.handlers[col] = renderer.connect_after('editing-started', send_keys, self.widget_tree, col.name) |
354 | 864 | 864 | ||
355 | 865 | 865 | ||
356 | 866 | def set_invisible_attr(self): | 866 | def set_invisible_attr(self): |
357 | 867 | 867 | ||
358 | === modified file 'bin/widget/view/tree_gtk/editabletree.py' | |||
359 | --- bin/widget/view/tree_gtk/editabletree.py 2010-12-23 09:52:21 +0000 | |||
360 | +++ bin/widget/view/tree_gtk/editabletree.py 2011-04-19 08:45:00 +0000 | |||
361 | @@ -149,7 +149,12 @@ | |||
362 | 149 | def get_cursor(self): | 149 | def get_cursor(self): |
363 | 150 | res = super(EditableTreeView, self).get_cursor() | 150 | res = super(EditableTreeView, self).get_cursor() |
364 | 151 | return res | 151 | return res |
366 | 152 | 152 | ||
367 | 153 | def get_current_model(self): | ||
368 | 154 | path, column = self.get_cursor() | ||
369 | 155 | store = self.get_model() | ||
370 | 156 | return store.get_value(store.get_iter(path), 0) | ||
371 | 157 | |||
372 | 153 | def set_value(self): | 158 | def set_value(self): |
373 | 154 | path, column = self.get_cursor() | 159 | path, column = self.get_cursor() |
374 | 155 | store = self.get_model() | 160 | store = self.get_model() |
375 | @@ -175,7 +180,7 @@ | |||
376 | 175 | def on_keypressed(self, entry, event, cell_value): | 180 | def on_keypressed(self, entry, event, cell_value): |
377 | 176 | path, column = self.get_cursor() | 181 | path, column = self.get_cursor() |
378 | 177 | store = self.get_model() | 182 | store = self.get_model() |
380 | 178 | model = store.get_value(store.get_iter(path), 0) | 183 | model = self.get_current_model() |
381 | 179 | if event.keyval in self.leaving_events: | 184 | if event.keyval in self.leaving_events: |
382 | 180 | shift_pressed = bool(gtk.gdk.SHIFT_MASK & event.state) | 185 | shift_pressed = bool(gtk.gdk.SHIFT_MASK & event.state) |
383 | 181 | if isinstance(entry, gtk.Entry): | 186 | if isinstance(entry, gtk.Entry): |
384 | 182 | 187 | ||
385 | === modified file 'bin/widget/view/tree_gtk/parser.py' | |||
386 | --- bin/widget/view/tree_gtk/parser.py 2011-03-20 11:26:23 +0000 | |||
387 | +++ bin/widget/view/tree_gtk/parser.py 2011-04-19 08:45:00 +0000 | |||
388 | @@ -33,6 +33,7 @@ | |||
389 | 33 | from editabletree import EditableTreeView | 33 | from editabletree import EditableTreeView |
390 | 34 | from widget.view import interface | 34 | from widget.view import interface |
391 | 35 | from widget.view.list import group_record | 35 | from widget.view.list import group_record |
392 | 36 | from widget.model.field import SelectionField, M2OField | ||
393 | 36 | import time | 37 | import time |
394 | 37 | import date_renderer | 38 | import date_renderer |
395 | 38 | 39 | ||
396 | @@ -47,13 +48,16 @@ | |||
397 | 47 | import gobject | 48 | import gobject |
398 | 48 | import pango | 49 | import pango |
399 | 49 | 50 | ||
402 | 50 | def send_keys(renderer, entry, position, treeview): | 51 | def send_keys(renderer, entry, position, treeview, col_name): |
403 | 51 | if entry: | 52 | if entry: |
404 | 52 | entry.connect('key_press_event', treeview.on_keypressed, renderer.get_property('text')) | 53 | entry.connect('key_press_event', treeview.on_keypressed, renderer.get_property('text')) |
405 | 53 | entry.set_data('renderer', renderer) | 54 | entry.set_data('renderer', renderer) |
406 | 54 | entry.editing_done_id = entry.connect('editing_done', treeview.on_editing_done) | 55 | entry.editing_done_id = entry.connect('editing_done', treeview.on_editing_done) |
407 | 55 | if isinstance(entry, gtk.ComboBoxEntry): | 56 | if isinstance(entry, gtk.ComboBoxEntry): |
408 | 56 | entry.connect('changed', treeview.on_editing_done) | 57 | entry.connect('changed', treeview.on_editing_done) |
409 | 58 | if isinstance(entry, gtk.ComboBoxEntry): | ||
410 | 59 | popup = treeview.cells[col_name].popup | ||
411 | 60 | entry.connect('notify::popup-shown', popup, treeview) | ||
412 | 57 | 61 | ||
413 | 58 | def sort_model(column, screen): | 62 | def sort_model(column, screen): |
414 | 59 | unsaved_model = [x for x in screen.models if x.id == None or x.modified] | 63 | unsaved_model = [x for x in screen.models if x.id == None or x.modified] |
415 | @@ -107,10 +111,8 @@ | |||
416 | 107 | treeview.sequence = False | 111 | treeview.sequence = False |
417 | 108 | treeview.connect("motion-notify-event", treeview.set_tooltip) | 112 | treeview.connect("motion-notify-event", treeview.set_tooltip) |
418 | 109 | treeview.connect('key-press-event', treeview.on_tree_key_press) | 113 | treeview.connect('key-press-event', treeview.on_tree_key_press) |
419 | 110 | |||
420 | 111 | for node in root_node: | 114 | for node in root_node: |
421 | 112 | node_attrs = tools.node_attributes(node) | 115 | node_attrs = tools.node_attributes(node) |
422 | 113 | |||
423 | 114 | if node.tag == 'button': | 116 | if node.tag == 'button': |
424 | 115 | cell = Cell('button')(node_attrs['string'], treeview, node_attrs) | 117 | cell = Cell('button')(node_attrs['string'], treeview, node_attrs) |
425 | 116 | cell.name = node_attrs['name'] | 118 | cell.name = node_attrs['name'] |
426 | @@ -158,16 +160,17 @@ | |||
427 | 158 | self.window) | 160 | self.window) |
428 | 159 | treeview.cells[fname] = cell | 161 | treeview.cells[fname] = cell |
429 | 160 | renderer = cell.renderer | 162 | renderer = cell.renderer |
431 | 161 | 163 | col = gtk.TreeViewColumn(None, renderer) | |
432 | 164 | col.name = fname | ||
433 | 162 | write_enable = editable and not node_attrs.get('readonly', False) | 165 | write_enable = editable and not node_attrs.get('readonly', False) |
434 | 163 | if isinstance(renderer, gtk.CellRendererToggle): | 166 | if isinstance(renderer, gtk.CellRendererToggle): |
435 | 164 | renderer.set_property('activatable', write_enable) | 167 | renderer.set_property('activatable', write_enable) |
436 | 165 | elif isinstance(renderer, (gtk.CellRendererText, gtk.CellRendererCombo, date_renderer.DecoratorRenderer)): | 168 | elif isinstance(renderer, (gtk.CellRendererText, gtk.CellRendererCombo, date_renderer.DecoratorRenderer)): |
437 | 166 | renderer.set_property('editable', write_enable) | 169 | renderer.set_property('editable', write_enable) |
438 | 167 | if write_enable: | 170 | if write_enable: |
442 | 168 | handler_id = renderer.connect_after('editing-started', send_keys, treeview) | 171 | handler_id = renderer.connect_after('editing-started', send_keys, treeview, col.name) |
443 | 169 | 172 | ||
444 | 170 | col = gtk.TreeViewColumn(None, renderer) | 173 | |
445 | 171 | treeview.handlers[col] = handler_id | 174 | treeview.handlers[col] = handler_id |
446 | 172 | col_label = gtk.Label('') | 175 | col_label = gtk.Label('') |
447 | 173 | if fields[fname].get('required', False): | 176 | if fields[fname].get('required', False): |
448 | @@ -176,7 +179,7 @@ | |||
449 | 176 | col_label.set_text(fields[fname]['string']) | 179 | col_label.set_text(fields[fname]['string']) |
450 | 177 | col_label.show() | 180 | col_label.show() |
451 | 178 | col.set_widget(col_label) | 181 | col.set_widget(col_label) |
453 | 179 | col.name = fname | 182 | |
454 | 180 | col._type = fields[fname]['type'] | 183 | col._type = fields[fname]['type'] |
455 | 181 | col.set_cell_data_func(renderer, cell.setter) | 184 | col.set_cell_data_func(renderer, cell.setter) |
456 | 182 | col.set_clickable(True) | 185 | col.set_clickable(True) |
457 | @@ -549,6 +552,13 @@ | |||
458 | 549 | return rpc.name_get([found[0]], context)[0] | 552 | return rpc.name_get([found[0]], context)[0] |
459 | 550 | else: | 553 | else: |
460 | 551 | return False, None | 554 | return False, None |
461 | 555 | |||
462 | 556 | def get_textual_value(self, model): | ||
463 | 557 | if isinstance(model[self.field_name], SelectionField): | ||
464 | 558 | key = model[self.field_name].get_client(model) | ||
465 | 559 | return model[self.field_name].selection.get_value(key) | ||
466 | 560 | return model[self.field_name].get_client(model) or '' | ||
467 | 561 | |||
468 | 552 | 562 | ||
469 | 553 | 563 | ||
470 | 554 | class O2M(Char): | 564 | class O2M(Char): |
471 | @@ -609,29 +619,46 @@ | |||
472 | 609 | def __init__(self, *args): | 619 | def __init__(self, *args): |
473 | 610 | super(Selection, self).__init__(*args) | 620 | super(Selection, self).__init__(*args) |
474 | 611 | self.renderer = gtk.CellRendererCombo() | 621 | self.renderer = gtk.CellRendererCombo() |
479 | 612 | selection_data = gtk.ListStore(object, str) | 622 | self.selection_data = gtk.ListStore(str, str) |
480 | 613 | for x in self.attrs.get('selection', []): | 623 | selection = self.attrs.get('selection', []) |
481 | 614 | selection_data.append(x) | 624 | for x in selection: |
482 | 615 | self.renderer.set_property('model', selection_data) | 625 | self.selection_data.append(x) |
483 | 626 | if not selection: | ||
484 | 627 | self.selection_data.append([False, '']) | ||
485 | 628 | self.renderer.set_property('model', self.selection_data) | ||
486 | 616 | self.renderer.set_property('text-column', 1) | 629 | self.renderer.set_property('text-column', 1) |
487 | 630 | self.relation = self.attrs.get('relation') | ||
488 | 617 | 631 | ||
489 | 618 | def get_textual_value(self, model): | 632 | def get_textual_value(self, model): |
492 | 619 | selection = dict(self.attrs['selection']) | 633 | key = model[self.field_name].get(model) |
493 | 620 | selection_value = selection.get(model[self.field_name].get(model), '') | 634 | selection_value = model[self.field_name].selection.get_value(key) |
494 | 621 | if isinstance(model, group_record): | 635 | if isinstance(model, group_record): |
495 | 622 | return selection_value + model[self.field_name].count | 636 | return selection_value + model[self.field_name].count |
496 | 623 | return selection_value | 637 | return selection_value |
497 | 638 | |||
498 | 639 | def popup(self, combobox, para, treeview): | ||
499 | 640 | if combobox.get_property('popup-shown') and self.relation: | ||
500 | 641 | entry = combobox.get_child() | ||
501 | 642 | text = entry.get_property('text') | ||
502 | 643 | rpc = RPCProxy(self.relation) | ||
503 | 644 | model = treeview.get_current_model() | ||
504 | 645 | domain = model[self.field_name].domain_get(model) | ||
505 | 646 | context = model[self.field_name].context_get(model) | ||
506 | 647 | key = model[self.field_name].selection.get_key(text) | ||
507 | 648 | if key: | ||
508 | 649 | text = '' | ||
509 | 650 | selection = rpc.name_search(text, domain, 'ilike',context, False) | ||
510 | 651 | if selection: | ||
511 | 652 | self.selection_data.clear() | ||
512 | 653 | model = treeview.get_current_model() | ||
513 | 654 | model[self.field_name].selection.update(dict(selection)) | ||
514 | 655 | for x in selection: | ||
515 | 656 | self.selection_data.append(x) | ||
516 | 624 | 657 | ||
517 | 625 | def value_from_text(self, model, text): | 658 | def value_from_text(self, model, text): |
527 | 626 | selection = self.attrs['selection'] | 659 | key = model[self.field_name].get(model) |
528 | 627 | text = tools.ustr(text) | 660 | selection_value = model[self.field_name].selection.get_value(key) |
529 | 628 | res = False | 661 | return model[self.field_name].selection.get_key(text) |
521 | 629 | for val, txt in selection: | ||
522 | 630 | if txt[:len(text)].lower() == text.lower(): | ||
523 | 631 | if len(txt) == len(text): | ||
524 | 632 | return val | ||
525 | 633 | res = val | ||
526 | 634 | return res | ||
530 | 635 | 662 | ||
531 | 636 | 663 | ||
532 | 637 | class ProgressBar(object): | 664 | class ProgressBar(object): |
533 | 638 | 665 | ||
534 | === modified file 'bin/widget_search/selection.py' | |||
535 | --- bin/widget_search/selection.py 2011-04-04 11:19:53 +0000 | |||
536 | +++ bin/widget_search/selection.py 2011-04-19 08:45:00 +0000 | |||
537 | @@ -28,25 +28,37 @@ | |||
538 | 28 | class selection(wid_int.wid_int): | 28 | class selection(wid_int.wid_int): |
539 | 29 | def __init__(self, name, parent, attrs={}, model=None, screen=None): | 29 | def __init__(self, name, parent, attrs={}, model=None, screen=None): |
540 | 30 | wid_int.wid_int.__init__(self, name, parent, attrs, screen) | 30 | wid_int.wid_int.__init__(self, name, parent, attrs, screen) |
541 | 31 | |||
542 | 32 | self.widget = gtk.combo_box_entry_new_text() | 31 | self.widget = gtk.combo_box_entry_new_text() |
543 | 32 | self.widget.connect('notify::popup-shown', self.popup_show) | ||
544 | 33 | self.context = screen.context | ||
545 | 34 | self.relation_model = self.attrs.get('relation', '') | ||
546 | 33 | self.widget.child.set_editable(True) | 35 | self.widget.child.set_editable(True) |
547 | 34 | self.attrs = attrs | 36 | self.attrs = attrs |
548 | 35 | self._selection = {} | 37 | self._selection = {} |
549 | 36 | self.name = name | 38 | self.name = name |
553 | 37 | self.val_id = False | 39 | self.set_popdown(attrs.get('selection',[])) |
551 | 38 | if 'selection' in attrs: | ||
552 | 39 | self.set_popdown(attrs.get('selection',[])) | ||
554 | 40 | if self.default_search: | 40 | if self.default_search: |
555 | 41 | if isinstance(self.default_search,list): | 41 | if isinstance(self.default_search,list): |
556 | 42 | self.default_search = self.default_search[0] | 42 | self.default_search = self.default_search[0] |
557 | 43 | if self.attrs['type'] == 'many2one': | 43 | if self.attrs['type'] == 'many2one': |
559 | 44 | self._value_set(int(self.default_search)) | 44 | sel = rpc.session.rpc_exec_auth('/object', 'execute', self.relation_model, 'name_search', '' , [('id','=',self.default_search)] , 'ilike', self.context, False) |
560 | 45 | self.set_popdown(sel) | ||
561 | 46 | self._value_set(int(self.default_search)) | ||
562 | 45 | else: | 47 | else: |
563 | 46 | self._value_set(str(self.default_search)) | 48 | self._value_set(str(self.default_search)) |
564 | 47 | if self.widget.child.get_text() in self._selection.keys(): | 49 | if self.widget.child.get_text() in self._selection.keys(): |
565 | 48 | self.widget.set_active(self.indexes[self.widget.child.get_text()]-1) | 50 | self.widget.set_active(self.indexes[self.widget.child.get_text()]-1) |
566 | 49 | 51 | ||
567 | 52 | def popup_show(self, combobox, popup_show): | ||
568 | 53 | search_text = self.widget.child.get_text() | ||
569 | 54 | # if self._selection.get(search_text, False): | ||
570 | 55 | # search_text ='' | ||
571 | 56 | if combobox.get_property('popup-shown') and self.attrs['type'] == 'many2one': | ||
572 | 57 | selection = rpc.session.rpc_exec_auth('/object', 'execute', self.relation_model, 'name_search', search_text , [] , 'ilike', self.context, False) | ||
573 | 58 | self.set_popdown(selection) | ||
574 | 59 | if not selection: | ||
575 | 60 | self.widget.child.set_text('') | ||
576 | 61 | |||
577 | 50 | def set_popdown(self, selection): | 62 | def set_popdown(self, selection): |
578 | 51 | self.model = self.widget.get_model() | 63 | self.model = self.widget.get_model() |
579 | 52 | self.model.clear() | 64 | self.model.clear() |
Hello,
For the client side stuff, there are few bugs I found.
1: The feature of search view "search_ default_ XXXX" in the context is not working causing a regression here with the above change.
2: setting value of the field which has widget="selection" thru an onchange does not work. Again a regression.
3:If a O2M has a subfield which has widget="selection" attribute behaves very odd
4:Once I have selected the value from the list that the name_search returns then on my next click the domain should take the text that is already selected in the field. currently it takes a ""(blank) value resulting in all records.
Thanks