Pergunta

Is there a way to change how selection field looks? I need to change it to look like a bunch of boolean fields (technically it would be one field, not multiple boolean fields. Only look would change)?

It should look something like this (it looks like there are multiple fields, but technically it should be only one):

enter image description here

And it should function like selection field - that you can only select one value. Is it possible to do it?

Update: Found this - http://help.openerp.com/question/29061/how-to-add-radio-button-widget/

It seems it is possible to do with widget on OpenERP 8 (using radio widget for selection field). So I think it might be possible to move such functionality in OpenERP 7.

Foi útil?

Solução

I managed to move radio widget from OpenERP 8 to OpenERP 7. So I will post it how I've done. Maybe some one will need it too.

Basically you only need two main files, one js and one xml (also empty __init__.py is needed, because OpenERP will throw error that it didn't find that module).

in __openerp__.py:

 'js': ['static/src/js/widget_radio.js'],
'qweb': ['static/src/xml/widget_radio.xml'],

widget_radio.js (web_widget_radio is addon name):

openerp.web_widget_radio = function (instance)
{
    instance.web.form.widgets.add('radio', 'instance.web_widget_radio.FieldRadio');
    instance.web_widget_radio.FieldRadio = instance.web.form.AbstractField.extend(instance.web.form.ReinitializeFieldMixin, {
        template: 'FieldRadio',
        events: {
            'click input': 'click_change_value'
        },
        init: function(field_manager, node) {
            /* Radio button widget: Attributes options:
            * - "horizontal" to display in column
            * - "no_radiolabel" don't display text values
            */
            this._super(field_manager, node);
            this.selection = _.clone(this.field.selection) || [];
            this.domain = false;
        },
        initialize_content: function () {
            this.uniqueId = _.uniqueId("radio");
            this.on("change:effective_readonly", this, this.render_value);
            this.field_manager.on("view_content_has_changed", this, this.get_selection);
            this.get_selection();
        },
        click_change_value: function (event) {
            var val = $(event.target).val();
            val = this.field.type == "selection" ? val : +val;
            if (val == this.get_value()) {
                this.set_value(false);
            } else {
                this.set_value(val);
            }
        },
        /** Get the selection and render it
         *  selection: [[identifier, value_to_display], ...]
         *  For selection fields: this is directly given by this.field.selection
         *  For many2one fields:  perform a search on the relation of the many2one field
         */
        get_selection: function() {
            var self = this;
            var selection = [];
            var def = $.Deferred();
            if (self.field.type == "many2one") {
                var domain = instance.web.pyeval.eval('domain', this.build_domain()) || [];
                if (! _.isEqual(self.domain, domain)) {
                    self.domain = domain;
                    var ds = new instance.web.DataSetStatic(self, self.field.relation, self.build_context());
                    ds.call('search', [self.domain])
                        .then(function (records) {
                            ds.name_get(records).then(function (records) {
                                selection = records;
                                def.resolve();
                            });
                        });
                } else {
                    selection = self.selection;
                    def.resolve();
                }
            }
            else if (self.field.type == "selection") {
                selection = self.field.selection || [];
                def.resolve();
            }
            return def.then(function () {
                if (! _.isEqual(selection, self.selection)) {
                    self.selection = _.clone(selection);
                    self.renderElement();
                    self.render_value();
                }
            });
        },
        set_value: function (value_) {
            if (value_) {
                if (this.field.type == "selection") {
                    value_ = _.find(this.field.selection, function (sel) { return sel[0] == value_;});
                }
                else if (!this.selection.length) {
                    this.selection = [value_];
                }
            }
            this._super(value_);
        },
        get_value: function () {
            var value = this.get('value');
            return value instanceof Array ? value[0] : value;
        },
        render_value: function () {
            var self = this;
            this.$el.toggleClass("oe_readonly", this.get('effective_readonly'));
            this.$("input:checked").prop("checked", false);
            if (this.get_value()) {
                this.$("input").filter(function () {return this.value == self.get_value();}).prop("checked", true);
                this.$(".oe_radio_readonly").text(this.get('value') ? this.get('value')[1] : "");
            }
        }
    });
};

widget_radio.xml:

<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
    <t t-name="FieldRadio">
        <span t-attf-class="oe_form_field oe_form_field_radio #{widget.options.horizontal ? 'oe_horizontal' : 'oe_vertical'}" t-att-style="widget.node.attrs.style">
            <span t-if="!widget.get('effective_readonly')">
                <t t-if="widget.options.horizontal">
                    <t t-set="width" t-value="Math.floor(100 / widget.selection.length)"/>
                    <t t-if="!widget.options.no_radiolabel">
                        <t t-foreach="widget.selection" t-as="selection">
                            <label t-att-for="widget.uniqueId + '_' + selection[0]" t-att-style="'width: ' + width + '%;'"><t t-esc="selection[1]"/></label>
                        </t>
                        <br/>
                    </t>
                    <t t-foreach="widget.selection" t-as="selection">
                        <div t-att-style="'width: ' + width + '%;'">
                            <span class="oe_radio_input"><input type="radio" t-att-name="widget.uniqueId" t-att-id="widget.uniqueId + '_' + selection[0]" t-att-value="selection[0]"/></span>
                        </div>
                    </t>
                </t>
                <t t-if="!widget.options.horizontal">
                    <t t-foreach="widget.selection" t-as="selection">
                        <div>
                            <span class="oe_radio_input"><input type="radio" t-att-id="widget.uniqueId + '_' + selection[0]" t-att-name="widget.uniqueId" t-att-value="selection[0]"/></span><label t-if="!widget.options.no_radiolabel" t-att-for="widget.uniqueId + '_' + selection[0]"><t t-esc="selection[1]"/></label>
                        </div>
                    </t>
                </t>
            </span>
            <span t-if="widget.get('effective_readonly')" class="oe_radio_readonly"><t t-esc="widget.get('value')[1]"/></span>
        </span>
    </t>
</templates> 

P.S. You can find original code in OpenERP trunk version.

Outras dicas

Yes. its possible. You can see a similar example in openerp itself. Go to settings / users /access rights tab. There you can see all the list of boolean and selection fields for adding the groups. Actually it is a many2many field related to res.groups and its view is modified in such a way that all the groups that are inherited and under the same category will be viewed as a selection list and all others will be in boolean. Please check the code in the base/ res/res_users.py file. Hope it will be helpful for you.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top