Java tutorial
/** Exhibit A - UIRF Open-source Based Public Software License. * * The contents of this file are subject to the UIRF Open-source Based * Public Software License(the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * openelis.uhl.uiowa.edu * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * * The Original Code is OpenELIS code. * * The Initial Developer of the Original Code is The University of Iowa. * Portions created by The University of Iowa are Copyright 2006-2008. All * Rights Reserved. * * Contributor(s): ______________________________________. * * Alternatively, the contents of this file marked * "Separately-Licensed" may be used under the terms of a UIRF Software * license ("UIRF Software License"), in which case the provisions of a * UIRF Software License are applicable instead of those above. */ package org.openelis.ui.widget.calendar; import java.util.ArrayList; import org.openelis.ui.common.Datetime; import org.openelis.ui.common.Exceptions; import org.openelis.ui.common.Util; import org.openelis.ui.common.data.QueryData; import org.openelis.ui.messages.Messages; import org.openelis.ui.messages.UIMessages; import org.openelis.ui.resources.CalendarCSS; import org.openelis.ui.resources.UIResources; import org.openelis.ui.widget.Balloon; import org.openelis.ui.widget.DateHelper; import org.openelis.ui.widget.HasExceptions; import org.openelis.ui.widget.HasHelper; import org.openelis.ui.widget.HasBalloon; import org.openelis.ui.widget.Queryable; import org.openelis.ui.widget.ScreenWidgetInt; import org.openelis.ui.widget.TextBase; import org.openelis.ui.widget.WidgetHelper; import org.openelis.ui.widget.Balloon.Placement; import org.openelis.ui.widget.datetimepicker.DatetimePicker; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.shared.GWT; import com.google.gwt.dom.client.Style.Cursor; 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.FocusEvent; import com.google.gwt.event.dom.client.FocusHandler; import com.google.gwt.event.dom.client.HasBlurHandlers; import com.google.gwt.event.dom.client.HasFocusHandlers; 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.dom.client.KeyUpEvent; import com.google.gwt.event.dom.client.KeyUpHandler; import com.google.gwt.event.dom.client.MouseDownEvent; import com.google.gwt.event.dom.client.MouseOutEvent; import com.google.gwt.event.dom.client.MouseOutHandler; import com.google.gwt.event.dom.client.MouseOverEvent; import com.google.gwt.event.dom.client.MouseOverHandler; import com.google.gwt.event.logical.shared.CloseEvent; import com.google.gwt.event.logical.shared.CloseHandler; 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.uibinder.client.UiBinder; import com.google.gwt.uibinder.client.UiChild; import com.google.gwt.uibinder.client.UiField; import com.google.gwt.uibinder.client.UiHandler; import com.google.gwt.uibinder.client.UiTemplate; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.FocusPanel; import com.google.gwt.user.client.ui.Focusable; import com.google.gwt.user.client.ui.HasValue; import com.google.gwt.user.client.ui.LayoutPanel; import com.google.gwt.user.client.ui.PopupPanel; import com.google.gwt.user.client.ui.ValueBoxBase.TextAlignment; import com.google.gwt.user.client.ui.Widget; /** * This class extends the TextBox<Datetime> and adds a button for using the * CalendarWidget to pick Dates. * */ public class Calendar extends Composite implements ScreenWidgetInt, Queryable, Focusable, HasBlurHandlers, HasFocusHandlers, HasValue<Datetime>, HasHelper<Datetime>, HasExceptions, HasBalloon { @UiTemplate("Select.ui.xml") interface CalendarUiBinder extends UiBinder<Widget, Calendar> { }; public static final CalendarUiBinder uiBinder = GWT.create(CalendarUiBinder.class); /** * Used for Calendar display */ @UiField protected LayoutPanel display; @UiField protected FocusPanel button; protected PopupPanel popup; protected DatetimePicker picker; protected int width; protected boolean showingCalendar, queryMode, required; @UiField protected TextBase textbox; protected Datetime value; protected WidgetHelper<Datetime> helper = new DateHelper(); final Calendar source; /** * Exceptions list */ protected Exceptions exceptions; protected Balloon.Options options; protected CalendarCSS css; /** * Default no-arg constructor */ public Calendar() { source = this; final KeyboardHandler keyHandler = new KeyboardHandler(); initWidget(uiBinder.createAndBindUi(this)); /* * Set the focus style when the Focus event is fired Externally */ addFocusHandler(new FocusHandler() { public void onFocus(FocusEvent event) { if (isEnabled()) { display.addStyleName(css.Focus()); textbox.selectAll(); } } }); /* * Removes the focus style when the Blue event is fires externally */ addBlurHandler(new BlurHandler() { public void onBlur(BlurEvent event) { display.removeStyleName(css.Focus()); finishEditing(true); } }); exceptions = new Exceptions(); addHandler(keyHandler, KeyDownEvent.getType()); setCSS(UIResources.INSTANCE.calendar()); setWidth("90px"); } @UiHandler("textbox") public void onFocus(FocusEvent event) { FocusEvent.fireNativeEvent(event.getNativeEvent(), this); } @UiHandler("textbox") public void onBlur(BlurEvent event) { display.removeStyleName(css.Focus()); if (!showingCalendar && isEnabled()) BlurEvent.fireNativeEvent(event.getNativeEvent(), this); } @UiHandler("button") public void onClick(ClickEvent event) { textbox.setFocus(true); showPopup(); } @UiHandler("button") public void onMouseDown(MouseDownEvent event) { showingCalendar = true; } public String getText() { return textbox.getText(); } public void setText(String text) { textbox.setText(text); } /** * This method will initialize and show the popup panel for this widget. */ protected void showPopup() { Datetime time = null; showingCalendar = true; if (popup == null) { popup = new PopupPanel(true); popup.setStyleName(css.Popup()); popup.setPreviewingAllNativeEvents(false); popup.addCloseHandler(new CloseHandler<PopupPanel>() { public void onClose(final CloseEvent<PopupPanel> event) { showingCalendar = false; Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() { public void execute() { setText(helper.format(picker.getDatetime())); if (event.isAutoClosed()) setFocus(true); } }); } }); } try { time = helper.getValue(textbox.getText()); } catch (Exception e) { time = null; } if (picker == null) { picker = new DatetimePicker(((DateHelper) helper).getBegin(), ((DateHelper) helper).getEnd(), time); popup.setWidget(picker); } else picker.setDatetime(time); popup.showRelativeTo(source); } @Override public void setWidth(String w) { width = Util.stripUnits(w); if (display != null) { display.setWidth(w); } } public int getWidth() { return width; } @Override public void setHeight(String height) { display.setHeight(height); button.setHeight(height); } /** * This private class will handle key events for this widget * * @author tschmidt * */ private class KeyboardHandler implements KeyDownHandler { public void onKeyDown(KeyDownEvent event) { switch (event.getNativeKeyCode()) { case KeyCodes.KEY_ENTER: showPopup(); break; case KeyCodes.KEY_TAB: if (showingCalendar) { setText(helper.format(picker.getDatetime())); popup.hide(); } } } } /** * Overridden method from TextBox for enabling and disabling the widget */ @Override public void setEnabled(boolean enabled) { textbox.enforceMask(enabled && !queryMode); textbox.setReadOnly(!enabled); if (enabled) { sinkEvents(Event.ONKEYDOWN | Event.ONKEYUP); button.sinkEvents(Event.ONCLICK); button.getElement().getStyle().setCursor(Cursor.POINTER); } else { unsinkEvents(Event.ONKEYDOWN | Event.ONKEYUP); button.unsinkEvents(Event.ONCLICK); button.getElement().getStyle().setCursor(Cursor.AUTO); } } /** * Overridden method from TextBox for setting the Exception style. */ @Override public void addExceptionStyle() { if (Balloon.isWarning(this)) addStyleName(css.InputWarning()); else addStyleName(css.InputError()); } /** * Overridden method from TextBox for removing the Exception style. */ @Override public void removeExceptionStyle() { removeStyleName(css.InputError()); removeStyleName(css.InputWarning()); } @Override public void setHelper(WidgetHelper<Datetime> helper) { DateHelper dh; this.helper = helper; setDefaultMask(); } public void setPrecision(byte begin, byte end) { assert (begin < end) : "Precsion in wrong order"; ((DateHelper) getHelper()).setBegin(begin); ((DateHelper) getHelper()).setEnd(end); picker = null; setDefaultMask(); } public void setBegin(int begin) { ((DateHelper) getHelper()).setBegin((byte) begin); picker = null; setDefaultMask(); } public void setEnd(int end) { ((DateHelper) getHelper()).setEnd((byte) end); picker = null; setDefaultMask(); } public int getBegin() { return ((DateHelper) helper).getBegin(); } public int getEnd() { return ((DateHelper) helper).getEnd(); } private void setDefaultMask() { DateHelper dh; dh = (DateHelper) getHelper(); /* * Setting default mask based on precision of helper * internationalized mask pictures should be set from * xsl, but defaults are provided if none set. */ if (dh.getBegin() > Datetime.DAY) { textbox.setMask(getMessages().gen_timeMask()); setWidth("60px"); } else if (dh.getEnd() < Datetime.HOUR) { textbox.setMask(getMessages().gen_dateMask()); setWidth("90px"); } else { textbox.setMask(getMessages().gen_dateTimeMask()); setWidth("125px"); } } /** * Returns the current value for this widget. */ public Datetime getValue() { return value; } /** * Sets the current value of this widget without firing the * ValueChangeEvent. */ public void setValue(Datetime value) { setValue(value, false); } /** * Sets the current value of this widget and will fire a ValueChangeEvent if * the value is different than what is currently stored. */ public void setValue(Datetime value, boolean fireEvents) { boolean diff; diff = Util.isDifferent(this.value, value); this.value = value; textbox.setText(helper.format(value)); clearValidateExceptions(); if (fireEvents && diff) ValueChangeEvent.fire(this, value); } /** * This method is made available so the Screen can on commit make sure all * required fields are entered without having the user visit each widget on * the screen. */ public void finishEditing() { finishEditing(false); } /** * This method will call the Helper to get the T value from the entered * string input. if invalid input is entered, Helper is expected to throw an * en exception and that exception will be added to the validate exceptions * list. * * @param fireEvents */ protected void finishEditing(boolean fireEvents) { String text; if (isEnabled()) { if (queryMode) { validateQuery(); } else { text = textbox.getText(); clearValidateExceptions(); try { setValue(helper.getValue(text), fireEvents); if (required && value == null) addValidateException(new Exception(getMessages().exc_fieldRequired())); } catch (Exception e) { addValidateException(e); } Balloon.checkExceptionHandlers(this); } } } /** * Method used to validate the inputed query string by the user. */ public void validateQuery() { try { clearValidateExceptions(); helper.validateQuery(textbox.getText()); } catch (Exception e) { addValidateException(e); } Balloon.checkExceptionHandlers(this); } // ********** Implementation of HasException interface *************** /** * Convenience method to check if a widget has exceptions so we do not need * to go through the cost of merging the logical and validation exceptions * in the getExceptions method. * * @return */ public boolean hasExceptions() { if (getValidateExceptions() != null) return true; if (!queryMode && required && getValue() == null) { addValidateException(new Exception(Messages.get().exc_fieldRequired())); Balloon.checkExceptionHandlers(this); } return getEndUserExceptions() != null || getValidateExceptions() != null; } /** * Adds a manual Exception to the widgets exception list. */ public void addException(Exception error) { exceptions.addException(error); Balloon.checkExceptionHandlers(this); } protected void addValidateException(Exception error) { exceptions.addValidateException(error); } /** * Combines both exceptions list into a single list to be displayed on the * screen. */ public ArrayList<Exception> getValidateExceptions() { return exceptions.getValidateExceptions(); } public ArrayList<Exception> getEndUserExceptions() { return exceptions.getEndUserExceptions(); } /** * Clears all manual and validate exceptions from the widget. */ public void clearExceptions() { exceptions.clearExceptions(); removeExceptionStyle(); Balloon.clearExceptionHandlers(this); } public void clearEndUserExceptions() { exceptions.clearEndUserExceptions(); Balloon.checkExceptionHandlers(this); } public void clearValidateExceptions() { exceptions.clearValidateExceptions(); Balloon.checkExceptionHandlers(this); } // ************* Implementation of Focusable ****************** /** * Method only implemented to satisfy Focusable interface. */ public int getTabIndex() { return -1; } /** * Method only implemented to satisfy Focusable interface. */ public void setTabIndex(int index) { } /** * Method only implemented to satisfy Focusable interface. */ public void setAccessKey(char key) { } /** * Exposing this method on the wrapped widget */ public void selectAll() { textbox.selectAll(); } /** * Exposing this method on the wrapped widget */ public void setSelectionRange(int pos, int length) { textbox.setSelectionRange(pos, length); } /** * Exposing this method on the wrapped widget */ public void unselectAll() { textbox.setSelectionRange(0, 0); } public void setMask(String mask) { textbox.setMask(mask); } /** * This is need for Focusable interface and to allow programmatic setting of * focus to this widget. We use the wrapped TextBox to make this work. */ public void setFocus(boolean focused) { textbox.setFocus(true); } // ************ Handler Registration methods ********************* /** * The Screen will add its screenHandler here to register for the * onValueChangeEvent */ public HandlerRegistration addValueChangeHandler(ValueChangeHandler<Datetime> handler) { return addHandler(handler, ValueChangeEvent.getType()); } /** * This Method is here so the Focus logic of ScreenPanel can be notified */ public HandlerRegistration addBlurHandler(BlurHandler handler) { return addDomHandler(handler, BlurEvent.getType()); } /** * This method is here so the Focus logic of ScreenPanel can be notified */ public HandlerRegistration addFocusHandler(FocusHandler handler) { return addDomHandler(handler, FocusEvent.getType()); } /** * Adds a mouseover handler to the textbox for displaying Exceptions */ public HandlerRegistration addMouseOverHandler(MouseOverHandler handler) { return addDomHandler(handler, MouseOverEvent.getType()); } /** * Adds a MouseOut handler for hiding exceptions display */ public HandlerRegistration addMouseOutHandler(MouseOutHandler handler) { return addDomHandler(handler, MouseOutEvent.getType()); } public HandlerRegistration addKeyUpHandler(KeyUpHandler handler) { return addDomHandler(handler, KeyUpEvent.getType()); } @Override public WidgetHelper<Datetime> getHelper() { return helper; } // ******** Implementation of Queryable ***************** /** * This method will toggle TextBox into and from query mode and suspend or * resume any format restrictions */ public void setQueryMode(boolean query) { if (queryMode == query) return; queryMode = query; textbox.enforceMask(!query); textbox.setText(""); value = null; } /** * Returns a single QueryData object representing the query string entered * by the user. The Helper class is used here to create the correct * QueryData object for the passed type T. */ public Object getQuery() { Object query; query = helper.getQuery(textbox.getText()); return query; } /** * Sets a query string to this widget when loaded from a table model */ public void setQuery(QueryData qd) { if (qd != null) textbox.setText(qd.getQuery()); else textbox.setText(""); } /** * Method used to determine if widget is currently in Query mode */ public boolean isQueryMode() { return queryMode; } @Override public boolean isEnabled() { return !textbox.isReadOnly(); } /** * Set the text alignment. */ public void setTextAlignment(TextAlignment alignment) { textbox.setTextAlignment(alignment); } /** * Method used to set if this widget is required to have a value inputed. * @param required */ public void setRequired(boolean required) { this.required = required; } public void setCSS(CalendarCSS css) { css.ensureInjected(); this.css = css; button.setStyleName(css.CalendarButton()); display.setStyleName(css.SelectBox()); textbox.setStyleName(css.SelectText()); } public void setAsText(boolean asTextBox) { button.setVisible(false); } public void setTip(String text) { if (text != null) { if (options == null) options = new Balloon.Options(this); options.setTip(text); } else if (text == null && options != null) { options.destroy(); options = null; } } public void setTipPlacement(Placement placement) { if (options == null) options = new Balloon.Options(this); options.setPlacement(placement); } @UiChild(tagname = "balloonOptions", limit = 1) public void setBalloonOptions(Balloon.Options tip) { this.options = tip; options.setTarget(this); } public Balloon.Options getBalloonOptions() { return options; } protected UIMessages getMessages() { return Messages.get(); } }