def set_on_change(self, record, value): record.modified_fields.setdefault(self.name) self._set_default_value(record) if isinstance(value, (list, tuple)): self._set_value(record, value, modified=True) return if value and (value.get('add') or value.get('update')): context = self.get_context(record) fields = record.value[self.name].fields values = chain(value.get('update', []), (d for _, d in value.get('add', []))) field_names = set(f for v in values for f in v if f not in fields and f != 'id') if field_names: try: fields = RPCExecute('model', self.attrs['relation'], 'fields_get', list(field_names), context=context) except RPCException: return else: fields = {} to_remove = [] for record2 in record.value[self.name]: if not record2.id: to_remove.append(record2) if value and value.get('remove'): for record_id in value['remove']: record2 = record.value[self.name].get(record_id) if record2 is not None: to_remove.append(record2) for record2 in to_remove: record.value[self.name].remove(record2, signal=False, force_remove=False) if value and (value.get('add') or value.get('update', [])): record.value[self.name].add_fields(fields, signal=False) for index, vals in value.get('add', []): new_record = record.value[self.name].new(default=False) record.value[self.name].add(new_record, index, signal=False) new_record.set_on_change(vals) for vals in value.get('update', []): if 'id' not in vals: continue record2 = record.value[self.name].get(vals['id']) if record2 is not None: record2.set_on_change(vals)
def response(self, win, response_id): if response_id == Gtk.ResponseType.OK: if self.screen.current_record.validate(): vals = copy.copy(self.screen.get()) try: RPCExecute('model', 'res.user', 'set_preferences', vals) except RPCException: return rpc.context_reset() self.parent.present() self.destroy() self.callback()
def copy(self): ids = [r.id for r in self.selected_records] try: new_ids = RPCExecute('model', self.model_name, 'copy', ids, {}, context=self.context) except RPCException: return False self.load(new_ids) return True
def add_view_id(self, view_id, view_type): if view_id and str(view_id) in self.views_preload: view = self.views_preload[str(view_id)] elif not view_id and view_type in self.views_preload: view = self.views_preload[view_type] else: try: view = RPCExecute('model', self.model_name, 'fields_view_get', view_id, view_type, context=self.context) except RPCException: return return self.add_view(view)
def do_autocomplete(self, fieldname): self.autocompletion[fieldname] = [] autocomplete = self.group.fields[fieldname].attrs['autocomplete'] args = self._get_on_change_args(autocomplete) try: res = RPCExecute( 'model', self.model_name, 'autocomplete_' + fieldname, args, context=self.get_context()) except RPCException: # ensure res is a list res = [] self.autocompletion[fieldname] = res
def end(self, callback=None): def end_callback(action): self.destroy(action=action()) if callback: callback() try: RPCExecute('wizard', self.action, 'delete', self.session_id, process_exception=False, callback=end_callback) except Exception: logger.warn( _("Unable to delete wizard %s") % self.session_id, exc_info=True)
def set_tree_state(self): view = self.current_view if view.view_type not in ('tree', 'form'): return if id(view) in self.tree_states_done: return if view.view_type == 'form' and self.tree_states_done: return parent = self.parent.id if self.parent else None expanded_nodes, selected_nodes = [], [] timestamp = self.parent._timestamp if self.parent else None state = self.tree_states[parent][view.children_field] if state: state_timestamp, expanded_nodes, selected_nodes = state if (timestamp != state_timestamp and view.view_type != 'form'): state = None if state is None and CONFIG['client.save_tree_state'] and ( view.view_type != 'tree' or not view.always_expand): json_domain = self.get_tree_domain(parent) try: expanded_nodes, selected_nodes = RPCExecute( 'model', 'ir.ui.view_tree_state', 'get', self.model_name, json_domain, view.children_field) expanded_nodes = json.loads(expanded_nodes) selected_nodes = json.loads(selected_nodes) except RPCException: logging.getLogger(__name__).warn( _('Unable to get view tree state')) self.tree_states[parent][view.children_field] = (timestamp, expanded_nodes, selected_nodes) if view.view_type == 'tree': view.expand_nodes(expanded_nodes) view.select_nodes(selected_nodes) else: if selected_nodes: record = None for node in selected_nodes[0]: new_record = self.group.get(node) if node < 0 and -node < len(self.group): # Negative id is the index of the new record new_record = self.group[-node] if not new_record: break else: record = new_record if record and record != self.current_record: self.current_record = record # Force a display of the view to synchronize the # widgets with the new record view.display() self.tree_states_done.add(id(view))
def update_selection(self, record, field): if not field: return domain = field.domain_get(record) if 'relation' not in self.attrs: change_with = self.attrs.get('selection_change_with') or [] value = record._get_on_change_args(change_with) value.pop('id', None) self.init_selection(value) self.filter_selection(domain, record, field) else: context = field.get_context(record) domain_cache_key = (freeze_value(domain), freeze_value(context)) if domain_cache_key in self._domain_cache: self.selection = self._domain_cache[domain_cache_key] self._last_domain = (domain, context) if (domain, context) == self._last_domain: return fields = ['rec_name'] help_field = self.attrs.get('help_field') if help_field: fields.append(help_field) try: result = RPCExecute('model', self.attrs['relation'], 'search_read', domain, 0, None, None, fields, context=context) except RPCException: result = False if isinstance(result, list): selection = [(x['id'], x['rec_name']) for x in result] if self.nullable_widget: selection.append((None, '')) if help_field: help_ = {x['id']: x[help_field] for x in result} else: help_ = {} self._last_domain = (domain, context) self._domain_cache[domain_cache_key] = selection else: selection = [] help_ = {} self._last_domain = None self.selection = selection[:] self.help = help_ self.inactive_selection = []
def fill_predefwin(self): try: export_ids = RPCExecute('model', 'ir.export', 'search', [('resource', '=', self.model)], 0, None, None, context=self.context) except RPCException: return try: exports = RPCExecute('model', 'ir.export', 'read', export_ids, None, context=self.context) except RPCException: return try: lines = RPCExecute('model', 'ir.export.line', 'read', sum((list(x['export_fields']) for x in exports), []), None, context=self.context) except RPCException: return id2lines = {} for line in lines: id2lines.setdefault(line['export'], []).append(line) for export in exports: self.predef_model.append( (export['id'], [x['name'] for x in id2lines.get(export['id'], [])], export['name'])) self.pref_export.set_model(self.predef_model)
def init_selection(self, key=None): if key is None: key = tuple(sorted((k, None) for k in self.attrs.get('selection_change_with') or [])) selection = self.attrs.get('selection', [])[:] if (not isinstance(selection, (list, tuple)) and key not in self._values2selection): try: if self.attrs.get('selection_change_with'): selection = RPCExecute('model', self.model_name, selection, dict(key)) else: selection = RPCExecute('model', self.model_name, selection) except RPCException: selection = [] self._values2selection[key] = selection elif key in self._values2selection: selection = self._values2selection[key] if self.attrs.get('sort', True): selection.sort(key=operator.itemgetter(1)) self.selection = selection[:] self.inactive_selection = []
def execute(act_id, data, action_type=None, context=None, keyword=False): # Must be executed synchronously to avoid double execution # on double click. if not action_type: action, = RPCExecute('model', 'ir.action', 'read', [act_id], ['type'], context=context) action_type = action['type'] action, = RPCExecute('model', action_type, 'fetch_action', act_id, context=context) if keyword: keywords = { 'ir.action.report': 'form_report', 'ir.action.wizard': 'form_action', 'ir.action.act_window': 'form_relate', } action.setdefault('keyword', keywords.get(action_type, '')) Action._exec_action(action, data, context=context)
def get_button_clicks(self, name): if self.id < 0: return clicks = self.button_clicks.get(name) if clicks is not None: return clicks try: clicks = RPCExecute('model', 'ir.model.button.click', 'get_click', self.model_name, name, self.id) self.button_clicks[name] = clicks except RPCException: return return clicks
def pre_validate(self): if not self.modified_fields: return True values = self._get_on_change_args(self.modified_fields) try: RPCExecute('model', self.model_name, 'pre_validate', values, context=self.get_context()) except RPCException: return False return True
def add_keys(self, keys): context = self.field.get_context(self.record) domain = self.field.domain_get(self.record) batchlen = min(10, CONFIG['client.limit']) for i in xrange(0, len(keys), batchlen): sub_keys = keys[i:i + batchlen] try: key_ids = RPCExecute('model', self.schema_model, 'search', [('name', 'in', sub_keys), domain], 0, CONFIG['client.limit'], None, context=context) except RPCException: key_ids = [] if not key_ids: continue try: values = RPCExecute('model', self.schema_model, 'get_keys', key_ids, context=context) except RPCException: values = [] if not values: continue self.keys.update({k['name']: k for k in values})
def add_name_suffix(name, context=None): if not data.get('ids') or not data.get('model'): return name max_records = 5 rec_names = RPCExecute('model', data['model'], 'read', data['ids'][:max_records], ['rec_name'], context=context) name_suffix = _(', ').join([x['rec_name'] for x in rec_names]) if len(data['ids']) > max_records: name_suffix += _(',\u2026') return _('%s (%s)') % (name, name_suffix)
def update(widget, search_text, callback=None): def end(): if callback: callback() return False if search_text != widget.get_text(): return end() gmodel = global_search_completion.get_model() if not search_text or not gmodel: gmodel.clear() gmodel.search_text = search_text return end() if getattr(gmodel, 'search_text', None) == search_text: return end() def set_result(result): try: result = result() except RPCException: result = [] if search_text != widget.get_text(): if callback: callback() return False gmodel.clear() for r in result: _, model, model_name, record_id, record_name, icon = r if icon: text = common.to_xml(record_name) pixbuf = common.IconFactory.get_pixbuf( icon, Gtk.IconSize.BUTTON) else: text = '<b>%s:</b>\n %s' % (common.to_xml(model_name), common.to_xml(record_name)) pixbuf = None gmodel.append([pixbuf, text, model, record_id, model_name]) gmodel.search_text = search_text # Force display of popup widget.emit('changed') end() RPCExecute('model', 'ir.model', 'global_search', search_text, CONFIG['client.limit'], self.menu_screen.model_name, context=self.menu_screen.context, callback=set_result) return False
def on_write_ids(self, ids): if not self.on_write: return [] res = [] for fnct in self.on_write: try: res += RPCExecute('model', self.model_name, fnct, ids, context=self.context) except RPCException: return [] return list({}.fromkeys(res))
def add_name_suffix(name, context=None): if not data.get('ids') or not data.get('model'): return name max_records = 5 ids = list(filter(lambda id: id >= 0, data['ids']))[:max_records] if not ids: return name rec_names = RPCExecute('model', data['model'], 'read', ids, ['rec_name'], context=context) name_suffix = _(', ').join([x['rec_name'] for x in rec_names]) if len(data['ids']) > len(ids): name_suffix += _(',...') return _('%s (%s)') % (name, name_suffix)
def sig_copy(self, widget=None): if not common.MODELACCESS[self.model]['create']: return if not self.modified_save(): return res_ids = self.sel_ids_get() try: new_ids = RPCExecute('model', self.model, 'copy', res_ids, {}, context=self.context) except RPCException: return self.screen.load(new_ids) self.message_info(_('Working now on the duplicated record(s)!'), 'green')
def translate(self, *args): if self.record.id < 0 or self.record.modified: common.message( _('You need to save the record before adding translations!')) return try: lang_ids = RPCExecute('model', 'ir.lang', 'search', [ ('translatable', '=', True), ]) except RPCException: return if not lang_ids: common.message(_('No other language available!')) return try: languages = RPCExecute('model', 'ir.lang', 'read', lang_ids, ['code', 'name']) except RPCException: return TranslateDialog(self, languages)
def search_active(self, active=True): if active and not self.parent: if not self.fields_view_tree: try: self.fields_view_tree = RPCExecute('model', self.model_name, 'fields_view_get', False, 'tree', context=self.context) except RPCException: return if not self.domain_parser: fields = copy.deepcopy(self.fields_view_tree['fields']) for name, props in fields.iteritems(): if props['type'] not in ('selection', 'reference'): continue if isinstance(props['selection'], (tuple, list)): continue props['selection'] = self.get_selection(props) # Filter only fields in XML view xml_dom = xml.dom.minidom.parseString( self.fields_view_tree['arch']) root_node, = xml_dom.childNodes xml_fields = [node_attributes(node).get('name') for node in root_node.childNodes if node.nodeName == 'field'] fields = collections.OrderedDict( (name, fields[name]) for name in xml_fields) for name, string, type_ in ( ('id', _('ID'), 'integer'), ('create_uid', _('Creation User'), 'many2one'), ('create_date', _('Creation Date'), 'datetime'), ('write_uid', _('Modification User'), 'many2one'), ('write_date', _('Modification Date'), 'datetime'), ): if name not in fields: fields[name] = { 'string': string.decode('utf-8'), 'name': name, 'type': type_, } if type_ == 'datetime': fields[name]['format'] = '"%H:%M:%S"' self.domain_parser = DomainParser(fields) self.screen_container.set_screen(self) self.screen_container.show_filter() else: self.screen_container.hide_filter()
def _button_instance(self, button): record = self.current_record args = record.expr_eval(button.get('change', [])) values = record._get_on_change_args(args) try: changes = RPCExecute('model', self.model_name, button['name'], values, context=self.context) except RPCException: return record.set_on_change(changes) record.signal('record-changed')
def save(self, force_reload=True): if self.id < 0 or self.modified: if self.id < 0: value = self.get() try: res, = RPCExecute('model', self.model_name, 'create', [value], context=self.get_context()) except RPCException: return False old_id = self.id self.id = res self.group.id_changed(old_id) elif self.modified: value = self.get() if value: context = self.get_context() context = context.copy() context['_timestamp'] = self.get_timestamp() try: RPCExecute('model', self.model_name, 'write', [self.id], value, context=context) except RPCException: return False self.cancel() if force_reload: self.reload() if self.group: self.group.written(self.id) if self.parent: self.parent.modified_fields.pop(self.group.child_name, None) self.parent.save(force_reload=force_reload) return self.id
def _sig_add(self, *args, **kwargs): if not self.focus_out: return access = common.MODELACCESS[self.screen.model_name] if not access['write'] or not access['read']: return self.view.set_value() domain = self.field.domain_get(self.record) context = self.field.context_get(self.record) domain = [domain, self.record.expr_eval(self.attrs.get('add_remove'))] removed_ids = self.field.get_removed_ids(self.record) self.focus_out = False try: if self.wid_text.get_text(): dom = [('rec_name', 'ilike', '%' + self.wid_text.get_text() + '%'), ['OR', domain, ('id', 'in', removed_ids)]] else: dom = ['OR', domain, ('id', 'in', removed_ids)] ids = RPCExecute('model', self.attrs['relation'], 'search', dom, 0, CONFIG['client.limit'], None, context=context) except RPCException: self.focus_out = True return False sequence = None if self.screen.current_view.view_type == 'tree': sequence = self.screen.current_view.widget_tree.sequence def callback(result): self.focus_out = True if result: ids = [x[0] for x in result] self.screen.load(ids, modified=True) self.screen.display(res_id=ids[0]) if sequence: self.screen.group.set_sequence(field=sequence) self.screen.set_cursor() self.wid_text.set_text('') if len(ids) != 1 or kwargs.get('win_search', False): WinSearch(self.attrs['relation'], callback, sel_multi=True, ids=ids, context=context, domain=domain, view_ids=self.attrs.get('view_ids', '').split(','), views_preload=self.attrs.get('views', {}), new=self.but_new.get_property('sensitive')) else: callback([(i, None) for i in ids])
def get_inactive_selection(self, value): if 'relation' not in self.attrs: return '' for val, text in self.inactive_selection: if str(val) == str(value): return text else: try: result, = RPCExecute('model', self.attrs['relation'], 'read', [value], ['rec_name']) self.inactive_selection.append( (result['id'], result['rec_name'])) return result['rec_name'] except RPCException: return ''
def on_change(self, fieldnames): values = {} for fieldname in fieldnames: on_change = self.group.fields[fieldname].attrs.get('on_change') if not on_change: continue values.update(self._get_on_change_args(on_change)) if values: try: if len(fieldnames) == 1: fieldname, = fieldnames changes = [] changes.append(RPCExecute( 'model', self.model_name, 'on_change_' + fieldname, values, context=self.get_context())) else: changes = RPCExecute( 'model', self.model_name, 'on_change', values, fieldnames, context=self.get_context()) except RPCException: return for change in changes: self.set_on_change(change)
def callback(result): if result: self.send_modified() try: new_fields = RPCExecute('model', self.schema_model, 'get_keys', [r[0] for r in result], context=context) except RPCException: new_fields = [] for new_field in new_fields: if new_field['name'] not in self.fields: self.keys[new_field['name']] = new_field self.add_line(new_field['name']) self.wid_text.set_text('')
def execute(action, data, context=None, keyword=False): if isinstance(action, int): # Must be executed synchronously to avoid double execution # on double click. action = RPCExecute( 'model', 'ir.action', 'get_action_value', action, context=context) if keyword: keywords = { 'ir.action.report': 'form_report', 'ir.action.wizard': 'form_action', 'ir.action.act_window': 'form_relate', } action.setdefault('keyword', keywords.get(action['type'], '')) Action._exec_action(action, data, context=context)
def fill_predefwin(self): try: exports = RPCExecute( 'model', 'ir.export', 'search_read', [('resource', '=', self.model)], 0, None, None, ['name', 'export_fields.name'], context=self.context) except RPCException: return for export in exports: self.predef_model.append(( export['id'], [f['name'] for f in export['export_fields.']], export['name'])) self.pref_export.set_model(self.predef_model)
def update(search_text, domain): if not entry.props.window: return False if search_text != entry.get_text(): return False completion_model = entry.get_completion().get_model() if not search_text or not model: completion_model.clear() completion_model.search_text = search_text return False if getattr(completion_model, 'search_text', None) == search_text: return False if domain is None: domain = field.domain_get(record) context = field.get_search_context(record) domain = [('rec_name', 'ilike', likify(search_text)), domain] order = field.get_search_order(record) def callback(results): try: results = results() except (TrytonError, TrytonServerError): results = [] if search_text != entry.get_text(): return False completion_model.clear() for result in results: completion_model.append([result['rec_name'], result['id']]) completion_model.search_text = search_text # Force display of popup entry.emit('changed') try: RPCExecute('model', model, 'search_read', domain, 0, CONFIG['client.limit'], order, ['rec_name'], context=context, process_exception=False, callback=callback) except Exception: logger.warning("Unable to search for completion of %s", model, exc_info=True) return False