diff --git a/CHANGELOG b/CHANGELOG index 65fb7251b3..d35e52886e 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,5 @@ +* Selection widget used for many2one dynamically change their content following + the domain specification * Added a connection manager à la gajim * Fix warning in wizards * Added possibility to use server-side icons diff --git a/tryton/common/domain_inversion.py b/tryton/common/domain_inversion.py index 85078ac536..05480c8624 100644 --- a/tryton/common/domain_inversion.py +++ b/tryton/common/domain_inversion.py @@ -22,7 +22,9 @@ OPERATORS = { 'not child_of': lambda a, b: True, } -def locale_part(expression): +def locale_part(expression, field_name): + if expression == field_name: + return 'id' if '.' in expression: fieldname, local = expression.split('.', 1) return local @@ -75,14 +77,14 @@ def eval_domain(domain, context, boolop=operator.and_): return boolop(eval_domain(domain[0], context), eval_domain(domain[1:], context, boolop)) -def localize_domain(domain): +def localize_domain(domain, field_name=None): "returns only locale part of domain. eg: langage.code -> code" if domain in ('AND', 'OR', True, False): return domain elif is_leaf(domain): - return [locale_part(domain[0])] + domain[1:] + return [locale_part(domain[0], field_name)] + domain[1:] else: - return [localize_domain(part) for part in domain] + return [localize_domain(part, field_name) for part in domain] def unlocalize_domain(domain, fieldname): if domain in ('AND', 'OR', True, False): diff --git a/tryton/gui/window/view_form/model/field.py b/tryton/gui/window/view_form/model/field.py index 9d24c5f782..3275a97843 100644 --- a/tryton/gui/window/view_form/model/field.py +++ b/tryton/gui/window/view_form/model/field.py @@ -394,7 +394,7 @@ class M2OField(CharField): def domain_get(self, record): screen_domain, attr_domain = self.domains_get(record) - return localize_domain(inverse_leaf(screen_domain)) + attr_domain + return localize_domain(inverse_leaf(screen_domain), self.name) + attr_domain class O2OField(M2OField): diff --git a/tryton/gui/window/view_form/view/form_gtk/selection.py b/tryton/gui/window/view_form/view/form_gtk/selection.py index e5850f6289..94a032fd3c 100644 --- a/tryton/gui/window/view_form/view/form_gtk/selection.py +++ b/tryton/gui/window/view_form/view/form_gtk/selection.py @@ -32,47 +32,50 @@ class Selection(WidgetInterface): self.widget.set_focus_chain([child]) self._selection = {} - selection = attrs.get('selection', [])[:] - self.selection = selection[:] - if not attrs.get('domain'): - domain = [] - else: - domain = PYSONDecoder(rpc.CONTEXT).decode(attrs.get('domain')) - if 'relation' in attrs: + self.selection = attrs.get('selection', [])[:] + self.attrs = attrs + self._last_domain = None + self.init_selection() + + def init_selection(self): + selection = self.attrs.get('selection', [])[:] + if not isinstance(selection, (list, tuple)): try: - result = rpc.execute('model', attrs['relation'], 'search_read', - domain, 0, None, None, ['rec_name'], rpc.CONTEXT) - selection = [(x['id'], x['rec_name']) for x in result] + selection = rpc.execute('model', + self.model_name, selection, rpc.CONTEXT) except Exception, exception: common.process_exception(exception, self.window) selection = [] - self.selection = selection[:] - else: - if not isinstance(selection, (list, tuple)): - try: - selection = rpc.execute('model', - self.model_name, selection, rpc.CONTEXT) - except Exception, exception: - common.process_exception(exception, self.window) - selection = [] - self.selection = selection[:] - - for dom in common.filter_domain(domain): - if dom[1] in ('=', '!='): - todel = [] - for i in range(len(selection)): - if (dom[1] == '=' \ - and selection[i][0] != dom[2]) \ - or (dom[1] == '!=' \ - and selection[i][0] == dom[2]): - todel.append(i) - for i in todel[::-1]: - del selection[i] - - if attrs.get('sort', True): + self.selection = selection[:] + if self.attrs.get('sort', True): selection.sort(lambda x, y: cmp(x[1], y[1])) self.set_popdown(selection) - self.last_key = (None, 0) + + def update_selection(self, record): + if not self.field: + return + if 'relation' not in self.attrs: + return + + domain = self.field.domain_get(record) + if domain == self._last_domain: + return + + args = ('model', self.attrs['relation'], 'search_read', domain, 0, None, + None, ['rec_name'], rpc.CONTEXT) + try: + result = rpc.execute(*args) + except Exception, exception: + result = common.process_exception(exception, self.window, args) + if isinstance(result, list): + selection = [(x['id'], x['rec_name']) for x in result] + selection.append((False, '')) + self._last_domain = domain + else: + selection = [] + self._last_domain = None + self.selection = selection[:] + self.set_popdown(selection) def grab_focus(self): return self.entry.grab_focus() @@ -140,6 +143,7 @@ class Selection(WidgetInterface): super(Selection, self)._menu_sig_default_set(reset=reset) def display(self, record, field): + self.update_selection(record) child = self.entry.get_child() self.changed = False if not field: @@ -168,6 +172,8 @@ class Selection(WidgetInterface): child.set_text(long_text) found = True break + if not found: + child.set_text('') self.changed = True def display_value(self):