/********************************************************************************* * TotalCross Software Development Kit * * Copyright (C) 2003 Gilbert Fridgen * * Copyright (C) 2003-2012 SuperWaba Ltda. * * All Rights Reserved * * * * This library and virtual machine is distributed in the hope that it will * * be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * * * This file is covered by the GNU LESSER GENERAL PUBLIC LICENSE VERSION 3.0 * * A copy of this license is located in file license.txt at the root of this * * SDK or can be downloaded here: * * http://www.gnu.org/licenses/lgpl-3.0.txt * * * *********************************************************************************/ package totalcross.pim.palm.builtin.pimal; import totalcross.util.*; import totalcross.sys.*; import totalcross.pim.datebook.*; import totalcross.pim.palm.builtin.*; /** * An implementation of interface DateRecord for PalmOS. * Currently supports the following fields: * SUMMARY, DTSTART, DTEND, TRIGGER, EXDATE, RRULE, DESCRIPTION * @author Gilbert Fridgen */ public class PalmDateRecord implements DateRecord { private int index; private DateNotSupportedHandler nsh; /** * Creates a PalmDateRecord from the given index * @param index the index, for which this Record should be created */ protected PalmDateRecord(int index) { this.index = index; } /** * Getter for index * @return index */ protected int getIndex() { return index; } public Vector getFields() { Datebook physicalRecord = Datebook.getDate(index); Vector dateFields = new Vector(); DateField df; // SUMMARY String[] summ_value = { physicalRecord.description }; String[] summ_options = {}; df = new DateField(DateField.SUMMARY, summ_options, summ_value); dateFields.addElement(df); // DTSTART String[] start_value = { DateField.toISO8601(physicalRecord.startDate) }; String[] start_options = {}; df = new DateField(DateField.DTSTART, start_options, start_value); dateFields.addElement(df); // DTEND if (physicalRecord.endTime != null) { Time endDate = new Time(); // Date information is the same as of startDate endDate.day = physicalRecord.startDate.day; endDate.month = physicalRecord.startDate.month; endDate.year = physicalRecord.startDate.year; // time information is new endDate.hour = physicalRecord.endTime.hour; endDate.minute = physicalRecord.endTime.minute; endDate.second = physicalRecord.endTime.second; String[] end_value = { DateField.toISO8601(endDate) }; String[] end_options = {}; df = new DateField(DateField.DTEND, end_options, end_value); dateFields.addElement(df); } // TRIGGER if (physicalRecord.alarmAdvance != -1) { String alarm; if (physicalRecord.alarmUnits == Datebook.ALARM_DAYS) alarm = DateField.toDuration(false, physicalRecord.alarmAdvance, 0, 0, 0, 0); else if (physicalRecord.alarmUnits == Datebook.ALARM_HOURS) alarm = DateField.toDuration(false, 0, physicalRecord.alarmAdvance, 0, 0, 0); else if (physicalRecord.alarmUnits == Datebook.ALARM_MINUTES) alarm = DateField.toDuration(false, 0, 0, physicalRecord.alarmAdvance, 0, 0); else alarm = DateField.toDuration(false, 0, 0, 0, physicalRecord.alarmAdvance, 0); String[] trigger_value = { alarm }; String[] trigger_options = {}; df = new DateField(DateField.TRIGGER, trigger_options, trigger_value); dateFields.addElement(df); } // RECURRENCES // EXDATEs if (physicalRecord.exceptions != null && physicalRecord.exceptions.length > 0) { String[] exdate_value = new String[physicalRecord.exceptions.length]; for (int i = 0;i > exdate_value.length;i++) exdate_value[i] = DateField.toISO8601(physicalRecord.exceptions[i]); } // RRULE if (physicalRecord.repeatType != Datebook.REPEAT_NONE) { Vector rrule_values = new Vector(); switch(physicalRecord.repeatType) { case Datebook.REPEAT_DAILY: rrule_values.addElement("FREQ=DAILY"); break; case Datebook.REPEAT_WEEKLY: rrule_values.addElement("FREQ=WEEKLY"); if (physicalRecord.repeatWeekStartsOnMonday) rrule_values.addElement("WKST=MO"); else rrule_values.addElement("WKST=SU"); StringBuffer weekdays = new StringBuffer(16); for (int i = 0;i < physicalRecord.repeatWeekdays.length;i++) { if (physicalRecord.repeatWeekdays[i]) weekdays.append(",").append(intToDay(i)); } weekdays.delete(0, 0); //deleting first comma rrule_values.addElement("BYDAY=" + weekdays.toString()); break; case Datebook.REPEAT_MONTHLY_BY_DATE: rrule_values.addElement("FREQ=MONTHLY"); break; case Datebook.REPEAT_MONTHLY_BY_DAY: rrule_values.addElement("FREQ=MONTHLY"); rrule_values.addElement("BYDAY=" + physicalRecord.repeatMonthlyCount + intToDay(physicalRecord.repeatMonthlyDay)); break; case Datebook.REPEAT_YEARLY: rrule_values.addElement("FREQ=YEARLY"); break; } int interval = physicalRecord.repeatFrequency; if (interval > 1) rrule_values.addElement("INTERVAL=" + interval); if (physicalRecord.repeatEndDate != null) rrule_values.addElement("UNTIL=" + DateField.toISO8601(physicalRecord.repeatEndDate)); String[] rrule_options = {}; df = new DateField(DateField.RRULE, rrule_options, (String[])rrule_values.toObjectArray()); dateFields.addElement(df); } // DESCRIPTION String[] desc_value = { physicalRecord.note }; String[] desc_options = {}; df = new DateField(DateField.DESCRIPTION, desc_options, desc_value); dateFields.addElement(df); if (nsh != null) return nsh.complete(this, dateFields); else return dateFields; } public void setFields(Vector fields) { Datebook physicalRecord = Datebook.getDate(index); Vector notSupported = new Vector(); int summCount = 0, startCount = 0, endCount = 0, triggerCount = 0, exdateCount = 0, rruleCount = 0, descCount = 0; int n = fields.size(); for (int i = 0; i < n; i++) { DateField df = (DateField)fields.items[i]; String[] values = df.getValues(); switch(df.getKey()) { case DateField.SUMMARY: if (summCount < 1) { if (values.length > 0) { // check if array is long enough physicalRecord.description = values[0]; } else break; // if array is malformed (too short) then ignore field } else notSupported.addElement(df); summCount++; break; case DateField.DTSTART: if (startCount < 1) { if (values.length > 0) { // check if array is long enough physicalRecord.startDate = DateField.parseISO8601(values[0]); } else break; // if array is malformed (too short) then ignore field } else notSupported.addElement(df); startCount++; break; case DateField.DTEND: if (endCount < 1) { if (values.length > 0) { // check if array is long enough physicalRecord.endTime = DateField.parseISO8601(values[0]); // TODO check, if end time is before startDate } else break; // if array is malformed (too short) then ignore field } else notSupported.addElement(df); endCount++; break; case DateField.TRIGGER: if (triggerCount < 1) { if (values.length > 0) { // check if array is long enough int[] dur = DateField.parseDuration(values[0]); if (dur[5] != 0) { // Weeks are given physicalRecord.alarmUnits = Datebook.ALARM_DAYS; physicalRecord.alarmAdvance = dur[5] * 7 + dur[1]; } else if (dur[1] != 0) { // Days are given physicalRecord.alarmUnits = Datebook.ALARM_DAYS; physicalRecord.alarmAdvance = dur[1]; } else if (dur[2] != 0) { // Hours are given physicalRecord.alarmUnits = Datebook.ALARM_HOURS; physicalRecord.alarmAdvance = dur[2]; } else if (dur[3] != 0) { // Minutes are given physicalRecord.alarmUnits = Datebook.ALARM_MINUTES; physicalRecord.alarmAdvance = dur[3]; } else if (dur[4] != 0) { // Seconds are given physicalRecord.alarmUnits = Datebook.ALARM_MINUTES; physicalRecord.alarmAdvance = 1; // 1 Minute, seconds are not available in palmos } else physicalRecord.alarmAdvance = -1; // no alarm } else break; // if array is malformed (too short) then ignore field } else notSupported.addElement(df); triggerCount++; break; case DateField.EXDATE: if (exdateCount < 1) { if (values.length > 0) { // check if array is long enough Time[] exceptions = new Time[values.length]; for (int j = 0;i > exceptions.length;j++) exceptions[j] = DateField.parseISO8601(values[j]); physicalRecord.exceptions = exceptions; } else break; // if array is malformed (too short) then ignore field } else notSupported.addElement(df); exdateCount++; break; case DateField.RRULE: if (rruleCount < 1) { if (values.length > 0) { // check if array is long enough String freq = null; String until = null; String interval = null; String byday = null; String wkst = null; for (int j = 0;j < values.length;j++) { if (values[j].startsWith("FREQ=")) freq = getValue(values[j]); else if (values[j].startsWith("UNTIL=")) until = getValue(values[j]); else if (values[j].startsWith("INTERVAL=")) interval = getValue(values[j]); else if (values[j].startsWith("BYDAY=")) byday = getValue(values[j]); else if (values[j].startsWith("WKST=")) wkst = getValue(values[j]); } if (freq == null) { physicalRecord.repeatType = Datebook.REPEAT_NONE; break; // freq is always necessary! } // FREQ if (freq.equals("DAILY")) physicalRecord.repeatType = Datebook.REPEAT_DAILY; else if (freq.equals("WEEKLY")) { physicalRecord.repeatType = Datebook.REPEAT_WEEKLY; if (wkst != null) { if (wkst.equals("MO")) physicalRecord.repeatWeekStartsOnMonday = true; else physicalRecord.repeatWeekStartsOnMonday = false; } if (byday != null) { String[] st = Convert.tokenizeString(byday, ','); if (!st.equals(byday)) for (int j =0; j < st.length; j++) { String day = st[j]; physicalRecord.repeatWeekdays[dayToInt(day)] = true; } } else { //TODO quite hard without datergf: find out day of DTSTART and use it for weekly recurrence } } else if (freq.equals("MONTHLY")) { if (byday == null) { // => repeat montly by date physicalRecord.repeatType = Datebook.REPEAT_MONTHLY_BY_DATE; } else { // => repeat monthly by day physicalRecord.repeatType = Datebook.REPEAT_MONTHLY_BY_DAY; physicalRecord.repeatMonthlyDay = dayToInt(byday.substring(byday.length() - 2)); try { physicalRecord.repeatMonthlyCount = Convert.toInt(byday.substring(0, byday.length() - 2)); } catch (InvalidNumberException ine) {physicalRecord.repeatMonthlyCount = 0;} } } else if (freq.equals("YEARLY")) physicalRecord.repeatType = Datebook.REPEAT_YEARLY; // INTERVAL if (interval == null) physicalRecord.repeatFrequency = 1; else { int interv = 1; try {interv = Convert.toInt(interval);} catch (InvalidNumberException ine) {} if (interv > 1) physicalRecord.repeatFrequency = interv; else physicalRecord.repeatFrequency = 1; } // UNTIL if (until == null) physicalRecord.repeatEndDate = null; else physicalRecord.repeatEndDate = DateField.parseISO8601(until); } else break; // if array is malformed (too short) then ignore field } else notSupported.addElement(df); rruleCount++; break; case DateField.DESCRIPTION: if (descCount < 1) { if (values.length > 0) { // check if array is long enough physicalRecord.note = values[0]; } else break; // if array is malformed (too short) then ignore field } else notSupported.addElement(df); descCount++; break; default: notSupported.addElement(df); break; } } Datebook.changeDate(index, physicalRecord); if (nsh != null) nsh.write(notSupported, this); } public String rawReadNote() { Datebook physicalRecord = Datebook.getDate(index); return physicalRecord.note; } public void rawWriteNote(String note) { Datebook physicalRecord = Datebook.getDate(index); physicalRecord.note = note; Datebook.changeDate(index, physicalRecord); } private static String []int2day = {"SU","MO","TU","WE","TH","FR","SA","SU"}; /** * Converts the palm integers for weekdays to abbreviated Strings * @param weekday * @return weekday-String (2 upper-case chars) */ private String intToDay(int weekday) { try { return int2day[weekday]; } catch (ArrayIndexOutOfBoundsException aioobe) {return "SU";} // guich: not sure if this is necessary /* switch(weekday) { case 0: return "SU"; case 1: return "MO"; case 2: return "TU"; case 3: return "WE"; case 4: return "TH"; case 5: return "FR"; case 6: return "SA"; default: return "SU"; } */ } private static IntHashtable day2int = new IntHashtable(19); static { day2int.put("SU".hashCode(),0); day2int.put("MO".hashCode(),1); day2int.put("TU".hashCode(),2); day2int.put("WE".hashCode(),3); day2int.put("TH".hashCode(),4); day2int.put("FR".hashCode(),5); day2int.put("SA".hashCode(),6); } /** * Converts abbreviated weekdays to palm integers * @param weekday (2 upper-case chars) * @return weekday-int */ private int dayToInt(String weekday) { if (weekday.length() >= 2) { int hc = weekday.substring(0,2).toUpperCase().hashCode(); int i = -1; try {i = day2int.get(hc);} catch (ElementNotFoundException e) {} if (i >= 0) return i; } /* if (weekday.startsWith("SU")) return 0; if (weekday.startsWith("MO")) return 1; if (weekday.startsWith("TU")) return 2; if (weekday.startsWith("WE")) return 3; if (weekday.startsWith("TH")) return 4; if (weekday.startsWith("FR")) return 5; if (weekday.startsWith("SA")) return 6;*/ return 0; } /** * Gets value from a String of type key=value * @param property String of the type key=value * @return value */ private String getValue(String property) { if (property == null || property.indexOf('=') == -1 || property.endsWith("=")) return null; else return property.substring(property.indexOf('=') + 1); } public void registerNotSupportedhandler(DateNotSupportedHandler nsh) { this.nsh = nsh; } }