org.vaadin.alump.distributionbar.DistributionBar.java Source code

Java tutorial

Introduction

Here is the source code for org.vaadin.alump.distributionbar.DistributionBar.java

Source

/**
 * DistributionBar.java (DistributionBar)
 * 
 * Copyright 2012 Vaadin Ltd, Sami Viitanen <alump@vaadin.org>
 *
 * 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.
 */
package org.vaadin.alump.distributionbar;

import java.util.LinkedList;
import java.util.List;

import org.vaadin.alump.distributionbar.gwt.client.connect.DistributionBarServerRpc;
import org.vaadin.alump.distributionbar.gwt.client.shared.DistributionBarState;
import org.vaadin.alump.distributionbar.gwt.client.shared.DistributionBarState.Part;

import com.vaadin.ui.AbstractComponent;

/**
 * Server side component for the VDistributionBar widget. Distribution Bar is
 * simple graphical bar that can be used to show distribution of items between
 * different groups. For example distribution of YES and NO votes. Bar must have
 * at least two values, but there is not any upper limit. Layout where bar is
 * used can limit the amount of parts that will fit to screen.
 */
@SuppressWarnings("serial")
public class DistributionBar extends AbstractComponent implements DistributionBarServerRpc {

    private List<DistributionBarClickListener> clickListeners = new LinkedList<DistributionBarClickListener>();

    public interface DistributionBarClickListener {
        void onItemClicked(int index);
    }

    /**
     * Will make distribution bar with 2 parts (size value zero).
     */
    public DistributionBar() {
        this(2);
    }

    /**
     * Generate distribution bar with given number of parts. All parts created
     * will get the default size value: zero.
     * 
     * @param numberOfParts
     *            Number of parts. Must be 1 or more.
     */
    public DistributionBar(int numberOfParts) {

        if (numberOfParts < 1) {
            throw new IllegalArgumentException(
                    "Distribution bar must have at least one part: " + numberOfParts + " parts given");
        }

        registerRpc(this);
        for (int i = 0; i < numberOfParts; ++i) {
            getState().getParts().add(new Part());
        }

    }

    /**
     * Create new distribution bar and define sizes for all parts
     * 
     * @param sizes
     *            Part sizes in integer array. Must have at least 2 sizes. If
     *            less two parts are made with size zero.
     */
    public DistributionBar(final int[] sizes) {

        this(sizes.length);

        this.updatePartSizes(sizes);
    }

    @Override
    public DistributionBarState getState() {
        return (DistributionBarState) super.getState();
    }

    /**
     * Update multiple sizes once. If given list is smaller than number of parts
     * then parts at the end will not be updated. If given list has more sizes
     * than there is parts, then rest of the sizes are ignored.
     * 
     * @param partSizes
     *            Sizes in integer array
     */
    public void updatePartSizes(int[] partSizes) {
        for (int i = 0; i < getNumberOfParts() && i < partSizes.length; ++i) {
            getState().getParts().get(i).setSize(partSizes[i]);
        }
    }

    /**
     * Setup part by defining both size and tooltip with one command
     * 
     * @param index
     *            Index of part [0..N]. Only give valid indexes.
     * @param size
     *            Size as integer number
     * @param tooltip
     *            Tooltip content is XHTML
     */
    public void setupPart(int index, int size, String tooltip) {
        setupPart(index, size, tooltip, null);
    }

    /**
     * Setup part by defining size, tooltip and style name with one command
     *
     * @param index
     *            Index of part [0..N]. Only give valid indexes.
     * @param size
     *            Size as integer number
     * @param tooltip
     *            Tooltip content is XHTML
     * @param styleName
     *            Stylename added to part
     */
    public void setupPart(int index, int size, String tooltip, String styleName) {

        Part part = getState().getParts().get(index);
        part.setSize(size);
        part.setTooltip(tooltip);
        part.setTooltip(styleName);
    }

