com.servoy.j2db.server.headlessclient.dataui.WebBaseSelectBox.java Source code

Java tutorial

Introduction

Here is the source code for com.servoy.j2db.server.headlessclient.dataui.WebBaseSelectBox.java

Source

/*
 This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2010 Servoy BV
    
 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU Affero General Public License as published by the Free
 Software Foundation; either version 3 of the License, or (at your option) any
 later version.
    
 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details.
    
 You should have received a copy of the GNU Affero General Public License along
 with this program; if not, see http://www.gnu.org/licenses or write to the Free
 Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
 */

package com.servoy.j2db.server.headlessclient.dataui;

import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

import javax.swing.SwingConstants;
import javax.swing.border.Border;
import javax.swing.event.ListDataListener;
import javax.swing.text.Document;

import org.apache.wicket.Component;
import org.apache.wicket.MarkupContainer;
import org.apache.wicket.RequestCycle;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.IAjaxCallDecorator;
import org.apache.wicket.ajax.calldecorator.AjaxCallDecorator;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.MarkupStream;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.form.FormComponent;
import org.apache.wicket.model.IModel;

import com.servoy.base.util.ITagResolver;
import com.servoy.j2db.FormManager;
import com.servoy.j2db.IApplication;
import com.servoy.j2db.IMainContainer;
import com.servoy.j2db.IScriptExecuter;
import com.servoy.j2db.IServiceProvider;
import com.servoy.j2db.component.INullableAware;
import com.servoy.j2db.dataprocessing.IDisplayData;
import com.servoy.j2db.dataprocessing.IEditListener;
import com.servoy.j2db.dataprocessing.IValueList;
import com.servoy.j2db.scripting.JSEvent;
import com.servoy.j2db.server.headlessclient.MainPage;
import com.servoy.j2db.ui.IEventExecutor;
import com.servoy.j2db.ui.IFieldComponent;
import com.servoy.j2db.ui.ILabel;
import com.servoy.j2db.ui.IProviderStylePropertyChanges;
import com.servoy.j2db.ui.IStylePropertyChanges;
import com.servoy.j2db.ui.ISupportOnRender;
import com.servoy.j2db.ui.ISupportSimulateBounds;
import com.servoy.j2db.ui.ISupportSimulateBoundsProvider;
import com.servoy.j2db.ui.ISupportValueList;
import com.servoy.j2db.ui.ISupportWebBounds;
import com.servoy.j2db.ui.scripting.AbstractRuntimeField;
import com.servoy.j2db.util.HtmlUtils;
import com.servoy.j2db.util.ISupplyFocusChildren;
import com.servoy.j2db.util.Text;
import com.servoy.j2db.util.Utils;

/**
 * @author lvostinar
 *
 */
