com.jaspersoft.studio.property.color.chooser.AdvancedColorWidget.java Source code

Java tutorial

Introduction

Here is the source code for com.jaspersoft.studio.property.color.chooser.AdvancedColorWidget.java

Source

/*******************************************************************************
 * Copyright (C) 2005 - 2014 TIBCO Software Inc. All rights reserved.
 * http://www.jaspersoft.com.
 * 
 * Unless you have purchased  a commercial license agreement from Jaspersoft,
 * the following license terms  apply:
 * 
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 ******************************************************************************/
package com.jaspersoft.studio.property.color.chooser;

import java.awt.AWTException;
import java.awt.Robot;
import java.util.ArrayList;
import java.util.List;

import net.sf.jasperreports.eclipse.ui.util.UIUtils;

import org.apache.commons.lang.StringUtils;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Scale;
import org.eclipse.swt.widgets.Spinner;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.ui.PlatformUI;
import org.eclipse.wb.swt.ResourceManager;

import com.jaspersoft.studio.JaspersoftStudioPlugin;
import com.jaspersoft.studio.messages.Messages;
import com.jaspersoft.studio.utils.AlfaRGB;
import com.jaspersoft.studio.utils.ImageUtils;

/**
 * A composite that offer advanced controls to choose a color like the selection of 
 * a transparency, the selection of the color between many visualization...
 * 
 * @author Orlandin Marco
 *
 */
public class AdvancedColorWidget extends Composite implements IColorProvider {

    /**
     * Widget where is shown the actual color space and the user can choose a color from that with a mouse click
     */
    private ColorsSelectorWidget colorsSelector;

    /**
     * Preview area where is shown the selected color, if provided it is also compared with the and old color
     * we are replacing
     */
    private ColorPreviewWidget previewComposite = null;

    /**
     * Control to define the alpha value by sliding a cursor
     */
    private Scale alphaSlider = null;

    /**
     * Control to define the alpha value by a numeric spinner
     */
    private Spinner alphaText = null;

    /**
     * Numeric value that represent the alpha transparency of the new color
     */
    private int alpha = 255;

    /**
     * List of radio buttons used to have only one button selected at time
     */
    private List<Button> radioList = new ArrayList<Button>();

    /**
     * Numeric spinner to define the hue of a color
     */
    private Spinner hue = null;

    /**
     * Numeric spinner to define the saturation of a color
     */
    private Spinner saturation = null;

    /**
     * Numeric spinner to define the brightness of a color
     */
    private Spinner brightness = null;

    /**
     * Numeric spinner to define the red component of a color
     */
    private Spinner red = null;

    /**
     * Numeric spinner to define the green component of a color
     */
    private Spinner green = null;

    /**
     * Numeric spinner to define the blue component of a color
     */
    private Spinner blue = null;

    /**
     * Textual field where the user can define a color like a hex number
     */
    private Text hex = null;

    /**
     * Button to press to acquire a color from the screen
     */
    private Button pickColorButton;

    /**
     * Boolean guard to avoid the start of the modify listener when 
     * the textual\spinner fields are updated
     */
    private Boolean modfiedGuard = true;

    /**
     * Font used inside the pick color button when it is pressed
     */
    private Font buttonFont = ResourceManager.getFont("Arial", 9, SWT.BOLD); //$NON-NLS-1$

    /** 
     * timer interval for checking color under the mouse cursor
     * 
     */
    private static final int TIMER_INTERVAL = 50;

    /**
     * Flag used to hide the alpha slider controls
     */
    private boolean hideSliderBar = false;

    /**
     * Boolean flag to know if there is an acquiring action by the color picker
     */
    private boolean isAcquiring = false;

    /**
     * Color that we are changing from the color dialog, used to compare the new color 
     * to the old one. If it is null it is not shown
     */
    private RGB oldColor = null;

    /**
     * The actually selected color
     */
    private AlfaRGB newColor = null;

    /**
     * Thread that at every time interval check the color under the mouse 
     * position on the screen and use it for the color selected by the user
     * 
     * @author Orlandin Marco
     *
     */
    private class ColorPickerThreadClass implements Runnable {

        /**
         * Boolean flag that is used to terminate the thread
         */
        private Boolean stopThread = false;

        /**
         * Check if the thread should stop
         * 
         * @return true if the thread should terminate false if he must
         * continue its cycle of color picking
         */
        public boolean getStop() {
            synchronized (this) {
                return stopThread;
            }
        }

