org.eclipse.ice.client.widgets.moose.CheckboxCellContentProvider.java Source code

Java tutorial

Introduction

Here is the source code for org.eclipse.ice.client.widgets.moose.CheckboxCellContentProvider.java

Source

/*******************************************************************************
 * Copyright (c) 2014 UT-Battelle, LLC.
 * All rights reserved. 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
 *
 * Contributors:
 *   Initial API and implementation and/or initial documentation - Jay Jay Billings,
 *   Jordan H. Deyton, Dasha Gorin, Alexander J. McCaskey, Taylor Patterson,
 *   Claire Saunders, Matthew Wang, Anna Wojtowicz
 *******************************************************************************/
package org.eclipse.ice.client.widgets.moose;

import java.util.concurrent.atomic.AtomicBoolean;

import org.eclipse.ice.client.common.properties.IButtonCellContentProvider;
import org.eclipse.ice.client.common.properties.ICellContentProvider;
import org.eclipse.ice.client.common.properties.TreeProperty;
import org.eclipse.ice.client.common.properties.TreePropertyCellContentProvider;
import org.eclipse.ice.datastructures.entry.IEntry;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.ColumnViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

/**
 * This class provides an {@link ICellContentProvider} for cells that display a
 * checkbox <code>Button</code>.
 * <p>
 * <b>Note:</b> There is a limitation with embedding SWT widgets in a
 * <code>TableViewer</code>. In particular, performance decreases due to the
 * number of widgets that may be involved. This class uses a workaround by
 * creating images for each state of a checkbox <code>Button</code>. The states
 * are determined by combining enabled/disabled and selected/unselected (or
 * checked/unchecked). The four {@link Image}s are registered with the JFace
 * {@link ImageRegistry} and placed in each cell that is not currently being
 * edited.
 * </p>
 * 
 * @author Jordan H. Deyton
 * 
 */
