com.visural.wicket.component.viewmode.ViewOrEdit.java Source code

Java tutorial

Introduction

Here is the source code for com.visural.wicket.component.viewmode.ViewOrEdit.java

Source

/*
 *  Copyright 2009 Richard Nichols.
 * 
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 * 
 *       http://www.apache.org/licenses/LICENSE-2.0
 * 
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *  under the License.
 */
package com.visural.wicket.component.viewmode;

import com.visural.wicket.security.IPrivilege;
import com.visural.wicket.security.ISecureEnableInstance;
import com.visural.wicket.security.ISecureRenderInstance;
import org.apache.wicket.Component;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.AbstractChoice;
import org.apache.wicket.markup.html.form.CheckBox;
import org.apache.wicket.markup.html.form.FormComponent;
import org.apache.wicket.markup.html.form.FormComponentPanel;
import org.apache.wicket.markup.html.form.TextArea;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.markup.html.panel.Fragment;
import org.apache.wicket.model.AbstractReadOnlyModel;
import org.apache.wicket.model.IComponentInheritedModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.IWrapModel;
import org.apache.wicket.model.Model;

/**
 * A wrapper for a FormComponent which replaces the component with a Label
 * when the wrapped control is in "view mode".
 *
 * Apply to a containing DOM element, e.g. `<span></span>` or `<div></div>`
 * 
 * The component you provide to the constructor must be given as ID matching
 * `ViewOrEdit.COMP_ID`.
 *
 * The idea is to allow the rendering of web-like modern applications where
 * non-editable elements are represented in text form, using the same wicket
 * page / form implementation.
 *
 * What is "view mode" for a given component is determined by the method 
 * `isViewMode()`. The default implementation of this method uses the component
 * and its form's `isEnabled()` state to determine view or edit.
 * 
 * You may override this implementation and create any sort of complex logic you
 * wish for your specific use case.
 * 
 * The `ViewOrEdit` container automatically creates a dynamic wrapping model so
 * that you can still apply `CompoundPropertyModels` to your form and have them
 * apply to form elements wrapped in a `ViewOrEdit` container. Just name your
 * `ViewOrEdit` element as per the property you wish to apply to the child
 * control.
 *
 * @version $Id: ViewOrEdit.java 217 2010-09-30 23:57:10Z tibes80@gmail.com $
 * @author Richard Nichols
 */
public class ViewOrEdit extends FormComponentPanel implements ISecureRenderInstance, ISecureEnableInstance {
    private static final long serialVersionUID = 1L;
    /**
     * This is the id of the component to be contained within the ViewOrEdit container.
     * Any component provided to the ViewOrEdit component should be identified as ViewOrEdit.COMP_ID
     */
    public final static String COMP_ID = "component";

    private final FormComponent component;
    private Label label;

    public ViewOrEdit(String id, FormComponent component) {
        this(id, component, null, null);
    }

    public ViewOrEdit(String id, FormComponent component, IModel labelModel) {
        this(id, component, labelModel, null);
    }

    public ViewOrEdit(String id, FormComponent component, ComponentModelToLabel componentModelToLabel) {
        this(id, component, null, componentModelToLabel);
    }

    protected ViewOrEdit(final String id, final FormComponent component, IModel labelModel,
            final ComponentModelToLabel componentModelToLabel) {
        super(id);
        this.component = component;

        if (labelModel == null && componentModelToLabel != null) {
            labelModel = new AbstractReadOnlyModel() {

                private final ComponentModelToLabel converter = componentModelToLabel;

                @Override
                public Object getObject() {
                    return converter.convertToLabel(component.getModelObject());
                }
            };
        }

        if (component == null || !component.getId().equals(COMP_ID)) {
            throw new IllegalArgumentException(
                    "The component provided to LabelOnViewOnly(...) must have the id \"" + COMP_ID + "\"");
        }

        Fragment f = resolveComponentFragment(labelModel);
        if (f == null) {
            throw new UnsupportedOperationException(
                    "No view mode fragment for component of type " + component.getClass().getName());
        }
        add(f);
    }

    /**
     * Provide support for using CompountPropertyModel or similar on form
     * and having that property model chain to the form component being wrapped
     * in a ViewOrEdit.
     *
     * @return
     */
    @Override
    protected IModel<?> initModel() {
        final IModel parentModel = super.initModel();
        if (parentModel != null && parentModel instanceof IWrapModel) {
            // we want to set this model to wrap the form component
            return new WrappedParentModel((IWrapModel) parentModel);
        }
        // we do this in case there is no parent model to avoid
        // "Attempt to set model object on null model of component" errors
        return new Model();
    }

    @Override
    protected void convertInput() {
        // this forces a call to initModel()
        getDefaultModel();
    }

    /**
     * Determine whether the component is in view mode or not.
     *
     * By default, the implementation will assume view mode when this component
     * is not enabled or the form component is not enabled or the form itself
     * is not enabled, however this behaviour may be overriden as req'd.
     *
     * @return
     */
    public boolean isViewMode() {
        return !this.isEnabled() || !component.isEnabled() || !component.getForm().isEnabled();
    }

    @Override
    protected void onBeforeRender() {
        // this forces a call to initModel()
        getDefaultModel();
        // now proceed as normal
        super.onBeforeRender();
        boolean isView = this.isViewMode();
        label.setVisible(isView);
        component.setVisible(!isView);
    }

    private Fragment resolveComponentFragment(IModel labelModel) {
        if (labelModel == null) {
            // TODO: rather than doing this, maybe lookup converter?
            labelModel = new IModel() {

                public Object getObject() {
                    return (component.getModelObject() == null ? null : component.getModelObject().toString());
                }

                public void setObject(Object arg0) {
                }

                public void detach() {
                }
            };
        }
        label = new Label("viewLabel", labelModel);
        label.setEscapeModelStrings(isEscapeLabelModelStrings());
        if (TextField.class.isAssignableFrom(component.getClass())) {
            Fragment f = new Fragment("controlPair", "textfield", this);
            f.add(label);
            f.add(component);
            return f;
        }
        if (CheckBox.class.isAssignableFrom(component.getClass())) {
            Fragment f = new Fragment("controlPair", "checkbox", this);
            f.add(label);
            f.add(component);
            return f;
        }
        if (TextArea.class.isAssignableFrom(component.getClass())) {
            Fragment f = new Fragment("controlPair", "textarea", this);
            f.add(label);
            f.add(component);
            return f;
        }
        if (AbstractChoice.class.isAssignableFrom(component.getClass())) {
            Fragment f = new Fragment("controlPair", "choice", this);
            f.add(label);
            f.add(component);
            return f;
        }
        return null;
    }

    public FormComponent getComponent() {
        return component;
    }

    public boolean isEscapeLabelModelStrings() {
        return false;
    }

    class WrappedParentModel implements IComponentInheritedModel {
        private final IWrapModel realParent;

        public WrappedParentModel(IWrapModel realParent) {
            this.realParent = realParent;
        }

        public IWrapModel wrapOnInheritance(Component arg0) {
            if (arg0 == ViewOrEdit.this.component) {
                return realParent;
            } else {
                return null;
            }
        }

        public Object getObject() {
            return null;
        }

        public void setObject(Object arg0) {
        }

        public void detach() {
        }
    }

    public IPrivilege getRenderPrivilege() {
        return IPrivilege.NULL;
    }

    public IPrivilege getEnablePrivilege() {
        return IPrivilege.NULL;
    }

}