All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.tractionsoftware.gwt.user.client.ui.impl.UTCTimeBoxImplHtml4 Maven / Gradle / Ivy

There is a newer version: 5.8.4
Show newest version
/*
 * Copyright 2010 Traction Software, 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.tractionsoftware.gwt.user.client.ui.impl;

import java.util.Date;

import com.google.gwt.event.dom.client.BlurEvent;
import com.google.gwt.event.dom.client.BlurHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyDownEvent;
import com.google.gwt.event.dom.client.KeyDownHandler;
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.i18n.client.DateTimeFormat;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.TextBox;
import com.tractionsoftware.gwt.user.client.ui.UTCDateBox;

/**
 * HTML4 implementation of UTCTimeBox.
 *
 * 

* Time is represented as the number of milliseconds after midnight * independent of time zone. *

* *

* It will use the GWT DateTimeFormat to parse in the browser * timezone, but it will then convert the time to be independent of * timezone. *

* *

* It will first parse a manually typed date using the time format * specified (defaulting to TIME_SHORT). It will then attempt the * following formats in order: "hh:mm a", "hh:mma", "HH:mm". If all of * these fail, it will attempt to insert a colon in the right place * (e.g. 12 -> 12:00, 123 -> 1:23, and 1234 -> 12:34) and try the * specified time format and the fallback formats again. *

* *

* The control supports an unspecified value of null with a blank * textbox. *

* *

Code Source

* *

* This is external code that was copied into the CedarCommon codebase under * the terms of its license. *

* *
* * * * * * * * * * * * * * * *
Source:Traction Software
Date:July, 2014
Reason:The official Traction-supplied jar in Maven only supports Java 1.7+, but CedarCommon supports Java 1.6+.
*
* * @author Andy @ Traction Software */ public class UTCTimeBoxImplHtml4 extends UTCTimeBoxImplShared { private static final String CLASSNAME_INVALID = "invalid"; private TextBox textbox; private TimeBoxMenu menu; private Long lastKnownValue; /** * Keyboard handler for the TextBox shows and hides the menu, * scrolls through the menu, and accepts a value. */ private class TextBoxHandler implements KeyDownHandler, BlurHandler, ClickHandler { @Override public void onKeyDown(KeyDownEvent event) { switch (event.getNativeKeyCode()) { case KeyCodes.KEY_UP: menu.adjustHighlight(-1); break; case KeyCodes.KEY_DOWN: menu.adjustHighlight(1); break; case KeyCodes.KEY_ENTER: case KeyCodes.KEY_TAB: // accept current value if (menu.isShowing()) { menu.acceptHighlighted(); hideMenu(); clearInvalidStyle(); } else { // added a sync here because this is when we // accept the value we've typed if we're typing in // a new value. syncValueToText(); validate(); } break; case KeyCodes.KEY_ESCAPE: validate(); hideMenu(); break; default: hideMenu(); clearInvalidStyle(); break; } } @Override public void onBlur(BlurEvent event) { validate(); } @Override public void onClick(ClickEvent event) { showMenu(); } } /** * A single option is represented by an anchor in a div. */ private class TimeBoxMenuOption extends SimplePanel { private long offsetFromMidnight; private String value; public TimeBoxMenuOption(long offsetFromMidnight) { this.offsetFromMidnight = offsetFromMidnight; // format the time in the local time zone long time = UTCDateBox.timezoneOffsetMillis(new Date(0)) + offsetFromMidnight; value = timeFormat.format(new Date(time)); Anchor anchor = new Anchor(value); anchor.addClickHandler(new ClickHandler() { @Override public void onClick(ClickEvent event) { acceptValue(); hideMenu(); clearInvalidStyle(); } }); setWidget(anchor); } public void acceptValue() { setText(value); } public void setSelected(boolean isSelected) { setStyleName("selected", isSelected); } public void setHighlighted(boolean isHighlighted) { setStyleName("highlighted", isHighlighted); } private long getTime() { return offsetFromMidnight; } public boolean isTimeEqualTo(long time) { long compare = getTime(); return compare == time; } public boolean isTimeLessThan(long time) { return getTime() < time; } } /** * The menu is a div with a bunch of TimeBoxMenuOptions */ private class TimeBoxMenu extends PopupPanel { private static final long INTERVAL = 30 * 60 * 1000L; private static final long DAY = 24 * 60 * 60 * 1000L; private TimeBoxMenuOption[] options; private int highlightedOptionIndex = -1; public TimeBoxMenu() { super(true); setStyleName("gwt-TimeBox-menu"); addAutoHidePartner(textbox.getElement()); FlowPanel container = new FlowPanel(); int numOptions = (int) (DAY / INTERVAL); options = new TimeBoxMenuOption[numOptions]; // we need to use times for formatting, but we don't keep // them around. the purpose is only to generate text to // insert into the textbox. for (int i = 0; i < numOptions; i++) { options[i] = new TimeBoxMenuOption(i * INTERVAL); container.add(options[i]); } add(container); } /** * Moves the highlighted value * * @param distance * The number of values to move (typically -1 or 1 * for keyboard handling) */ public void adjustHighlight(int distance) { // make the list of times visible if it isn't if (!isShowing()) { showTimePicker(); } // highlight the new value int index = normalizeOptionIndex(highlightedOptionIndex + distance); setHighlightedIndex(index); scrollToIndex(index); } /** * Accepts the highlighted value */ public void acceptHighlighted() { if (hasHighlightedOption()) { options[highlightedOptionIndex].acceptValue(); } } /** * Returns true if there is an option currently highlighted */ private boolean hasHighlightedOption() { return (highlightedOptionIndex != -1); } /** * Normalizes the option index to be within the range * [0,options.length) */ private int normalizeOptionIndex(int index) { if (index < 0) { return 0; } else if (index >= options.length) { return options.length - 1; } else { return index; } } /** * Makes sure the specified index is visible using * scrollIntoView. */ public void scrollToIndex(int index) { options[normalizeOptionIndex(index)].getElement().scrollIntoView(); getContainerElement().setScrollLeft(0); } /** * Highlights the specified index. */ public void setHighlightedIndex(int index) { if (index != highlightedOptionIndex) { if (hasHighlightedOption()) { options[highlightedOptionIndex].setHighlighted(false); } highlightedOptionIndex = index; options[index].setHighlighted(true); scrollToIndex(index); } } /** * Displays the time picker (a.k.a. this menu). */ public void showTimePicker() { showRelativeTo(textbox); int lastOptionLessThanCurrentTime = 0; // reset while we try to find an option to highlight highlightedOptionIndex = -1; Long currentTime = getValue(); for (int i = 0; i < options.length; i++) { TimeBoxMenuOption option = options[i]; boolean isEqual = currentTime != null && option.isTimeEqualTo(currentTime); if (isEqual) { highlightedOptionIndex = i; } option.setSelected(isEqual); option.setHighlighted(isEqual); if (currentTime != null && option.isTimeLessThan(currentTime)) { lastOptionLessThanCurrentTime = i; } } int index; if (hasHighlightedOption()) { index = highlightedOptionIndex; } else { index = normalizeOptionIndex(lastOptionLessThanCurrentTime); } // include a little extra to center the current time setHighlightedIndex(index); scrollToIndex(index + 6); } } /** * Allows a UTCTimeBox to be created with a specified format. */ public UTCTimeBoxImplHtml4() { this.textbox = new TextBox(); TextBoxHandler handler = new TextBoxHandler(); textbox.addKeyDownHandler(handler); textbox.addBlurHandler(handler); textbox.addClickHandler(handler); textbox.setStyleName("gwt-TimeBox"); initWidget(textbox); } @Override public void setTimeFormat(DateTimeFormat timeFormat) { super.setTimeFormat(timeFormat); this.menu = new TimeBoxMenu(); } /** * Returns the TextBox on which this control is based. */ public TextBox getTextBox() { return textbox; } // ---------------------------------------------------------------------- // menu /** * Displays the time picker menu */ public void showMenu() { // make the menu visible and select the appropriate value menu.showTimePicker(); } /** * Hides the time picker menu */ public void hideMenu() { menu.hide(); } // ---------------------------------------------------------------------- // HasValue public boolean hasValue() { return getText().trim().length() > 0; } /** * A valid value is either empty (null) or filled with a valid * time. */ public boolean hasValidValue() { return !hasValue() || getValue() != null; } /** * Returns the time value (as milliseconds since midnight * independent of time zone) */ @Override public Long getValue() { return text2value(getText()); } /** * Sets the time value (as milliseconds since midnight independent * of time zone) */ @Override public void setValue(Long value, boolean fireEvents) { setValue(value, true, fireEvents); } protected void setValue(Long value, boolean updateTextBox, boolean fireEvents) { if (updateTextBox) { syncTextToValue(value); } // keep track of the last known value so that we only fire // when it's different. Long oldValue = lastKnownValue; lastKnownValue = value; if (fireEvents && !isSameValue(oldValue, value)) { ValueChangeEvent.fire(this, getValue()); } } protected boolean isSameValue(Long a, Long b) { return (a == null) ? (b == null) : a.equals(b); } @Override public HandlerRegistration addValueChangeHandler(ValueChangeHandler handler) { return addHandler(handler, ValueChangeEvent.getType()); } // ---------------------------------------------------------------------- // Interaction with the textbox @Override public String getText() { return textbox.getValue(); } @Override public void setText(String text) { textbox.setValue(text); syncValueToText(); } // ---------------------------------------------------------------------- // synchronization between text and value protected void syncTextToValue(Long value) { textbox.setValue(value2text(value)); } protected void syncValueToText() { setValue(text2value(getText()), false, true); } // ---------------------------------------------------------------------- // styling @Override public void validate() { boolean valid = true; if (hasValue()) { Long value = getValue(); if (value != null) { // scrub the value to format properly setText(value2text(value)); } else { // empty is ok and value != null ok, this is invalid valid = false; } } setStyleName(CLASSNAME_INVALID, !valid); } @Override public void setVisibleLength(int length) { textbox.setVisibleLength(length); } @Override public void setTabIndex(int tabIndex) { textbox.setTabIndex(tabIndex); } public void clearInvalidStyle() { removeStyleName(CLASSNAME_INVALID); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy