DateTimeService for all components, provides localised month and daynames etc. New IDateField implementation: one superclass, which different proper implementations extend. Partially working version of "calendar"-style for DateField. svn changeset:1816/svn branch:trunktags/6.7.0.beta1
@@ -42,6 +42,8 @@ public class Client implements EntryPoint { | |||
private HashMap paintables = new HashMap(); | |||
private WidgetFactory widgetFactory = new DefaultWidgetFactory(); | |||
private LocaleService locale; | |||
/** | |||
* This is the entry point method. | |||
@@ -121,6 +123,13 @@ public class Client implements EntryPoint { | |||
String key = (String) i.next(); | |||
resourcesMap.put(key, ((JSONString)resources.get(key)).stringValue()); | |||
} | |||
// Store locale data | |||
if(((JSONObject)json).containsKey("locales")) { | |||
JSONArray l = (JSONArray) ((JSONObject) json).get("locales"); | |||
for(int i=0; i < l.size(); i++) | |||
LocaleService.addLocale((JSONObject) l.get(i)); | |||
} | |||
// Process changes | |||
JSONArray changes = (JSONArray) ((JSONObject) json).get("changes"); | |||
@@ -353,31 +362,4 @@ public class Client implements EntryPoint { | |||
public String getResource(String name) { | |||
return (String) resourcesMap.get(name); | |||
} | |||
public JSONObject getLocale(String locale) { | |||
// TODO should perform synchronous call to server to fetch | |||
// locale specific strings | |||
// (GWT only supports synchrounous requests from v. 1.4) | |||
console.log("Loading a new locale: " + locale); | |||
rb = new RequestBuilder(RequestBuilder.POST, appUri | |||
+ "/locale/?requestId=" + (Math.random()) + "&" + locale); | |||
/*try { | |||
rb.sendRequest(locale, new RequestCallback() { | |||
public void onError(Request request, Throwable exception) { | |||
console.error("Got error"); | |||
} | |||
public void onResponseReceived(Request request, | |||
Response response) { | |||
handleReceivedJSONMessage(response); | |||
} | |||
}); | |||
} catch (RequestException e) { | |||
console.error(e.getMessage()); | |||
}*/ | |||
// TODO | |||
return null; | |||
} | |||
} |
@@ -1,44 +1,132 @@ | |||
package com.itmill.toolkit.terminal.gwt.client; | |||
import java.util.Date; | |||
/** | |||
* This class provides date/time parsing services to all components. | |||
* This class provides date/time parsing services to | |||
* all components on the client side. | |||
* | |||
* @author Jouni Koivuviita | |||
* @author IT Mill Ltd. | |||
* | |||
*/ | |||
public class DateTimeService { | |||
private LocaleService localeService; | |||
private String currentLocale; | |||
public DateTimeService(Client client) { | |||
localeService = new LocaleService(client); | |||
private static int [] maxDaysInMonth = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; | |||
/** | |||
* Creates a new date time service with the application default locale. | |||
*/ | |||
public DateTimeService() { | |||
currentLocale = LocaleService.getDefaultLocale(); | |||
} | |||
public DateTimeService(Client client, String locale) { | |||
this(client); | |||
/** | |||
* Creates a new date time service with a given locale. | |||
* | |||
* @param locale e.g. fi, en etc. | |||
* @throws LocaleNotLoadedException | |||
*/ | |||
public DateTimeService(String locale) throws LocaleNotLoadedException { | |||
setLocale(locale); | |||
} | |||
public void setLocale(String locale) { | |||
currentLocale = locale; | |||
public void setLocale(String locale) throws LocaleNotLoadedException { | |||
if(LocaleService.getAvailableLocales().contains(locale)) | |||
currentLocale = locale; | |||
else throw new LocaleNotLoadedException(locale); | |||
} | |||
public String getLocale() { | |||
return currentLocale; | |||
} | |||
public String getMonth(int month) throws Exception { | |||
if(currentLocale != null) | |||
return localeService.getMonthNames(currentLocale)[month]; | |||
else throw new Exception("No locale specified."); | |||
public String getMonth(int month) { | |||
try { | |||
return LocaleService.getMonthNames(currentLocale)[month]; | |||
} catch (LocaleNotLoadedException e) { | |||
// TODO redirect to console | |||
System.out.println(e + ":" + e.getMessage()); | |||
} | |||
return null; | |||
} | |||
public String getShortMonth(int month) { | |||
try { | |||
return LocaleService.getShortMonthNames(currentLocale)[month]; | |||
} catch (LocaleNotLoadedException e) { | |||
// TODO redirect to console | |||
System.out.println(e + ":" + e.getMessage()); | |||
} | |||
return null; | |||
} | |||
public String getDay(int day) { | |||
try { | |||
return LocaleService.getDayNames(currentLocale)[day]; | |||
} catch (LocaleNotLoadedException e) { | |||
// TODO redirect to console | |||
System.out.println(e + ":" + e.getMessage()); | |||
} | |||
return null; | |||
} | |||
public String getShortDay(int day) { | |||
try { | |||
return LocaleService.getShortDayNames(currentLocale)[day]; | |||
} catch (LocaleNotLoadedException e) { | |||
// TODO redirect to console | |||
System.out.println(e + ":" + e.getMessage()); | |||
} | |||
return null; | |||
} | |||
public int getFirstDayOfWeek() { | |||
try { | |||
return LocaleService.getFirstDayOfWeek(currentLocale); | |||
} catch (LocaleNotLoadedException e) { | |||
// TODO redirect to console | |||
System.out.println(e + ":" + e.getMessage()); | |||
} | |||
return 0; | |||
} | |||
public int getStartWeekDay(Date date){ | |||
Date dateForFirstOfThisMonth = new Date(date.getYear(), date.getMonth(), 1); | |||
int firstDay; | |||
try { | |||
firstDay = LocaleService.getFirstDayOfWeek(currentLocale); | |||
} catch (LocaleNotLoadedException e) { | |||
firstDay = 0; | |||
// TODO redirect to console | |||
System.out.println(e + ":" + e.getMessage()); | |||
} | |||
int start = dateForFirstOfThisMonth.getDay() - firstDay; | |||
if(start < 0) start = 6; | |||
return start; | |||
} | |||
public static int getNumberOfDaysInMonth(Date date){ | |||
int month = date.getMonth(); | |||
if(month == 1 && true == isLeapYear(date)) | |||
return 29; | |||
return maxDaysInMonth[month]; | |||
} | |||
public String getShortMonth(int month) throws Exception { | |||
if(currentLocale != null) | |||
return localeService.getShortMonthNames(currentLocale)[month]; | |||
else throw new Exception("No locale specified."); | |||
public static boolean isLeapYear(Date date){ | |||
// Instantiate the date for 1st March of that year | |||
Date firstMarch = new Date(date.getYear(), 2, 1); | |||
// Go back 1 day | |||
long firstMarchTime = firstMarch.getTime(); | |||
long lastDayTimeFeb = firstMarchTime - (24*60*60*1000); // NUM_MILLISECS_A_DAY | |||
//Instantiate new Date with this time | |||
Date febLastDay = new Date(lastDayTimeFeb); | |||
// Check for date in this new instance | |||
return (29 == febLastDay.getDate()) ? true : false; | |||
} | |||
} |
@@ -3,10 +3,10 @@ package com.itmill.toolkit.terminal.gwt.client; | |||
import com.google.gwt.core.client.GWT; | |||
import com.google.gwt.user.client.ui.Widget; | |||
import com.itmill.toolkit.terminal.gwt.client.ui.IButton; | |||
import com.itmill.toolkit.terminal.gwt.client.ui.ICalendar; | |||
import com.itmill.toolkit.terminal.gwt.client.ui.ICheckBox; | |||
import com.itmill.toolkit.terminal.gwt.client.ui.IComponent; | |||
import com.itmill.toolkit.terminal.gwt.client.ui.ICustomLayout; | |||
import com.itmill.toolkit.terminal.gwt.client.ui.IDateField; | |||
import com.itmill.toolkit.terminal.gwt.client.ui.IEmbedded; | |||
import com.itmill.toolkit.terminal.gwt.client.ui.IGridLayout; | |||
import com.itmill.toolkit.terminal.gwt.client.ui.IHorizontalLayout; | |||
@@ -14,11 +14,13 @@ import com.itmill.toolkit.terminal.gwt.client.ui.ILabel; | |||
import com.itmill.toolkit.terminal.gwt.client.ui.IOptionGroup; | |||
import com.itmill.toolkit.terminal.gwt.client.ui.IPanel; | |||
import com.itmill.toolkit.terminal.gwt.client.ui.IPasswordField; | |||
import com.itmill.toolkit.terminal.gwt.client.ui.IPopupCalendar; | |||
import com.itmill.toolkit.terminal.gwt.client.ui.ISelect; | |||
import com.itmill.toolkit.terminal.gwt.client.ui.ITablePaging; | |||
import com.itmill.toolkit.terminal.gwt.client.ui.ITabsheet; | |||
import com.itmill.toolkit.terminal.gwt.client.ui.ITextArea; | |||
import com.itmill.toolkit.terminal.gwt.client.ui.ITextField; | |||
import com.itmill.toolkit.terminal.gwt.client.ui.ITextualDate; | |||
import com.itmill.toolkit.terminal.gwt.client.ui.ITree; | |||
import com.itmill.toolkit.terminal.gwt.client.ui.ITwinColSelect; | |||
import com.itmill.toolkit.terminal.gwt.client.ui.IUnknownComponent; | |||
@@ -82,8 +84,14 @@ public class DefaultWidgetFactory implements WidgetFactory { | |||
} | |||
return new ITablePaging(); | |||
} | |||
if("datefield".equals(tag)) | |||
return new IDateField(); | |||
if("datefield".equals(tag)) { | |||
if(uidl.hasAttribute("style")) | |||
if("calendar".equals(uidl.getStringAttribute("style"))) | |||
return new ICalendar(); | |||
else if("text".equals(uidl.getStringAttribute("style"))) | |||
return new ITextualDate(); | |||
return new IPopupCalendar(); | |||
} | |||
return new IUnknownComponent(); | |||
} |
@@ -0,0 +1,13 @@ | |||
package com.itmill.toolkit.terminal.gwt.client; | |||
public class LocaleNotLoadedException extends Exception { | |||
/** | |||
* Serial generated by Eclipse. | |||
*/ | |||
private static final long serialVersionUID = 2005227056545210838L; | |||
public LocaleNotLoadedException(String locale) { | |||
super(locale); | |||
} | |||
} |
@@ -2,80 +2,151 @@ package com.itmill.toolkit.terminal.gwt.client; | |||
import java.util.HashMap; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import com.google.gwt.json.client.JSONArray; | |||
import com.google.gwt.json.client.JSONBoolean; | |||
import com.google.gwt.json.client.JSONNumber; | |||
import com.google.gwt.json.client.JSONObject; | |||
import com.google.gwt.json.client.JSONString; | |||
/** | |||
* Date / time etc. localisation service for all widgets. | |||
* Should cache all loaded locales as JSON strings. | |||
* | |||
* @author Jouni Koivuviita | |||
* @author IT Mill Ltd. | |||
* | |||
*/ | |||
public class LocaleService { | |||
private Client client; | |||
private static Map cache = new HashMap(); | |||
private static String defaultLocale; | |||
public static void addLocale(JSONObject json) { | |||
String key = ((JSONString)json.get("name")).stringValue(); | |||
if(cache.containsKey(key)) | |||
cache.remove(key); | |||
cache.put(key, json); | |||
if(cache.size()==1) | |||
setDefaultLocale(key); | |||
} | |||
public static void setDefaultLocale(String locale) { | |||
defaultLocale = locale; | |||
} | |||
private Map cache = new HashMap(); | |||
public static String getDefaultLocale() { | |||
return defaultLocale; | |||
} | |||
public static Set getAvailableLocales() { | |||
return cache.keySet(); | |||
} | |||
public static String[] getMonthNames(String locale) throws LocaleNotLoadedException { | |||
if(cache.containsKey(locale)) { | |||
JSONObject l = (JSONObject) cache.get(locale); | |||
JSONArray mn = (JSONArray) l.get("mn"); | |||
String[] temp = new String[12]; | |||
temp[0] = ((JSONString)mn.get(0)).stringValue(); | |||
temp[1] = ((JSONString)mn.get(1)).stringValue(); | |||
temp[2] = ((JSONString)mn.get(2)).stringValue(); | |||
temp[3] = ((JSONString)mn.get(3)).stringValue(); | |||
temp[4] = ((JSONString)mn.get(4)).stringValue(); | |||
temp[5] = ((JSONString)mn.get(5)).stringValue(); | |||
temp[6] = ((JSONString)mn.get(6)).stringValue(); | |||
temp[7] = ((JSONString)mn.get(7)).stringValue(); | |||
temp[8] = ((JSONString)mn.get(8)).stringValue(); | |||
temp[9] = ((JSONString)mn.get(9)).stringValue(); | |||
temp[10] = ((JSONString)mn.get(10)).stringValue(); | |||
temp[11] = ((JSONString)mn.get(11)).stringValue(); | |||
return temp; | |||
} else throw new LocaleNotLoadedException(locale); | |||
} | |||
public LocaleService(Client client){ | |||
this.client = client; | |||
public static String[] getShortMonthNames(String locale) throws LocaleNotLoadedException { | |||
if(cache.containsKey(locale)) { | |||
JSONObject l = (JSONObject) cache.get(locale); | |||
JSONArray smn = (JSONArray) l.get("smn"); | |||
String[] temp = new String[12]; | |||
temp[0] = ((JSONString)smn.get(0)).stringValue(); | |||
temp[1] = ((JSONString)smn.get(1)).stringValue(); | |||
temp[2] = ((JSONString)smn.get(2)).stringValue(); | |||
temp[3] = ((JSONString)smn.get(3)).stringValue(); | |||
temp[4] = ((JSONString)smn.get(4)).stringValue(); | |||
temp[5] = ((JSONString)smn.get(5)).stringValue(); | |||
temp[6] = ((JSONString)smn.get(6)).stringValue(); | |||
temp[7] = ((JSONString)smn.get(7)).stringValue(); | |||
temp[8] = ((JSONString)smn.get(8)).stringValue(); | |||
temp[9] = ((JSONString)smn.get(9)).stringValue(); | |||
temp[10] = ((JSONString)smn.get(10)).stringValue(); | |||
temp[11] = ((JSONString)smn.get(11)).stringValue(); | |||
return temp; | |||
} else throw new LocaleNotLoadedException(locale); | |||
} | |||
private void loadLocale(String locale) { | |||
JSONObject resp = client.getLocale(locale); | |||
cache.put(locale, resp); | |||
public static String[] getDayNames(String locale) throws LocaleNotLoadedException{ | |||
if(cache.containsKey(locale)) { | |||
JSONObject l = (JSONObject) cache.get(locale); | |||
JSONArray dn = (JSONArray) l.get("dn"); | |||
String[] temp = new String[7]; | |||
temp[0] = ((JSONString)dn.get(0)).stringValue(); | |||
temp[1] = ((JSONString)dn.get(1)).stringValue(); | |||
temp[2] = ((JSONString)dn.get(2)).stringValue(); | |||
temp[3] = ((JSONString)dn.get(3)).stringValue(); | |||
temp[4] = ((JSONString)dn.get(4)).stringValue(); | |||
temp[5] = ((JSONString)dn.get(5)).stringValue(); | |||
temp[6] = ((JSONString)dn.get(6)).stringValue(); | |||
return temp; | |||
} else throw new LocaleNotLoadedException(locale); | |||
} | |||
public String[] getMonthNames(String locale) { | |||
// TODO | |||
//if(cache.containsKey(locale)) | |||
//else loadLocale(locale); | |||
String[] temp = new String[12]; | |||
temp[0] = "tammi"; temp[1] = "helmi"; temp[2] = "maalis"; temp[3] = "huhti"; | |||
temp[4] = "touko"; temp[5] = "kesä"; temp[6] = "heinä"; temp[7] = "elo"; | |||
temp[8] = "syys"; temp[9] = "loka"; temp[10] = "marras"; temp[11] = "joulu"; | |||
return temp; | |||
public static String[] getShortDayNames(String locale) throws LocaleNotLoadedException { | |||
if(cache.containsKey(locale)) { | |||
JSONObject l = (JSONObject) cache.get(locale); | |||
JSONArray sdn = (JSONArray) l.get("sdn"); | |||
String[] temp = new String[7]; | |||
temp[0] = ((JSONString)sdn.get(0)).stringValue(); | |||
temp[1] = ((JSONString)sdn.get(1)).stringValue(); | |||
temp[2] = ((JSONString)sdn.get(2)).stringValue(); | |||
temp[3] = ((JSONString)sdn.get(3)).stringValue(); | |||
temp[4] = ((JSONString)sdn.get(4)).stringValue(); | |||
temp[5] = ((JSONString)sdn.get(5)).stringValue(); | |||
temp[6] = ((JSONString)sdn.get(6)).stringValue(); | |||
return temp; | |||
} else throw new LocaleNotLoadedException(locale); | |||
} | |||
public String[] getShortMonthNames(String locale) { | |||
// TODO | |||
//if(cache.containsKey(locale)) | |||
//else loadLocale(locale); | |||
String[] temp = new String[12]; | |||
temp[0] = "tam"; temp[1] = "hel"; temp[2] = "maa"; temp[3] = "huh"; | |||
temp[4] = "tou"; temp[5] = "kes"; temp[6] = "hei"; temp[7] = "elo"; | |||
temp[8] = "syy"; temp[9] = "lok"; temp[10] = "mar"; temp[11] = "jou"; | |||
return temp; | |||
public static int getFirstDayOfWeek(String locale) throws LocaleNotLoadedException { | |||
if(cache.containsKey(locale)) { | |||
JSONObject l = (JSONObject) cache.get(locale); | |||
JSONNumber fdow = (JSONNumber) l.get("fdow"); | |||
return (int) fdow.getValue(); | |||
} else throw new LocaleNotLoadedException(locale); | |||
} | |||
public String[] getDayNames(String locale) { | |||
// TODO | |||
//if(cache.containsKey(locale)) | |||
//else loadLocale(locale); | |||
String[] temp = new String[7]; | |||
temp[1] = "maanatai"; temp[2] = "tiistai"; temp[3] = "keskiviikko"; | |||
temp[4] = "torstai"; temp[5] = "perjantai"; temp[6] = "lauantai"; | |||
temp[0] = "sunnuntai"; | |||
return temp; | |||
public static String getDateFormat(String locale) throws LocaleNotLoadedException { | |||
if(cache.containsKey(locale)) { | |||
JSONObject l = (JSONObject) cache.get(locale); | |||
JSONString df = (JSONString) l.get("df"); | |||
return df.stringValue(); | |||
} else throw new LocaleNotLoadedException(locale); | |||
} | |||
public String[] getShortDayNames(String locale) { | |||
// TODO | |||
//if(cache.containsKey(locale)) | |||
//else loadLocale(locale); | |||
String[] temp = new String[7]; | |||
temp[1] = "ma"; temp[2] = "ti"; temp[3] = "ke"; | |||
temp[4] = "to"; temp[5] = "pe"; temp[6] = "la"; | |||
temp[0] = "su"; | |||
return temp; | |||
public static boolean isTwelveHourClock(String locale) throws LocaleNotLoadedException { | |||
if(cache.containsKey(locale)) { | |||
JSONObject l = (JSONObject) cache.get(locale); | |||
JSONBoolean thc = (JSONBoolean) l.get("thc"); | |||
return thc.booleanValue(); | |||
} else throw new LocaleNotLoadedException(locale); | |||
} | |||
public int getFirstDayOfWeek(String locale) { | |||
// TODO | |||
//if(cache.containsKey(locale)) | |||
//else loadLocale(locale); | |||
return 1; | |||
public static String getClockDelimiter(String locale) throws LocaleNotLoadedException { | |||
if(cache.containsKey(locale)) { | |||
JSONObject l = (JSONObject) cache.get(locale); | |||
JSONString hmd = (JSONString) l.get("hmd"); | |||
return hmd.stringValue(); | |||
} else throw new LocaleNotLoadedException(locale); | |||
} | |||
} |
@@ -0,0 +1,25 @@ | |||
package com.itmill.toolkit.terminal.gwt.client.ui; | |||
import com.itmill.toolkit.terminal.gwt.client.Client; | |||
import com.itmill.toolkit.terminal.gwt.client.UIDL; | |||
public class ICalendar extends IDateField { | |||
private ICalendarPanel body; | |||
private String locale; | |||
public ICalendar() { | |||
super(); | |||
body = new ICalendarPanel(this); | |||
container.add(body); | |||
} | |||
public void updateFromUIDL(UIDL uidl, Client client) { | |||
super.updateFromUIDL(uidl, client); | |||
boolean needsRedraw = (locale == null || !locale.equals(currentLocale)); | |||
body.updateCalendar(needsRedraw); | |||
locale = currentLocale; | |||
} | |||
} |
@@ -0,0 +1,123 @@ | |||
package com.itmill.toolkit.terminal.gwt.client.ui; | |||
import java.util.Date; | |||
import com.google.gwt.user.client.ui.ClickListener; | |||
import com.google.gwt.user.client.ui.FlexTable; | |||
import com.google.gwt.user.client.ui.Widget; | |||
import com.itmill.toolkit.terminal.gwt.client.DateTimeService; | |||
public class ICalendarPanel extends FlexTable implements ClickListener { | |||
private IDateField datefield; | |||
private IButton prevYear; | |||
private IButton nextYear; | |||
private IButton prevMonth; | |||
private IButton nextMonth; | |||
public ICalendarPanel(IDateField parent) { | |||
datefield = parent; | |||
// Force table size | |||
setText(0, 0, ""); | |||
setText(7, 6, ""); | |||
buildCalendar(true); | |||
} | |||
public void buildCalendar(boolean forceRedraw) { | |||
buildCalendarHeader(forceRedraw); | |||
buildCalendarBody(); | |||
} | |||
private void clearCalendarBody() { | |||
for (int row=2; row < 8; row++){ | |||
for (int col=0; col < 7; col++){ | |||
setText(row, col, ""); | |||
} | |||
} | |||
} | |||
private void buildCalendarHeader(boolean forceRedraw) { | |||
if(forceRedraw) { | |||
prevYear = new IButton(); prevYear.setText("«"); | |||
nextYear = new IButton(); nextYear.setText("»"); | |||
prevMonth = new IButton(); prevMonth.setText("‹"); | |||
nextMonth = new IButton(); nextMonth.setText("›"); | |||
prevYear.addClickListener(this); nextYear.addClickListener(this); | |||
prevMonth.addClickListener(this); nextMonth.addClickListener(this);setWidget(0, 0, prevYear); | |||
setWidget(0, 1, prevMonth); | |||
setWidget(0, 3, nextMonth); | |||
setWidget(0, 4, nextYear); | |||
getFlexCellFormatter().setColSpan(0, 2, 3); | |||
int firstDay = datefield.dts.getFirstDayOfWeek(); | |||
for(int i = 0; i < 7; i++) { | |||
int day = i + firstDay; | |||
if(day > 6) day = 0; | |||
setText(1,i, datefield.dts.getShortDay(day)); | |||
} | |||
} | |||
String monthName = datefield.dts.getMonth(datefield.date.getMonth()); | |||
int year = datefield.date.getYear()+1900; | |||
setText(0, 2, monthName + " " + year); | |||
} | |||
private void buildCalendarBody() { | |||
Date date = datefield.date; | |||
int startWeekDay = datefield.dts.getStartWeekDay(date); | |||
int numDays = DateTimeService.getNumberOfDaysInMonth(date); | |||
int dayCount = 0; | |||
for (int row = 2; row < 8; row++){ | |||
for (int col = 0; col < 7; col++){ | |||
if(row == 2 && col < startWeekDay){ | |||
setText(row, col, ""); | |||
//cellValues[row][col] = ""; | |||
} else { | |||
if(numDays > dayCount){ | |||
int selectedDate = ++dayCount; | |||
//cellValues[row][col] = selectedDate +""; | |||
//if(true == isSelectedDate(date, selectedDate)){ | |||
//setHTML(row, col, "<font class='currentDate'>" + selectedDate+"<font>"); | |||
//}else{ | |||
setText(row, col, ""+selectedDate); | |||
//} | |||
} else { | |||
setText(row, col, ""); | |||
//cellValues[row][col] = ""; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
/** | |||
* | |||
* @param forceRedraw Build all from scratch, in case of e.g. locale changes | |||
*/ | |||
public void updateCalendar(boolean forceRedraw) { | |||
clearCalendarBody(); | |||
buildCalendar(forceRedraw); | |||
} | |||
public void onClick(Widget sender) { | |||
if(sender == prevYear) { | |||
datefield.date.setYear(datefield.date.getYear()-1); | |||
datefield.client.updateVariable(datefield.id, "year", datefield.date.getYear()+1900, datefield.immediate); | |||
updateCalendar(false); | |||
} else if(sender == nextYear) { | |||
datefield.date.setYear(datefield.date.getYear()+1); | |||
datefield.client.updateVariable(datefield.id, "year", datefield.date.getYear()+1900, datefield.immediate); | |||
updateCalendar(false); | |||
} else if(sender == prevMonth) { | |||
datefield.date.setMonth(datefield.date.getMonth()-1); | |||
datefield.client.updateVariable(datefield.id, "month", datefield.date.getMonth()+1, datefield.immediate); | |||
updateCalendar(false); | |||
} else if(sender == nextMonth) { | |||
datefield.date.setMonth(datefield.date.getMonth()+1); | |||
datefield.client.updateVariable(datefield.id, "month", datefield.date.getMonth()+1, datefield.immediate); | |||
updateCalendar(false); | |||
} | |||
} | |||
} |
@@ -2,61 +2,46 @@ package com.itmill.toolkit.terminal.gwt.client.ui; | |||
import java.util.Date; | |||
import com.google.gwt.user.client.ui.ChangeListener; | |||
import com.google.gwt.user.client.ui.Composite; | |||
import com.google.gwt.user.client.ui.FlowPanel; | |||
import com.google.gwt.user.client.ui.ListBox; | |||
import com.google.gwt.user.client.ui.Widget; | |||
import com.itmill.toolkit.terminal.gwt.client.Client; | |||
import com.itmill.toolkit.terminal.gwt.client.DateTimeService; | |||
import com.itmill.toolkit.terminal.gwt.client.LocaleNotLoadedException; | |||
import com.itmill.toolkit.terminal.gwt.client.Paintable; | |||
import com.itmill.toolkit.terminal.gwt.client.UIDL; | |||
public class IDateField extends Composite implements Paintable, ChangeListener { | |||
/* | |||
* This implementation is old already. | |||
* We should use the DateTimeService class (which is a draft) to get | |||
* locale specific strings and use them to build the datefield | |||
* and its different styles (with inheritance of course). | |||
* | |||
* Drafting usage patterns: | |||
* | |||
* DateTimeService dts = new DateTimeService(client, "fi_FI"); | |||
* String month = dts.getMonth(0); // Returns "January" | |||
* String day = dts.getDay(19); // Returns e.g. "sunday" | |||
* String dateformat = dts.getDateFormat(); // Returns something like MM_/_DD_/_YYYY | |||
* String timeformat = dts.getTimeFormat(); // Returns something like HH_:_MM | |||
* String date = dts.parseDate(new Date()); // Returns e.g. 6/19/2007 14:32 | |||
* String date = dts.parseFullDate(new Date()); // Returns e.g. Tuesday 6th June 2007 14:32 | |||
*/ | |||
public class IDateField extends Composite implements Paintable { | |||
public static final String CLASSNAME = "i-datefield"; | |||
String id; | |||
Client client; | |||
protected FlowPanel container; | |||
private boolean immediate; | |||
protected boolean immediate; | |||
private FlowPanel container; | |||
protected static int RESOLUTION_YEAR = 0; | |||
protected static int RESOLUTION_MONTH = 1; | |||
protected static int RESOLUTION_DAY = 2; | |||
protected static int RESOLUTION_HOUR = 3; | |||
protected static int RESOLUTION_MIN = 4; | |||
protected static int RESOLUTION_SEC = 5; | |||
protected static int RESOLUTION_MSEC = 6; | |||
protected int currentResolution = RESOLUTION_YEAR; | |||
private ListBox year; | |||
protected String currentLocale; | |||
private static int RESOLUTION_YEAR = 0; | |||
private static int RESOLUTION_MONTH = 1; | |||
private static int RESOLUTION_DAY = 2; | |||
private static int RESOLUTION_HOUR = 3; | |||
private static int RESOLUTION_MIN = 4; | |||
private static int RESOLUTION_SEC = 5; | |||
private static int RESOLUTION_MSEC = 6; | |||
private int currentResolution = RESOLUTION_YEAR; | |||
protected Date date; | |||
protected DateTimeService dts; | |||
public IDateField() { | |||
container = new FlowPanel(); | |||
initWidget(container); | |||
date = new Date(); | |||
dts = new DateTimeService(); | |||
} | |||
public void updateFromUIDL(UIDL uidl, Client client) { | |||
@@ -69,6 +54,18 @@ public class IDateField extends Composite implements Paintable, ChangeListener { | |||
id = uidl.getId(); | |||
immediate = uidl.getBooleanAttribute("immediate"); | |||
if(uidl.hasAttribute("locale")) { | |||
String locale = uidl.getStringAttribute("locale"); | |||
try { | |||
dts.setLocale(locale); | |||
currentLocale = locale; | |||
} catch (LocaleNotLoadedException e) { | |||
dts = new DateTimeService(); | |||
currentLocale = dts.getLocale(); | |||
System.out.println("Tried to use an unloaded locale \"" + locale + "\". Using default locale (" + currentLocale + ")."); | |||
} | |||
} | |||
int newResolution = RESOLUTION_YEAR; | |||
if(uidl.hasAttribute("month")) | |||
newResolution = RESOLUTION_MONTH; | |||
@@ -86,41 +83,38 @@ public class IDateField extends Composite implements Paintable, ChangeListener { | |||
if(currentResolution > newResolution) | |||
container.clear(); | |||
if(uidl.hasVariable("year")) { | |||
int selectedYear = uidl.getIntVariable("year"); | |||
int y = container.getWidgetIndex(year); | |||
if(y > -1) { | |||
year = (ListBox) container.getWidget(y); | |||
// Deselect old value | |||
year.setItemSelected(year.getSelectedIndex(), false); | |||
// and select new | |||
for(int i=0; i < year.getItemCount(); i++) | |||
if(year.getValue(i).equals(""+selectedYear)) { | |||
year.setSelectedIndex(i); | |||
break; | |||
} | |||
} else { | |||
year = new ListBox(); | |||
year.setStyleName(ISelect.CLASSNAME); | |||
int today = 1900 + (new Date()).getYear(); | |||
for(int i=1970; i<today+400; i++) { | |||
year.addItem(""+i, ""+i); | |||
if(i == selectedYear) | |||
year.setSelectedIndex(year.getItemCount()-1); | |||
} | |||
year.addChangeListener(this); | |||
container.add(year); | |||
} | |||
} | |||
currentResolution = newResolution; | |||
int year = uidl.getIntAttribute("year"); | |||
int month = uidl.getIntAttribute("month"); | |||
int day = uidl.getIntAttribute("day"); | |||
int hour = uidl.getIntAttribute("hour"); | |||
int min = uidl.getIntAttribute("min"); | |||
int sec = uidl.getIntAttribute("sec"); | |||
int msec = uidl.getIntAttribute("msec"); | |||
currentResolution = newResolution; | |||
} | |||
public void onChange(Widget sender) { | |||
if(sender == year && client != null) | |||
client.updateVariable(id, "year", year.getValue(year.getSelectedIndex()), immediate); | |||
date = new Date((long) buildDate(year, month, day, hour, min, sec, msec)); | |||
} | |||
/* | |||
* We need this redundant native function because | |||
* GWT hasn't implemented setMilliseconds to the Date class. | |||
*/ | |||
private native double buildDate(int y, int m, int d, int h, int mi, int s, int ms) /*-{ | |||
try { | |||
var date = new Date(); | |||
if(y) date.setFullYear(y-1900); | |||
if(m) date.setMonth(m-1); | |||
if(d) date.setDate(d); | |||
if(h) date.setHour(h); | |||
if(mi) date.setMinutes(mi); | |||
if(s) date.setSeconds(s); | |||
if(ms) date.setMilliseconds(ms); | |||
return date.getTime(); | |||
} catch (e) { | |||
console.error(e); | |||
} | |||
}-*/; | |||
} |
@@ -0,0 +1,5 @@ | |||
package com.itmill.toolkit.terminal.gwt.client.ui; | |||
public class IPopupCalendar extends IDateField { | |||
} |
@@ -0,0 +1,113 @@ | |||
package com.itmill.toolkit.terminal.gwt.client.ui; | |||
import java.util.Date; | |||
import com.google.gwt.user.client.ui.ChangeListener; | |||
import com.google.gwt.user.client.ui.ListBox; | |||
import com.google.gwt.user.client.ui.Widget; | |||
import com.itmill.toolkit.terminal.gwt.client.Client; | |||
import com.itmill.toolkit.terminal.gwt.client.Paintable; | |||
import com.itmill.toolkit.terminal.gwt.client.UIDL; | |||
public class ITextualDate extends IDateField implements Paintable, ChangeListener { | |||
private ListBox year; | |||
private ListBox month; | |||
private ListBox day; | |||
public ITextualDate() { | |||
} | |||
public void updateFromUIDL(UIDL uidl, Client client) { | |||
super.updateFromUIDL(uidl, client); | |||
if(uidl.hasVariable("year")) { | |||
int selectedYear = uidl.getIntVariable("year"); | |||
int y = container.getWidgetIndex(year); | |||
if(y > -1 || !currentLocale.equals(uidl.getStringAttribute("locale"))) { | |||
year = (ListBox) container.getWidget(y); | |||
// Deselect old value | |||
year.setItemSelected(year.getSelectedIndex(), false); | |||
// and select new | |||
for(int i=0; i < year.getItemCount(); i++) | |||
if(year.getValue(i).equals(""+selectedYear)) { | |||
year.setSelectedIndex(i); | |||
break; | |||
} | |||
} else { | |||
year = new ListBox(); | |||
year.setStyleName(ISelect.CLASSNAME); | |||
int today = 1900 + (new Date()).getYear(); | |||
for(int i=1970; i<today+400; i++) { | |||
year.addItem(""+i, ""+i); | |||
if(i == selectedYear) | |||
year.setSelectedIndex(year.getItemCount()-1); | |||
} | |||
year.addChangeListener(this); | |||
container.add(year); | |||
} | |||
} | |||
if(uidl.hasVariable("month")) { | |||
int selectedMonth = uidl.getIntVariable("month"); | |||
int y = container.getWidgetIndex(month); | |||
if(y > -1) { | |||
month = (ListBox) container.getWidget(y); | |||
// Deselect old value | |||
month.setItemSelected(month.getSelectedIndex(), false); | |||
// and select new | |||
for(int i=0; i < month.getItemCount(); i++) | |||
if(month.getValue(i).equals(""+selectedMonth)) { | |||
month.setSelectedIndex(i); | |||
break; | |||
} | |||
} else { | |||
month = new ListBox(); | |||
month.setStyleName(ISelect.CLASSNAME); | |||
int today = (new Date()).getMonth(); | |||
for(int i=0; i<12; i++) { | |||
month.addItem(""+(i+1), ""+i); | |||
if(i == selectedMonth) | |||
month.setSelectedIndex(month.getItemCount()-1); | |||
} | |||
month.addChangeListener(this); | |||
container.add(month); | |||
} | |||
} | |||
if(uidl.hasVariable("day")) { | |||
int selectedMonth = uidl.getIntVariable("day"); | |||
int y = container.getWidgetIndex(day); | |||
if(y > -1) { | |||
day = (ListBox) container.getWidget(y); | |||
// Deselect old value | |||
day.setItemSelected(day.getSelectedIndex(), false); | |||
// and select new | |||
for(int i=0; i <day.getItemCount(); i++) | |||
if(day.getValue(i).equals(""+selectedMonth)) { | |||
day.setSelectedIndex(i); | |||
break; | |||
} | |||
} else { | |||
day = new ListBox(); | |||
day.setStyleName(ISelect.CLASSNAME); | |||
int today = (new Date()).getDay(); | |||
for(int i=0; i<31; i++) { | |||
day.addItem(""+(i+1), ""+i); | |||
if(i == selectedMonth) | |||
day.setSelectedIndex(day.getItemCount()-1); | |||
} | |||
day.addChangeListener(this); | |||
container.add(day); | |||
} | |||
} | |||
} | |||
public void onChange(Widget sender) { | |||
if(sender == year && client != null) | |||
client.updateVariable(id, "year", year.getValue(year.getSelectedIndex()), immediate); | |||
} | |||
} |
@@ -35,13 +35,18 @@ import java.io.InputStreamReader; | |||
import java.io.OutputStream; | |||
import java.io.OutputStreamWriter; | |||
import java.io.PrintWriter; | |||
import java.text.DateFormatSymbols; | |||
import java.text.SimpleDateFormat; | |||
import java.util.ArrayList; | |||
import java.util.Calendar; | |||
import java.util.Collections; | |||
import java.util.Comparator; | |||
import java.util.GregorianCalendar; | |||
import java.util.HashSet; | |||
import java.util.Iterator; | |||
import java.util.LinkedHashSet; | |||
import java.util.List; | |||
import java.util.Locale; | |||
import java.util.Map; | |||
import java.util.Set; | |||
import java.util.WeakHashMap; | |||
@@ -96,9 +101,14 @@ public class AjaxApplicationManager implements | |||
private Set removedWindows = new HashSet(); | |||
private PaintTarget paintTarget; | |||
private List locales; | |||
private int pendingLocalesIndex; | |||
public AjaxApplicationManager(Application application) { | |||
this.application = application; | |||
requireLocale(application.getLocale().getLanguage()); | |||
} | |||
/** | |||
@@ -220,6 +230,10 @@ public class AjaxApplicationManager implements | |||
if (repaintAll) { | |||
paintables = new LinkedHashSet(); | |||
paintables.add(window); | |||
// Reset sent locales | |||
locales = null; | |||
requireLocale(application.getLocale().getLanguage()); | |||
// Adds all non-native windows | |||
for (Iterator i = window.getApplication().getWindows() | |||
@@ -382,7 +396,115 @@ public class AjaxApplicationManager implements | |||
} | |||
} | |||
outWriter.print("}"); | |||
// Store JVM default locale for later restoration | |||
// (we'll have to change the default locale for a while) | |||
Locale jvmDefault = Locale.getDefault(); | |||
// Send locale informations to client | |||
outWriter.print(", \"locales\":["); | |||
for(;pendingLocalesIndex < locales.size(); pendingLocalesIndex++) { | |||
Locale l = new Locale((String) locales.get(pendingLocalesIndex)); | |||
// Locale name | |||
outWriter.print("{\"name\":\"" + l.toString() + "\","); | |||
/* | |||
* Month names (both short and full) | |||
*/ | |||
DateFormatSymbols dfs = new DateFormatSymbols(l); | |||
String[] short_months = dfs.getShortMonths(); | |||
String[] months = dfs.getMonths(); | |||
outWriter.print("\"smn\":[\"" + // ShortMonthNames | |||
short_months[0] + "\",\"" + | |||
short_months[1] + "\",\"" + | |||
short_months[2] + "\",\"" + | |||
short_months[3] + "\",\"" + | |||
short_months[4] + "\",\"" + | |||
short_months[5] + "\",\"" + | |||
short_months[6] + "\",\"" + | |||
short_months[7] + "\",\"" + | |||
short_months[8] + "\",\"" + | |||
short_months[9] + "\",\"" + | |||
short_months[10] + "\",\"" + | |||
short_months[11] + "\"" + | |||
"],"); | |||
outWriter.print("\"mn\":[\"" + // MonthNames | |||
months[0] + "\",\"" + | |||
months[1] + "\",\"" + | |||
months[2] + "\",\"" + | |||
months[3] + "\",\"" + | |||
months[4] + "\",\"" + | |||
months[5] + "\",\"" + | |||
months[6] + "\",\"" + | |||
months[7] + "\",\"" + | |||
months[8] + "\",\"" + | |||
months[9] + "\",\"" + | |||
months[10] + "\",\"" + | |||
months[11] + "\"" + | |||
"],"); | |||
/* | |||
* Weekday names (both short and full) | |||
*/ | |||
String[] short_days = dfs.getShortWeekdays(); | |||
String[] days = dfs.getWeekdays(); | |||
outWriter.print("\"sdn\":[\"" + // ShortDayNames | |||
short_days[1] + "\",\"" + | |||
short_days[2] + "\",\"" + | |||
short_days[3] + "\",\"" + | |||
short_days[4] + "\",\"" + | |||
short_days[5] + "\",\"" + | |||
short_days[6] + "\",\"" + | |||
short_days[7] + "\"" + | |||
"],"); | |||
outWriter.print("\"dn\":[\"" + // DayNames | |||
days[1] + "\",\"" + | |||
days[2] + "\",\"" + | |||
days[3] + "\",\"" + | |||
days[4] + "\",\"" + | |||
days[5] + "\",\"" + | |||
days[6] + "\",\"" + | |||
days[7] + "\"" + | |||
"],"); | |||
/* | |||
* First day of week (0 = sunday, 1 = monday) | |||
*/ | |||
Calendar cal = new GregorianCalendar(l); | |||
outWriter.print("\"fdow\":" + (cal.getFirstDayOfWeek() - 1) + ","); | |||
/* | |||
* Date formatting (MM/DD/YYYY etc.) | |||
*/ | |||
// Force our locale as JVM default for a while (SimpleDateFormat uses JVM default) | |||
Locale.setDefault(l); | |||
String df = new SimpleDateFormat().toPattern(); | |||
// TODO we suppose all formats separate date and time with a whitespace | |||
String dateformat = df.substring(0,df.indexOf(" ")); | |||
outWriter.print("\"df\":\"" + dateformat + "\","); | |||
/* | |||
* Time formatting (24 or 12 hour clock and AM/PM suffixes) | |||
*/ | |||
String timeformat = df.substring(df.indexOf(" ")+1, df.length()); // Doesn't return second or milliseconds | |||
// We use timeformat to determine 12/24-hour clock | |||
boolean twelve_hour_clock = timeformat.contains("a"); | |||
// TODO there are other possibilities as well, like 'h' in french (ignore them, too complicated) | |||
String hour_min_delimiter = timeformat.contains(".")? "." : ":"; | |||
//outWriter.print("\"tf\":\"" + timeformat + "\","); | |||
outWriter.print("\"thc\":" + twelve_hour_clock + ","); | |||
outWriter.print("\"hmd\":\"" + hour_min_delimiter + "\""); | |||
outWriter.print("}"); | |||
if(pendingLocalesIndex < locales.size()-1) | |||
outWriter.print(","); | |||
} | |||
outWriter.print("]"); // Close locales | |||
// Restore JVM default locale | |||
Locale.setDefault(jvmDefault); | |||
outWriter.flush(); | |||
outWriter.close(); | |||
out.flush(); | |||
@@ -778,4 +900,14 @@ public class AjaxApplicationManager implements | |||
return this.owner; | |||
} | |||
} | |||
public void requireLocale(String value) { | |||
if(locales == null) { | |||
locales = new ArrayList(); | |||
locales.add(application.getLocale().getLanguage()); | |||
pendingLocalesIndex = 0; | |||
} | |||
if(!locales.contains(value)) | |||
locales.add(value); | |||
} | |||
} |
@@ -450,6 +450,9 @@ public class AjaxJsonPaintTarget implements PaintTarget, AjaxPaintTarget { | |||
if (customLayoutArgumentsOpen && "style".equals(name)) | |||
getPreCachedResources().add("layout/" + value + ".html"); | |||
if(name.equals("locale")) | |||
manager.requireLocale(value); | |||
} | |||