        /**
         * Set the termination status of the thread
         * 
         * @param value true if the thread should terminate false if he must
         * continue its cycle of color picking
         */
        private void setStop(boolean value) {
            synchronized (this) {
                stopThread = value;
            }
        }

        /**
         * If the stop guard is false the thread read the color under the mouse position,
         * update the actual color and will re-execute himself after a time interval, otherwise
         * its run will be terminated
         */
        @Override
        public void run() {
            if (!getStop()) {
                checkColorPicker();
                Display.getCurrent().timerExec(TIMER_INTERVAL, this);
            }
        }
    };

    /**
    * Thread used to read the color under the mouse cursor
    */
    private ColorPickerThreadClass colorPickerThread = new ColorPickerThreadClass();

    /**
     * Modify listener used when a textual control or a numeric one is modified by the user
     */
    private ModifyListener valueModifedListener = new ModifyListener() {

        @Override
        public void modifyText(ModifyEvent e) {
            synchronized (modfiedGuard) {
                if (modfiedGuard) {
                    //since one modification throw a chain of modification on the other control we need to consider only the first one
                    modfiedGuard = false;
                    hue.getParent().getParent().setRedraw(false);
                    if (e.widget == hue || e.widget == saturation || e.widget == brightness) {
                        float h = (float) hue.getSelection();
                        float s = (float) saturation.getSelection() / 100;
                        float b = (float) brightness.getSelection() / 100;
                        colorsSelector.setSelectedColor(h, s, b, false);
                        updateText(h, s, b, e.widget);
                    } else if (e.widget == red || e.widget == green || e.widget == blue) {
                        RGB rgbColor = new RGB(red.getSelection(), green.getSelection(), blue.getSelection());
                        colorsSelector.setSelectedColor(rgbColor, false);
                        updateText(rgbColor, rgbColor.getHSB(), e.widget);
                    } else if (e.widget == hex) {
                        AlfaRGB rgbColor = hexParser(hex.getText());
                        if (rgbColor != null) {
                            colorsSelector.setSelectedColor(rgbColor.getRgb(), false);
                            //The alpha widget is optional so we need to check if it is present
                            if (alphaText != null)
                                alphaText.setSelection(rgbColor.getAlfa());
                            updateText(rgbColor.getRgb(), rgbColor.getRgb().getHSB(), e.widget);
                        }
                    }
                    hue.getParent().getParent().setRedraw(true);
                    modfiedGuard = true;
                }
            }
        }

    };

    /**
     * Listener used to stop the color picking thread when the space key is pressed
     */
    private Listener spaceKeyListener = new Listener() {

        public void handleEvent(Event e) {
            if (e.keyCode == UIUtils.SWT_SPACE) {
                if (!isAcquiring) {
                    isAcquiring = true;
                    colorPickerThread.setStop(false);
                    Display.getCurrent().timerExec(TIMER_INTERVAL, colorPickerThread);
                    pickColorButton.setImage(null);
                    pickColorButton.setText(Messages.ColorDialog_stopPickingActionText);
                    pickColorButton.setEnabled(false);
                    pickColorButton.setLayoutData(new GridData(GridData.FILL_BOTH));
                    pickColorButton.getParent().layout(true, true);
                } else {
                    stopPickerThread();
                    isAcquiring = false;
                }
            }
        }
    };

