Package org.carrot2.workbench.editors.impl.numeric

Source Code of org.carrot2.workbench.editors.impl.numeric.UnboundedEditorBase

/*
* Carrot2 project.
*
* Copyright (C) 2002-2014, Dawid Weiss, Stanisław Osiński.
* All rights reserved.
*
* Refer to the full license file "carrot2.LICENSE"
* in the root folder of the repository checkout or at:
* http://www.carrot2.org/carrot2.LICENSE
*/

package org.carrot2.workbench.editors.impl.numeric;

import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.carrot2.workbench.core.helpers.GUIFactory;
import org.carrot2.workbench.editors.*;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.*;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.*;

/**
* Base class for unbounded editors.
*/
abstract class UnboundedEditorBase<T extends Number> extends AttributeEditorAdapter
{
    /**
     * Text box for editing.
     */
    protected Text text;

    /** Last valid value cache. */
    private T lastValidValue;

    /**
     * A temporary flag used to avoid event looping.
     */
    private boolean duringSelection;

    protected String tooltip;
    protected T min;
    protected T max;
    protected T pageIncrement;

    /*
     *
     */
    @Override
    protected AttributeEditorInfo init(Map<String,Object> defaultValues)
    {
        return new AttributeEditorInfo(1, false);
    }

    /*
     * Return the current editor value.
     */
    @Override
    public Object getValue()
    {
        return lastValidValue;
    }

    /*
     *
     */
    @Override
    public void setValue(Object object)
    {
        if (object != null && object.equals(getValue()))
        {
            return;
        }

        if (object != null && !(object instanceof Number))
        {
            return;
        }

        if (object == null)
        {
            propagateNewValue(null);
        }
        else
        {
            propagateNewValue(to_s((Number) object));
        }
    }

    /*
     *
     */
    @Override
    public void createEditor(Composite parent, int gridColumns)
    {
        createText(parent, gridColumns);
    }

    /**
     * Create the scale control.
     */
    private void createText(Composite parent, int gridColumns)
    {
        final GridDataFactory factory = GUIFactory.editorGridData();

        final GridData layoutData = factory.create();
        layoutData.horizontalSpan = gridColumns;
        layoutData.grabExcessHorizontalSpace = false;
        layoutData.verticalAlignment = SWT.CENTER;

        text = new Text(parent, SWT.LEAD | SWT.SINGLE | SWT.BORDER);
        text.setLayoutData(layoutData);

        /*
         * Hook event listener.
         */
        text.addModifyListener(new ModifyListener()
        {
            public void modifyText(ModifyEvent e)
            {
                /*
                 * Propagate valid intermediate values as soon
                 * as the user types them in, but do not
                 * refresh {@link #text}, as it causes selection caret to be reset.
                 */
                if (isValid(text.getText()))
                {
                    propagateNewValue(text.getText(), false);
                }
            }
        });

        text.addFocusListener(new FocusAdapter()
        {
            public void focusLost(FocusEvent e)
            {
                /*
                 * Update with last valid value on focus lost (if the intermediate
                 * value was for some reason invalid, for example consisted
                 * only of a '-' sign, it will be reverted to the last valid value.
                 */
                propagateNewValue(to_s((Number) lastValidValue));
            }
        });

        text.addVerifyListener(new VerifyListener()
        {
            /*
             * Allow only these modifications that result in a valid value or
             * a temporary string that can lead to one.
             */
            public void verifyText(VerifyEvent e)
            {
                if (duringSelection) return;

                final String currentText = text.getText();
                final String newText = currentText.substring(0, e.start) + e.text
                    + currentText.substring(e.end);

                e.doit = StringUtils.isEmpty(newText) || isValidForEditing(newText);
            }
        });

        text.addListener(SWT.MouseWheel, new Listener()
        {
            /*
             * On mouse wheel, update value by page increment and
             * stop wheel event's propagation.
             */
            public void handleEvent(Event event)
            {
                event.doit = false;

                if (getValue() != null)
                {
                    doPageIncrement(event.count > 0);
                }
            }
        });

        text.setToolTipText(tooltip);
    }

    /**
     * {@Link #propagateNewValue(String, boolean)} and refresh {@link #text}'s value.
     */
    protected final void propagateNewValue(String value)
    {
        propagateNewValue(value, true);
    }
   
    /**
     * Propagates value change event to all listeners and updates GUI widgets.
     */
    protected final void propagateNewValue(String value, boolean refreshTextBox)
    {
        if (!this.duringSelection)
        {
            this.duringSelection = true;

            if (refreshTextBox)
            {
                this.text.setText(value == null ? "" : value);
            }

            if (isValid(value))
            {
                try
                {
                    this.lastValidValue = toRange(to_v(value));
                    fireAttributeChanged(new AttributeEvent(this));
                }
                catch (NumberFormatException e)
                {
                    // Just skip.
                }
            }

            this.duringSelection = false;
        }
    }

    /*
     *
     */
    protected abstract void doPageIncrement(boolean positive);

    /*
     *
     */
    protected abstract T toRange(T d);

    /**
     * Should return <code>true</code> if and only if the value is valid
     * and will parse with {@link #to_v}.
     */
    protected abstract boolean isValid(String value);

    /**
     * Should return <code>true</code> if the value is valid as a temporal value of the
     * input text editor, but may not validate with {@link #isValid(String)}. Examples:
     * <code>-</code>, <code>+</code> and an empty string are all valid temporary
     * states, but not numbers.
     */
    protected abstract boolean isValidForEditing(String value);

    /**
     * Parse the number and return its string representation.
     */
    protected abstract String to_s(Number object);

    /*
     *
     */
    protected abstract T to_v(String value);
}
TOP

Related Classes of org.carrot2.workbench.editors.impl.numeric.UnboundedEditorBase

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.