@SuppressWarnings("nls")
public abstract class WebBaseSelectBox extends MarkupContainer implements IFieldComponent, IDisplayData,
        IProviderStylePropertyChanges, INullableAware, ISupportWebBounds, IRightClickListener,
        ISupplyFocusChildren<Component>, ISupportValueList, ISupportSimulateBoundsProvider, ISupportOnRender {
    protected static final long serialVersionUID = 1L;
    protected static final String NO_COLOR = "NO_COLOR";

    protected IValueList onValue;
    protected final WebEventExecutor eventExecutor;

    protected Cursor cursor;
    protected boolean needEntireState;
    protected int maxLength;
    protected Insets margin;
    protected int horizontalAlignment;
    protected Point loc;
    protected String inputId;
    protected boolean allowNull = true;
    protected String tmpForeground = NO_COLOR;

    protected final IApplication application;
    protected final FormComponent<?> selector;
    protected final AbstractRuntimeField<IFieldComponent> scriptable;

    public WebBaseSelectBox(final IApplication application, AbstractRuntimeField<IFieldComponent> scriptable,
            String id, String text) {
        super(id);
        this.scriptable = scriptable;
        this.application = application;
        selector = getSelector("check_" + id); //$NON-NLS-1$

        boolean useAJAX = Utils.getAsBoolean(application.getRuntimeProperties().get("useAJAX"));
        eventExecutor = new WebEventExecutor(selector, useAJAX);
        setOutputMarkupPlaceholderTag(true);

        add(selector);
        Label selectLabel = new Label("text_" + id, "") {
            @Override
            protected void onComponentTag(ComponentTag tag) {
                super.onComponentTag(tag);
                if (tag.getName().compareToIgnoreCase("label") == 0) //$NON-NLS-1$
                {
                    tag.put("for", selector.getMarkupId()); //$NON-NLS-1$
                }
            }

            @Override
            protected void onBeforeRender() {
                super.onBeforeRender();
                String txt = getDefaultModelObjectAsString();
                if (HtmlUtils.startsWithHtml(txt)) {
                    txt = StripHTMLTagsConverter.convertBodyText(this, txt, application.getFlattenedSolution())
                            .getBodyTxt().toString();
                    setDefaultModelObject(txt);
                }
            }

        };
        selectLabel.setOutputMarkupId(true);
        add(selectLabel); //$NON-NLS-1$ //$NON-NLS-2$
        setText(Text.processTags(text, null));

        selector.add(new FocusIfInvalidAttributeModifier(selector));
        add(StyleAttributeModifierModel.INSTANCE);
        add(TooltipAttributeModifier.INSTANCE);
    }

    protected abstract FormComponent<?> getSelector(String id);

    private String text;

    public void setText(String txt) {
        this.text = txt;
        Component c = get("text_" + getId()); //$NON-NLS-1$
        if (txt == null || txt.trim().length() == 0) {
            c.setVisible(false);
        } else {
            c.setDefaultModelObject(txt);
            c.setVisible(true);
            c.setEscapeModelStrings(false);
        }
    }

    public String getText() {
        return text;
    }

    /**
     * @see org.apache.wicket.Component#getLocale()
     */
    @Override
    public Locale getLocale() {
        return application.getLocale();
    }

    public IStylePropertyChanges getStylePropertyChanges() {
        return scriptable.getChangesRecorder();
    }

    /*
     * _____________________________________________________________ Methods for event handling
     */
    public void addScriptExecuter(IScriptExecuter el) {
        eventExecutor.setScriptExecuter(el);
    }

    public IEventExecutor getEventExecutor() {
        return eventExecutor;
    }

    public void setEnterCmds(String[] ids, Object[][] args) {
        //we cannot add focus in web on checkbox, onAction runs at same time as onfocus, making onfocus useless, and giving unprdicted behaviour
        //eventExecutor.setEnterCmds(ids);
    }

    public void setLeaveCmds(String[] ids, Object[][] args) {
        eventExecutor.setLeaveCmds(ids, args);
    }

    public boolean isValueValid() {
        return isValueValid;
    }

    private boolean isValueValid = true;
    private Object previousValidValue;

    public void setValueValid(boolean valid, Object oldVal) {
        application.getRuntimeProperties().put(IServiceProvider.RT_LASTFIELDVALIDATIONFAILED_FLAG,
                Boolean.valueOf(!valid));
        isValueValid = valid;
        if (!isValueValid) {
            previousValidValue = oldVal;
            requestFocusToComponent();
            if (tmpForeground == NO_COLOR) {
                tmpForeground = scriptable.getFgcolor();
                scriptable.setFgcolor("red");
            }
        } else {
            previousValidValue = null;
            if (tmpForeground != NO_COLOR) {
                scriptable.setFgcolor(tmpForeground);
                tmpForeground = NO_COLOR;
            }
        }
    }

    public Component[] getFocusChildren() {
        Component component = null;
        if (onValue != null)
            component = this;
        else
            component = selector;
        return new Component[] { component };
    }

    public void notifyLastNewValueWasChange(final Object oldVal, final Object newVal) {
        if (eventExecutor.hasChangeCmd()) {
            application.invokeLater(new Runnable() {
                public void run() {
                    WebEventExecutor.setSelectedIndex(WebBaseSelectBox.this, null,
                            IEventExecutor.MODIFIERS_UNSPECIFIED);
                    eventExecutor.fireChangeCommand(previousValidValue == null ? oldVal : previousValidValue,
                            newVal, false, WebBaseSelectBox.this);
                }
            });
        } else {
            setValueValid(true, null);
        }
    }

    public void setChangeCmd(String id, Object[] args) {
        eventExecutor.setChangeCmd(id, args);
    }

    public void setActionCmd(String id, Object[] args) {
        eventExecutor.setActionCmd(id, args);
    }

    private boolean wasEditable;

    public void setValidationEnabled(boolean b) {
        if (eventExecutor.getValidationEnabled() == b)
            return;

        boolean prevEditState = editState;
        if (b) {
            setEditable(wasEditable);
        } else {
            wasEditable = editable;
            if (!Boolean.TRUE
                    .equals(application.getClientProperty(IApplication.LEAVE_FIELDS_READONLY_IN_FIND_MODE))) {
                setEditable(true);
            }
        }
        editState = prevEditState;
        eventExecutor.setValidationEnabled(b);
        getStylePropertyChanges().setChanged();
    }

    public void setSelectOnEnter(boolean b) {
        eventExecutor.setSelectOnEnter(b);
    }

    //_____________________________________________________________

    /**
     * @see wicket.markup.html.WebMarkupContainer#onRender()
     */
    @Override
    protected void onRender(final MarkupStream markupStream) {
        super.onRender(markupStream);

        getStylePropertyChanges().setRendered();
        IModel<?> model = getInnermostModel();

        if (model instanceof RecordItemModel) {
            ((RecordItemModel) model).updateRenderedValue(this);
        }
    }

    @Override
    protected void onComponentTag(ComponentTag tag) {
        super.onComponentTag(tag);

        boolean useAJAX = Utils.getAsBoolean(application.getRuntimeProperties().get("useAJAX")); //$NON-NLS-1$
        if (useAJAX) {
            Object oe = scriptable.getClientProperty("ajax.enabled");
            if (oe != null)
                useAJAX = Utils.getAsBoolean(oe);
        }
        if (!useAJAX) {
            Form<?> f = getForm();
            if (f != null) {
                if (eventExecutor.hasRightClickCmd()) {
                    CharSequence urlr = urlFor(IRightClickListener.INTERFACE);
                    // We need a "return false;" so that the context menu is not displayed in the browser.
                    tag.put("oncontextmenu", f.getJsForInterfaceUrl(urlr) + " return false;"); //$NON-NLS-1$ //$NON-NLS-2$
                }
            }
        }
    }

    /**
     * @see com.servoy.j2db.ui.IFieldComponent#setNeedEntireState(boolean)
     */
    public void setNeedEntireState(boolean needEntireState) {
        this.needEntireState = needEntireState;
    }

    /**
     * @see com.servoy.j2db.dataprocessing.IDisplayData#needEntireState()
     */
    public boolean needEntireState() {
        return needEntireState;
    }

    /**
     * @see com.servoy.j2db.ui.IFieldComponent#setMaxLength(int)
     */
    public void setMaxLength(int maxLength) {
        this.maxLength = maxLength;
    }

    protected boolean editable;
    protected boolean editState;

    public void setEditable(boolean b) {
        editState = b;
        editable = b;
    }

    public boolean isEditable() {
        return !isReadOnly();
    }

    /**
     * @see com.servoy.j2db.ui.IFieldComponent#setMargin(java.awt.Insets)
     */
    public void setMargin(Insets margin) {
        this.margin = margin;
    }

    public Insets getMargin() {
        return margin;
    }

    /**
     * @see com.servoy.j2db.ui.IFieldComponent#setHorizontalAlignment(int)
     */
    public void setHorizontalAlignment(int horizontalAlignment) {
        this.horizontalAlignment = horizontalAlignment;
    }

    /**
     * @see com.servoy.j2db.ui.IComponent#setCursor(java.awt.Cursor)
     */
    public void setCursor(Cursor cursor) {
        this.cursor = cursor;
    }

    public Object getValueObject() {
        return getDefaultModelObject();
    }

    public void setAllowNull(boolean allowNull) {
        this.allowNull = allowNull;
    }

    public boolean getAllowNull() {
        return allowNull;
    }

    public boolean needEditListener() {
        return false;
    }

    public void addEditListener(IEditListener l) {
        //ignore
    }

    /**
     * @see com.servoy.j2db.dataprocessing.IDisplayData#getDocument()
     */
    public Document getDocument() {
        return null;
    }

    public boolean stopUIEditing(boolean looseFocus) {
        if (!isValueValid) {
            requestFocusToComponent();
            return false;
        }
        return true;
    }

    public void requestFocusToComponent() {
        // is the current container always the right one...
        IMainContainer currentContainer = ((FormManager) application.getFormManager()).getCurrentContainer();
        if (currentContainer instanceof MainPage) {
            ((MainPage) currentContainer).componentToFocus(selector);
        }
    }

    public void setName(String n) {
        name = n;
    }

    private String name;

    public String getName() {
        return name;
    }

    /*
     * border---------------------------------------------------
     */
    protected Border border;

    public void setBorder(Border border) {
        this.border = border;
    }

    public Border getBorder() {
        return border;
    }

    /*
     * opaque---------------------------------------------------
     */
    public void setOpaque(boolean opaque) {
        this.opaque = opaque;
    }

    protected boolean opaque;

    // Searches for a parent form, up the hierarchy of controls in the page.
    protected Form<?> getForm() {
        Component c = this;
        while ((c != null) && !(c instanceof Form))
            c = c.getParent();
        return (Form<?>) c;
    }

    @Override
    protected void onBeforeRender() {
        super.onBeforeRender();
        fireOnRender(false);
    }

    public void fireOnRender(boolean force) {
        if (scriptable != null) {
            boolean isFocused = false;
            IMainContainer currentContainer = ((FormManager) application.getFormManager()).getCurrentContainer();
            if (currentContainer instanceof MainPage) {
                isFocused = this.equals(((MainPage) currentContainer).getFocusedComponent());
            }
            if (force)
                scriptable.getRenderEventExecutor().setRenderStateChanged();
            scriptable.getRenderEventExecutor().fireOnRender(isFocused);
        }
    }

    public IValueList getValueList() {
        return onValue;
    }

    public ListDataListener getListener() {
        return null;
    }

    public void setValueList(IValueList vl) {
        this.onValue = vl;
        getStylePropertyChanges().setChanged();

    }

    /*
     * readonly---------------------------------------------------
     */

    public void setReadOnly(boolean b) {
        if (b && !editable)
            return;
        if (b) {
            setEditable(false);
            editState = true;
        } else {
            setEditable(editState);
        }
    }

    public boolean isReadOnly() {
        return !editable;
    }

    /*
     * dataprovider---------------------------------------------------
     */
    protected String dataProviderID;

    public void setDataProviderID(String dataProviderID) {
        this.dataProviderID = dataProviderID;
    }

    public String getDataProviderID() {
        return dataProviderID;
    }

    public boolean isOpaque() {
        return opaque;
    }

    private String titleText = null;

    public void setTitleText(String title) {
        this.titleText = title;
        setText(Text.processTags(title, resolver));
    }

    public String getTitleText() {
        return Text.processTags(titleText, resolver);
    }

    private String tooltip;

    public void setToolTipText(String tooltip) {
        this.tooltip = Utils.stringIsEmpty(tooltip) ? null : tooltip;
    }

    protected ITagResolver resolver;

    public void setTagResolver(ITagResolver resolver) {
        this.resolver = resolver;
    }

    /**
     * @see com.servoy.j2db.ui.IComponent#getToolTipText()
     */
    public String getToolTipText() {
        if (tooltip != null && getInnermostModel() instanceof RecordItemModel) {
            return Text.processTags(tooltip, resolver);
        }
        return tooltip;
    }

    /*
     * font---------------------------------------------------
     */
    public void setFont(Font font) {
        this.font = font;
    }

    private Font font;

    public Font getFont() {
        return font;
    }

    private Color background;

    public void setBackground(Color cbg) {
        this.background = cbg;
    }

    public Color getBackground() {
        return background;
    }

    private Color foreground;

    private List<ILabel> labels;

    public void setForeground(Color cfg) {
        this.foreground = cfg;
    }

    public Color getForeground() {
        return foreground;
    }

    /*
     * visible---------------------------------------------------
     */
    public void setComponentVisible(boolean visible) {
        if (viewable || !visible) {
            setVisible(visible);
            if (labels != null) {
                for (int i = 0; i < labels.size(); i++) {
                    ILabel label = labels.get(i);
                    label.setComponentVisible(visible);
                }
            }
        }
    }

    public void addLabelFor(ILabel label) {
        if (labels == null)
            labels = new ArrayList<ILabel>(3);
        labels.add(label);
    }

    public List<ILabel> getLabelsFor() {
        return labels;
    }

    public void setComponentEnabled(final boolean b) {
        if (accessible || !b) {
            super.setEnabled(b);
            getStylePropertyChanges().setChanged();
            if (labels != null) {
                for (int i = 0; i < labels.size(); i++) {
                    ILabel label = labels.get(i);
                    label.setComponentEnabled(b);
                }
            }
        }
    }

    private boolean accessible = true;

    public void setAccessible(boolean b) {
        if (!b)
            setComponentEnabled(b);
        accessible = b;
    }

    private boolean viewable = true;

    public void setViewable(boolean b) {
        if (!b)
            setComponentVisible(b);
        this.viewable = b;
    }

    public boolean isViewable() {
        return viewable;
    }

    /*
     * location---------------------------------------------------
     */
    private Point location = new Point(0, 0);

    public int getAbsoluteFormLocationY() {
        WebDataRenderer parent = findParent(WebDataRenderer.class);
        if (parent != null) {
            return parent.getYOffset() + getLocation().y;
        }
        return getLocation().y;
    }

    public void setLocation(Point location) {
        this.location = location;
    }

    public Point getLocation() {
        return location;
    }

    /*
     * size---------------------------------------------------
     */
    private Dimension size = new Dimension(0, 0);

    public Dimension getSize() {
        return size;
    }

    public Rectangle getWebBounds() {
        if (size != null) {
            Dimension d = ((ChangesRecorder) scriptable.getChangesRecorder()).calculateWebSize(size.width,
                    size.height, border, margin, 0, null, true, SwingConstants.CENTER);
            return new Rectangle(location, d);
        }
        return null;
    }

    /**
     * @see com.servoy.j2db.ui.ISupportWebBounds#getPaddingAndBorder()
     */
    public Insets getPaddingAndBorder() {
        return ((ChangesRecorder) scriptable.getChangesRecorder()).getPaddingAndBorder(
                size == null ? 0 : size.height, border, margin, 0, null, true, SwingConstants.CENTER);
    }

    public void setSize(Dimension size) {
        this.size = size;
    }

    public void setRightClickCommand(String rightClickCmd, Object[] args) {
        eventExecutor.setRightClickCmd(rightClickCmd, args);
        add(new ServoyAjaxEventBehavior("oncontextmenu", "SelectBox", true) //$NON-NLS-1$
        {
            @Override
            protected void onEvent(AjaxRequestTarget target) {
                eventExecutor.onEvent(JSEvent.EventType.rightClick, target, WebBaseSelectBox.this,
                        Utils.getAsInteger(
                                RequestCycle.get().getRequest().getParameter(IEventExecutor.MODIFIERS_PARAMETER)));
            }

            @Override
            public boolean isEnabled(Component component) {
                if (super.isEnabled(component)) {
                    Object oe = WebBaseSelectBox.this.scriptable.getClientProperty("ajax.enabled");
                    if (oe != null)
                        return Utils.getAsBoolean(oe);
                    return true;
                }
                return false;
            }

            // We need to return false, otherwise the context menu of the browser is displayed.
            @Override
            protected IAjaxCallDecorator getAjaxCallDecorator() {
                return new AjaxCallDecorator() {
                    @Override
                    public CharSequence decorateScript(CharSequence script) {
                        return script + " return false;";
                    }
                };
            }
        });
    }

    public void onRightClick() {
        Form<?> f = getForm();
        if (f != null) {
            // If form validation fails, we don't execute the method.
            if (f.process())
                eventExecutor.onEvent(JSEvent.EventType.rightClick, null, this,
                        IEventExecutor.MODIFIERS_UNSPECIFIED);
        }
    }

    public ISupportSimulateBounds getBoundsProvider() {
        return findParent(ISupportSimulateBounds.class);
    }

    interface ISelector {
        public WebBaseSelectBox getSelectBox();
    }
}