    /**
     * Change size of given part
     * 
     * @param index
     *            Index of part [0..N]. Only give valid indexes.
     * @param size
     *            Size as integer number
     */
    public void setPartSize(int index, int size) {
        getState().getParts().get(index).setSize(size);
    }

    /**
     * Change title of given part. This is normal HTML title attribute. For many
     * use cases tooltip is better option.
     * 
     * @param index
     *            Index of part [0..N]. Only give valid indexes.
     * @param title
     *            Title for part
     */
    public void setPartTitle(int index, String title) {
        getState().getParts().get(index).setTitle(title);
    }

    /**
     * Change tooltip of given part.
     * 
     * @param index
     *            Index of part [0..N]. Only give valid indexes.
     * @param tooltip
     *            Content of tooltip (empty is do not show tooltip). Content is
     *            given in XHTML format.
     */
    public void setPartTooltip(int index, String tooltip) {
        getState().getParts().get(index).setTooltip(tooltip);
    }

    /**
     * Change stylename of given part.
     *
     * @param index
     *            Index of part [0..N]. Only give valid indexes.
     * @param styleName
     *            Style name of part
     */
    public void setPartStyleName(int index, String styleName) {
        getState().getParts().get(index).setStyleName(styleName);
    }

    /**
     * Get number of parts in distribution bar
     * 
     * @return Number of parts in distribution bar
     */
    public int getNumberOfParts() {
        return getState().getParts().size();
    }

    private void changeStatePartsSize(int newSize) {

        while (getState().getParts().size() < newSize) {
            getState().getParts().add(new Part());
        }
        while (getState().getParts().size() > newSize) {
            getState().getParts().remove(newSize);
        }
    }

    /**
     * Change number of parts in distribution bar.
     * 
     * @param numberOfParts
     *            New number of parts. If this is different than earlier number
     *            of parts then all parts will be initialized to default state
     *            with size zero. If given value is less than 2 it will be
     *            converted to two.
     */
    public void setNumberOfParts(int numberOfParts) {
        if (numberOfParts > 1 && getNumberOfParts() != numberOfParts) {
            changeStatePartsSize(numberOfParts);
        }
    }

    @Override
    public void onItemClicked(int index) {
        for (DistributionBarClickListener listener : clickListeners) {
            listener.onItemClicked(index);
        }
    }

    /**
     * Add click listener
     * @param listener Listener added to listeners
     */
    public void addDistributionBarClickListener(DistributionBarClickListener listener) {

        if (clickListeners.isEmpty()) {
            getState().sendClicks = true;
        }

        clickListeners.add(listener);
    }

    /**
     * Remove click listener
     * @param listener Listener removed from listeners
     */
    public void removeDistributionBarClickListener(DistributionBarClickListener listener) {
        clickListeners.remove(listener);

        if (clickListeners.isEmpty()) {
            getState().sendClicks = false;
        }
    }

    /**
     * Define if parts with size 0 should still be shown in distribution bar
     * @param zeroVisible true if zero sized are shown, false if shrunk to invisible
     */
    public void setZeroSizedVisible(boolean zeroVisible) {
        getState().zeroVisible = zeroVisible;
    }

    /**
     * See if zero sized parts are shown or shrunk to invisible
     * @return true if zero sized are shown, false if shrunk to invisible
     */
    public boolean isZeroSizedVisible() {
        return getState().zeroVisible;
    }

    /**
     * Define minimum with of part with value. Experimental API!
     * @deprecated Experimental API!
     * @param pixels With in pixels.
     */
    @Deprecated
    public void setMinPartWidth(double pixels) {
        getState().minWidth = pixels;
    }

    /**
     * Get minimum width of part with value. Experimental API!
     * @deprecated Experimental API!
     * @return Minimum with of part in pixels.
     */
    @Deprecated
    public double getMinPartWidth() {
        return getState().minWidth;
    }
}