public class CheckboxCellContentProvider extends TreePropertyCellContentProvider
        implements IButtonCellContentProvider {

    /**
     * Whether or not the platform-specific checkbox images have been generated
     * and registered with the JFace <code>ImageRegistry</code>.
     */
    private static final AtomicBoolean IMAGES_REGISTERED = new AtomicBoolean(false);
    /**
     * The JFace <code>ImageRegistry</code> key for the enabled and checked
     * checkbox <code>Image</code>.
     */
    private static final String ENABLED_CHECKED = "ENABLED_CHECKED";
    /**
     * The JFace <code>ImageRegistry</code> key for the enabled and unchecked
     * checkbox <code>Image</code>.
     */
    private static final String ENABLED_UNCHECKED = "ENABLED_UNCHECKED";
    /**
     * The JFace <code>ImageRegistry</code> key for the disabled and checked
     * checkbox <code>Image</code>.
     */
    private static final String DISABLED_CHECKED = "DISABLED_CHECKED";
    /**
     * The JFace <code>ImageRegistry</code> key for the disabled and unchecked
     * checkbox <code>Image</code>.
     */
    private static final String DISABLED_UNCHECKED = "DISABLED_UNCHECKED";

    /**
     * The default constructor.
     * 
     * @param viewer
     *            The viewer whose contents are managed by this provider.
     */
    public CheckboxCellContentProvider(ColumnViewer viewer) {

        // Make sure the checkbox Images have been registered before calls to
        // getImage(Object).
        registerImages(viewer.getControl().getDisplay(), viewer.getControl().getBackground());

        return;
    }

    /**
     * The cell is enabled if the {@link TreeProperty}'s {@link Entry} is
     * required, otherwise it is disabled.
     */
    @Override
    public boolean isEnabled(Object element) {
        return isValid(element) && !((TreeProperty) element).getEntry().isRequired();
    }

    /**
     * The cell is selected if its {@link TreeProperty}'s {@link Entry}'s tag is
     * set to "true", false otherwise.
     */
    @Override
    public boolean isSelected(Object element) {
        return (Boolean) getValue(element);
    }

    /**
     * Override the default tool tip to provide information about being enabled
     * or disabled.
     */
    @Override
    public String getToolTipText(Object element) {
        String tooltip;

        if (isSelected(element)) {
            tooltip = "This parameter is enabled.\n" + "It will be included in the input file.";
        } else {
            tooltip = "This parameter is disabled.\n" + "It will be commented out in the input file.";
        }

        return tooltip;
    }

    /**
     * Provides a checkbox <code>Image</code> depending on whether the cell is
     * enabled/disabled and selected/unselected.
     */
    @Override
    public Image getImage(Object element) {
        Image image = null;

        // Depending on whether or not the element is checked and enabled, set
        // its image.
        if (isEnabled(element)) {
            if (isSelected(element)) {
                image = JFaceResources.getImage(ENABLED_CHECKED);
            } else {
                image = JFaceResources.getImage(ENABLED_UNCHECKED);
            }
        } else if (isSelected(element)) {
            image = JFaceResources.getImage(DISABLED_CHECKED);
        } else {
            image = JFaceResources.getImage(DISABLED_UNCHECKED);
        }

        return image;
    }

    /**
     * Returns true if the element is valid and the {@link TreeProperty}'s
     * {@link Entry}'s tag is not "false" (case ignored), false otherwise.
     */
    @Override
    public Object getValue(Object element) {

        // First, check that the element is valid.
        boolean isSelected = isValid(element);

        // If the element is valid, we should mark the flag as false only if the
        // tag is some variation of "false" (case ignored).
        if (isSelected) {
            String tag = ((TreeProperty) element).getEntry().getTag();
            isSelected = tag == null || !"false".equals(tag.trim().toLowerCase());
        }

        return isSelected;
    }

    /**
     * Sets the {@link TreeProperty}'s {@link Entry}'s tag to "true" if the
     * value is true and "false" otherwise.
     */
    @Override
    public boolean setValue(Object element, Object value) {

        boolean changed = false;

        if (isValid(element) && value != null) {
            String newValue = ((Boolean) value).toString();
            IEntry entry = ((TreeProperty) element).getEntry();
            // If the value has changed, mark the changed flag and set the new
            // value.
            if (changed = !newValue.equals(entry.getTag())) {
                entry.setTag(newValue);
            }
        }

        return changed;
    }

    /**
     * If the enabled/disabled checked/unchecked checkbox <code>Image</code>s
     * have not already been created and added to the JFace
     * <code>ImageRegistry</code>, this method generates and registers them.
     * This produces platform-specific images at run-time.
     * 
     * @param display
     *            The <code>Display</code> shared with the underlying
     *            <code>ColumnViewer</code>.
     * @param background
     *            The background of the <code>ColumnViewer</code>'s cells.
     */
    private static void registerImages(final Display display, Color background) {

        if (display != null && IMAGES_REGISTERED.compareAndSet(false, true)) {

            // Get the ImageRegistry for JFace images. We will load up images
            // for each combination of checkbox enabled/disabled and
            // checked/unchecked.
            ImageRegistry jfaceImages = JFaceResources.getImageRegistry();

            // Create a temporary shell and checkbox Button to generate
            // platform-specific images of checkboxes.
            Shell shell = new Shell(display, SWT.NO_TRIM);
            Button checkbox = new Button(shell, SWT.CHECK);

            // Set the widget's background to the viewer's cell background.
            checkbox.setBackground(background);

            // Reduce the size of the shell to a square (checkboxes are supposed
            // to be square!!!).
            Point size = checkbox.computeSize(SWT.DEFAULT, SWT.DEFAULT);
            // int width = Math.min(size.x, size.y);
            checkbox.setSize(size);
            // checkbox.setLocation(width - size.x, width - size.y);
            // shell.setSize(width, width);
            shell.setSize(size);

            // Open the shell to enable widget drawing.
            shell.open();

            // Create the enabled/unchecked image.
            jfaceImages.put(ENABLED_UNCHECKED, createImage(checkbox));
            // Create the enabled/checked image.
            checkbox.setSelection(true);
            jfaceImages.put(ENABLED_CHECKED, createImage(checkbox));
            // Create the disabled/checked image.
            checkbox.setEnabled(false);
            jfaceImages.put(DISABLED_CHECKED, createImage(checkbox));
            // Create the disabled/unchecked image.
            checkbox.setSelection(false);
            jfaceImages.put(DISABLED_UNCHECKED, createImage(checkbox));

            // Release any remaining resources.
            // gc.dispose();
            shell.close();
        }

        return;
    }

    /**
     * Creates an <code>Image</code> from the specified <code>Control</code>
     * (widget).
     * 
     * @param control
     *            The <code>Control</code> to convert to an <code>Image</code>.
     * @return An <code>Image</code> of the specified <code>Control</code>.
     */
    private static Image createImage(Control control) {

        // We have to create a separate Image per combination of
        // checked/unchecked (of course). We also have to create a single GC per
        // Image (not so obvious, but re-using them does not appear to work well
        // and does not sync with the UI thread properly, so you get the same
        // image multiple times [but not all the time]).

        Image image = new Image(control.getDisplay(), control.getBounds());
        GC gc = new GC(image);
        control.print(gc);
        gc.dispose();

        return image;
    }

}