/* * Copyright 2008 Google Inc. * * 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 com.eas.widgets.progress; import com.eas.core.XElement; import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.Style; import com.google.gwt.event.logical.shared.ValueChangeEvent; import com.google.gwt.event.logical.shared.ValueChangeHandler; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.user.client.DOM; import com.google.gwt.user.client.ui.HasValue; import com.google.gwt.user.client.ui.RequiresResize; import com.google.gwt.user.client.ui.Widget; /** * A widget that displays progress on an arbitrary scale. * * <h3>CSS Style Rules</h3> * <ul class='css'> * <li>.gwt-ProgressBar-shell { primary style } </li> * <li>.gwt-ProgressBar-shell .gwt-ProgressBar-bar { the actual progress bar } * </li> * <li>.gwt-ProgressBar-shell .gwt-ProgressBar-text { text on the bar } </li> * <li>.gwt-ProgressBar-shell .gwt-ProgressBar-text-firstHalf { applied to text * when progress is less than 50 percent } </li> * <li>.gwt-ProgressBar-shell .gwt-ProgressBar-text-secondHalf { applied to text * when progress is greater than 50 percent } </li> * </ul> */ public class ProgressBar extends Widget implements RequiresResize, HasValue<Double> { /** * A formatter used to format the text displayed in the progress bar widget. */ public interface TextFormatter { /** * Generate the text to display in the ProgressBar based on the current * value. * * Override this method to change the text displayed within the * ProgressBar. * * @param bar the progress bar * @param curProgress the current progress * @return the text to display in the progress bar */ public String getText(ProgressBar bar, Double curProgress); } /** * The bar element that displays the progress. */ private Element barElement; /** * The current progress. */ private Double value; /** * The maximum progress. */ private double maxProgress; /** * The minimum progress. */ private double minProgress; /** * A boolean that determines if the text is visible. */ private boolean textVisible = true; /** * The element that displays text on the page. */ private Element textElement; /** * The current text formatter. */ private TextFormatter textFormatter; /** * Create a progress bar with default range of 0 to 100. */ public ProgressBar() { this(0.0, 100.0, 0.0); } /** * Create a progress bar with an initial progress and a default range of 0 * to 100. * * @param aValue the current progress */ public ProgressBar(Double aValue) { this(0.0, 100.0, aValue); } /** * Create a progress bar within the given range. * * @param aMinProgress the minimum progress * @param aMaxProgress the maximum progress */ public ProgressBar(double aMinProgress, double aMaxProgress) { this(aMinProgress, aMaxProgress, 0.0); } /** * Create a progress bar within the given range starting at the specified * progress amount. * * @param aMinProgress the minimum progress * @param aMaxProgress the maximum progress * @param aValue the current progress */ public ProgressBar(double aMinProgress, double aMaxProgress, Double aValue) { this(aMinProgress, aMaxProgress, aValue, null); } /** * Create a progress bar within the given range starting at the specified * progress amount. * * @param aMinProgress the minimum progress * @param aMaxProgress the maximum progress * @param aValue the current progress * @param aTextFormatter the text formatter */ public ProgressBar(double aMinProgress, double aMaxProgress, Double aValue, TextFormatter aTextFormatter) { super(); minProgress = aMinProgress; maxProgress = aMaxProgress; value = aValue; setTextFormatter(aTextFormatter); // Create the outer shell setElement(Document.get().createDivElement()); getElement().getStyle().setDisplay(Style.Display.INLINE_BLOCK); getElement().getStyle().setPosition(Style.Position.RELATIVE); // default preferred size getElement().getStyle().setWidth(150, Style.Unit.PX); getElement().getStyle().setHeight(16, Style.Unit.PX); setStyleName("gwt-ProgressBar-shell"); // Create the bar element barElement = DOM.createDiv(); getElement().appendChild(barElement); barElement.getStyle().setHeight(100, Style.Unit.PCT); barElement.setClassName("gwt-ProgressBar-bar"); // Create the text element textElement = DOM.createDiv(); DOM.appendChild(getElement(), textElement); textElement.getStyle().setPosition(Style.Position.ABSOLUTE); textElement.getStyle().setTop(0, Style.Unit.PX); textElement.setClassName("gwt-ProgressBar-text"); // Set the current progress setValue(aValue); getElement().<XElement>cast().addResizingTransitionEnd(this); } /** * Get the maximum progress. * * @return the maximum progress */ public double getMaxProgress() { return maxProgress; } /** * Get the minimum progress. * * @return the minimum progress */ public double getMinProgress() { return minProgress; } /** * Get the current percent complete, relative to the minimum and maximum * values. The percent will always be between 0.0 - 1.0. * * @return the current percent complete */ public double getPercent() { // If we have no range if (maxProgress <= minProgress) { return 0.0; } // Calculate the relative progress double percent = ((value != null ? value : 0) - minProgress) / (maxProgress - minProgress); return Math.max(0.0, Math.min(1.0, percent)); } /** * Get the current progress. * * @return the current progress */ @Override public Double getValue() { return value; } /** * Get the text formatter. * * @return the text formatter */ public TextFormatter getTextFormatter() { return textFormatter; } /** * Check whether the text is visible or not. * * @return true if the text is visible */ public boolean isTextVisible() { return textVisible; } /** * This method is called when the dimensions of the parent element change. * Subclasses should override this method as needed. * * Move the text to the center of the progress bar. * */ @Override public void onResize() { if (textVisible) { int width = getElement().getClientWidth(); int height = getElement().getClientHeight(); int textWidth = textElement.getOffsetWidth(); int textHeight = textElement.getOffsetHeight(); int left = (width / 2) - (textWidth / 2); textElement.getStyle().setLeft(left, Style.Unit.PX); textElement.getStyle().setTop((height - textHeight) / 2, Style.Unit.PX); } } /** * Redraw the progress bar when something changes the layout. */ public void redraw() { if (isAttached()) { onResize(); } } /** * Set the maximum progress. If the minimum progress is more than the * current progress, the current progress is adjusted to be within the new * range. * * @param aValue the maximum progress */ public void setMaxProgress(double aValue) { maxProgress = aValue; value = Math.min((value != null ? value : 0), aValue); resetProgress(); } /** * Set the minimum progress. If the minimum progress is more than the * current progress, the current progress is adjusted to be within the new * range. * * @param aValue the minimum progress */ public void setMinProgress(double aValue) { minProgress = aValue; value = Math.max((value != null ? value : 0), aValue); resetProgress(); } /** * Set the current progress. * * @param aValue the current aValue */ @Override public void setValue(Double aValue) { setValue(aValue, false); } /** * Set the current progress. * * @param aValue the current aValue * @param fireEvents */ @Override public void setValue(Double aValue, boolean fireEvents) { value = aValue != null ? Math.max(minProgress, Math.min(maxProgress, aValue)) : null; // Calculate percent complete int percent = (int) (100 * getPercent()); barElement.getStyle().setWidth(percent, Style.Unit.PCT); textElement.setInnerHTML(generateText(value)); // Set the style depending on the size of the bar if (percent < 50) { textElement.removeClassName("gwt-ProgressBar-text-secondHalf"); textElement.addClassName("gwt-ProgressBar-text-firstHalf"); } else { textElement.removeClassName("gwt-ProgressBar-text-firstHalf"); textElement.addClassName("gwt-ProgressBar-text-secondHalf"); } // Realign the text redraw(); if (fireEvents) { ValueChangeEvent.fire(ProgressBar.this, getValue()); } } @Override public HandlerRegistration addValueChangeHandler(ValueChangeHandler<Double> handler) { return addHandler(handler, ValueChangeEvent.getType()); } /** * Set the text formatter. * * @param aFormatter the text formatter */ public void setTextFormatter(TextFormatter aFormatter) { textFormatter = aFormatter; if(isAttached()){ setValue(getValue()); } } /** * Sets whether the text is visible over the bar. * * @param aValue True to show text, false to hide it */ public void setTextVisible(boolean aValue) { textVisible = aValue; if (textVisible) { textElement.getStyle().clearDisplay(); redraw(); } else { textElement.getStyle().setDisplay(Style.Display.NONE); } } /** * Generate the text to display within the progress bar. Override this * function to change the default progress percent to a more informative * message, such as the number of kilobytes downloaded. * * @param curProgress the current progress * @return the text to display in the progress bar */ protected String generateText(Double curProgress) { if (textFormatter != null) { return textFormatter.getText(this, curProgress); } else { return (int) (100 * getPercent()) + "%"; } } /** * Get the bar element. * * @return the bar element */ protected Element getBarElement() { return barElement; } /** * Get the text element. * * @return the text element */ protected Element getTextElement() { return textElement; } @Override protected void onAttach() { super.onAttach(); redraw(); } /** * Reset the progress text based on the current min and max progress range. */ protected void resetProgress() { setValue(getValue()); } }