Beispiel #1
0
    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
Beispiel #2
0
 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)
Beispiel #3
0
    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)
Beispiel #4
0
 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)
Beispiel #5
0
 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)
Beispiel #7
0
 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)
Beispiel #8
0
 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, 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)
Beispiel #10
0
 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)
Beispiel #12
0
 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)
Beispiel #13
0
    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
Beispiel #14
0
    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
Beispiel #15
0
 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
Beispiel #16
0
    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
Beispiel #17
0
    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
Beispiel #18
0
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()
Beispiel #19
0
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()
Beispiel #20
0
    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
Beispiel #21
0
 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 []
Beispiel #22
0
    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]
Beispiel #23
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)
Beispiel #24
0
    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)
Beispiel #26
0
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
Beispiel #28
0
 def __init__(self, cmdname, options):
     self.proxy = RPCProxy()
     self.cmdname = cmdname
     self.options = options
Beispiel #29
0
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)
Beispiel #30
0
    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()
Beispiel #31
0
    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()
Beispiel #32
0
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()
Beispiel #33
0
    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()
Beispiel #34
0
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
Beispiel #35
0
 def __init__(self, cmdname, options):
     self.proxy = RPCProxy()
     self.cmdname = cmdname
     self.options = options
Beispiel #36
0
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)
Beispiel #37
0
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
Beispiel #38
0
    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()
Beispiel #39
0
 def __init__(self, object, relation, screen):
     self.object = object
     self.rpc = RPCProxy(relation)
     self.screen = screen
     self.domain = []
     self.type = screen.type
Beispiel #40
0
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
Beispiel #41
0
    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')
Beispiel #42
0
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)
Beispiel #43
0
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()