blob: 2e39f8424ecc0a9ee7aa338cc7d73eba4ab6c691 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to you 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.apache.pivot.wtk;
import java.util.Locale;
import org.apache.pivot.annotations.UnsupportedOperation;
import org.apache.pivot.collections.Dictionary;
import org.apache.pivot.json.JSON;
import org.apache.pivot.json.JSONSerializer;
import org.apache.pivot.serialization.SerializationException;
import org.apache.pivot.util.CalendarDate;
import org.apache.pivot.util.Filter;
import org.apache.pivot.util.ListenerList;
import org.apache.pivot.util.Utils;
import org.apache.pivot.wtk.content.CalendarButtonDataRenderer;
/**
* A component that allows a user to select a calendar date. The calendar is
* hidden until the user pushes the button.
*/
public class CalendarButton extends Button {
/**
* CalendarButton skin interface. CalendarButton skins must implement this
* interface to facilitate additional communication between the component
* and the skin.
*/
public interface Skin {
public Window getCalendarPopup();
}
private int year;
private int month;
private CalendarDate selectedDate = null;
private Locale locale = Locale.getDefault();
private Filter<CalendarDate> disabledDateFilter = null;
private String selectedDateKey = null;
private BindType selectedDateBindType = BindType.BOTH;
private Calendar.SelectedDateBindMapping selectedDateBindMapping = null;
private CalendarButtonListener.Listeners calendarButtonListeners = new CalendarButtonListener.Listeners();
private CalendarButtonSelectionListener.Listeners calendarButtonSelectionListeners =
new CalendarButtonSelectionListener.Listeners();
private CalendarButtonBindingListener.Listeners calendarButtonBindingListeners =
new CalendarButtonBindingListener.Listeners();
public static final String LANGUAGE_KEY = "language";
public static final String COUNTRY_KEY = "country";
public static final String VARIANT_KEY = "variant";
private static final Button.DataRenderer DEFAULT_DATA_RENDERER = new CalendarButtonDataRenderer();
public CalendarButton() {
this(new CalendarDate());
}
private CalendarButton(CalendarDate calendarDate) {
this(calendarDate.year, calendarDate.month);
}
public CalendarButton(int year, int month) {
this.year = year;
this.month = month;
setDataRenderer(DEFAULT_DATA_RENDERER);
installSkin(CalendarButton.class);
setSelectedDate(new CalendarDate());
}
@Override
protected void setSkin(org.apache.pivot.wtk.Skin skin) {
checkSkin(skin, CalendarButton.Skin.class);
super.setSkin(skin);
}
/**
* @return the popup window associated with this components skin
*/
public Window getListPopup() {
return ((CalendarButton.Skin) getSkin()).getCalendarPopup();
}
/**
* @throws UnsupportedOperationException This method is not supported by
* CalendarButton.
*/
@Override
@UnsupportedOperation
public void setToggleButton(boolean toggleButton) {
throw new UnsupportedOperationException("Calendar buttons cannot be toggle buttons.");
}
/**
* @return The year to which this calendar button is currently set.
*/
public int getYear() {
return year;
}
/**
* Sets this calendar's year.
*
* @param year The new current year for this calendar button.
*/
public void setYear(int year) {
int previousYear = this.year;
if (previousYear != year) {
this.year = year;
calendarButtonListeners.yearChanged(this, previousYear);
}
}
/**
* @return The month to which this calendar button is currently set.
*/
public int getMonth() {
return month;
}
/**
* Sets this calendar's month.
*
* @param month The new month value to set this calendar button to.
*/
public void setMonth(int month) {
int previousMonth = this.month;
if (previousMonth != month) {
this.month = month;
calendarButtonListeners.monthChanged(this, previousMonth);
}
}
/**
* Returns the currently selected date.
*
* @return The currently selected date, or <tt>null</tt> if nothing is
* selected.
*/
public CalendarDate getSelectedDate() {
return selectedDate;
}
/**
* Sets the selected date.
*
* @param selectedDate The date to select, or <tt>null</tt> to clear the
* selection.
*/
public void setSelectedDate(CalendarDate selectedDate) {
CalendarDate previousSelectedDate = this.selectedDate;
if (previousSelectedDate != selectedDate) {
this.selectedDate = selectedDate;
calendarButtonSelectionListeners.selectedDateChanged(this, previousSelectedDate);
}
}
/**
* Sets the selected date to the date represented by the specified date
* string. The date string must be in the <tt>ISO 8601</tt> "calendar date"
* format, which is <tt>[YYYY]-[MM]-[DD]</tt>.
*
* @param selectedDate A string in the form of <tt>[YYYY]-[MM]-[DD]</tt>
* (e.g. 2008-07-23)
* @throws IllegalArgumentException if the selected data value is {@code null}.
*/
public final void setSelectedDate(String selectedDate) {
setSelectedDate(CalendarDate.decode(selectedDate));
}
/**
* @return The locale used to present calendar data.
*/
public Locale getLocale() {
return locale;
}
/**
* Sets the locale used to present calendar data.
*
* @param locale The new locale used to format/present the data.
* @throws IllegalArgumentException if the given locale is {@code null}.
*/
public void setLocale(Locale locale) {
Utils.checkNull(locale, "locale");
Locale previousLocale = this.locale;
if (previousLocale != locale) {
this.locale = locale;
calendarButtonListeners.localeChanged(this, previousLocale);
}
}
/**
* Sets the locale used to present calendar data.
*
* @param locale An dictionary containing values for language, country, and
* variant. Country and variant are optional but the must adhere to the
* following rules: <ul> <li>If variant is specified, language and country
* are required;</li> <li>Otherwise, if country is specified, language is
* required;</li> <li>Otherwise, language is required.</li> </ul>
* @throws IllegalArgumentException if the given locale dictionary is {@code null}.
*/
public void setLocale(Dictionary<String, ?> locale) {
Utils.checkNull(locale, "locale");
String language = (String) locale.get(LANGUAGE_KEY);
String country = (String) locale.get(COUNTRY_KEY);
String variant = (String) locale.get(VARIANT_KEY);
if (variant != null) {
setLocale(new Locale(language, country, variant));
} else if (country != null) {
setLocale(new Locale(language, country));
} else {
setLocale(new Locale(language));
}
}
/**
* Sets the locale used to present calendar data.
*
* @param locale A JSON map containing values for language, country, and
* variant.
* @throws IllegalArgumentException if the locale string is {@code null} or
* if there is a problem parsing the string.
* @see #setLocale(Dictionary)
*/
public void setLocale(String locale) {
Utils.checkNullOrEmpty(locale, "locale");
try {
setLocale(JSONSerializer.parseMap(locale));
} catch (SerializationException exception) {
throw new IllegalArgumentException(exception);
}
}
public Filter<CalendarDate> getDisabledDateFilter() {
return disabledDateFilter;
}
public void setDisabledDateFilter(Filter<CalendarDate> disabledDateFilter) {
Filter<CalendarDate> previousDisabledDateFilter = this.disabledDateFilter;
if (previousDisabledDateFilter != disabledDateFilter) {
this.disabledDateFilter = disabledDateFilter;
calendarButtonListeners.disabledDateFilterChanged(this, previousDisabledDateFilter);
}
}
/**
* @return The data binding key that is set on this calendar button.
*/
public String getSelectedDateKey() {
return selectedDateKey;
}
/**
* Sets this calendar button's data binding key.
*
* @param selectedDateKey The new binding key for the calendar's selected date.
*/
public void setSelectedDateKey(String selectedDateKey) {
String previousSelectedDateKey = this.selectedDateKey;
if (previousSelectedDateKey != selectedDateKey) {
this.selectedDateKey = selectedDateKey;
calendarButtonBindingListeners.selectedDateKeyChanged(this, previousSelectedDateKey);
}
}
public BindType getSelectedDateBindType() {
return selectedDateBindType;
}
public void setSelectedDateBindType(BindType selectedDateBindType) {
Utils.checkNull(selectedDateBindType, "selectedDateBindType");
BindType previousSelectedDateBindType = this.selectedDateBindType;
if (previousSelectedDateBindType != selectedDateBindType) {
this.selectedDateBindType = selectedDateBindType;
calendarButtonBindingListeners.selectedDateBindTypeChanged(this,
previousSelectedDateBindType);
}
}
public Calendar.SelectedDateBindMapping getSelectedDateBindMapping() {
return selectedDateBindMapping;
}
public void setSelectedDateBindMapping(Calendar.SelectedDateBindMapping bindMapping) {
Calendar.SelectedDateBindMapping previousSelectedDateBindMapping = this.selectedDateBindMapping;
if (previousSelectedDateBindMapping != bindMapping) {
this.selectedDateBindMapping = bindMapping;
calendarButtonBindingListeners.selectedDateBindMappingChanged(this,
previousSelectedDateBindMapping);
}
}
@Override
public void load(Object context) {
if (selectedDateKey != null && JSON.containsKey(context, selectedDateKey)
&& selectedDateBindType != BindType.STORE) {
Object value = JSON.get(context, selectedDateKey);
CalendarDate selectedDateLocal = null;
if (value instanceof CalendarDate) {
selectedDateLocal = (CalendarDate) value;
} else if (selectedDateBindMapping == null) {
if (value != null) {
selectedDateLocal = CalendarDate.decode(value.toString());
}
} else {
selectedDateLocal = selectedDateBindMapping.toDate(value);
}
setSelectedDate(selectedDateLocal);
}
}
@Override
public void store(Object context) {
if (selectedDateKey != null && selectedDateBindType != BindType.LOAD) {
JSON.put(context, selectedDateKey, (selectedDateBindMapping == null) ? selectedDate
: selectedDateBindMapping.valueOf(selectedDate));
}
}
@Override
public void clear() {
super.clear(); // for better consistency with superclass
if (selectedDateKey != null) {
setSelectedDate((CalendarDate) null);
}
}
/**
* Clears the selection.
*/
public void clearSelection() {
setSelectedDate((CalendarDate) null);
}
/**
* @return The calendar button listener list.
*/
public ListenerList<CalendarButtonListener> getCalendarButtonListeners() {
return calendarButtonListeners;
}
/**
* @return The calendar button selection listener list.
*/
public ListenerList<CalendarButtonSelectionListener> getCalendarButtonSelectionListeners() {
return calendarButtonSelectionListeners;
}
/**
* @return The calendar button binding listener list.
*/
public ListenerList<CalendarButtonBindingListener> getCalendarButtonBindingListeners() {
return calendarButtonBindingListeners;
}
}