def __init__(self, resource, fields, ids=[], parent=None, context={}, is_wizard=False, screen=None): super(ModelRecordGroup, self).__init__() self._readonly = False self.parent = parent self._context = context self._context.update(rpc.session.context) self.resource = resource self.rpc = RPCProxy(resource) self.fields = fields self.mfields = {} self.mfields_load(fields.keys(), self) self.screen = screen self.models = ModelList(self) self.current_idx = None self.load(ids) self.models_removed = [] self.on_write = '' self.is_wizard = is_wizard self.list_parent = False self.list_group = False
def __init__(self, resource, id, group=None, parent=None, new=False, list_parent=None): super(ModelRecord, self).__init__() self.resource = str(resource) self.rpc = RPCProxy(self.resource) self.id = id self.list_parent = list_parent self._loaded = False self.parent = parent self.mgroup = group self.value = {} self.state_attrs = {} self.modified = False self.modified_fields = {} self.pager_cache = {} self.is_m2m_modified = False self._concurrency_check_data = False for key, val in self.mgroup.mfields.items(): self.value[key] = val.create(self) if (new and val.attrs['type'] == 'one2many') and (val.attrs.get( 'mode', 'tree,form').startswith('form')): mod = self.value[key].model_new() self.value[key].model_add(mod)
def _get_colors(self, models, color_field, color_field_custom): auto_color_count = 0 # how many color do we need to generate auto. colors = {} for model in models: name = value = key = model.value[color_field] if isinstance(key, (tuple, list)): value, name = key key = tuple(key) if key in colors: # already present skip continue # if field is many2one, try to get color from object # 'color' field field_color = None field_widget = model.mgroup.mfields.get(color_field, False) if field_widget and field_widget.attrs['type'] == 'many2one': fproxy = RPCProxy(field_widget.attrs['relation']) try: fdata = fproxy.read(value, [color_field_custom]) if fdata: field_color = fdata.get(color_field_custom) and str(fdata.get(color_field_custom)) or None except Exception, e: #TODO: Need to limit exception self.log.exception(e) pass if not field_color: # increment total color to generate auto_color_count += 1 colors[key] = (name, value, field_color)
def cond_default(self, field, value): ir = RPCProxy('ir.values') values = ir.get('default', '%s=%s' % (field, value), [(self.resource, False)], False, {}) data = {} for index, fname, value in values: data[fname] = value self.set_default(data)
def cond_default(self, field, value): if field in self.mgroup.mfields: if self.mgroup.mfields[field].attrs.get("change_default", False): ir = RPCProxy("ir.values") values = ir.get("default", "%s=%s" % (field, value), [(self.resource, False)], False, {}) data = {} for index, fname, value in values: data[fname] = value self.set_default(data)
def cond_default(self, field, value): if field in self.mgroup.mfields: if self.mgroup.mfields[field].attrs.get('change_default', False): ir = RPCProxy('ir.values') values = ir.get('default', '%s=%s' % (field, value), [(self.resource, False)], False, {}) data = {} for index, fname, value in values: data[fname] = value self.set_default(data)
def set(self, model, value, test_state=False, modified=False): if value and isinstance(value, (int, str, unicode, long)): rpc2 = RPCProxy(self.attrs['relation']) result = rpc2.name_get([value], rpc.session.context) model.value[self.name] = result and result[0] or '' else: model.value[self.name] = value if modified: model.modified = True model.modified_fields.setdefault(self.name)
def set(self, model, value, modified=False): ## The case where M2M may appear in a domain as string ## eg: if I have a domain on partner list view as ## [('categ_id','=','supplier')] if value and isinstance(value[0], (str, unicode)): rpc2 = RPCProxy(self.attrs["relation"]) result = [] for val in value: result += rpc2.name_search(val, [], "=", rpc.session.context) value = map(lambda x: x[0], result) model.value[self.name] = value and value[: self.limit] or [] model.pager_cache[self.name] = value or [] if modified: model.modified = True model.modified_fields.setdefault(self.name)
def set(self, model, value, test_state=False, modified=False): if not value: model.value[self.name] = False return ref_model, id = value.split(',') if id: id = int(id) rpc2 = RPCProxy(ref_model) result = rpc2.name_get([id], rpc.session.context) if result: model.value[self.name] = ref_model, result[0] else: model.value[self.name] = False if modified: model.modified = True model.modified_fields.setdefault(self.name)
def open_remote(self, model, create=True, changed=False, text=None): modelfield = model.mgroup.mfields[self.field_name] relation = modelfield.attrs['relation'] domain = modelfield.domain_get(model) context = modelfield.context_get(model) if create: id = None elif not changed: id = modelfield.get(model) else: rpc = RPCProxy(relation) names = rpc.name_search(text, domain, 'ilike', context) if len(names) == 1: return True, names[0] searched = self.search_remote(relation, [x[0] for x in names], domain=domain, context=context) if searched[0]: return True, searched return False, False dia = M2ODialog(relation, id, domain=domain, context=context, window=self.window) ok, value = dia.run() dia.destroy() if ok: return True, value else: return False, False
def open_remote(self, model, create=True, changed=False, text=None): modelfield = model[self.field_name] relation = modelfield.attrs['relation'] rpc = RPCProxy(relation) context = model[self.field_name].context_get(model) domain = model[self.field_name].domain_get(model) if create: if text and len(text) and text[0] <> '(': domain.append(('name', '=', text)) ids = rpc.search(domain) if ids and len(ids) == 1: return True, ids else: ids = model[self.field_name].get_client(model) win = win_search(relation, sel_multi=True, ids=ids, context=context, domain=domain) found = win.go() if found: return True, found else: return False, None
def display(self, model, model_field): if not model_field: self.ok = False self.widget_combo.child.set_text('') return False super(reference, self).display(model, model_field) value = model_field.get_client(model) self.ok = False img = gtk.Image() if not value: model, (id, name) = '', (0, '') self.wid_text.set_text('') self.widget_combo.child.set_text('') else: model, (id, name) = value if id: self.widget_combo.child.set_text(self._selection2[model]) if not name: id, name = RPCProxy(model).name_get([id], rpc.session.context)[0] self.wid_text.set_text(name) img.set_from_stock('gtk-open', gtk.ICON_SIZE_BUTTON) self.but_open.set_image(img) else: # self.wid_text.set_text('') # this is commented as this caused many2one set to be unenterable img.set_from_stock('gtk-find', gtk.ICON_SIZE_BUTTON) self.but_open.set_image(img) self.ok = True
def search_remote(self, relation, ids=[], domain=[], context={}): rpc = RPCProxy(relation) win = win_search(relation, sel_multi=False, ids=ids, context=context, domain=domain) found = win.go() if found: return rpc.name_get([found[0]], context)[0] else: return False, None
def set_default(self, model, value): from widget.model.group import ModelRecordGroup fields = {} if value and len(value): context = self.context_get(model) rpc2 = RPCProxy(self.attrs['relation']) fields = rpc2.fields_get(value[0].keys(), context) model.value[self.name] = ModelRecordGroup(resource=self.attrs['relation'], fields=fields, parent=model) model.value[self.name].signal_connect(model.value[self.name], 'model-changed', self._model_changed) mod=None for record in (value or []): mod = model.value[self.name].model_new(default=False) mod.set_default(record) model.value[self.name].model_add(mod) model.value[self.name].current_model = mod #mod.signal('record-changed') return True
class _CmdHandler: def __handle_register(self): self.proxy.register_entity(self.options.id, _config_from_opts(self.options)) def __handle_unregister(self): self.proxy.unregister_entity(self.options.id) def __handle_set_config(self): cfg = self.proxy.get_entity_config(self.options.id) self.proxy.set_entity_config(self.options.id, _config_from_opts(self.options, default=cfg)) def __handle_get_config(self): print self.proxy.get_entity_config(self.options.id) def __handle_list(self): for id, cfg in self.proxy.get_entities(): print "%s <%s>" % (id, cfg) __handlers = { "register": __handle_register, "unregister": __handle_unregister, "set_config": __handle_set_config, "get_config": __handle_get_config, "list": __handle_list, } def __init__(self, cmdname, options): self.proxy = RPCProxy() self.cmdname = cmdname self.options = options def __nonzero__(self): return self.cmdname in self.__handlers def handle(self): self.proxy.connect(self.options.socket) try: self.__handlers[self.cmdname](self) finally: self.proxy.disconnect()
class _CmdHandler: def __handle_register(self): self.proxy.register_entity(self.options.id, _config_from_opts(self.options)) def __handle_unregister(self): self.proxy.unregister_entity(self.options.id) def __handle_set_config(self): cfg = self.proxy.get_entity_config(self.options.id) self.proxy.set_entity_config( self.options.id, _config_from_opts(self.options, default=cfg)) def __handle_get_config(self): print self.proxy.get_entity_config(self.options.id) def __handle_list(self): for id, cfg in self.proxy.get_entities(): print "%s <%s>" % (id, cfg) __handlers = { "register": __handle_register, "unregister": __handle_unregister, "set_config": __handle_set_config, "get_config": __handle_get_config, "list": __handle_list, } def __init__(self, cmdname, options): self.proxy = RPCProxy() self.cmdname = cmdname self.options = options def __nonzero__(self): return self.cmdname in self.__handlers def handle(self): self.proxy.connect(self.options.socket) try: self.__handlers[self.cmdname](self) finally: self.proxy.disconnect()
def set_default(self, model, value): from widget.model.group import ModelRecordGroup fields = {} if value and len(value): context = self.context_get(model) rpc2 = RPCProxy(self.attrs['relation']) fields = rpc2.fields_get(value[0].keys(), context) model.value[self.name] = ModelRecordGroup( resource=self.attrs['relation'], fields=fields, parent=model) model.value[self.name].signal_connect(model.value[self.name], 'model-changed', self._model_changed) mod = None for record in (value or []): mod = model.value[self.name].model_new(default=False) mod.set_default(record) model.value[self.name].model_add(mod) model.value[self.name].current_model = mod #mod.signal('record-changed') return True
def value_from_text(self, model, text): if not text: return [] if not (text[0]<>'('): return model[self.field_name].get(model) relation = model[self.field_name].attrs['relation'] rpc = RPCProxy(relation) domain = model[self.field_name].domain_get(model) context = model[self.field_name].context_get(model) names = rpc.name_search(text, domain, 'ilike', context) ids = [x[0] for x in names] win = win_search(relation, sel_multi=True, ids=ids, context=context, domain=domain) found = win.go() return found or []
def value_from_text(self, model, text): if not text: return False relation = model[self.field_name].attrs['relation'] rpc = RPCProxy(relation) domain = model[self.field_name].domain_get(model) context = model[self.field_name].context_get(model) names = rpc.name_search(text, domain, 'ilike', context) if len(names) != 1: return self.search_remote(relation, [x[0] for x in names], domain=domain, context=context)[0] return names[0]
def __init__(self, resource, id, group=None, parent=None, new=False ): super(ModelRecord, self).__init__() self.resource = str(resource) self.rpc = RPCProxy(self.resource) self.id = id self._loaded = False self.parent = parent self.mgroup = group self.value = {} self.state_attrs = {} self.modified = False self.modified_fields = {} self._concurrency_check_data = False for key,val in self.mgroup.mfields.items(): self.value[key] = val.create(self) if (new and val.attrs['type']=='one2many') and (val.attrs.get('mode','tree,form').startswith('form')): mod = self.value[key].model_new() self.value[key].model_add(mod)
def __init__(self, resource, fields, ids=[], parent=None, context={}, is_wizard=False): super(ModelRecordGroup, self).__init__() self._readonly = False self.parent = parent self._context = context self._context.update(rpc.session.context) self.resource = resource self.rpc = RPCProxy(resource) self.fields = fields self.mfields = {} self.mfields_load(fields.keys(), self) self.models = ModelList(self) self.current_idx = None self.load(ids) self.models_removed = [] self.on_write = '' self.is_wizard = is_wizard
def __init__(self, resource, id, group=None, parent=None, new=False, list_parent=None): super(ModelRecord, self).__init__() self.resource = str(resource) self.rpc = RPCProxy(self.resource) self.id = id self.list_parent = list_parent self._loaded = False self.parent = parent self.mgroup = group self.value = {} self.state_attrs = {} self.modified = False self.modified_fields = {} self.pager_cache = {} self.is_m2m_modified = False self._concurrency_check_data = False for key, val in self.mgroup.mfields.items(): self.value[key] = val.create(self) if (new and val.attrs["type"] == "one2many") and (val.attrs.get("mode", "tree,form").startswith("form")): mod = self.value[key].model_new() self.value[key].model_add(mod)
class ModelRecord(signal_event.signal_event): def __init__(self, resource, id, group=None, parent=None, new=False): super(ModelRecord, self).__init__() self.resource = str(resource) self.rpc = RPCProxy(self.resource) self.id = id self._loaded = False self.parent = parent self.mgroup = group self.value = {} self.state_attrs = {} self.modified = False self.modified_fields = {} self._concurrency_check_data = False for key, val in self.mgroup.mfields.items(): self.value[key] = val.create(self) if (new and val.attrs['type'] == 'one2many') and (val.attrs.get( 'mode', 'tree,form').startswith('form')): mod = self.value[key].model_new() self.value[key].model_add(mod) def __getitem__(self, name): return self.mgroup.mfields.get(name, False) def __repr__(self): return '<ModelRecord %s@%s>' % (self.id, self.resource) def is_modified(self): return self.modified def is_wizard(self): return self.mgroup.is_wizard def fields_get(self): return self.mgroup.mfields def _check_load(self): if not self._loaded: self.reload() return True return False def update_context_with_concurrency_check_data(self, context): if self.id and self.is_modified(): context.setdefault( CONCURRENCY_CHECK_FIELD, {})["%s,%d" % (self.resource, self.id)] = self._concurrency_check_data for name, field in self.mgroup.mfields.items(): if isinstance(field, O2MField): if field.name not in self.value.keys(): continue v = self.value[field.name] from itertools import chain for m in chain(v.models, v.models_removed): m.update_context_with_concurrency_check_data(context) def get(self, get_readonly=True, includeid=False, check_load=True, get_modifiedonly=False): if check_load: self._check_load() value = [] for name, field in self.mgroup.mfields.items(): if (get_readonly or not field.get_state_attrs(self).get('readonly', False)) \ and (not get_modifiedonly or (field.name in self.modified_fields or isinstance(field, O2MField))): value.append((name, field.get(self, readonly=get_readonly, modified=get_modifiedonly))) value = dict(value) if includeid: value['id'] = self.id return value def cancel(self): self._loaded = False self.reload() def failed_validation(self): invalid_fields = self.rpc.get_invalid_fields() for item in invalid_fields: if item in self.mgroup.mfields: self.mgroup.mfields[item].get_state_attrs( self)['valid'] = False def save(self, reload=True): self._check_load() if not self.id: value = self.get(get_readonly=False) self.id = self.rpc.create(value, self.context_get()) if not self.id: self.failed_validation() else: if not self.is_modified(): return self.id value = self.get(get_readonly=False, get_modifiedonly=True) context = self.context_get().copy() self.update_context_with_concurrency_check_data(context) if not self.rpc.write([self.id], value, context): self.failed_validation() return False self._loaded = False if reload: self.reload() else: # just reload the CONCURRENCY_CHECK_FIELD self._reload([CONCURRENCY_CHECK_FIELD]) return self.id def default_get(self, domain=[], context={}): if len(self.mgroup.fields): val = self.rpc.default_get(self.mgroup.fields.keys(), context) for d in domain: if d[0] in self.mgroup.fields: if d[1] == '=': val[d[0]] = d[2] if d[1] == 'in' and len(d[2]) == 1: val[d[0]] = d[2][0] self.set_default(val) def name_get(self): name = self.rpc.name_get([self.id], rpc.session.context)[0] return name def validate_set(self): change = self._check_load() for fname in self.mgroup.mfields: field = self.mgroup.mfields[fname] change = change or not field.get_state_attrs(self).get( 'valid', True) field.get_state_attrs(self)['valid'] = True if change: self.signal('record-changed') self.reload() return change def validate(self): self._check_load() ok = True mfields_with_errors = [] for fname, _object in self.mgroup.mfields.iteritems(): if not self.mgroup.mfields[fname].validate(self): print("Not valid field: %s" % (fname)) mfields_with_errors.append(_object.attrs.get('string', fname)) ok = False if mfields_with_errors: common.warning( _('Invalid form, correct following fields:\n') + '\n'.join(mfields_with_errors)) return False return True def _get_invalid_fields(self): res = [] for fname, field in self.mgroup.mfields.items(): if not field.get_state_attrs(self).get('valid', True): res.append((fname, field.attrs['string'])) return dict(res) invalid_fields = property(_get_invalid_fields) def context_get(self): return self.mgroup.context def get_default(self): self._check_load() value = dict([(name, field.get_default(self)) for name, field in self.mgroup.mfields.items()]) return value def set_default(self, val): for fieldname, value in val.items(): if fieldname not in self.mgroup.mfields: continue self.mgroup.mfields[fieldname].set_default(self, value) self._loaded = True self.signal('record-changed') def set(self, val, modified=False, signal=True): later = {} for fieldname, value in val.items(): if fieldname == CONCURRENCY_CHECK_FIELD: self._concurrency_check_data = value if fieldname not in self.mgroup.mfields: continue if isinstance(self.mgroup.mfields[fieldname], field.O2MField): later[fieldname] = value continue self.mgroup.mfields[fieldname].set(self, value, modified=modified) for fieldname, value in later.items(): self.mgroup.mfields[fieldname].set(self, value, modified=modified) self._loaded = True self.modified = modified if not self.modified: self.modified_fields = {} if signal: self.signal('record-changed') def reload(self): return self._reload(self.mgroup.mfields.keys() + [CONCURRENCY_CHECK_FIELD]) def _reload(self, fields): if not self.id: return c = rpc.session.context.copy() c.update(self.context_get()) c['bin_size'] = True res = self.rpc.read([self.id], fields, c) if res: value = res[0] if self.parent: self.set(value, signal=False) else: self.set(value) def expr_eval(self, dom, check_load=True): if not isinstance(dom, basestring): return dom if check_load: self._check_load() d = {} for name, mfield in self.mgroup.mfields.items(): d[name] = mfield.get(self, check_load=check_load) d['current_date'] = time.strftime('%Y-%m-%d') d['time'] = time d['context'] = self.context_get() d['active_id'] = self.id if self.parent: d['parent'] = EvalEnvironment(self.parent) val = tools.expr_eval(dom, d) return val #XXX Shoud use changes of attributes (ro, ...) def on_change(self, callback): match = re.match('^(.*?)\((.*)\)$', callback) if not match: raise Exception, 'ERROR: Wrong on_change trigger: %s' % callback func_name = match.group(1) arg_names = [n.strip() for n in match.group(2).split(',') if n.strip()] args = [self.expr_eval(arg) for arg in arg_names] ids = self.id and [self.id] or [] response = getattr(self.rpc, func_name)(ids, *args) if response: self.set(response.get('value', {}), modified=True) if 'domain' in response: for fieldname, value in response['domain'].items(): if fieldname not in self.mgroup.mfields: continue self.mgroup.mfields[fieldname].attrs['domain'] = value warning = response.get('warning', {}) if warning: common.warning(warning['message'], warning['title']) self.signal('record-changed') def on_change_attrs(self, callback): self.signal('attrs-changed') def cond_default(self, field, value): ir = RPCProxy('ir.values') values = ir.get('default', '%s=%s' % (field, value), [(self.resource, False)], False, {}) data = {} for index, fname, value in values: data[fname] = value self.set_default(data)
class ModelRecord(signal_event.signal_event): def __init__(self, resource, id, group=None, parent=None, new=False, list_parent=None): super(ModelRecord, self).__init__() self.resource = str(resource) self.rpc = RPCProxy(self.resource) self.id = id self.list_parent = list_parent self._loaded = False self.parent = parent self.mgroup = group self.value = {} self.state_attrs = {} self.modified = False self.modified_fields = {} self.pager_cache = {} self.is_m2m_modified = False self._concurrency_check_data = False for key, val in self.mgroup.mfields.items(): self.value[key] = val.create(self) if (new and val.attrs['type']=='one2many') and (val.attrs.get('mode', 'tree,form').startswith('form')): mod = self.value[key].model_new() self.value[key].model_add(mod) def __getitem__(self, name): return self.mgroup.mfields.get(name, False) def __repr__(self): return '<ModelRecord %s@%s>' % (self.id, self.resource) def is_modified(self): return self.modified def is_wizard(self): return self.mgroup.is_wizard def fields_get(self): return self.mgroup.mfields def _check_load(self): if not self._loaded: self.reload() return True return False def update_context_with_concurrency(self, context): if self.id and self.is_modified(): context.setdefault(CONCURRENCY_CHECK_FIELD, {})["%s,%s" % (self.resource, self.id)] = self._concurrency_check_data for name, field in self.mgroup.mfields.items(): if isinstance(field, O2MField): v = self.value[field.name] from itertools import chain for m in chain(v.models, v.models_removed): m.update_context_with_concurrency(context) def get(self, get_readonly=True, includeid=False, check_load=True, get_modifiedonly=False): if check_load: self._check_load() value = [] for name, field in self.mgroup.mfields.items(): if (get_readonly or not field.get_state_attrs(self).get('readonly', False)) \ and (not get_modifiedonly or (field.name in self.modified_fields or isinstance(field, O2MField))): value.append((name, field.get(self, readonly=get_readonly, modified=get_modifiedonly))) value = dict(value) if includeid: value['id'] = self.id return value def cancel(self): self._loaded = False self.reload() def failed_validation(self): invalid_fields = self.rpc.get_invalid_fields() for item in invalid_fields: if item in self.mgroup.mfields: self.mgroup.mfields[item].get_state_attrs(self)['valid'] = False def save(self, reload=True): self._check_load() try: if not self.id: value = self.get(get_readonly=False) self.id = self.rpc.create(value, self.context_get()) else: if not self.is_modified(): return self.id value = self.get(get_readonly=False, get_modifiedonly=True) context = self.context_get().copy() self.update_context_with_concurrency(context) res = self.rpc.write([self.id], value, context) if type(res)==type({}): obj = service.LocalService('action.main') obj._exec_action(res,{}, context) except Exception, e: if hasattr(e, 'faultCode') and e.faultCode.find('ValidateError')>-1: self.failed_validation() return False pass self._loaded = False if reload: self.reload() else: # just reload the CONCURRENCY_CHECK_FIELD self._reload([CONCURRENCY_CHECK_FIELD]) return self.id
def __init__(self, cmdname, options): self.proxy = RPCProxy() self.cmdname = cmdname self.options = options
class Screen(signal_event.signal_event): def __init__(self, model_name, view_ids=None, view_type=None,help={}, parent=None, context=None, views_preload=None, tree_saves=True, domain=None, create_new=False, row_activate=None, hastoolbar=False, hassubmenu=False,default_get=None, show_search=False, window=None, limit=100, readonly=False, auto_search=True, is_wizard=False, search_view=None,win_search=False): if view_ids is None: view_ids = [] if view_type is None: view_type = ['tree', 'form'] if views_preload is None: views_preload = {} if not domain: domain = [] if default_get is None: default_get = {} if search_view is None: search_view = "{}" super(Screen, self).__init__() self.win_search = win_search self.win_search_domain = [] self.win_search_ids = [] self.win_search_callback = False self.show_search = show_search self.auto_search = auto_search self.search_count = 0 self.hastoolbar = hastoolbar self.hassubmenu = hassubmenu self.default_get=default_get self.sort = False self.type = None self.dummy_cal = False self.openerp_widgets = {'form':[ 'date','time','datetime','float','integer','selection','char','float_time', 'boolean','button','reference','binary','picture','text','text_wiki','text_tag', 'one2many','one2many_form','one2many_list','many2many','many2one','email','url', 'callto','sip','image','uri','progressbar'], 'tree':['char','many2one','date','one2many','many2many','selection','float','float_time','integer', 'datetime','boolean','progressbar','button']} if not row_activate: self.row_activate = lambda self,screen=None: self.switch_view(screen, 'form') else: self.row_activate = row_activate self.create_new = create_new self.name = model_name self.domain_init = domain self.action_domain = [] self.action_domain += domain self.latest_search = [] self.views_preload = views_preload self.resource = model_name self.rpc = RPCProxy(model_name) self.context_init = context or {} self.context_update() self.views = [] self.fields = {} self.view_ids = view_ids self.models = None self.parent=parent self.window=window self.is_wizard = is_wizard self.search_view = eval(search_view) models = ModelRecordGroup(model_name, self.fields, parent=self.parent, context=self.context, is_wizard=is_wizard, screen=self) self.models_set(models) self.current_model = None self.screen_container = screen_container(self.win_search) self.filter_widget = None self.widget = self.screen_container.widget_get() self.__current_view = 0 self.tree_saves = tree_saves self.limit = limit self.old_limit = limit self.offset = 0 self.readonly= readonly self.view_fields = {} # Used to switch self.fields when the view switchs self.sort_domain = [] self.old_ctx = {} self.help_mode = False if view_type: self.view_to_load = view_type[1:] view_id = False if view_ids: view_id = view_ids.pop(0) if view_type[0] in ('tree','graph','calendar'): self.screen_container.help = help self.help_mode = view_type[0] view = self.add_view_id(view_id, view_type[0], help=help) self.screen_container.set(view.widget) self.display() def context_update(self, ctx={}, dmn=[]): self.context = self.context_init.copy() self.context.update(rpc.session.context) self.context.update(ctx) self.domain = self.domain_init[:] self.domain += dmn def readonly_get(self): return self._readonly def readonly_set(self, value): self._readonly = value self.models._readonly = value readonly = property(readonly_get, readonly_set) def search_active(self, active=True, show_search=True): if active: if not self.filter_widget: if not self.search_view: self.search_view = rpc.session.rpc_exec_auth('/object', 'execute', self.name, 'fields_view_get', False, 'search', self.context) self.filter_widget = widget_search.form(self.search_view['arch'], self.search_view['fields'], self.name, self.window, self.domain, (self, self.search_filter)) self.screen_container.add_filter(self) if active and show_search: self.screen_container.show_filter() else: self.screen_container.hide_filter() def update_scroll(self, *args): offset = self.offset limit = self.screen_container.get_limit() if self.screen_container.but_previous: if offset<=0: self.screen_container.but_previous.set_sensitive(False) else: self.screen_container.but_previous.set_sensitive(True) if self.screen_container.but_next: if not limit or offset+limit>=self.search_count: self.screen_container.but_next.set_sensitive(False) else: self.screen_container.but_next.set_sensitive(True) if self.win_search: self.win_search_callback() def search_offset_next(self, *args): offset=self.offset limit = self.screen_container.get_limit() self.offset = offset+limit self.search_filter() if self.win_search: self.win_search_callback() def search_offset_previous(self, *args): offset=self.offset limit = self.screen_container.get_limit() self.offset = max(offset-limit,0) self.search_filter() if self.win_search: self.win_search_callback() def search_clear(self, *args): self.filter_widget.clear() if not self.win_search: self.screen_container.action_combo.set_active(0) self.clear() def get_calenderDomain(self, field_name=None, old_date='', mode='month'): args = [] old_date = old_date.date() if not old_date: old_date = datetime.today().date() if mode =='month': start_date = (old_date + relativedelta(months = -1)).strftime('%Y-%m-%d') args.append((field_name, '>',start_date)) end_date = (old_date + relativedelta(months = 1)).strftime('%Y-%m-%d') args.append((field_name, '<',end_date)) if mode=='week': start_date = (old_date + relativedelta(weeks = -1)).strftime('%Y-%m-%d') args.append((field_name, '>',start_date)) end_date = (old_date + relativedelta(weeks = 1)).strftime('%Y-%m-%d') args.append((field_name, '<',end_date)) if mode=='day': start_date = (old_date + relativedelta(days = -1)).strftime('%Y-%m-%d') args.append((field_name, '>',start_date)) end_date = (old_date + relativedelta(days = 1)).strftime('%Y-%m-%d') args.append((field_name, '<',end_date)) return args def search_filter(self, *args): if not self.auto_search: self.auto_search = True return limit = self.screen_container.get_limit() self.screen_container.show_limit() val = self.filter_widget and self.filter_widget.value or {} if self.current_view.view_type == 'graph': self.screen_container.hide_limit() limit = False if self.current_view.view.key: self.domain = self.domain_init[:] self.domain += val.get('domain',[]) + self.sort_domain else: self.context_update(val.get('context',{}), val.get('domain',[]) + self.sort_domain) else: self.context_update(val.get('context',{}), val.get('domain',[]) + self.sort_domain) v = self.domain if self.win_search: v += self.win_search_domain if self.current_view.view_type == 'calendar': field_name = self.current_view.view.date_start old_date = self.current_view.view.date mode = self.current_view.view.mode calendar_domain = self.get_calenderDomain(field_name, old_date, mode) v += calendar_domain filter_keys = [] for ele in self.domain: if isinstance(ele,tuple): filter_keys.append(ele[0]) if self.latest_search != v: self.offset = 0 offset = self.offset self.latest_search = v if (self.context.get('group_by') or \ self.context.get('group_by_no_leaf')) \ and not self.current_view.view_type == 'graph': self.current_view.reload = True self.search_count = rpc.session.rpc_exec_auth_try('/object', 'execute', self.name, 'search_count', v, self.context) self.display() return True ids = rpc.session.rpc_exec_auth('/object', 'execute', self.name, 'search', v, offset, limit, self.sort, self.context) ids = self.win_search_ids = self.models.remove_duplicate(ids) if self.win_search and self.win_search_domain: for dom in self.win_search_domain: if dom in v: v.remove(dom) self.win_search_domain = [] if len(ids) < limit: self.search_count = len(ids) else: self.search_count = rpc.session.rpc_exec_auth_try('/object', 'execute', self.name, 'search_count', v, self.context) self.update_scroll() self.clear() if self.sort_domain in v: v.remove(self.sort_domain) self.sort_domain = [] self.load(ids) return True def execute_action(self, combo): combo_model = combo.get_model() active_id = combo.get_active() flag = active_id != -1 and combo_model[active_id][1] action_name = active_id != -1 and flag not in ['mf','blk', 'sf'] and combo_model[active_id][4] public_action = active_id != -1 and flag not in ['mf','blk', 'sf'] and combo_model[active_id][3] == 0 # 'mf' Section manages Filters def clear_domain_ctx(): for key in self.old_ctx.keys(): if key in self.context_init: del self.context_init[key] for domain in self.latest_search: if domain in self.domain_init: self.domain_init.remove(domain) #append action domain to filter domain self.domain_init += self.action_domain if flag == 'mf': obj = service.LocalService('action.main') act = {'name': _('Manage Filters'), 'res_model': 'ir.filters', 'type': 'ir.actions.act_window', 'view_type': 'form', 'view_mode': 'tree,form'} ctx = dict(self.context) for key in ('group_by','group_by_no_leaf'): ctx.pop(key, None) ctx.update(search_default_my_filters=True, search_default_model_id=self.name) value = obj._exec_action(act, {}, ctx) if flag in ['blk','mf']: self.screen_container.last_active_filter = False self.screen_container.last_active_filter_public = False clear_domain_ctx() if flag == 'blk': self.search_filter() combo.set_active(0) return True #This section handles shortcut and action creation elif flag in ['sf']: ui2 = openerp_gtk_builder('openerp.ui', ['dia_get_action']) win = ui2.get_object('dia_get_action') win.set_icon(common.OPENERP_ICON) lbl = ui2.get_object('label157') win.set_size_request(300, 165) text_entry = ui2.get_object('action_name') lbl.set_text('Filter Name:') table = ui2.get_object('table8') info_lbl = gtk.Label(_('(Any existing filter with the \nsame name will be replaced)')) public_chk = gtk.CheckButton(_('Share with all users')) public_chk.set_tooltip_text(_('Check this option to make the filter visible to all users')) table.attach(public_chk,1,2,2,3, gtk.FILL, gtk.EXPAND) table.attach(info_lbl,1,2,3,4, gtk.FILL, gtk.EXPAND) if self.screen_container.last_active_filter: text_entry.set_text(self.screen_container.last_active_filter) if self.screen_container.last_active_filter_public: public_chk.set_active(True) win.show_all() response = win.run() # grab a safe copy of the entered text before destroy() to avoid GTK bug https://bugzilla.gnome.org/show_bug.cgi?id=613241 action_name = text_entry.get_text() public_filter = public_chk.get_active() win.destroy() combo.set_active(0) if response == gtk.RESPONSE_OK and action_name: filter_domain = self.filter_widget and self.filter_widget.value.get('domain',[]) filter_context = self.filter_widget and self.filter_widget.value.get('context',{}) values = {'name': action_name, 'model_id': self.name, 'user_id': False if public_filter else rpc.session.uid} if flag == 'sf': domain, context = self.screen_container.get_filter(action_name) for dom in eval(domain): if dom not in filter_domain: filter_domain.append(dom) groupby_list = eval(context).get('group_by',[]) + filter_context.get('group_by',[]) filter_context.update(eval(context)) if groupby_list: filter_context.update({'group_by':groupby_list}) values.update({'domain':str(filter_domain), 'context':str(filter_context), }) action_id = rpc.session.rpc_exec_auth('/object', 'execute', 'ir.filters', 'create_or_replace', values, self.context) self.screen_container.fill_filter_combo(self.name, action_id) else: try: self.screen_container.last_active_filter = action_name self.screen_container.last_active_filter_public = public_action filter_domain = flag and tools.expr_eval(flag) clear_domain_ctx() if combo.get_active() >= 0: combo_model = combo.get_model() val = combo_model[combo.get_active()][2] if val: self.old_ctx = eval(val) self.context_init.update(self.old_ctx) self.domain_init += filter_domain or [] if isinstance(self.domain_init,type([])): self.search_filter() self.reload() except Exception: return True def models_set(self, models): import time c = time.time() if self.models: self.models.signal_unconnect(self.models) self.models = models self.parent = models.parent if len(models.models): self.current_model = models.models[0] else: self.current_model = None self.models.signal_connect(self, 'record-cleared', self._record_cleared) self.models.signal_connect(self, 'record-changed', self._record_changed) self.models.signal_connect(self, 'model-changed', self._model_changed) models.add_fields(self.fields, models) self.fields.update(models.fields) models.is_wizard = self.is_wizard def _record_cleared(self, model_group, signal, *args): for view in self.views: view.reload = True def _record_changed(self, model_group, signal, *args): try: for view in self.views: view.signal_record_changed(signal[0], model_group.models, signal[1], *args) except: pass def _model_changed(self, model_group, model): if (not model) or (model==self.current_model): self.display() def _get_current_model(self): return self.__current_model # # Check more or less fields than in the screen ! # def _set_current_model(self, value): self.__current_model = value try: offset = int(self.offset) except: offset = 0 try: pos = self.models.models.index(value) except: pos = -1 self.signal('record-message', (pos + offset, len(self.models.models or []) + offset, self.search_count, value and value.id)) return True current_model = property(_get_current_model, _set_current_model) def destroy(self): for view in self.views: view.destroy() if hasattr(self, 'filter_widget') and self.filter_widget: self.filter_widget.destroy() del self.filter_widget self.widget.destroy() self.models.signal_unconnect(self) self.models.destroy() del self.models del self.widget del self.views del self.fields del self.view_fields del self.search_view del self._Screen__current_model del self._Screen__current_view del self.action_domain del self.auto_search del self.create_new del self.dummy_cal del self.help_mode del self.is_wizard del self.latest_search del self.offset del self.old_ctx del self.row_activate del self.screen_container del self.search_count del self.show_search del self.tree_saves del self.type del self.view_ids del self.view_to_load del self.views_preload del self.win_search del self.win_search_callback del self.window def set_tooltips(self): terp_main = service.LocalService('gui.main') page_id= terp_main.notebook.get_current_page() form_obj = terp_main.pages[page_id] action_name = form_obj.name or '' if self.current_view.view_type == 'form': tips = unicode(self.current_model and self.current_model.value.get('name') or action_name) tooltips = tips == action_name and action_name or action_name + ': ' + tips[:64] label = tips == action_name and action_name or action_name + ': ' + tips[:6] else: tooltips = action_name label = action_name form_obj.page_label.set_text(label) form_obj.page_label.set_tooltip_text(tooltips) # mode: False = next view, value = open this view def switch_view(self, screen=None, mode=False): if isinstance(self.current_model, group_record) and mode != 'graph': return if mode == 'calendar' and self.dummy_cal: mode = 'dummycalendar' self.current_view.set_value() self.fields = {} if self.current_model and self.current_model not in self.models.models: self.current_model = None if mode: ok = False for vid in range(len(self.views)): if self.views[vid].view_type==mode: self.__current_view = vid ok = True break if len(self.view_to_load) and mode in self.view_to_load: self.load_view_to_load(mode=mode) for vid in range(len(self.views)): if self.views[vid].view_type==mode: self.__current_view = vid ok = True break if not ok: self.__current_view = len(self.views) - 1 else: if len(self.view_to_load): self.load_view_to_load() self.__current_view = len(self.views) - 1 else: self.__current_view = (self.__current_view + 1) % len(self.views) self.fields = self.view_fields.get(self.__current_view, self.fields) # Switch the fields # TODO: maybe add_fields_custom is needed instead of add_fields on some cases self.models.add_fields(self.fields, self.models) # Switch the model fields too widget = self.current_view.widget self.screen_container.set(self.current_view.widget) if self.current_model: self.current_model.validate_set() elif self.current_view.view_type=='form': self.new() if self.current_view.view_type == 'graph': self.current_view.view.key = False self.display() self.current_view.set_cursor() main = service.LocalService('gui.main') if mode: self.set_tooltips() if main: main.sb_set() # TODO: set True or False accoring to the type def load_view_to_load(self, mode=False): if len(self.view_to_load): if mode: idx = self.view_to_load.index(mode) view_id = self.view_ids and self.view_ids.pop(idx) or False else: idx = 0 view_id = False type = self.view_to_load.pop(idx) self.add_view_id(view_id,type) def add_view_custom(self, arch, fields, display=False, toolbar={}, submenu={}): return self.add_view(arch, fields, display, True, toolbar=toolbar, submenu=submenu) def add_view_id(self, view_id, view_type, display=False, help={}, context=None): if context is None: context = {} if view_type in self.views_preload: return self.add_view(self.views_preload[view_type]['arch'], self.views_preload[view_type]['fields'], display, toolbar=self.views_preload[view_type].get('toolbar', False), submenu=self.views_preload[view_type].get('submenu', False), name=self.views_preload[view_type].get('name', False), help=help, context=context) else: view = self.rpc.fields_view_get(view_id, view_type, self.context, self.hastoolbar, self.hassubmenu) context.update({'view_type' : view_type}) return self.add_view(view['arch'], view['fields'], display, help=help, toolbar=view.get('toolbar', False), submenu=view.get('submenu', False), name=view.get('name',False), context=context) def add_view(self, arch, fields, display=False, custom=False, toolbar=None, submenu=None, name=False, help={}, context=None): if toolbar is None: toolbar = {} if submenu is None: submenu = {} def _parse_fields(node, fields, type): if node.tag =='field': attrs = tools.node_attributes(node) if attrs.get('widget', False): if attrs['widget'] == 'one2many_list': attrs['widget'] = 'one2many' if attrs['widget'] not in self.openerp_widgets.get(type, []): attrs['type'] = fields[str(attrs['name'])]['type'] del attrs['widget'] else: 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, type) root_node = etree.XML(arch) _parse_fields(root_node, fields, type=root_node.tag) from widget.view.widget_parse import widget_parse models = self.models.models if self.current_model and (self.current_model not in models): models = models + [self.current_model] if context and context.get('view_type','') == 'diagram': fields = {} if custom: self.models.add_fields_custom(fields, self.models) else: 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, name=name, help=help) if view: self.views.append(view) if display: self.__current_view = len(self.views) - 1 self.current_view.display() self.screen_container.set(view.widget) # Store the fields for this view (we will use them when switching views) self.view_fields[len(self.views)-1] = copy.deepcopy(self.fields) return view def editable_get(self): if hasattr(self.current_view, 'widget_tree'): return self.current_view.widget_tree.editable else: return False def new(self, default=True, context={}): if self.current_view and self.current_view.view_type == 'tree' \ and not self.current_view.widget_tree.editable: self.switch_view(mode='form') ctx = self.context.copy() ctx.update(context) model = self.models.model_new(default, self.action_domain, ctx) if (not self.current_view) or self.current_view.model_add_new or self.create_new: self.models.model_add(model, self.new_model_position()) self.current_model = model self.current_model.validate_set() self.display() if self.current_view: self.current_view.set_cursor(new=True) return self.current_model def new_model_position(self): position = -1 if self.current_view and self.current_view.view_type =='tree' \ and self.current_view.widget_tree.editable == 'top': position = 0 return position def set_on_write(self, func_name): self.models.on_write = func_name def cancel_current(self): if self.current_model: self.current_model.cancel() if self.current_view: self.current_view.cancel() self.current_view.reset() def save_current(self): if not self.current_model: return False self.current_view.set_value() id = False if self.current_model.validate(): id = self.current_model.save(reload=True) self.models.writen(id) if not id: self.current_view.display() else: self.current_view.display() self.current_view.set_cursor() return False if self.current_view.view_type == 'tree': for model in self.models.models: if model.is_modified(): if model.validate(): id = model.save(reload=True) self.models.writen(id) else: self.current_model = model self.display() self.current_view.set_cursor() return False self.display() self.current_view.set_cursor() if self.current_model not in self.models: self.models.model_add(self.current_model) return id def _getCurrentView(self): if not len(self.views): return None return self.views[self.__current_view] current_view = property(_getCurrentView) def get(self): if not self.current_model: return None self.current_view.set_value() return self.current_model.get() def is_modified(self): if not self.current_model: return False self.current_view.set_value() if self.current_view.view_type != 'tree': return self.current_model.is_modified() else: for model in self.models.models: if model.is_modified(): return True return False def reload(self): self.current_model.reload() if self.parent: self.parent.reload() self.display() def remove(self, unlink = False): id = False if self.current_view.view_type == 'form' and self.current_model: id = self.current_model.id if not id and unlink: self.new() return False idx = self.models.models.index(self.current_model) if not id: self.models.models.remove(self.models.models[idx]) self.current_model=None if self.models.models: idx = min(idx, len(self.models.models)-1) self.current_model = self.models.models[idx] self.display() self.current_view.set_cursor() return False ctx = self.current_model.context_get().copy() self.current_model.update_context_with_concurrency(ctx) if unlink and id: if not self.rpc.unlink([id], ctx): return False self.models.remove(self.current_model) if self.models.models: idx = min(idx, len(self.models.models)-1) self.current_model = self.models.models[idx] else: self.current_model = None self.display() self.current_view.set_cursor() if self.current_view.view_type == 'tree': ids = self.current_view.sel_ids_get() ctx = self.models.context.copy() for m in self.models: if m.id in ids: m.update_context_with_concurrency(ctx) if unlink and ids: if not self.rpc.unlink(ids, ctx): return False for model in self.current_view.sel_models_get(): self.models.remove(model) self.current_model = None self.display() self.current_view.set_cursor() id = ids return id def load(self, ids): limit = self.screen_container.get_limit() self.models.load(ids, display=False, context=self.context) self.current_view.reset() if ids: self.display(ids[0]) else: self.current_model = None self.display() def display(self, res_id=None): if res_id: self.current_model = self.models[res_id] if self.views: self.current_view.display() self.current_view.widget.set_sensitive(bool(self.models.models or (self.current_view.view_type!='form') or self.current_model)) vt = self.current_view.view_type if self.screen_container.help_frame: if vt != self.help_mode: self.screen_container.help_frame.hide_all() else: self.screen_container.help_frame.show_all() self.search_active( active=self.show_search and vt in ('tree', 'graph'), show_search=self.show_search and vt in ('tree', 'graph'), ) def groupby_next(self): if not self.models.models: self.current_model = self.models.list_group.lst[0] elif self.current_view.store.on_iter_has_child(self.current_model): path = self.current_view.store.on_get_path(self.current_model) if path == (0,): self.current_view.expand_row(path) self.current_model = self.current_view.store.on_iter_children(self.current_model) else: if self.current_model in self.current_model.list_group.lst: idx = self.current_model.list_group.lst.index(self.current_model) if idx + 1 >= len(self.current_model.list_group.lst): parent = True while parent: parent = self.current_view.store.on_iter_parent(self.current_model) if parent: self.current_model = parent if self.current_view.store.on_iter_next(parent): break self.current_model = self.current_view.store.on_iter_next(self.current_model) if self.current_model == None: self.current_model = self.current_view.store.on_get_iter \ (self.current_view.store.on_get_path \ (self.current_view.store.get_iter_first())) else: idx = (idx+1) % len(self.current_model.list_group.lst) self.current_model = self.current_model.list_group.lst[idx] if self.current_model: path = self.current_view.store.on_get_path(self.current_model) self.current_view.expand_row(path) return def groupby_prev(self): if not self.models.models : self.current_model = self.models.list_group.lst[-1] else: if self.current_model in self.current_model.list_group.lst: idx = self.current_model.list_group.lst.index(self.current_model) - 1 if idx < 0 : parent = self.current_view.store.on_iter_parent(self.current_model) if parent: self.current_model = parent else: idx = (idx) % len(self.current_model.list_group.lst) self.current_model = self.current_model.list_group.lst[idx] if self.current_model: path = self.current_view.store.on_get_path(self.current_model) self.current_view.collapse_row(path) return def display_next(self): self.current_view.set_value() if self.context.get('group_by') and \ not self.current_view.view_type == 'form': if self.current_model: self.groupby_next() else: if self.current_model in self.models.models: idx = self.models.models.index(self.current_model) idx = (idx+1) % len(self.models.models) self.current_model = self.models.models[idx] else: self.current_model = len(self.models.models) and self.models.models[0] self.check_state() self.current_view.set_cursor() def display_prev(self): self.current_view.set_value() if self.context.get('group_by') and \ not self.current_view.view_type == 'form': if self.current_model: self.groupby_prev() else: if self.current_model in self.models.models: idx = self.models.models.index(self.current_model)-1 if idx<0: idx = len(self.models.models)-1 self.current_model = self.models.models[idx] else: self.current_model = len(self.models.models) and self.models.models[-1] self.check_state() self.current_view.set_cursor() def check_state(self): if not self.type == 'one2many' \ and (not self.context.get('group_by') \ or self.current_view.view_type == 'form'): if self.current_model: self.current_model.validate_set() self.display() if self.type == 'one2many': self.display() def sel_ids_get(self): return self.current_view.sel_ids_get() def id_get(self): if not self.current_model: return False return self.current_model.id def ids_get(self): return [x.id for x in self.models if x.id] def clear(self): self.models.clear() def on_change(self, callback): self.current_model.on_change(callback) self.display() def make_buttons_readonly(self, value=False): # This method has been created because # Some times if the user executes an action on an unsaved record in a dialog box # the record gets saved in the dialog's Group before going to the particular widgets group # and as a result it crashes. So we just set the buttons visible on the # dialog box screen to non-sensitive if the model is not saved. def process(widget, val): for wid in widget: if hasattr(wid, 'get_children'): process(wid, val=value) if isinstance(wid, gtk.Button) and \ not isinstance(wid.parent, (gtk.HBox,gtk.VBox)): wid.set_sensitive(val) if value and self.current_model and not self.current_model.id: return True process(self.widget, value)
def __init__(self, model_name, view_ids=None, view_type=None,help={}, parent=None, context=None, views_preload=None, tree_saves=True, domain=None, create_new=False, row_activate=None, hastoolbar=False, hassubmenu=False,default_get=None, show_search=False, window=None, limit=100, readonly=False, auto_search=True, is_wizard=False, search_view=None,win_search=False): if view_ids is None: view_ids = [] if view_type is None: view_type = ['tree', 'form'] if views_preload is None: views_preload = {} if not domain: domain = [] if default_get is None: default_get = {} if search_view is None: search_view = "{}" super(Screen, self).__init__() self.win_search = win_search self.win_search_domain = [] self.win_search_ids = [] self.win_search_callback = False self.show_search = show_search self.auto_search = auto_search self.search_count = 0 self.hastoolbar = hastoolbar self.hassubmenu = hassubmenu self.default_get=default_get self.sort = False self.type = None self.dummy_cal = False self.openerp_widgets = {'form':[ 'date','time','datetime','float','integer','selection','char','float_time', 'boolean','button','reference','binary','picture','text','text_wiki','text_tag', 'one2many','one2many_form','one2many_list','many2many','many2one','email','url', 'callto','sip','image','uri','progressbar'], 'tree':['char','many2one','date','one2many','many2many','selection','float','float_time','integer', 'datetime','boolean','progressbar','button']} if not row_activate: self.row_activate = lambda self,screen=None: self.switch_view(screen, 'form') else: self.row_activate = row_activate self.create_new = create_new self.name = model_name self.domain_init = domain self.action_domain = [] self.action_domain += domain self.latest_search = [] self.views_preload = views_preload self.resource = model_name self.rpc = RPCProxy(model_name) self.context_init = context or {} self.context_update() self.views = [] self.fields = {} self.view_ids = view_ids self.models = None self.parent=parent self.window=window self.is_wizard = is_wizard self.search_view = eval(search_view) models = ModelRecordGroup(model_name, self.fields, parent=self.parent, context=self.context, is_wizard=is_wizard, screen=self) self.models_set(models) self.current_model = None self.screen_container = screen_container(self.win_search) self.filter_widget = None self.widget = self.screen_container.widget_get() self.__current_view = 0 self.tree_saves = tree_saves self.limit = limit self.old_limit = limit self.offset = 0 self.readonly= readonly self.view_fields = {} # Used to switch self.fields when the view switchs self.sort_domain = [] self.old_ctx = {} self.help_mode = False if view_type: self.view_to_load = view_type[1:] view_id = False if view_ids: view_id = view_ids.pop(0) if view_type[0] in ('tree','graph','calendar'): self.screen_container.help = help self.help_mode = view_type[0] view = self.add_view_id(view_id, view_type[0], help=help) self.screen_container.set(view.widget) self.display()
def __init__(self, model_name, view_ids=None, view_type=None, parent=None, context=None, views_preload=None, tree_saves=True, domain=None, create_new=False, row_activate=None, hastoolbar=False, default_get=None, show_search=False, window=None, limit=80, readonly=False, is_wizard=False): if view_ids is None: view_ids = [] if view_type is None: view_type = ['tree', 'form'] if context is None: context = {} if views_preload is None: views_preload = {} if domain is None: domain = [] if default_get is None: default_get = {} super(Screen, self).__init__() self.show_search = show_search self.search_count = 0 self.hastoolbar = hastoolbar self.default_get = default_get if not row_activate: self.row_activate = lambda self, screen=None: self.switch_view( screen, 'form') else: self.row_activate = row_activate self.create_new = create_new self.name = model_name self.domain = domain self.latest_search = [] self.views_preload = views_preload self.resource = model_name self.rpc = RPCProxy(model_name) self.context = context self.context.update(rpc.session.context) self.views = [] self.fields = {} self.view_ids = view_ids self.models = None self.parent = parent self.window = window self.is_wizard = is_wizard models = ModelRecordGroup(model_name, self.fields, parent=self.parent, context=self.context, is_wizard=is_wizard) self.models_set(models) self.current_model = None self.screen_container = screen_container() self.filter_widget = None self.widget = self.screen_container.widget_get() self.__current_view = 0 self.tree_saves = tree_saves self.limit = limit self.readonly = readonly self.view_fields = { } # Used to switch self.fields when the view switchs if view_type: self.view_to_load = view_type[1:] view_id = False if view_ids: view_id = view_ids.pop(0) view = self.add_view_id(view_id, view_type[0]) self.screen_container.set(view.widget) self.display()
class Screen(signal_event.signal_event): def __init__(self, model_name, view_ids=None, view_type=None, parent=None, context=None, views_preload=None, tree_saves=True, domain=None, create_new=False, row_activate=None, hastoolbar=False, default_get=None, show_search=False, window=None, limit=80, readonly=False, is_wizard=False): if view_ids is None: view_ids = [] if view_type is None: view_type = ['tree', 'form'] if context is None: context = {} if views_preload is None: views_preload = {} if domain is None: domain = [] if default_get is None: default_get = {} super(Screen, self).__init__() self.show_search = show_search self.search_count = 0 self.hastoolbar = hastoolbar self.default_get=default_get if not row_activate: self.row_activate = lambda self,screen=None: self.switch_view(screen, 'form') else: self.row_activate = row_activate self.create_new = create_new self.name = model_name self.domain = domain self.latest_search = [] self.views_preload = views_preload self.resource = model_name self.rpc = RPCProxy(model_name) self.context = context self.context.update(rpc.session.context) self.views = [] self.fields = {} self.view_ids = view_ids self.models = None self.parent=parent self.window=window self.is_wizard = is_wizard models = ModelRecordGroup(model_name, self.fields, parent=self.parent, context=self.context, is_wizard=is_wizard) self.models_set(models) self.current_model = None self.screen_container = screen_container() self.filter_widget = None self.widget = self.screen_container.widget_get() self.__current_view = 0 self.tree_saves = tree_saves self.limit = limit self.readonly= readonly self.view_fields = {} # Used to switch self.fields when the view switchs if view_type: self.view_to_load = view_type[1:] view_id = False if view_ids: view_id = view_ids.pop(0) view = self.add_view_id(view_id, view_type[0]) self.screen_container.set(view.widget) self.display() def readonly_get(self): return self._readonly def readonly_set(self, value): self._readonly = value self.models._readonly = value readonly = property(readonly_get, readonly_set) def search_active(self, active=True, show_search=True): if active: if not self.filter_widget: view_form = rpc.session.rpc_exec_auth('/object', 'execute', self.name, 'fields_view_get', False, 'form', self.context) view_tree = rpc.session.rpc_exec_auth('/object', 'execute', self.name, 'fields_view_get', False, 'tree', self.context) dom = xml.dom.minidom.parseString(view_tree['arch']) child_node=dom.childNodes[0].childNodes arch='' for i in range(1,len(child_node)): arch += child_node[i].toxml() #Generic case when we need to remove the last occurance of </form> from form view view_form['arch'] = view_form['arch'][0:view_form['arch'].rfind('</form>')] #Special case when form is replaced,we need to remove </form> find_form = view_form['arch'].rfind('</form>') if find_form > 0: view_form['arch'] = view_form['arch'][0:find_form] view_form['arch'] = view_form['arch'] + arch + '\n</form>' view_form['fields'].update(view_tree['fields']) self.filter_widget = widget_search.form(view_form['arch'], view_form['fields'], self.name, self.window, self.domain, (self, self.search_filter)) self.screen_container.add_filter(self.filter_widget.widget, self.search_filter, self.search_clear, self.search_offset_next, self.search_offset_previous) self.filter_widget.set_limit(self.limit) if active and show_search: self.screen_container.show_filter() else: self.screen_container.hide_filter() def update_scroll(self, *args): offset=self.filter_widget.get_offset() limit=self.filter_widget.get_limit() if offset<=0: self.screen_container.but_previous.set_sensitive(False) else: self.screen_container.but_previous.set_sensitive(True) if offset+limit>=self.search_count: self.screen_container.but_next.set_sensitive(False) else: self.screen_container.but_next.set_sensitive(True) def search_offset_next(self, *args): offset=self.filter_widget.get_offset() limit=self.filter_widget.get_limit() self.filter_widget.set_offset(offset+limit) self.search_filter() def search_offset_previous(self, *args): offset=self.filter_widget.get_offset() limit=self.filter_widget.get_limit() self.filter_widget.set_offset(max(offset-limit,0)) self.search_filter() def search_clear(self, *args): self.filter_widget.clear() self.clear() def search_filter(self, *args): v = self.filter_widget.value filter_keys = [ key for key, _, _ in v] for element in self.domain: if not isinstance(element,tuple): # Filtering '|' symbol v.append(element) else: (key, op, value) = element if key not in filter_keys and not (key=='active' and self.context.get('active_test', False)): v.append((key, op, value)) # v.extend((key, op, value) for key, op, value in domain if key not in filter_keys and not (key=='active' and self.context.get('active_test', False))) if self.latest_search != v: self.filter_widget.set_offset(0) limit=self.filter_widget.get_limit() offset=self.filter_widget.get_offset() self.latest_search = v ids = rpc.session.rpc_exec_auth('/object', 'execute', self.name, 'search', v, offset, limit, 0, self.context) if len(ids) < limit: self.search_count = len(ids) else: self.search_count = rpc.session.rpc_exec_auth_try('/object', 'execute', self.name, 'search_count', v, self.context) self.update_scroll() self.clear() self.load(ids) return True def models_set(self, models): import time c = time.time() if self.models: self.models.signal_unconnect(self.models) self.models = models self.parent = models.parent if len(models.models): self.current_model = models.models[0] else: self.current_model = None self.models.signal_connect(self, 'record-cleared', self._record_cleared) self.models.signal_connect(self, 'record-changed', self._record_changed) self.models.signal_connect(self, 'model-changed', self._model_changed) models.add_fields(self.fields, models) self.fields.update(models.fields) models.is_wizard = self.is_wizard def _record_cleared(self, model_group, signal, *args): for view in self.views: view.reload = True def _record_changed(self, model_group, signal, *args): try: for view in self.views: view.signal_record_changed(signal[0], model_group.models, signal[1], *args) except: pass def _model_changed(self, model_group, model): if (not model) or (model==self.current_model): self.display() def _get_current_model(self): return self.__current_model # # Check more or less fields than in the screen ! # def _set_current_model(self, value): self.__current_model = value try: offset = int(self.filter_widget.get_offset()) except: offset = 0 try: pos = self.models.models.index(value) except: pos = -1 self.signal('record-message', (pos + offset, len(self.models.models or []) + offset, self.search_count, value and value.id)) return True current_model = property(_get_current_model, _set_current_model) def destroy(self): for view in self.views: view.destroy() del view #del self.current_model self.models.signal_unconnect(self) del self.models del self.views # mode: False = next view, value = open this view def switch_view(self, screen=None, mode=False): self.current_view.set_value() self.fields = {} if self.current_model and self.current_model not in self.models.models: self.current_model = None if mode: ok = False for vid in range(len(self.views)): if self.views[vid].view_type==mode: self.__current_view = vid ok = True break while not ok and len(self.view_to_load): self.load_view_to_load() if self.current_view.view_type==mode: ok = True for vid in range(len(self.views)): if self.views[vid].view_type==mode: self.__current_view = vid ok = True break if not ok: self.__current_view = len(self.views) - 1 else: if len(self.view_to_load): self.load_view_to_load() self.__current_view = len(self.views) - 1 else: self.__current_view = (self.__current_view + 1) % len(self.views) self.fields = self.view_fields.get(self.__current_view, self.fields) # Switch the fields # TODO: maybe add_fields_custom is needed instead of add_fields on some cases self.models.add_fields(self.fields, self.models) # Switch the model fields too widget = self.current_view.widget self.screen_container.set(self.current_view.widget) if self.current_model: self.current_model.validate_set() elif self.current_view.view_type=='form': self.new() self.display() self.current_view.set_cursor() main = service.LocalService('gui.main') if main: main.sb_set() # TODO: set True or False accoring to the type def load_view_to_load(self, mode=False): if len(self.view_to_load): if self.view_ids: view_id = self.view_ids.pop(0) view_type = self.view_to_load.pop(0) else: view_id = False view_type = self.view_to_load.pop(0) self.add_view_id(view_id, view_type) def add_view_custom(self, arch, fields, display=False, toolbar={}): return self.add_view(arch, fields, display, True, toolbar=toolbar) def add_view_id(self, view_id, view_type, display=False, context=None): if view_type in self.views_preload: return self.add_view(self.views_preload[view_type]['arch'], self.views_preload[view_type]['fields'], display, toolbar=self.views_preload[view_type].get('toolbar', False), context=context) else: view = self.rpc.fields_view_get(view_id, view_type, self.context, self.hastoolbar) return self.add_view(view['arch'], view['fields'], display, toolbar=view.get('toolbar', False), context=context) def add_view(self, arch, fields, display=False, custom=False, toolbar=None, context=None): if toolbar is None: toolbar = {} def _parse_fields(node, fields): if node.nodeType == node.ELEMENT_NODE: if node.localName=='field': attrs = tools.node_attributes(node) if attrs.get('widget', False): if attrs['widget']=='one2many_list': attrs['widget']='one2many' attrs['type'] = attrs['widget'] fields[unicode(attrs['name'])].update(attrs) for node2 in node.childNodes: _parse_fields(node2, fields) dom = xml.dom.minidom.parseString(arch) _parse_fields(dom, fields) for dom in self.domain: if dom[0] in fields: field_dom = str(fields[dom[0]].setdefault('domain', [])) fields[dom[0]]['domain'] = field_dom[:1] + \ str(('id', dom[1], dom[2])) + ',' + field_dom[1:] from widget.view.widget_parse import widget_parse models = self.models.models if self.current_model and (self.current_model not in models): models = models + [self.current_model] if custom: self.models.add_fields_custom(fields, self.models) else: self.models.add_fields(fields, self.models, context=context) self.fields = self.models.fields parser = widget_parse(parent=self.parent, window=self.window) dom = xml.dom.minidom.parseString(arch) view = parser.parse(self, dom, self.fields, toolbar=toolbar) if view: self.views.append(view) if display: self.__current_view = len(self.views) - 1 self.current_view.display() self.screen_container.set(view.widget) # Store the fields for this view (we will use them when switching views) self.view_fields[len(self.views)-1] = copy.deepcopy(self.fields) return view def editable_get(self): if hasattr(self.current_view, 'widget_tree'): return self.current_view.widget_tree.editable else: return False def new(self, default=True, context={}): if self.current_view and self.current_view.view_type == 'tree' \ and not self.current_view.widget_tree.editable: self.switch_view(mode='form') ctx = self.context.copy() ctx.update(context) model = self.models.model_new(default, self.domain, ctx) if (not self.current_view) or self.current_view.model_add_new or self.create_new: self.models.model_add(model, self.new_model_position()) self.current_model = model self.current_model.validate_set() self.display() if self.current_view: self.current_view.set_cursor(new=True) return self.current_model def new_model_position(self): position = -1 if self.current_view and self.current_view.view_type =='tree' \ and self.current_view.widget_tree.editable == 'top': position = 0 return position def set_on_write(self, func_name): self.models.on_write = func_name def cancel_current(self): if self.current_model: self.current_model.cancel() if self.current_view: self.current_view.cancel() def save_current(self): if not self.current_model: return False self.current_view.set_value() id = False if self.current_model.validate(): id = self.current_model.save(reload=True) self.models.writen(id) if not id: self.current_view.display() else: self.current_view.display() self.current_view.set_cursor() return False if self.current_view.view_type == 'tree': for model in self.models.models: if model.is_modified(): if model.validate(): id = model.save(reload=True) self.models.writen(id) else: self.current_model = model self.display() self.current_view.set_cursor() return False self.display() self.current_view.set_cursor() if self.current_model not in self.models: self.models.model_add(self.current_model) return id def _getCurrentView(self): if not len(self.views): return None return self.views[self.__current_view] current_view = property(_getCurrentView) def get(self): if not self.current_model: return None self.current_view.set_value() return self.current_model.get() def is_modified(self): if not self.current_model: return False self.current_view.set_value() if self.current_view.view_type != 'tree': return self.current_model.is_modified() else: for model in self.models.models: if model.is_modified(): return True return False def reload(self): self.current_model.reload() if self.parent: self.parent.reload() self.display() def remove(self, unlink = False): id = False if self.current_view.view_type == 'form' and self.current_model: id = self.current_model.id idx = self.models.models.index(self.current_model) if not id: lst=[] self.models.models.remove(self.models.models[idx]) self.current_model=None if self.models.models: idx = min(idx, len(self.models.models)-1) self.current_model = self.models.models[idx] self.display() self.current_view.set_cursor() return False ctx = self.current_model.context_get().copy() self.current_model.update_context_with_concurrency_check_data(ctx) if unlink and id: if not self.rpc.unlink([id], ctx): return False self.models.remove(self.current_model) if self.models.models: idx = min(idx, len(self.models.models)-1) self.current_model = self.models.models[idx] else: self.current_model = None self.display() self.current_view.set_cursor() if self.current_view.view_type == 'tree': ids = self.current_view.sel_ids_get() ctx = self.models.context.copy() for m in self.models: if m.id in ids: m.update_context_with_concurrency_check_data(ctx) if unlink and ids: if not self.rpc.unlink(ids, ctx): return False for model in self.current_view.sel_models_get(): self.models.remove(model) self.current_model = None self.display() self.current_view.set_cursor() id = ids return id def load(self, ids): if not isinstance(ids,list): ids = [ids] self.models.load(ids, display=False) self.current_view.reset() if ids: self.display(ids[0]) else: self.current_model = None self.display() def display(self, res_id=None): if res_id: self.current_model = self.models[res_id] if self.views: self.current_view.display() self.current_view.widget.set_sensitive(bool(self.models.models or (self.current_view.view_type!='form') or self.current_model)) vt = self.current_view.view_type self.search_active( active=self.show_search and vt in ('tree', 'graph', 'calendar'), show_search=self.show_search and vt in ('tree', 'graph'), ) def display_next(self): self.current_view.set_value() if self.current_model in self.models.models: idx = self.models.models.index(self.current_model) idx = (idx+1) % len(self.models.models) self.current_model = self.models.models[idx] else: self.current_model = len(self.models.models) and self.models.models[0] if self.current_model: self.current_model.validate_set() self.display() self.current_view.set_cursor() def display_prev(self): self.current_view.set_value() if self.current_model in self.models.models: idx = self.models.models.index(self.current_model)-1 if idx<0: idx = len(self.models.models)-1 self.current_model = self.models.models[idx] else: self.current_model = len(self.models.models) and self.models.models[-1] if self.current_model: self.current_model.validate_set() self.display() self.current_view.set_cursor() def sel_ids_get(self): return self.current_view.sel_ids_get() def id_get(self): if not self.current_model: return False return self.current_model.id def ids_get(self): return [x.id for x in self.models if x.id] def clear(self): self.models.clear() def on_change(self, callback): self.current_model.on_change(callback) self.display()
def __init__(self, model_name, view_ids=None, view_type=None, parent=None, context=None, views_preload=None, tree_saves=True, domain=None, create_new=False, row_activate=None, hastoolbar=False, default_get=None, show_search=False, window=None, limit=80, readonly=False, is_wizard=False): if view_ids is None: view_ids = [] if view_type is None: view_type = ['tree', 'form'] if context is None: context = {} if views_preload is None: views_preload = {} if domain is None: domain = [] if default_get is None: default_get = {} super(Screen, self).__init__() self.show_search = show_search self.search_count = 0 self.hastoolbar = hastoolbar self.default_get=default_get if not row_activate: self.row_activate = lambda self,screen=None: self.switch_view(screen, 'form') else: self.row_activate = row_activate self.create_new = create_new self.name = model_name self.domain = domain self.latest_search = [] self.views_preload = views_preload self.resource = model_name self.rpc = RPCProxy(model_name) self.context = context self.context.update(rpc.session.context) self.views = [] self.fields = {} self.view_ids = view_ids self.models = None self.parent=parent self.window=window self.is_wizard = is_wizard models = ModelRecordGroup(model_name, self.fields, parent=self.parent, context=self.context, is_wizard=is_wizard) self.models_set(models) self.current_model = None self.screen_container = screen_container() self.filter_widget = None self.widget = self.screen_container.widget_get() self.__current_view = 0 self.tree_saves = tree_saves self.limit = limit self.readonly= readonly self.view_fields = {} # Used to switch self.fields when the view switchs if view_type: self.view_to_load = view_type[1:] view_id = False if view_ids: view_id = view_ids.pop(0) view = self.add_view_id(view_id, view_type[0]) self.screen_container.set(view.widget) self.display()
class ModelRecordGroup(signal_event.signal_event): def __init__(self, resource, fields, ids=[], parent=None, context={}, is_wizard=False, screen=None): super(ModelRecordGroup, self).__init__() self._readonly = False self.parent = parent self._context = context self._context.update(rpc.session.context) self.resource = resource self.rpc = RPCProxy(resource) self.fields = fields self.mfields = {} self.mfields_load(fields.keys(), self) self.screen = screen self.models = ModelList(self) self.current_idx = None self.load(ids) self.models_removed = [] self.on_write = '' self.is_wizard = is_wizard self.list_parent = False self.list_group = False def destroy(self): for field in self.mfields.values(): field.destroy() if self.list_group: self.list_group.destroy() del self.mfields del self.fields del self.list_group del self.models def index(self, model): return self.models.index(model) def mfields_load(self, fkeys, models): for fname in fkeys: fvalue = models.fields[fname] modelfield = field.ModelField(fvalue['type']) fvalue['name'] = fname models.mfields[fname] = modelfield(models, fvalue) def model_move(self, model, position=0): self.models.move(model, position) def set_sequence(self, get_id, rec_id, field='sequence'): seq_ids = [] index = 0 for model in self.models: seq_ids += [model[field].get(model)] index = index +1 set_list = list(set(seq_ids)) if len(seq_ids) != len(set_list): set_list.sort() repeat = set_list[-1] mod_list = seq_ids[len(set_list):] for e in range(len(mod_list)): repeat = repeat + 1 mod_list[e]= repeat final_list = set_list + mod_list index = 0 for model in self.models: model[field].set(model, final_list[index], modified=True) if model.id: model.save() index = index +1 else: seq_id = [] if get_id < rec_id: for x in range(get_id, rec_id): seq_id += [self.models[x][field].get(self.models[x])] sort_seq = [seq_id[-1]] + seq_id[:-1] index = 0 for x in range(get_id, rec_id): self.models[x][field].set(self.models[x], sort_seq[index], modified=True) if self.models[x].id: self.models[x].save() index = index +1 else: for x in range(rec_id,get_id+1): seq_id += [self.models[x][field].get(self.models[x])] sort_seq = seq_id[1:] + [seq_id[0]] index = 0 for x in range(rec_id,get_id+1): self.models[x][field].set(self.models[x], sort_seq[index], modified=True) if self.models[x].id: self.models[x].save() index = index +1 def save(self): for model in self.models: saved = model.save() self.writen(saved) def writen(self, edited_id): if not self.on_write: return new_ids = getattr(self.rpc, self.on_write)(edited_id, self.context) model_idx = self.models.index(self[edited_id]) result = False for id in new_ids: cont = False for m in self.models: if m.id == id: cont = True m.reload() if cont: continue newmod = ModelRecord(self.resource, id, parent=self.parent, group=self) newmod.reload() if not result: result = newmod new_index = min(model_idx, len(self.models)-1) self.model_add(newmod, new_index) return result def pre_load(self, ids, display=True): if not ids: return True self.models.lock_signal = True for id in ids: newmod = ModelRecord(self.resource, id, parent=self.parent, group=self) self.model_add(newmod) #if display: # self.signal('model-changed', newmod) self.models.lock_signal = False self.signal('record-cleared') return True def load_for(self, values): self.models.lock_signal = True for value in values: newmod = ModelRecord(self.resource, value['id'], parent=self.parent, group=self) newmod.set(value) self.models.append(newmod) newmod.signal_connect(self, 'record-changed', self._record_changed) self.models.lock_signal = False self.signal('record-cleared') def load(self, ids, display=True, context={}): if not ids: return True if not self.fields: return self.pre_load(ids, display) c = rpc.session.context.copy() c.update(self.context) c.update(context) c['bin_size'] = True values = self.rpc.read(ids, self.fields.keys() + [rpc.CONCURRENCY_CHECK_FIELD], c) if not values: return False vdict = dict(map(lambda x: (x['id'], x), values)) v2 = [] for id in ids: if id in vdict: v2.append(vdict[id]) self.load_for(v2) self.current_idx = 0 return True def clear(self): self.models.clear() self.models_removed = [] def setContext(self, ctx): self._context.update(ctx) def getContext(self): ctx = {} ctx.update(self._context) #ctx['active_ids'] = [model.id for model in self.models if model.id] #if self.current_idx is not None: # ctx['active_id'] = self.models[self.current_idx].id or False #else: # ctx['active_id'] = False return ctx context = property(getContext, setContext) def model_add(self, model, position=-1): # # To be checked # if not model.mgroup is self: fields = {} for mf in model.mgroup.fields: fields[model.mgroup.fields[mf]['name']] = model.mgroup.fields[mf] self.add_fields(fields, self) self.add_fields(self.fields, model.mgroup) model.mgroup = self if position==-1: self.models.append(model) else: self.models.insert(position, model) self.current_idx = position model.parent = self.parent model.signal_connect(self, 'record-changed', self._record_changed) return model def model_new(self, default=True, domain=[], context={}): newmod = ModelRecord(self.resource, None, group=self, parent=self.parent, new=True) newmod.signal_connect(self, 'record-changed', self._record_changed) if default: ctx=context.copy() ctx.update(self.context) newmod.default_get(domain, ctx) self.signal('model-changed', newmod) newmod.list_parent = self.list_parent newmod.list_group = self.list_group return newmod def model_remove(self, model): idx = self.models.index(model) self.models.remove(model) if model.parent: model.parent.modified = True if self.models: self.current_idx = min(idx, len(self.models)-1) else: self.current_idx = None def _record_changed(self, model, signal_data): self.signal('model-changed', model) def prev(self): if self.models and self.current_idx is not None: self.current_idx = (self.current_idx - 1) % len(self.models) elif self.models: self.current_idx = 0 else: return None return self.models[self.current_idx] def next(self): if self.models and self.current_idx is not None: self.current_idx = (self.current_idx + 1) % len(self.models) elif self.models: self.current_idx = 0 else: return None return self.models[self.current_idx] def remove(self, model): try: idx = self.models.index(model) if self.models[idx].id: self.models_removed.append(self.models[idx]) self.models[idx].modified = True if model.parent: model.parent.modified = True self.models.remove(self.models[idx]) except: pass def add_fields_custom(self, fields, models): to_add = [] for f in fields.keys(): add_field = True if f in models.fields: if fields[f].get('widget','') == models.fields[f].get('widget',''): models.fields[f].update(fields[f]) add_field = False if f in models.mfields and fields[f].get('type','') == 'one2many': add_field = False if add_field: 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: m.value[fname] = self.mfields[fname].create(m) return to_add def add_fields(self, fields, models, context=None): import time ct = time.time() if context is None: context = {} to_add = self.add_fields_custom(fields, models) models = models.models if not len(models): return True old = [] new = [] for model in models: if model.id: old.append(model.id) else: new.append(model) ctx = context.copy() if len(old) and len(to_add): ctx.update(rpc.session.context) ctx.update(self.context) to_add_normal = [rpc.CONCURRENCY_CHECK_FIELD] to_add_binary = [] for f in to_add: if fields[f]['type'] in ('image', 'binary'): to_add_binary.append(f) else: to_add_normal.append(f) if to_add_normal: values = self.rpc.read(old, to_add_normal, ctx) if values: for v in values: id = v['id'] if 'id' not in to_add: del v['id'] self[id].set(v, signal=False) if to_add_binary: data = {}.fromkeys(to_add_binary, None) for m in self.models: m.set(data, signal=False) if len(new) and len(to_add): if self.parent and self.screen: ctx.update(self.parent.expr_eval(self.screen.default_get)) ctx.update(self.context) values = self.rpc.default_get(to_add, ctx) for t in to_add: if t not in values: values[t] = False for mod in new: mod.set_default(values) if values: mod.modified = True def __iter__(self): return iter(self.models) def get_by_id(self, id): for model in self.models: if model.id == id: return model __getitem__ = get_by_id
class ModelRecord(signal_event.signal_event): def __init__(self, resource, id, group=None, parent=None, new=False ): super(ModelRecord, self).__init__() self.resource = str(resource) self.rpc = RPCProxy(self.resource) self.id = id self._loaded = False self.parent = parent self.mgroup = group self.value = {} self.state_attrs = {} self.modified = False self.modified_fields = {} self._concurrency_check_data = False for key,val in self.mgroup.mfields.items(): self.value[key] = val.create(self) if (new and val.attrs['type']=='one2many') and (val.attrs.get('mode','tree,form').startswith('form')): mod = self.value[key].model_new() self.value[key].model_add(mod) def __getitem__(self, name): return self.mgroup.mfields.get(name, False) def __repr__(self): return '<ModelRecord %s@%s>' % (self.id, self.resource) def is_modified(self): return self.modified def is_wizard(self): return self.mgroup.is_wizard def fields_get(self): return self.mgroup.mfields def _check_load(self): if not self._loaded: self.reload() return True return False def update_context_with_concurrency_check_data(self, context): if self.id and self.is_modified(): context.setdefault(CONCURRENCY_CHECK_FIELD, {})["%s,%d" % (self.resource, self.id)] = self._concurrency_check_data for name, field in self.mgroup.mfields.items(): if isinstance(field, O2MField): if field.name not in self.value.keys(): continue v = self.value[field.name] from itertools import chain for m in chain(v.models, v.models_removed): m.update_context_with_concurrency_check_data(context) def get(self, get_readonly=True, includeid=False, check_load=True, get_modifiedonly=False): if check_load: self._check_load() value = [] for name, field in self.mgroup.mfields.items(): if (get_readonly or not field.get_state_attrs(self).get('readonly', False)) \ and (not get_modifiedonly or (field.name in self.modified_fields or isinstance(field, O2MField))): value.append((name, field.get(self, readonly=get_readonly, modified=get_modifiedonly))) value = dict(value) if includeid: value['id'] = self.id return value def cancel(self): self._loaded = False self.reload() def failed_validation(self): invalid_fields = self.rpc.get_invalid_fields() for item in invalid_fields: if item in self.mgroup.mfields: self.mgroup.mfields[item].get_state_attrs(self)['valid'] = False def save(self, reload=True): self._check_load() if not self.id: value = self.get(get_readonly=False) self.id = self.rpc.create(value, self.context_get()) if not self.id: self.failed_validation() else: if not self.is_modified(): return self.id value = self.get(get_readonly=False, get_modifiedonly=True) context = self.context_get().copy() self.update_context_with_concurrency_check_data(context) if not self.rpc.write([self.id], value, context): self.failed_validation() return False self._loaded = False if reload: self.reload() else: # just reload the CONCURRENCY_CHECK_FIELD self._reload([CONCURRENCY_CHECK_FIELD]) return self.id def default_get(self, domain=[], context={}): if len(self.mgroup.fields): val = self.rpc.default_get(self.mgroup.fields.keys(), context) for d in domain: if d[0] in self.mgroup.fields: if d[1] == '=': val[d[0]] = d[2] if d[1] == 'in' and len(d[2]) == 1: val[d[0]] = d[2][0] self.set_default(val) def name_get(self): name = self.rpc.name_get([self.id], rpc.session.context)[0] return name def validate_set(self): change = self._check_load() for fname in self.mgroup.mfields: field = self.mgroup.mfields[fname] change = change or not field.get_state_attrs(self).get('valid', True) field.get_state_attrs(self)['valid'] = True if change: self.signal('record-changed') self.reload() return change def validate(self): self._check_load() ok = True for fname in self.mgroup.mfields: if not self.mgroup.mfields[fname].validate(self): ok = False return ok def _get_invalid_fields(self): res = [] for fname, field in self.mgroup.mfields.items(): if not field.get_state_attrs(self).get('valid', True): res.append((fname, field.attrs['string'])) return dict(res) invalid_fields = property(_get_invalid_fields) def context_get(self): return self.mgroup.context def get_default(self): self._check_load() value = dict([(name, field.get_default(self)) for name, field in self.mgroup.mfields.items()]) return value def set_default(self, val): for fieldname, value in val.items(): if fieldname not in self.mgroup.mfields: continue self.mgroup.mfields[fieldname].set_default(self, value) self._loaded = True self.signal('record-changed') def set(self, val, modified=False, signal=True): later={} for fieldname, value in val.items(): if fieldname == CONCURRENCY_CHECK_FIELD: self._concurrency_check_data = value if fieldname not in self.mgroup.mfields: continue if isinstance(self.mgroup.mfields[fieldname], field.O2MField): later[fieldname]=value continue self.mgroup.mfields[fieldname].set(self, value, modified=modified) for fieldname, value in later.items(): self.mgroup.mfields[fieldname].set(self, value, modified=modified) self._loaded = True self.modified = modified if not self.modified: self.modified_fields = {} if signal: self.signal('record-changed') def reload(self): return self._reload(self.mgroup.mfields.keys() + [CONCURRENCY_CHECK_FIELD]) def _reload(self, fields): if not self.id: return c = rpc.session.context.copy() c.update(self.context_get()) c['bin_size'] = True res = self.rpc.read([self.id], fields, c) if res: value = res[0] if self.parent: self.set(value, signal=False) else: self.set(value) def expr_eval(self, dom, check_load=True): if not isinstance(dom, basestring): return dom if check_load: self._check_load() d = {} for name, mfield in self.mgroup.mfields.items(): d[name] = mfield.get(self, check_load=check_load) d['current_date'] = time.strftime('%Y-%m-%d') d['time'] = time d['context'] = self.context_get() d['active_id'] = self.id if self.parent: d['parent'] = EvalEnvironment(self.parent) val = tools.expr_eval(dom, d) return val #XXX Shoud use changes of attributes (ro, ...) def on_change(self, callback): match = re.match('^(.*?)\((.*)\)$', callback) if not match: raise Exception, 'ERROR: Wrong on_change trigger: %s' % callback func_name = match.group(1) arg_names = [n.strip() for n in match.group(2).split(',') if n.strip()] args = [self.expr_eval(arg) for arg in arg_names] ids = self.id and [self.id] or [] response = getattr(self.rpc, func_name)(ids, *args) if response: self.set(response.get('value', {}), modified=True) if 'domain' in response: for fieldname, value in response['domain'].items(): if fieldname not in self.mgroup.mfields: continue self.mgroup.mfields[fieldname].attrs['domain'] = value warning=response.get('warning',{}) if warning: common.warning(warning['message'], warning['title']) self.signal('record-changed') def on_change_attrs(self, callback): self.signal('attrs-changed') def cond_default(self, field, value): ir = RPCProxy('ir.values') values = ir.get('default', '%s=%s' % (field, value), [(self.resource, False)], False, {}) data = {} for index, fname, value in values: data[fname] = value self.set_default(data)
class ModelRecordGroup(signal_event.signal_event): def __init__(self, resource, fields, ids=[], parent=None, context={}, is_wizard=False, screen=None): super(ModelRecordGroup, self).__init__() self._readonly = False self.parent = parent self._context = context self._context.update(rpc.session.context) self.resource = resource self.rpc = RPCProxy(resource) self.fields = fields self.mfields = {} self.mfields_load(fields.keys(), self) self.screen = screen self.models = ModelList(self) self.current_idx = None self.load(ids) self.models_removed = [] self.on_write = '' self.is_wizard = is_wizard self.list_parent = False self.list_group = False def destroy(self): for field in self.mfields.values(): field.destroy() if self.list_group: self.list_group.destroy() del self.mfields del self.fields del self.list_group del self.models def index(self, model): return self.models.index(model) def mfields_load(self, fkeys, models): for fname in fkeys: fvalue = models.fields[fname] modelfield = field.ModelField(fvalue['type']) fvalue['name'] = fname models.mfields[fname] = modelfield(models, fvalue) def model_move(self, model, position=0): self.models.move(model, position) def set_sequence(self, get_id, rec_id, field='sequence'): seq_ids = [] index = 0 for model in self.models: seq_ids += [model[field].get(model)] index = index + 1 set_list = list(set(seq_ids)) if len(seq_ids) != len(set_list): set_list.sort() repeat = set_list[-1] mod_list = seq_ids[len(set_list):] for e in range(len(mod_list)): repeat = repeat + 1 mod_list[e] = repeat final_list = set_list + mod_list index = 0 for model in self.models: model[field].set(model, final_list[index], modified=True) if model.id: model.save() index = index + 1 else: seq_id = [] if get_id < rec_id: for x in range(get_id, rec_id): seq_id += [self.models[x][field].get(self.models[x])] sort_seq = [seq_id[-1]] + seq_id[:-1] index = 0 for x in range(get_id, rec_id): self.models[x][field].set(self.models[x], sort_seq[index], modified=True) if self.models[x].id: self.models[x].save() index = index + 1 else: for x in range(rec_id, get_id + 1): seq_id += [self.models[x][field].get(self.models[x])] sort_seq = seq_id[1:] + [seq_id[0]] index = 0 for x in range(rec_id, get_id + 1): self.models[x][field].set(self.models[x], sort_seq[index], modified=True) if self.models[x].id: self.models[x].save() index = index + 1 def save(self): for model in self.models: saved = model.save() self.writen(saved) def writen(self, edited_id): if not self.on_write: return new_ids = getattr(self.rpc, self.on_write)(edited_id, self.context) model_idx = self.models.index(self[edited_id]) result = False for id in new_ids: cont = False for m in self.models: if m.id == id: cont = True m.reload() if cont: continue newmod = ModelRecord(self.resource, id, parent=self.parent, group=self) newmod.reload() if not result: result = newmod new_index = min(model_idx, len(self.models) - 1) self.model_add(newmod, new_index) return result def pre_load(self, ids, display=True): if not ids: return True self.models.lock_signal = True for id in ids: newmod = ModelRecord(self.resource, id, parent=self.parent, group=self) self.model_add(newmod) #if display: # self.signal('model-changed', newmod) self.models.lock_signal = False self.signal('record-cleared') return True def load_for(self, values): self.models.lock_signal = True for value in values: newmod = ModelRecord(self.resource, value['id'], parent=self.parent, group=self) newmod.set(value) self.models.append(newmod) newmod.signal_connect(self, 'record-changed', self._record_changed) self.models.lock_signal = False self.signal('record-cleared') def load(self, ids, display=True, context={}): if not ids: return True if not self.fields: return self.pre_load(ids, display) c = rpc.session.context.copy() c.update(self.context) c.update(context) c['bin_size'] = True values = self.rpc.read( ids, self.fields.keys() + [rpc.CONCURRENCY_CHECK_FIELD], c) if not values: return False vdict = dict(map(lambda x: (x['id'], x), values)) v2 = [] for id in ids: if id in vdict: v2.append(vdict[id]) self.load_for(v2) self.current_idx = 0 return True def clear(self): self.models.clear() self.models_removed = [] def setContext(self, ctx): self._context.update(ctx) def getContext(self): ctx = {} ctx.update(self._context) #ctx['active_ids'] = [model.id for model in self.models if model.id] #if self.current_idx is not None: # ctx['active_id'] = self.models[self.current_idx].id or False #else: # ctx['active_id'] = False return ctx context = property(getContext, setContext) def model_add(self, model, position=-1): # # To be checked # if not model.mgroup is self: fields = {} for mf in model.mgroup.fields: fields[model.mgroup.fields[mf] ['name']] = model.mgroup.fields[mf] self.add_fields(fields, self) self.add_fields(self.fields, model.mgroup) model.mgroup = self if position == -1: self.models.append(model) else: self.models.insert(position, model) self.current_idx = position model.parent = self.parent model.signal_connect(self, 'record-changed', self._record_changed) return model def model_new(self, default=True, domain=[], context={}): newmod = ModelRecord(self.resource, None, group=self, parent=self.parent, new=True) newmod.signal_connect(self, 'record-changed', self._record_changed) if default: ctx = context.copy() ctx.update(self.context) newmod.default_get(domain, ctx) self.signal('model-changed', newmod) newmod.list_parent = self.list_parent newmod.list_group = self.list_group return newmod def model_remove(self, model): idx = self.models.index(model) self.models.remove(model) if model.parent: model.parent.modified = True if self.models: self.current_idx = min(idx, len(self.models) - 1) else: self.current_idx = None def _record_changed(self, model, signal_data): self.signal('model-changed', model) def prev(self): if self.models and self.current_idx is not None: self.current_idx = (self.current_idx - 1) % len(self.models) elif self.models: self.current_idx = 0 else: return None return self.models[self.current_idx] def next(self): if self.models and self.current_idx is not None: self.current_idx = (self.current_idx + 1) % len(self.models) elif self.models: self.current_idx = 0 else: return None return self.models[self.current_idx] def remove(self, model): try: idx = self.models.index(model) if self.models[idx].id: self.models_removed.append(self.models[idx]) self.models[idx].modified = True if model.parent: model.parent.modified = True self.models.remove(self.models[idx]) except: pass def add_fields_custom(self, fields, models): to_add = [] for f in fields.keys(): add_field = True if f in models.fields: if fields[f].get('widget', '') == models.fields[f].get('widget', ''): models.fields[f].update(fields[f]) add_field = False if f in models.mfields and fields[f].get('type', '') == 'one2many': add_field = False if add_field: 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: m.value[fname] = self.mfields[fname].create(m) return to_add def add_fields(self, fields, models, context=None): import time ct = time.time() if context is None: context = {} to_add = self.add_fields_custom(fields, models) models = models.models if not len(models): return True old = [] new = [] for model in models: if model.id: old.append(model.id) else: new.append(model) ctx = context.copy() if len(old) and len(to_add): ctx.update(rpc.session.context) ctx.update(self.context) to_add_normal = [rpc.CONCURRENCY_CHECK_FIELD] to_add_binary = [] for f in to_add: if fields[f]['type'] in ('image', 'binary'): to_add_binary.append(f) else: to_add_normal.append(f) if to_add_normal: values = self.rpc.read(old, to_add_normal, ctx) if values: for v in values: id = v['id'] if 'id' not in to_add: del v['id'] self[id].set(v, signal=False) if to_add_binary: data = {}.fromkeys(to_add_binary, None) for m in self.models: m.set(data, signal=False) if len(new) and len(to_add): ctx.update(self.context) values = self.rpc.default_get(to_add, ctx) for t in to_add: if t not in values: values[t] = False for mod in new: mod.set_default(values) def __iter__(self): return iter(self.models) def get_by_id(self, id): for model in self.models: if model.id == id: return model __getitem__ = get_by_id
def __init__(self, model_name, view_ids=None, view_type=None, help={}, parent=None, context=None, views_preload=None, tree_saves=True, domain=None, create_new=False, row_activate=None, hastoolbar=False, hassubmenu=False, default_get=None, show_search=False, window=None, limit=100, readonly=False, auto_search=True, is_wizard=False, search_view=None, win_search=False): if view_ids is None: view_ids = [] if view_type is None: view_type = ['tree', 'form'] if views_preload is None: views_preload = {} if not domain: domain = [] if default_get is None: default_get = {} if search_view is None: search_view = "{}" super(Screen, self).__init__() self.win_search = win_search self.win_search_domain = [] self.win_search_ids = [] self.win_search_callback = False self.show_search = show_search self.auto_search = auto_search self.search_count = 0 self.hastoolbar = hastoolbar self.hassubmenu = hassubmenu self.default_get = default_get self.sort = False self.type = None self.dummy_cal = False if not row_activate: self.row_activate = lambda self, screen=None: self.switch_view( screen, 'form') else: self.row_activate = row_activate self.create_new = create_new self.name = model_name self.domain_init = domain self.action_domain = [] self.action_domain += domain self.latest_search = [] self.views_preload = views_preload self.resource = model_name self.rpc = RPCProxy(model_name) self.context_init = context or {} self.context_update() self.views = [] self.fields = {} self.view_ids = view_ids self.models = None self.parent = parent self.window = window self.is_wizard = is_wizard self.search_view = eval(search_view) models = ModelRecordGroup(model_name, self.fields, parent=self.parent, context=self.context, is_wizard=is_wizard, screen=self) self.models_set(models) self.current_model = None self.screen_container = screen_container(self.win_search) self.filter_widget = None self.widget = self.screen_container.widget_get() self.__current_view = 0 self.tree_saves = tree_saves self.limit = limit self.old_limit = limit self.offset = 0 self.readonly = readonly self.custom_panels = [] self.view_fields = { } # Used to switch self.fields when the view switchs self.sort_domain = [] self.old_ctx = {} self.help_mode = False if view_type: self.view_to_load = view_type[1:] view_id = False if view_ids: view_id = view_ids.pop(0) if view_type[0] in ('tree', 'graph', 'calendar'): self.screen_container.help = help self.help_mode = view_type[0] view = self.add_view_id(view_id, view_type[0], help=help) self.screen_container.set(view.widget) self.display()
def __init__(self, object, relation, screen): self.object = object self.rpc = RPCProxy(relation) self.screen = screen self.domain = [] self.type = screen.type
class ModelRecord(signal_event.signal_event): def __init__(self, resource, id, group=None, parent=None, new=False, list_parent=None): super(ModelRecord, self).__init__() self.resource = str(resource) self.rpc = RPCProxy(self.resource) self.id = id self.list_parent = list_parent self._loaded = False self.parent = parent self.mgroup = group self.value = {} self.state_attrs = {} self.modified = False self.modified_fields = {} self.pager_cache = {} self.is_m2m_modified = False self._concurrency_check_data = False for key, val in self.mgroup.mfields.items(): self.value[key] = val.create(self) if (new and val.attrs['type'] == 'one2many') and (val.attrs.get( 'mode', 'tree,form').startswith('form')): mod = self.value[key].model_new() self.value[key].model_add(mod) def __getitem__(self, name): return self.mgroup.mfields.get(name, False) def __repr__(self): return '<ModelRecord %s@%s>' % (self.id, self.resource) def is_modified(self): return self.modified def is_wizard(self): return self.mgroup.is_wizard def fields_get(self): return self.mgroup.mfields def _check_load(self): if not self._loaded: self.reload() return True return False def update_context_with_concurrency(self, context): if self.id and self.is_modified(): context.setdefault( CONCURRENCY_CHECK_FIELD, {})["%s,%s" % (self.resource, self.id)] = self._concurrency_check_data for name, field in self.mgroup.mfields.items(): if isinstance(field, O2MField): v = self.value[field.name] from itertools import chain for m in chain(v.models, v.models_removed): m.update_context_with_concurrency(context) def get(self, get_readonly=True, includeid=False, check_load=True, get_modifiedonly=False): if check_load: self._check_load() value = [] for name, field in self.mgroup.mfields.items(): if (get_readonly or not field.get_state_attrs(self).get('readonly', False)) \ and (not get_modifiedonly or (field.name in self.modified_fields or isinstance(field, O2MField))): value.append((name, field.get(self, readonly=get_readonly, modified=get_modifiedonly))) value = dict(value) if includeid: value['id'] = self.id return value def cancel(self): self._loaded = False self.reload() def failed_validation(self): invalid_fields = self.rpc.get_invalid_fields() for item in invalid_fields: if item in self.mgroup.mfields: self.mgroup.mfields[item].get_state_attrs( self)['valid'] = False def save(self, reload=True): self._check_load() try: if not self.id: value = self.get(get_readonly=False) self.id = self.rpc.create(value, self.context_get()) else: if not self.is_modified(): return self.id value = self.get(get_readonly=False, get_modifiedonly=True) context = self.context_get().copy() self.update_context_with_concurrency(context) res = self.rpc.write([self.id], value, context) if type(res) == type({}): obj = service.LocalService('action.main') obj._exec_action(res, {}, context) except Exception, e: if hasattr(e, 'faultCode') and e.faultCode.find('ValidateError') > -1: self.failed_validation() return False pass self._loaded = False if reload: self.reload() else: # just reload the CONCURRENCY_CHECK_FIELD self._reload([CONCURRENCY_CHECK_FIELD]) return self.id
def drag_data_received(self, treeview, context, x, y, selection, info, etime): treeview.emit_stop_by_name('drag-data-received') if treeview.sequence: for model in self.screen.models.models: if model['sequence'].get_state_attrs(model).get( 'readonly', False): return model = treeview.get_model() data = eval(selection.data) get_id = data[0] drop_info = treeview.get_dest_row_at_pos(x, y) if drop_info: path, position = drop_info self.source_group_child = [] rec_id = model.on_iter_has_child( model.on_get_iter(path)) and path or path[:-1] group_by = self.screen.context.get('group_by') if group_by: if data and path and data[:-1] == path[:-1] \ and isinstance(model.on_get_iter(data), ModelRecord): if position in (gtk.TREE_VIEW_DROP_BEFORE, gtk.TREE_VIEW_DROP_INTO_OR_BEFORE): m_path = path[-1] else: m_path = path[-1] + 1 source_models_list = model.on_get_iter(path[:-1]) self.group_by_move(source_models_list, data[-1], m_path) else: source_group = model.on_get_iter(data) target_group = model.on_get_iter(rec_id) if model.on_iter_has_child(source_group): def process(parent): for child in parent.getChildren().lst: if model.on_iter_has_child(child): process(child) else: self.source_group_child.append(child) process(source_group) else: self.source_group_child = [source_group] if self.source_group_child: self.screen.current_model = self.source_group_child[0] target_domain = filter( lambda x: x[0] in group_by, target_group.children.context.get('__domain', [])) val = {} map(lambda x: val.update({x[0]: x[2]}), target_domain) rpc = RPCProxy(self.source_group_child[0].resource) rpc.write(map(lambda x: x.id, self.source_group_child), val) self.reload = True self.screen.reload() for expand_path in (data, path): treeview.expand_to_path(expand_path) else: idx = path[0] if position in (gtk.TREE_VIEW_DROP_BEFORE, gtk.TREE_VIEW_DROP_INTO_OR_BEFORE): model.move(data, idx) rec_id = idx else: model.move(data, idx + 1) rec_id = idx + 1 context.drop_finish(False, etime) if treeview.sequence and drop_info and not group_by: self.screen.models.set_sequence(get_id, rec_id, field='sequence')
class Screen(signal_event.signal_event): def __init__(self, model_name, view_ids=None, view_type=None, help={}, parent=None, context=None, views_preload=None, tree_saves=True, domain=None, create_new=False, row_activate=None, hastoolbar=False, hassubmenu=False, default_get=None, show_search=False, window=None, limit=100, readonly=False, auto_search=True, is_wizard=False, search_view=None, win_search=False): if view_ids is None: view_ids = [] if view_type is None: view_type = ['tree', 'form'] if views_preload is None: views_preload = {} if not domain: domain = [] if default_get is None: default_get = {} if search_view is None: search_view = "{}" super(Screen, self).__init__() self.win_search = win_search self.win_search_domain = [] self.win_search_ids = [] self.win_search_callback = False self.show_search = show_search self.auto_search = auto_search self.search_count = 0 self.hastoolbar = hastoolbar self.hassubmenu = hassubmenu self.default_get = default_get self.sort = False self.type = None self.dummy_cal = False if not row_activate: self.row_activate = lambda self, screen=None: self.switch_view( screen, 'form') else: self.row_activate = row_activate self.create_new = create_new self.name = model_name self.domain_init = domain self.action_domain = [] self.action_domain += domain self.latest_search = [] self.views_preload = views_preload self.resource = model_name self.rpc = RPCProxy(model_name) self.context_init = context or {} self.context_update() self.views = [] self.fields = {} self.view_ids = view_ids self.models = None self.parent = parent self.window = window self.is_wizard = is_wizard self.search_view = eval(search_view) models = ModelRecordGroup(model_name, self.fields, parent=self.parent, context=self.context, is_wizard=is_wizard, screen=self) self.models_set(models) self.current_model = None self.screen_container = screen_container(self.win_search) self.filter_widget = None self.widget = self.screen_container.widget_get() self.__current_view = 0 self.tree_saves = tree_saves self.limit = limit self.old_limit = limit self.offset = 0 self.readonly = readonly self.custom_panels = [] self.view_fields = { } # Used to switch self.fields when the view switchs self.sort_domain = [] self.old_ctx = {} self.help_mode = False if view_type: self.view_to_load = view_type[1:] view_id = False if view_ids: view_id = view_ids.pop(0) if view_type[0] in ('tree', 'graph', 'calendar'): self.screen_container.help = help self.help_mode = view_type[0] view = self.add_view_id(view_id, view_type[0], help=help) self.screen_container.set(view.widget) self.display() def context_update(self, ctx={}, dmn=[]): self.context = self.context_init.copy() self.context.update(rpc.session.context) self.context.update(ctx) self.domain = self.domain_init[:] self.domain += dmn def readonly_get(self): return self._readonly def readonly_set(self, value): self._readonly = value self.models._readonly = value readonly = property(readonly_get, readonly_set) def search_active(self, active=True, show_search=True): if active: if not self.filter_widget: if not self.search_view: self.search_view = rpc.session.rpc_exec_auth( '/object', 'execute', self.name, 'fields_view_get', False, 'search', self.context) self.filter_widget = widget_search.form( self.search_view['arch'], self.search_view['fields'], self.name, self.window, self.domain, (self, self.search_filter)) if self.context.has_key('group_by'): self.limit = None self.screen_container.add_filter( self.filter_widget.widget, self.search_filter, self.search_clear, self.search_offset_next, self.search_offset_previous, self.execute_action, self.add_custom, self.name, self.limit) if active and show_search: self.screen_container.show_filter() else: self.screen_container.hide_filter() def update_scroll(self, *args): offset = self.offset limit = self.screen_container.get_limit() if self.screen_container.but_previous: if offset <= 0: self.screen_container.but_previous.set_sensitive(False) else: self.screen_container.but_previous.set_sensitive(True) if self.screen_container.but_next: if not limit or offset + limit >= self.search_count: self.screen_container.but_next.set_sensitive(False) else: self.screen_container.but_next.set_sensitive(True) if self.win_search: self.win_search_callback() def search_offset_next(self, *args): offset = self.offset limit = self.screen_container.get_limit() self.offset = offset + limit self.search_filter() if self.win_search: self.win_search_callback() def search_offset_previous(self, *args): offset = self.offset limit = self.screen_container.get_limit() self.offset = max(offset - limit, 0) self.search_filter() if self.win_search: self.win_search_callback() def search_clear(self, *args): self.filter_widget.clear() if not self.win_search: self.screen_container.action_combo.set_active(0) self.clear() def get_calenderDomain(self, field_name=None, old_date='', mode='month'): args = [] old_date = old_date.date() if not old_date: old_date = datetime.today().date() if mode == 'month': start_date = (old_date + relativedelta(months=-1)).strftime('%Y-%m-%d') args.append((field_name, '>', start_date)) end_date = (old_date + relativedelta(months=1)).strftime('%Y-%m-%d') args.append((field_name, '<', end_date)) if mode == 'week': start_date = (old_date + relativedelta(weeks=-1)).strftime('%Y-%m-%d') args.append((field_name, '>', start_date)) end_date = (old_date + relativedelta(weeks=1)).strftime('%Y-%m-%d') args.append((field_name, '<', end_date)) if mode == 'day': start_date = (old_date + relativedelta(days=-1)).strftime('%Y-%m-%d') args.append((field_name, '>', start_date)) end_date = (old_date + relativedelta(days=1)).strftime('%Y-%m-%d') args.append((field_name, '<', end_date)) return args def search_filter(self, *args): if not self.auto_search: self.auto_search = True return val = self.filter_widget and self.filter_widget.value or {} if self.current_view.view_type == 'graph' and self.current_view.view.key: self.domain = self.domain_init[:] self.domain += val.get('domain', []) + self.sort_domain else: self.context_update(val.get('context', {}), val.get('domain', []) + self.sort_domain) v = self.domain if self.win_search: v += self.win_search_domain limit = self.screen_container.get_limit() if self.current_view.view_type == 'calendar': field_name = self.current_view.view.date_start old_date = self.current_view.view.date mode = self.current_view.view.mode calendar_domain = self.get_calenderDomain(field_name, old_date, mode) v += calendar_domain filter_keys = [] for ele in self.domain: if isinstance(ele, tuple): filter_keys.append(ele[0]) if self.latest_search != v: self.offset = 0 offset = self.offset self.latest_search = v if (self.context.get('group_by') or \ self.context.get('group_by_no_leaf')) \ and not self.current_view.view_type == 'graph': self.current_view.reload = True self.display() return True ids = rpc.session.rpc_exec_auth('/object', 'execute', self.name, 'search', v, offset, limit, self.sort, self.context) self.win_search_ids = ids if self.win_search and self.win_search_domain: for dom in self.win_search_domain: if dom in v: v.remove(dom) self.win_search_domain = [] if len(ids) < limit: self.search_count = len(ids) else: self.search_count = rpc.session.rpc_exec_auth_try( '/object', 'execute', self.name, 'search_count', v, self.context) self.update_scroll() self.clear() if self.sort_domain in v: v.remove(self.sort_domain) self.sort_domain = [] self.load(ids) return True def add_custom(self, dynamic_button): fields_list = [] for k, v in self.search_view['fields'].items(): if v['type'] in ('many2one', 'text', 'char', 'float', 'integer', 'date', 'datetime', 'selection', 'many2many', 'boolean', 'one2many') and v.get( 'selectable', False): selection = v.get('selection', False) fields_list.append([k, v['string'], v['type'], selection]) if fields_list: fields_list.sort(lambda x, y: cmp(x[1], y[1])) panel = self.filter_widget.add_custom(self.filter_widget, self.filter_widget.widget, fields_list) self.custom_panels.append(panel) if len(self.custom_panels) > 1: self.custom_panels[-1].condition_next.hide() self.custom_panels[-2].condition_next.show() def execute_action(self, combo): flag = combo.get_active_text() combo_model = combo.get_model() active_id = combo.get_active() action_name = active_id != -1 and flag not in [ 'mf', 'blk', 'sf' ] and combo_model[active_id][2] # 'mf' Section manages Filters def clear_domain_ctx(): for key in self.old_ctx.keys(): if key in self.context_init: del self.context_init[key] for domain in self.latest_search: if domain in self.domain_init: self.domain_init.remove(domain) #append action domain to filter domain self.domain_init += self.action_domain if flag == 'mf': obj = service.LocalService('action.main') act = { 'name': 'Manage Filters', 'res_model': 'ir.filters', 'type': 'ir.actions.act_window', 'view_type': 'form', 'view_mode': 'tree,form', 'domain': '[(\'model_id\',\'=\',\'' + self.name + '\'),(\'user_id\',\'=\',' + str(rpc.session.uid) + ')]' } ctx = self.context.copy() for key in ('group_by', 'group_by_no_leaf'): if key in ctx: del ctx[key] value = obj._exec_action(act, {}, ctx) if flag in ['blk', 'mf']: self.screen_container.last_active_filter = False clear_domain_ctx() if flag == 'blk': self.search_filter() combo.set_active(0) return True #This section handles shortcut and action creation elif flag in ['sf']: glade2 = glade.XML(common.terp_path("openerp.glade"), 'dia_get_action', gettext.textdomain()) widget = glade2.get_widget('action_name') win = glade2.get_widget('dia_get_action') win.set_icon(common.OPENERP_ICON) lbl = glade2.get_widget('label157') win.set_size_request(300, 165) text_entry = glade2.get_widget('action_name') lbl.set_text('Filter Name:') table = glade2.get_widget('table8') info_lbl = gtk.Label( _('(Any existing filter with the \nsame name will be replaced)' )) table.attach(info_lbl, 1, 2, 2, 3, gtk.FILL, gtk.EXPAND) if self.screen_container.last_active_filter: text_entry.set_text(self.screen_container.last_active_filter) win.show_all() response = win.run() # grab a safe copy of the entered text before destroy() to avoid GTK bug https://bugzilla.gnome.org/show_bug.cgi?id=613241 action_name = widget.get_text() win.destroy() combo.set_active(0) if response == gtk.RESPONSE_OK and action_name: filter_domain = self.filter_widget and self.filter_widget.value.get( 'domain', []) filter_context = self.filter_widget and self.filter_widget.value.get( 'context', {}) values = { 'name': action_name, 'model_id': self.name, 'user_id': rpc.session.uid } if flag == 'sf': domain, context = self.screen_container.get_filter( action_name) for dom in eval(domain): if dom not in filter_domain: filter_domain.append(dom) groupby_list = eval(context).get( 'group_by', []) + filter_context.get('group_by', []) filter_context.update(eval(context)) if groupby_list: filter_context.update({'group_by': groupby_list}) values.update({ 'domain': str(filter_domain), 'context': str(filter_context), }) action_id = rpc.session.rpc_exec_auth( '/object', 'execute', 'ir.filters', 'create_or_replace', values, self.context) self.screen_container.fill_filter_combo( self.name, action_name) else: try: self.screen_container.last_active_filter = action_name filter_domain = flag and tools.expr_eval(flag) clear_domain_ctx() if combo.get_active() >= 0: combo_model = combo.get_model() val = combo_model[combo.get_active()][1] if val: self.old_ctx = eval(val) self.context_init.update(self.old_ctx) self.domain_init += filter_domain or [] if isinstance(self.domain_init, type([])): self.search_filter() self.reload() except Exception: return True def models_set(self, models): import time c = time.time() if self.models: self.models.signal_unconnect(self.models) self.models = models self.parent = models.parent if len(models.models): self.current_model = models.models[0] else: self.current_model = None self.models.signal_connect(self, 'record-cleared', self._record_cleared) self.models.signal_connect(self, 'record-changed', self._record_changed) self.models.signal_connect(self, 'model-changed', self._model_changed) models.add_fields(self.fields, models) self.fields.update(models.fields) models.is_wizard = self.is_wizard def _record_cleared(self, model_group, signal, *args): for view in self.views: view.reload = True def _record_changed(self, model_group, signal, *args): try: for view in self.views: view.signal_record_changed(signal[0], model_group.models, signal[1], *args) except: pass def _model_changed(self, model_group, model): if (not model) or (model==self.current_model) and self.current_view \ and self.current_view.view_type != 'calendar': self.display() def _get_current_model(self): return self.__current_model # # Check more or less fields than in the screen ! # def _set_current_model(self, value): self.__current_model = value try: offset = int(self.offset) except: offset = 0 try: pos = self.models.models.index(value) except: pos = -1 self.signal('record-message', (pos + offset, len(self.models.models or []) + offset, self.search_count, value and value.id)) return True current_model = property(_get_current_model, _set_current_model) def destroy(self): for view in self.views: view.destroy() if hasattr(self, 'filter_widget') and self.filter_widget: self.filter_widget.destroy() del self.filter_widget self.widget.destroy() self.models.signal_unconnect(self) self.models.destroy() del self.models del self.widget del self.views del self.fields del self.view_fields del self.search_view del self._Screen__current_model del self._Screen__current_view del self.action_domain del self.auto_search del self.create_new del self.dummy_cal del self.help_mode del self.is_wizard del self.latest_search del self.offset del self.old_ctx del self.row_activate del self.screen_container del self.search_count del self.show_search del self.tree_saves del self.type del self.view_ids del self.view_to_load del self.views_preload del self.win_search del self.win_search_callback del self.window # mode: False = next view, value = open this view def switch_view(self, screen=None, mode=False): if isinstance(self.current_model, group_record) and mode != 'graph': return if mode == 'calendar' and self.dummy_cal: mode = 'dummycalendar' self.current_view.set_value() self.fields = {} if self.current_model and self.current_model not in self.models.models: self.current_model = None if mode: ok = False for vid in range(len(self.views)): if self.views[vid].view_type == mode: self.__current_view = vid ok = True break if len(self.view_to_load) and mode in self.view_to_load: self.load_view_to_load(mode=mode) for vid in range(len(self.views)): if self.views[vid].view_type == mode: self.__current_view = vid ok = True break if not ok: self.__current_view = len(self.views) - 1 else: if len(self.view_to_load): self.load_view_to_load() self.__current_view = len(self.views) - 1 else: self.__current_view = (self.__current_view + 1) % len( self.views) self.fields = self.view_fields.get(self.__current_view, self.fields) # Switch the fields # TODO: maybe add_fields_custom is needed instead of add_fields on some cases self.models.add_fields(self.fields, self.models) # Switch the model fields too widget = self.current_view.widget self.screen_container.set(self.current_view.widget) if self.current_model: self.current_model.validate_set() elif self.current_view.view_type == 'form': self.new() self.display() self.current_view.set_cursor() main = service.LocalService('gui.main') if main: main.sb_set() # TODO: set True or False accoring to the type def load_view_to_load(self, mode=False): if len(self.view_to_load): if mode: idx = self.view_to_load.index(mode) view_id = self.view_ids and self.view_ids.pop(idx) or False else: idx = 0 view_id = False type = self.view_to_load.pop(idx) self.add_view_id(view_id, type) def add_view_custom(self, arch, fields, display=False, toolbar={}, submenu={}): return self.add_view(arch, fields, display, True, toolbar=toolbar, submenu=submenu) def add_view_id(self, view_id, view_type, display=False, help={}, context=None): if context is None: context = {} if view_type in self.views_preload: return self.add_view( self.views_preload[view_type]['arch'], self.views_preload[view_type]['fields'], display, toolbar=self.views_preload[view_type].get('toolbar', False), submenu=self.views_preload[view_type].get('submenu', False), help=help, context=context) else: view = self.rpc.fields_view_get(view_id, view_type, self.context, self.hastoolbar, self.hassubmenu) context.update({'view_type': view_type}) return self.add_view(view['arch'], view['fields'], display, help=help, toolbar=view.get('toolbar', False), submenu=view.get('submenu', False), context=context) def add_view(self, arch, fields, display=False, custom=False, toolbar=None, submenu=None, help={}, context=None): if toolbar is None: toolbar = {} if submenu is None: submenu = {} def _parse_fields(node, fields): if node.tag == 'field': attrs = tools.node_attributes(node) if attrs.get('widget', False): 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) root_node = etree.XML(arch) _parse_fields(root_node, fields) from widget.view.widget_parse import widget_parse models = self.models.models if self.current_model and (self.current_model not in models): models = models + [self.current_model] if context and context.get('view_type', '') == 'diagram': fields = {} if custom: self.models.add_fields_custom(fields, self.models) else: 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: self.views.append(view) if display: self.__current_view = len(self.views) - 1 self.current_view.display() self.screen_container.set(view.widget) # Store the fields for this view (we will use them when switching views) self.view_fields[len(self.views) - 1] = copy.deepcopy(self.fields) return view def editable_get(self): if hasattr(self.current_view, 'widget_tree'): return self.current_view.widget_tree.editable else: return False def new(self, default=True, context={}): if self.current_view and self.current_view.view_type == 'tree' \ and not self.current_view.widget_tree.editable: self.switch_view(mode='form') ctx = self.context.copy() ctx.update(context) model = self.models.model_new(default, self.action_domain, ctx) if (not self.current_view ) or self.current_view.model_add_new or self.create_new: self.models.model_add(model, self.new_model_position()) self.current_model = model self.current_model.validate_set() self.display() if self.current_view: self.current_view.set_cursor(new=True) return self.current_model def new_model_position(self): position = -1 if self.current_view and self.current_view.view_type =='tree' \ and self.current_view.widget_tree.editable == 'top': position = 0 return position def set_on_write(self, func_name): self.models.on_write = func_name def cancel_current(self): if self.current_model: self.current_model.cancel() if self.current_view: self.current_view.cancel() self.current_view.reset() def save_current(self): if not self.current_model: return False self.current_view.set_value() id = False if self.current_model.validate(): id = self.current_model.save(reload=True) self.models.writen(id) if not id: self.current_view.display() else: self.current_view.display() self.current_view.set_cursor() return False if self.current_view.view_type == 'tree': for model in self.models.models: if model.is_modified(): if model.validate(): id = model.save(reload=True) self.models.writen(id) else: self.current_model = model self.display() self.current_view.set_cursor() return False self.display() self.current_view.set_cursor() if self.current_model not in self.models: self.models.model_add(self.current_model) return id def _getCurrentView(self): if not len(self.views): return None return self.views[self.__current_view] current_view = property(_getCurrentView) def get(self): if not self.current_model: return None self.current_view.set_value() return self.current_model.get() def is_modified(self): if not self.current_model: return False self.current_view.set_value() if self.current_view.view_type != 'tree': return self.current_model.is_modified() else: for model in self.models.models: if model.is_modified(): return True return False def reload(self): self.current_model.reload() if self.parent: self.parent.reload() self.display() def remove(self, unlink=False): id = False if self.current_view.view_type == 'form' and self.current_model: id = self.current_model.id idx = self.models.models.index(self.current_model) if not id: self.models.models.remove(self.models.models[idx]) self.current_model = None if self.models.models: idx = min(idx, len(self.models.models) - 1) self.current_model = self.models.models[idx] self.display() self.current_view.set_cursor() return False ctx = self.current_model.context_get().copy() self.current_model.update_context_with_concurrency(ctx) if unlink and id: if not self.rpc.unlink([id], ctx): return False self.models.remove(self.current_model) if self.models.models: idx = min(idx, len(self.models.models) - 1) self.current_model = self.models.models[idx] else: self.current_model = None self.display() self.current_view.set_cursor() if self.current_view.view_type == 'tree': ids = self.current_view.sel_ids_get() ctx = self.models.context.copy() for m in self.models: if m.id in ids: m.update_context_with_concurrency(ctx) if unlink and ids: if not self.rpc.unlink(ids, ctx): return False for model in self.current_view.sel_models_get(): self.models.remove(model) self.current_model = None self.display() self.current_view.set_cursor() id = ids return id def load(self, ids): limit = self.screen_container.get_limit() self.models.load(ids, display=False, context=self.context) self.current_view.reset() if ids: self.display(ids[0]) else: self.current_model = None self.display() def display(self, res_id=None): if res_id: self.current_model = self.models[res_id] if self.views: self.current_view.display() self.current_view.widget.set_sensitive( bool(self.models.models or (self.current_view.view_type != 'form') or self.current_model)) vt = self.current_view.view_type if self.screen_container.help_frame: if vt != self.help_mode: self.screen_container.help_frame.hide_all() else: self.screen_container.help_frame.show_all() self.search_active( active=self.show_search and vt in ('tree', 'graph'), show_search=self.show_search and vt in ('tree', 'graph'), ) def groupby_next(self): if not self.models.models: self.current_model = self.models.list_group.lst[0] elif self.current_view.store.on_iter_has_child(self.current_model): path = self.current_view.store.on_get_path(self.current_model) if path == (0, ): self.current_view.expand_row(path) self.current_model = self.current_view.store.on_iter_children( self.current_model) else: if self.current_model in self.current_model.list_group.lst: idx = self.current_model.list_group.lst.index( self.current_model) if idx + 1 >= len(self.current_model.list_group.lst): parent = True while parent: parent = self.current_view.store.on_iter_parent( self.current_model) if parent: self.current_model = parent if self.current_view.store.on_iter_next(parent): break self.current_model = self.current_view.store.on_iter_next( self.current_model) if self.current_model == None: self.current_model = self.current_view.store.on_get_iter \ (self.current_view.store.on_get_path \ (self.current_view.store.get_iter_first())) else: idx = (idx + 1) % len(self.current_model.list_group.lst) self.current_model = self.current_model.list_group.lst[idx] if self.current_model: path = self.current_view.store.on_get_path(self.current_model) self.current_view.expand_row(path) return def groupby_prev(self): if not self.models.models: self.current_model = self.models.list_group.lst[-1] else: if self.current_model in self.current_model.list_group.lst: idx = self.current_model.list_group.lst.index( self.current_model) - 1 if idx < 0: parent = self.current_view.store.on_iter_parent( self.current_model) if parent: self.current_model = parent else: idx = (idx) % len(self.current_model.list_group.lst) self.current_model = self.current_model.list_group.lst[idx] if self.current_model: path = self.current_view.store.on_get_path(self.current_model) self.current_view.collapse_row(path) return def display_next(self): self.current_view.set_value() if self.context.get('group_by') and \ not self.current_view.view_type == 'form': if self.current_model: self.groupby_next() else: if self.current_model in self.models.models: idx = self.models.models.index(self.current_model) idx = (idx + 1) % len(self.models.models) self.current_model = self.models.models[idx] else: self.current_model = len( self.models.models) and self.models.models[0] self.check_state() self.current_view.set_cursor() def display_prev(self): self.current_view.set_value() if self.context.get('group_by') and \ not self.current_view.view_type == 'form': if self.current_model: self.groupby_prev() else: if self.current_model in self.models.models: idx = self.models.models.index(self.current_model) - 1 if idx < 0: idx = len(self.models.models) - 1 self.current_model = self.models.models[idx] else: self.current_model = len( self.models.models) and self.models.models[-1] self.check_state() self.current_view.set_cursor() def check_state(self): if not self.type == 'one2many' \ and (not self.context.get('group_by') \ or self.current_view.view_type == 'form'): if self.current_model: self.current_model.validate_set() self.display() if self.type == 'one2many': self.display() def sel_ids_get(self): return self.current_view.sel_ids_get() def id_get(self): if not self.current_model: return False return self.current_model.id def ids_get(self): return [x.id for x in self.models if x.id] def clear(self): self.models.clear() def on_change(self, callback): self.current_model.on_change(callback) self.display() def make_buttons_readonly(self, value=False): # This method has been created because # Some times if the user executes an action on an unsaved record in a dialog box # the record gets saved in the dialog's Group before going to the particular widgets group # and as a result it crashes. So we just set the buttons visible on the # dialog box screen to non-sensitive if the model is not saved. def process(widget, val): for wid in widget: if hasattr(wid, 'get_children'): process(wid, val=value) if isinstance(wid, gtk.Button) and \ not isinstance(wid.parent, (gtk.HBox,gtk.VBox)): wid.set_sensitive(val) if value and not self.current_model.id: return True process(self.widget, value)
class Screen(signal_event.signal_event): def __init__(self, model_name, view_ids=None, view_type=None, parent=None, context=None, views_preload=None, tree_saves=True, domain=None, create_new=False, row_activate=None, hastoolbar=False, default_get=None, show_search=False, window=None, limit=80, readonly=False, is_wizard=False): if view_ids is None: view_ids = [] if view_type is None: view_type = ['tree', 'form'] if context is None: context = {} if views_preload is None: views_preload = {} if domain is None: domain = [] if default_get is None: default_get = {} super(Screen, self).__init__() self.show_search = show_search self.search_count = 0 self.hastoolbar = hastoolbar self.default_get = default_get if not row_activate: self.row_activate = lambda self, screen=None: self.switch_view( screen, 'form') else: self.row_activate = row_activate self.create_new = create_new self.name = model_name self.domain = domain self.latest_search = [] self.views_preload = views_preload self.resource = model_name self.rpc = RPCProxy(model_name) self.context = context self.context.update(rpc.session.context) self.views = [] self.fields = {} self.view_ids = view_ids self.models = None self.parent = parent self.window = window self.is_wizard = is_wizard models = ModelRecordGroup(model_name, self.fields, parent=self.parent, context=self.context, is_wizard=is_wizard) self.models_set(models) self.current_model = None self.screen_container = screen_container() self.filter_widget = None self.widget = self.screen_container.widget_get() self.__current_view = 0 self.tree_saves = tree_saves self.limit = limit self.readonly = readonly self.view_fields = { } # Used to switch self.fields when the view switchs if view_type: self.view_to_load = view_type[1:] view_id = False if view_ids: view_id = view_ids.pop(0) view = self.add_view_id(view_id, view_type[0]) self.screen_container.set(view.widget) self.display() def readonly_get(self): return self._readonly def readonly_set(self, value): self._readonly = value self.models._readonly = value readonly = property(readonly_get, readonly_set) def search_active(self, active=True, show_search=True): if active: if not self.filter_widget: view_form = rpc.session.rpc_exec_auth('/object', 'execute', self.name, 'fields_view_get', False, 'form', self.context) view_tree = rpc.session.rpc_exec_auth('/object', 'execute', self.name, 'fields_view_get', False, 'tree', self.context) dom = xml.dom.minidom.parseString(view_tree['arch']) child_node = dom.childNodes[0].childNodes arch = '' for i in range(1, len(child_node)): arch += child_node[i].toxml() #Generic case when we need to remove the last occurance of </form> from form view view_form['arch'] = view_form['arch'][0:view_form['arch']. rfind('</form>')] #Special case when form is replaced,we need to remove </form> find_form = view_form['arch'].rfind('</form>') if find_form > 0: view_form['arch'] = view_form['arch'][0:find_form] view_form['arch'] = view_form['arch'] + arch + '\n</form>' view_form['fields'].update(view_tree['fields']) self.filter_widget = widget_search.form( view_form['arch'], view_form['fields'], self.name, self.window, self.domain, (self, self.search_filter)) self.screen_container.add_filter(self.filter_widget.widget, self.search_filter, self.search_clear, self.search_offset_next, self.search_offset_previous) self.filter_widget.set_limit(self.limit) if active and show_search: self.screen_container.show_filter() else: self.screen_container.hide_filter() def update_scroll(self, *args): offset = self.filter_widget.get_offset() limit = self.filter_widget.get_limit() if offset <= 0: self.screen_container.but_previous.set_sensitive(False) else: self.screen_container.but_previous.set_sensitive(True) if offset + limit >= self.search_count: self.screen_container.but_next.set_sensitive(False) else: self.screen_container.but_next.set_sensitive(True) def search_offset_next(self, *args): offset = self.filter_widget.get_offset() limit = self.filter_widget.get_limit() self.filter_widget.set_offset(offset + limit) self.search_filter() def search_offset_previous(self, *args): offset = self.filter_widget.get_offset() limit = self.filter_widget.get_limit() self.filter_widget.set_offset(max(offset - limit, 0)) self.search_filter() def search_clear(self, *args): self.filter_widget.clear() self.clear() def search_filter(self, *args): v = self.filter_widget.value filter_keys = [key for key, _, _ in v] for element in self.domain: if not isinstance(element, tuple): # Filtering '|' symbol v.append(element) else: (key, op, value) = element if key not in filter_keys and not (key == 'active' and self.context.get( 'active_test', False)): v.append((key, op, value)) # v.extend((key, op, value) for key, op, value in domain if key not in filter_keys and not (key=='active' and self.context.get('active_test', False))) if self.latest_search != v: self.filter_widget.set_offset(0) limit = self.filter_widget.get_limit() offset = self.filter_widget.get_offset() self.latest_search = v ids = rpc.session.rpc_exec_auth('/object', 'execute', self.name, 'search', v, offset, limit, 0, self.context) if len(ids) < limit: self.search_count = len(ids) else: self.search_count = rpc.session.rpc_exec_auth_try( '/object', 'execute', self.name, 'search_count', v, self.context) self.update_scroll() self.clear() self.load(ids) return True def models_set(self, models): import time c = time.time() if self.models: self.models.signal_unconnect(self.models) self.models = models self.parent = models.parent if len(models.models): self.current_model = models.models[0] else: self.current_model = None self.models.signal_connect(self, 'record-cleared', self._record_cleared) self.models.signal_connect(self, 'record-changed', self._record_changed) self.models.signal_connect(self, 'model-changed', self._model_changed) models.add_fields(self.fields, models) self.fields.update(models.fields) models.is_wizard = self.is_wizard def _record_cleared(self, model_group, signal, *args): for view in self.views: view.reload = True def _record_changed(self, model_group, signal, *args): try: for view in self.views: view.signal_record_changed(signal[0], model_group.models, signal[1], *args) except: pass def _model_changed(self, model_group, model): if (not model) or (model == self.current_model): self.display() def _get_current_model(self): return self.__current_model # # Check more or less fields than in the screen ! # def _set_current_model(self, value): self.__current_model = value try: offset = int(self.filter_widget.get_offset()) except: offset = 0 try: pos = self.models.models.index(value) except: pos = -1 self.signal('record-message', (pos + offset, len(self.models.models or []) + offset, self.search_count, value and value.id)) return True current_model = property(_get_current_model, _set_current_model) def destroy(self): for view in self.views: view.destroy() del view #del self.current_model self.models.signal_unconnect(self) del self.models del self.views # mode: False = next view, value = open this view def switch_view(self, screen=None, mode=False): self.current_view.set_value() self.fields = {} if self.current_model and self.current_model not in self.models.models: self.current_model = None if mode: ok = False for vid in range(len(self.views)): if self.views[vid].view_type == mode: self.__current_view = vid ok = True break while not ok and len(self.view_to_load): self.load_view_to_load() if self.current_view.view_type == mode: ok = True for vid in range(len(self.views)): if self.views[vid].view_type == mode: self.__current_view = vid ok = True break if not ok: self.__current_view = len(self.views) - 1 else: if len(self.view_to_load): self.load_view_to_load() self.__current_view = len(self.views) - 1 else: self.__current_view = (self.__current_view + 1) % len( self.views) self.fields = self.view_fields.get(self.__current_view, self.fields) # Switch the fields # TODO: maybe add_fields_custom is needed instead of add_fields on some cases self.models.add_fields(self.fields, self.models) # Switch the model fields too widget = self.current_view.widget self.screen_container.set(self.current_view.widget) if self.current_model: self.current_model.validate_set() elif self.current_view.view_type == 'form': self.new() self.display() self.current_view.set_cursor() main = service.LocalService('gui.main') if main: main.sb_set() # TODO: set True or False accoring to the type def load_view_to_load(self, mode=False): if len(self.view_to_load): if self.view_ids: view_id = self.view_ids.pop(0) view_type = self.view_to_load.pop(0) else: view_id = False view_type = self.view_to_load.pop(0) self.add_view_id(view_id, view_type) def add_view_custom(self, arch, fields, display=False, toolbar={}): return self.add_view(arch, fields, display, True, toolbar=toolbar) def add_view_id(self, view_id, view_type, display=False, context=None): if view_type in self.views_preload: return self.add_view(self.views_preload[view_type]['arch'], self.views_preload[view_type]['fields'], display, toolbar=self.views_preload[view_type].get( 'toolbar', False), context=context) else: view = self.rpc.fields_view_get(view_id, view_type, self.context, self.hastoolbar) return self.add_view(view['arch'], view['fields'], display, toolbar=view.get('toolbar', False), context=context) def add_view(self, arch, fields, display=False, custom=False, toolbar=None, context=None): if toolbar is None: toolbar = {} def _parse_fields(node, fields): if node.nodeType == node.ELEMENT_NODE: if node.localName == 'field': attrs = tools.node_attributes(node) if attrs.get('widget', False): if attrs['widget'] == 'one2many_list': attrs['widget'] = 'one2many' attrs['type'] = attrs['widget'] fields[unicode(attrs['name'])].update(attrs) for node2 in node.childNodes: _parse_fields(node2, fields) dom = xml.dom.minidom.parseString(arch) _parse_fields(dom, fields) for dom in self.domain: if dom[0] in fields: field_dom = str(fields[dom[0]].setdefault('domain', [])) fields[dom[0]]['domain'] = field_dom[:1] + \ str(('id', dom[1], dom[2])) + ',' + field_dom[1:] from widget.view.widget_parse import widget_parse models = self.models.models if self.current_model and (self.current_model not in models): models = models + [self.current_model] if custom: self.models.add_fields_custom(fields, self.models) else: self.models.add_fields(fields, self.models, context=context) self.fields = self.models.fields parser = widget_parse(parent=self.parent, window=self.window) dom = xml.dom.minidom.parseString(arch) view = parser.parse(self, dom, self.fields, toolbar=toolbar) if view: self.views.append(view) if display: self.__current_view = len(self.views) - 1 self.current_view.display() self.screen_container.set(view.widget) # Store the fields for this view (we will use them when switching views) self.view_fields[len(self.views) - 1] = copy.deepcopy(self.fields) return view def editable_get(self): if hasattr(self.current_view, 'widget_tree'): return self.current_view.widget_tree.editable else: return False def new(self, default=True, context={}): if self.current_view and self.current_view.view_type == 'tree' \ and not self.current_view.widget_tree.editable: self.switch_view(mode='form') ctx = self.context.copy() ctx.update(context) model = self.models.model_new(default, self.domain, ctx) if (not self.current_view ) or self.current_view.model_add_new or self.create_new: self.models.model_add(model, self.new_model_position()) self.current_model = model self.current_model.validate_set() self.display() if self.current_view: self.current_view.set_cursor(new=True) return self.current_model def new_model_position(self): position = -1 if self.current_view and self.current_view.view_type =='tree' \ and self.current_view.widget_tree.editable == 'top': position = 0 return position def set_on_write(self, func_name): self.models.on_write = func_name def cancel_current(self): if self.current_model: self.current_model.cancel() if self.current_view: self.current_view.cancel() def save_current(self): if not self.current_model: return False self.current_view.set_value() id = False if self.current_model.validate(): id = self.current_model.save(reload=True) self.models.writen(id) if not id: self.current_view.display() else: self.current_view.display() self.current_view.set_cursor() return False if self.current_view.view_type == 'tree': for model in self.models.models: if model.is_modified(): if model.validate(): id = model.save(reload=True) self.models.writen(id) else: self.current_model = model self.display() self.current_view.set_cursor() return False self.display() self.current_view.set_cursor() if self.current_model not in self.models: self.models.model_add(self.current_model) return id def _getCurrentView(self): if not len(self.views): return None return self.views[self.__current_view] current_view = property(_getCurrentView) def get(self): if not self.current_model: return None self.current_view.set_value() return self.current_model.get() def is_modified(self): if not self.current_model: return False self.current_view.set_value() if self.current_view.view_type != 'tree': return self.current_model.is_modified() else: for model in self.models.models: if model.is_modified(): return True return False def reload(self): self.current_model.reload() if self.parent: self.parent.reload() self.display() def remove(self, unlink=False): id = False if self.current_view.view_type == 'form' and self.current_model: id = self.current_model.id idx = self.models.models.index(self.current_model) if not id: lst = [] self.models.models.remove(self.models.models[idx]) self.current_model = None if self.models.models: idx = min(idx, len(self.models.models) - 1) self.current_model = self.models.models[idx] self.display() self.current_view.set_cursor() return False ctx = self.current_model.context_get().copy() self.current_model.update_context_with_concurrency_check_data(ctx) if unlink and id: if not self.rpc.unlink([id], ctx): return False self.models.remove(self.current_model) if self.models.models: idx = min(idx, len(self.models.models) - 1) self.current_model = self.models.models[idx] else: self.current_model = None self.display() self.current_view.set_cursor() if self.current_view.view_type == 'tree': ids = self.current_view.sel_ids_get() ctx = self.models.context.copy() for m in self.models: if m.id in ids: m.update_context_with_concurrency_check_data(ctx) if unlink and ids: if not self.rpc.unlink(ids, ctx): return False for model in self.current_view.sel_models_get(): self.models.remove(model) self.current_model = None self.display() self.current_view.set_cursor() id = ids return id def load(self, ids): if not isinstance(ids, list): ids = [ids] self.models.load(ids, display=False) self.current_view.reset() if ids: self.display(ids[0]) else: self.current_model = None self.display() def display(self, res_id=None): if res_id: self.current_model = self.models[res_id] if self.views: self.current_view.display() self.current_view.widget.set_sensitive( bool(self.models.models or (self.current_view.view_type != 'form') or self.current_model)) vt = self.current_view.view_type self.search_active( active=self.show_search and vt in ('tree', 'graph', 'calendar'), show_search=self.show_search and vt in ('tree', 'graph'), ) def display_next(self): self.current_view.set_value() if self.current_model in self.models.models: idx = self.models.models.index(self.current_model) idx = (idx + 1) % len(self.models.models) self.current_model = self.models.models[idx] else: self.current_model = len( self.models.models) and self.models.models[0] if self.current_model: self.current_model.validate_set() self.display() self.current_view.set_cursor() def display_prev(self): self.current_view.set_value() if self.current_model in self.models.models: idx = self.models.models.index(self.current_model) - 1 if idx < 0: idx = len(self.models.models) - 1 self.current_model = self.models.models[idx] else: self.current_model = len( self.models.models) and self.models.models[-1] if self.current_model: self.current_model.validate_set() self.display() self.current_view.set_cursor() def sel_ids_get(self): return self.current_view.sel_ids_get() def id_get(self): if not self.current_model: return False return self.current_model.id def ids_get(self): return [x.id for x in self.models if x.id] def clear(self): self.models.clear() def on_change(self, callback): self.current_model.on_change(callback) self.display()