    /**
     * Create the controls
     * 
     * @param parent parent of the controls
     * @param style style of the main composite
     * @param oldColor old color, used to compare it into a preview area with the selected color
     * @param showAlpha true if the controls to set the alpha value of the new color should be displayed, false
     * otherwise
     */
    public AdvancedColorWidget(Composite parent, int style, AlfaRGB oldColor, boolean showAlpha) {
        super(parent, style);

        if (oldColor != null) {
            this.oldColor = oldColor.getRgb();
            this.alpha = oldColor.getAlfa();
        }
        hideSliderBar = !showAlpha;

        setLayout(new GridLayout(2, false));
        colorsSelector = new ColorsSelectorWidget(this, SWT.NONE, new HueBasedSelector());
        GridData rectangleData = new GridData(GridData.FILL_BOTH);
        rectangleData.widthHint = 250;
        rectangleData.heightHint = 150;
        colorsSelector.setLayoutData(rectangleData);
        if (this.oldColor != null)
            colorsSelector.setSelectedColor(this.oldColor, false);
        else
            colorsSelector.setSelectedColor(new RGB(255, 255, 255), false);

        colorsSelector.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                updateText();
            }
        });

        Composite righSide = new Composite(this, SWT.NONE);
        righSide.setLayout(new GridLayout(1, false));
        righSide.setLayoutData(new GridData(GridData.FILL_BOTH));

        previewComposite = new ColorPreviewWidget(righSide, SWT.NONE);
        if (oldColor != null) {
            previewComposite.setOldColor(this.oldColor, alpha);
        }
        previewComposite.setLayoutData(new GridData(GridData.FILL_BOTH));

        //Create the color picker button
        createColorPicker(previewComposite.getAdditionalComponentarea());

        //Create the alpha slider and textual controls
        if (!hideSliderBar)
            createSlider(righSide);
        //Create the textual\numeric controls
        createTextArea(righSide);
        updateText();

        PlatformUI.getWorkbench().getDisplay().addFilter(org.eclipse.swt.SWT.KeyDown, spaceKeyListener);
    }

    /**
     * Get the alpha rgb of the actually selected color
     * 
     * @return the actually selected color
     */
    public AlfaRGB getSelectedColor() {
        return newColor;
    }

    /**
     * Convert the text into a alfa RGB color, but only if there are exactly seven chars, a # symbol followed by three pair of hex values
     * or if it a sequence of 3 integers separated by comma (read as rgb) or if it is a sequence of 4 integers separated by comma (read as rgba)
     * 
     * @param text a text representing a color as HexDecimal value, rgb value or alfa rgb value
     * @return an alfa RGB color. If the color is provided as hex or as rgb the alpha is 255
     */
    private AlfaRGB hexParser(String text) {
        AlfaRGB newColor = null;
        try {
            if (text.startsWith("#") && text.length() == 7) { //$NON-NLS-1$
                newColor = AlfaRGB.getFullyOpaque(new RGB(Integer.valueOf(text.substring(1, 3), 16),
                        Integer.valueOf(text.substring(3, 5), 16), Integer.valueOf(text.substring(5, 7), 16)));
            } else if (!text.startsWith("#") && text.length() == 6) { //$NON-NLS-1$
                newColor = AlfaRGB.getFullyOpaque(new RGB(Integer.valueOf(text.substring(0, 2), 16),
                        Integer.valueOf(text.substring(2, 4), 16), Integer.valueOf(text.substring(4, 6), 16)));
            } else {
                String[] components = text.split(",");
                int[] resultComp = new int[] { 0, 0, 0, 255 };
                boolean colsedBars = (text.contains("[") && text.contains("]"))
                        || (text.contains("(") && text.contains(")")) || (text.contains("{") && text.contains("}"))
                        || (!text.contains("{") && !text.contains("[") && !text.contains("("));
                if (components.length > 2 && colsedBars) {
                    for (int i = 0; i < components.length && i < 4; i++) {
                        String component = components[i].replaceAll("[^\\d]", "");
                        ;
                        resultComp[i] = Integer.valueOf(component);
                    }
                    newColor = new AlfaRGB(new RGB(resultComp[0], resultComp[1], resultComp[2]), resultComp[3]);
                }
            }
        } catch (NumberFormatException ex) {
        } catch (IllegalArgumentException ex) {
        }
        return newColor;
    }

    /**
     * Return the hexadecimal representation of a color
     * 
     * @param color The color
     * @return The color hexadecimal representation
     */
    private String getHexFromRGB(RGB color) {
        int r = color.red;
        int g = color.green;
        int b = color.blue;
        String s = Integer.toHexString(r) + Integer.toHexString(g) + Integer.toHexString(b);
        return "#" + StringUtils.rightPad(s, 6, "0").toUpperCase(); //$NON-NLS-1$ //$NON-NLS-2$
    }

    /**
     * Refresh the text area with the values of the color inside the color selection widget.
     * It will also update the color preview area
     */
    private void updateText() {
        updateText(colorsSelector.getSelectedColorRGB(), colorsSelector.getSelectedColorHSB(), null);
    }

    /**
     * Refresh the text area with passed color
     * It will also update the color preview area
     * 
     * @param color the rgb of the new color
     * @param hsb an array of float that represent the hsb values of the color
     * @param source the widget that raised the event, to avoid a selection text problem
     * on some platforms the text that has raised the event must not be set, otherwise it 
     * will be automatically selected. It this value is null then all the widget will be set
     */
    private void updateText(RGB color, float[] hsb, Widget source) {
        synchronized (modfiedGuard) {
            modfiedGuard = false;
            hue.getParent().getParent().setRedraw(false);
            if (red != source)
                red.setSelection(color.red);
            if (green != source)
                green.setSelection(color.green);
            if (blue != source)
                blue.setSelection(color.blue);
            hex.setText(getHexFromRGB(color));
            int h = Math.round(hsb[0]);
            int s = Math.round(hsb[1] * 100);
            int b = Math.round(hsb[2] * 100);
            if (hue != source)
                hue.setSelection(h);
            if (saturation != source)
                saturation.setSelection(s);
            if (brightness != source)
                brightness.setSelection(b);
            hue.getParent().getParent().setRedraw(true);
            updatePreview();
            modfiedGuard = true;
        }
    }

    /**
     * Update the preview area with the color inside the selector widget
     */
    private void updatePreview() {
        newColor = new AlfaRGB(colorsSelector.getSelectedColorRGB(), alpha);
        previewComposite.setNewColor(colorsSelector.getSelectedColorRGB(), alpha);
    }

    /**
     * Refresh the text area with passed color
     * It will also update the color preview area
     * 
     * @param fh hue of the color
     * @param fs saturation of the color
     * @param fb brightness of the color
     * @param source the widget that raised the event, to avoid a selection text problem
     * on some platforms the text that has raised the event must not be set, otherwise it 
     * will be automatically selected. It this value is null then all the widget will be set
     */
    private void updateText(float fh, float fs, float fb, Widget source) {
        synchronized (modfiedGuard) {
            modfiedGuard = false;
            hue.getParent().getParent().setRedraw(false);
            int h = Math.round(fh);
            int s = Math.round(fs * 100);
            int b = Math.round(fb * 100);
            if (hue != source)
                hue.setSelection(h);
            if (saturation != source)
                saturation.setSelection(s);
            if (brightness != source)
                brightness.setSelection(b);
            RGB color = new RGB(fh, fs, fb);
            if (red != source)
                red.setSelection(color.red);
            if (green != source)
                green.setSelection(color.green);
            if (blue != source)
                blue.setSelection(color.blue);
            hex.setText(getHexFromRGB(color));
            hue.getParent().getParent().setRedraw(true);
            updatePreview();
            modfiedGuard = true;
        }
    }

    /**
     * Create the color picker button control, to press to start a color picking
     * 
     * @param parent where the control will be palced
     */
    private void createColorPicker(Composite parent) {
        pickColorButton = new Button(parent, SWT.WRAP);
        pickColorButton.setToolTipText(Messages.ColorDialog_pickerButtonTooltip);
        pickColorButton.setFont(buttonFont);
        pickColorButton.setAlignment(SWT.CENTER);
        GridData buttonData = new GridData();
        buttonData.widthHint = 50;
        buttonData.heightHint = 50;
        buttonData.verticalAlignment = SWT.CENTER;
        pickColorButton.setLayoutData(buttonData);
        pickColorButton.setText("");
        pickColorButton.addPaintListener(new PaintListener() {
            public void paintControl(PaintEvent e) {
                if (pickColorButton.getText().isEmpty()) {
                    int size = 24;
                    int x = (e.width / 2) - (size / 2);
                    int y = (e.height / 2) - (size / 2);
                    e.gc.setAntialias(SWT.ON);
                    e.gc.drawImage(getPickerImage(size), x, y);
                }
            }
        });
        //When the button is pressed the color picking thread is started,
        //the button is disabled and its content is changed to tell the user
        //how to stop the picking thread
        pickColorButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                isAcquiring = true;
                colorPickerThread.setStop(false);
                Display.getCurrent().timerExec(TIMER_INTERVAL, colorPickerThread);
                pickColorButton.setImage(null);
                pickColorButton.setText(Messages.ColorDialog_stopPickingActionText);
                pickColorButton.setEnabled(false);
                pickColorButton.setLayoutData(new GridData(GridData.FILL_BOTH));
                pickColorButton.getParent().layout(true, true);
                // getShell().forceFocus();
            }
        });
    }

    /**
     * Return the image of the color picker button and also cache it and removed 
     * when the application is closed.
     * The image can be requested of a specific size. But the width 
     * must be the same of the height
     * 
     * @param size height and width of the image
     * @return the image
     */
    private Image getPickerImage(int size) {
        String key = "pickerIcon" + String.valueOf(size); //$NON-NLS-1$
        Image result = ResourceManager.getImage(key);
        if (result == null) {
            result = ImageUtils.resize(
                    ResourceManager.getPluginImage(JaspersoftStudioPlugin.PLUGIN_ID, "/icons/resources/picker.gif"), //$NON-NLS-1$
                    size, size);
            ImageData data = result.getImageData();
            result.dispose();
            int whitePixel = data.palette.getPixel(new RGB(255, 255, 255));
            data.transparentPixel = whitePixel;
            result = new Image(Display.getCurrent(), data);
            ResourceManager.addImage(key, result);
        }
        return result;
    }

    /**
     * Create the slider and textual controls to define the alpha
     * 
     * @param parent parent of the controls
     */
    private void createSlider(Composite parent) {
        Composite container = new Composite(parent, SWT.NONE);
        container.setLayout(new GridLayout(3, false));
        container.setLayoutData(new GridData(GridData.FILL_BOTH));
        new Label(container, SWT.NONE).setText(Messages.ColorDialog_transparencyLabel);
        alphaSlider = new Scale(container, SWT.HORIZONTAL);
        alphaSlider.setMaximum(0);
        alphaSlider.setMaximum(255);
        alphaSlider.setSelection(alpha);
        alphaSlider.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
        alphaText = new Spinner(container, SWT.BORDER);
        alphaText.setMinimum(0);
        alphaText.setMaximum(255);
        alphaText.setSelection(alpha);
        //When the alpha slider change value update also the preview composite and the alpha textual value
        alphaSlider.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                alphaText.setSelection(alphaSlider.getSelection());
                alpha = alphaSlider.getSelection();
                updatePreview();
            }
        });
        //When the alpha text field change value update also the preview composite and the alpha slider value
        alphaText.addModifyListener(new ModifyListener() {
            @Override
            public void modifyText(ModifyEvent e) {
                alphaSlider.setSelection(alphaText.getSelection());
                alpha = alphaSlider.getSelection();
                updatePreview();
            }
        });
    }

    /**
     * Create the area where all the text fields describing the color values
     * are placed
     * 
     * @param parent parent of the area
     */
    private void createTextArea(Composite parent) {
        Composite container = new Composite(parent, SWT.NONE);
        container.setLayout(new GridLayout(2, false));
        container.setLayoutData(new GridData(GridData.FILL_BOTH));
        Composite leftPart = new Composite(container, SWT.NONE);
        leftPart.setLayout(new GridLayout(3, false));
        leftPart.setLayoutData(new GridData(GridData.FILL_BOTH));

        Composite rightPart = new Composite(container, SWT.NONE);
        rightPart.setLayout(new GridLayout(3, false));
        rightPart.setLayoutData(new GridData(GridData.FILL_BOTH));

        hue = createRadio(leftPart, "H:", "\u030A", new HueBasedSelector(), true, 0, 360); //$NON-NLS-1$ //$NON-NLS-2$
        saturation = createRadio(leftPart, "S:", "%", new SaturationBasedSelector(), false, 0, 100); //$NON-NLS-1$ //$NON-NLS-2$
        brightness = createRadio(leftPart, "B:", "%", new BrightnessBasedSelector(), false, 0, 100); //$NON-NLS-1$ //$NON-NLS-2$
        red = createRadio(rightPart, "R:", " ", new RedBasedSelector(), false, 0, 255); //$NON-NLS-1$ //$NON-NLS-2$
        green = createRadio(rightPart, "G:", " ", new GreenBasedSelector(), false, 0, 255); //$NON-NLS-1$ //$NON-NLS-2$
        blue = createRadio(rightPart, "B:", " ", new BluBasedSelector(), false, 0, 255); //$NON-NLS-1$ //$NON-NLS-2$
        hex = createText(leftPart, "Hex:", ""); //$NON-NLS-1$ //$NON-NLS-2$
    }

    /**
     * Create a single text area with a label before and after it
     * 
     * @param parent parent of the text area
     * @param title content of a label placed before the text area
     * @param suffix content of a label placed after the text area
     * @return the text area created
     */
    private Text createText(Composite parent, String title, String suffix) {
        new Label(parent, SWT.NONE).setText(title);
        Text actualText = new Text(parent, SWT.BORDER);
        actualText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
        if (suffix != null)
            new Label(parent, SWT.NONE).setText(suffix);
        else
            new Label(parent, SWT.NONE);
        actualText.addModifyListener(valueModifedListener);
        return actualText;
    }

    /**
     * Create a radio button followed by a spinner with a maximum and a minimum value. At the radio 
     * button can be associated a governor. This object define how the color picker area is painted.
     * This is done because when a button is selected its governor is set into the color picker widget
     * changing the color space. When a radio button created with this method is selected all the other
     * are deselected.
     * 
     * @param parent parent of the controls
     * @param title content of a label placed as text of the radio button
     * @param suffix content of a label placed after the spinner
     * @param governor the governor that is loaded in the color picker widget when the button is selected
     * @param defaultEnabled true if the radio button is enabled by default, false otherwise
     * @param min min int value for the spinner
     * @param max max int value for the spinner
     * @return the spinner created
     */
    private Spinner createRadio(Composite parent, String title, String suffix, IWidgetGovernor governor,
            boolean defaultEnabled, int min, int max) {
        final Button radio = new Button(parent, SWT.RADIO);
        radioList.add(radio);
        radio.setText(title);
        radio.setData(governor);
        radio.setSelection(defaultEnabled);
        radio.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                if (radio.getSelection()) {
                    disableAllRadioExceptOne(radio);
                    colorsSelector.setGovernor((IWidgetGovernor) radio.getData());
                }
            }

        });
        Spinner actualText = new Spinner(parent, SWT.BORDER);
        actualText.setMinimum(min);
        actualText.setMaximum(max);
        actualText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
        if (suffix != null)
            new Label(parent, SWT.NONE).setText(suffix);
        else
            new Label(parent, SWT.NONE);
        actualText.addModifyListener(valueModifedListener);
        return actualText;
    }

    /**
     * Disable all the radio buttons except the one passed as parameter
     * 
     * @param excludedRadio reference to the radio button that will not be disabled
     */
    private void disableAllRadioExceptOne(Button excludedRadio) {
        for (Button radio : radioList) {
            if (radio.getSelection() && radio != excludedRadio) {
                radio.setSelection(false);
            }
        }
    }

    /**
     * Read the color under the mouse position and set it as the current color. This 
     * is done only if JSS or one of its components are focused. It is necessary to control
     * this dialog and its content because it modal, so every other component of JSS can not be focused
     */
    private void checkColorPicker() {
        if (!isDisposed() && (getShell().isFocusControl() || checkControlFocused(getShell().getChildren()))) {
            Robot robot;
            try {
                robot = new Robot();
                Point pos = Display.getCurrent().getCursorLocation();
                java.awt.Color color = robot.getPixelColor(pos.x, pos.y);
                RGB rgbColor = new RGB(color.getRed(), color.getGreen(), color.getBlue());
                colorsSelector.setSelectedColor(rgbColor, false);
                updateText(rgbColor, rgbColor.getHSB(), null);
            } catch (AWTException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * Check if the passed controls or one of its children is focused 
     * 
     * @param controls 
     * @return true if a control in the searching set is focused, false if none 
     * control is focused
     */
    private boolean checkControlFocused(Control[] controls) {
        for (Control control : controls) {
            if (control.isFocusControl())
                return true;
            if (control instanceof Composite) {
                Composite comp = (Composite) control;
                boolean childrenFocused = checkControlFocused(comp.getChildren());
                if (childrenFocused)
                    return true;
            }
        }
        return false;
    }

    /**
     * Set the flag to close the color picker thread, remove the key listener
     * used to know when the thread should be stopped and restore the status 
     * of the button to restart the thread (so the user can restart it manually).
     */
    private void stopPickerThread() {
        colorPickerThread.setStop(true);
        if (!pickColorButton.isDisposed()) {
            pickColorButton.setText(""); //$NON-NLS-1$
            pickColorButton.setEnabled(true);
            GridData buttonData = new GridData();
            buttonData.widthHint = 50;
            buttonData.heightHint = 50;
            //pickColorButton.setImage(getPickerImage(24));
            pickColorButton.setLayoutData(buttonData);
            pickColorButton.getParent().layout(true, true);
        }
    }

    /**
     * Dispose the control and if it is still active stop the thread
     */
    @Override
    public void dispose() {
        super.dispose();
        PlatformUI.getWorkbench().getDisplay().removeFilter(org.eclipse.swt.SWT.KeyDown, spaceKeyListener);
        stopPickerThread();
    }

}