Index: trunk/hiptop/pester/locale/en_US/Pester.rsrc
===================================================================
--- trunk/hiptop/pester/locale/en_US/Pester.rsrc	(revision 239)
+++ trunk/hiptop/pester/locale/en_US/Pester.rsrc	(revision 240)
@@ -128,5 +128,5 @@
 		
 		checkBox
-			id = ID_PERIOD_REPEAT_BUTTON
+			id = ID_PERIOD_REPEAT_CHECKBOX
 			title = "Repeat"
 			alignBaseline = ID_PERIOD_UNITS_POPUP
@@ -150,4 +150,5 @@
 			id = ID_TIME_EDITOR
 			longTimeFormat
+			event = EVENT_TIME_EDITOR
 			alignBaseline = ID_AT_BUTTON
 			positionToRight = ID_AT_BUTTON : 1
@@ -155,4 +156,5 @@
 		dateEditor
 			id = ID_DATE_EDITOR
+			event = EVENT_DATE_EDITOR
 			positionToRight = ID_TIME_EDITOR : 1
 			alignBaseline = ID_TIME_EDITOR
@@ -160,4 +162,5 @@
 		datePicker
 			id = ID_DATE_PICKER
+			event = EVENT_DATE_PICKER
 			positionToRight = ID_DATE_EDITOR : 1
 			alignTop = ID_DATE_EDITOR
@@ -171,4 +174,5 @@
 
 	button
+		id = ID_SET_ALARM_BUTTON
 		position = buttonBottom1
 		title = "Set"
Index: trunk/hiptop/pester/net/sabi/pester/Alarm.java
===================================================================
--- trunk/hiptop/pester/net/sabi/pester/Alarm.java	(revision 239)
+++ trunk/hiptop/pester/net/sabi/pester/Alarm.java	(revision 240)
@@ -7,4 +7,5 @@
 import danger.internal.Date;
 import danger.util.StdActiveObject;
+import danger.util.DEBUG;
 
 public class Alarm extends StdActiveObject {
@@ -14,5 +15,5 @@
     private String mMessage;
     private int mType;
-    private long mPeriod;
+    private int mPeriod; // XXX rename to 'interval'
     private Date mDate;
 
@@ -27,9 +28,12 @@
 	return mMessage;
     }
-    public long getPeriod() {
+    public int getPeriod() {
 	return mPeriod;
     }
     public boolean getUsesPeriod() {
 	return mType != TYPE_DATE;
+    }
+    public boolean getRepeating() {
+	return mType == TYPE_PERIODIC_REPEATING;
     }
     public Date getDate() {
@@ -40,7 +44,9 @@
 	mMessage = message;
     }
-    public void setPeriod(long period, boolean repeating) {
+    public void setPeriod(int period, boolean repeating) {
 	mType = repeating ? TYPE_PERIODIC_REPEATING : TYPE_PERIODIC;
 	mPeriod = period;
+	mDate = new Date();
+	mDate.addSeconds(period);
     }
     public void setDate(Date date) {
@@ -56,5 +62,5 @@
 	    dataStream.writeByte(VERSION_1);
 	    dataStream.writeUTF(mMessage);
-	    dataStream.writeLong(mPeriod);
+	    dataStream.writeInt(mPeriod);
 	    dataStream.writeInt(mDate.getUnixTimeGMT());
 	    dataStream.writeInt(mType);
@@ -77,5 +83,5 @@
 	    }
 	    mMessage = dataStream.readUTF();
-	    mPeriod = dataStream.readLong();
+	    mPeriod = dataStream.readInt();
 	    mType = dataStream.readInt();
 	} catch (Exception e) {
@@ -90,4 +96,13 @@
     void endEditing() {
 	mStatus = STATUS_SCHEDULED;
+	DEBUG.p("schedule alarm: " + mMessage);
+	switch (mType) {
+	case TYPE_PERIODIC:
+	    DEBUG.p(" - periodic: " + mPeriod); break;
+	case TYPE_PERIODIC_REPEATING:
+	    DEBUG.p(" - periodic repeating: " + mPeriod); break;
+	case TYPE_DATE:
+	    DEBUG.p(" - date: " + mDate); break;
+	}
     }
     
Index: trunk/hiptop/pester/net/sabi/pester/AlarmListView.java
===================================================================
--- trunk/hiptop/pester/net/sabi/pester/AlarmListView.java	(revision 239)
+++ trunk/hiptop/pester/net/sabi/pester/AlarmListView.java	(revision 240)
@@ -3,7 +3,13 @@
 import danger.app.Application;
 import danger.app.Event;
+import danger.internal.Date;
 import danger.ui.ActiveListView;
 import danger.ui.Button;
+import danger.ui.CheckBox;
+import danger.ui.DateTimeEditor;
+import danger.ui.DatePicker;
 import danger.ui.DialogWindow;
+import danger.ui.NumberEditor;
+import danger.ui.PopupMenu;
 import danger.ui.RadioButton;
 import danger.ui.Rect;
@@ -23,6 +29,11 @@
     private static DialogWindow sEditWindow;
     private TypeAheadTextField sMessageField;
-    private Button sDiscardAlarmButton;
     private RadioButton sInButton, sAtButton;
+    private NumberEditor sPeriodField;
+    private PopupMenu sPeriodUnitsPopup;
+    private CheckBox sRepeatCheckBox;
+    private DateTimeEditor sTimeEditor, sDateEditor;
+    private DatePicker sDatePicker;
+    private Button sDiscardAlarmButton, sSetAlarmButton;
 
     private static Alarm sFocusedAlarm, sEditingAlarm;
@@ -42,5 +53,14 @@
 	sInButton = (RadioButton)sEditWindow.getDescendantWithID(ID_IN_BUTTON);
 	sAtButton = (RadioButton)sEditWindow.getDescendantWithID(ID_AT_BUTTON);
+	sPeriodField = (NumberEditor)sEditWindow.getDescendantWithID(ID_PERIOD_FIELD);
+	sPeriodUnitsPopup = (PopupMenu)sEditWindow.getDescendantWithID(ID_PERIOD_UNITS_POPUP);
+	sRepeatCheckBox = (CheckBox)sEditWindow.getDescendantWithID(ID_PERIOD_REPEAT_CHECKBOX);
+	sTimeEditor = (DateTimeEditor)sEditWindow.getDescendantWithID(ID_TIME_EDITOR);
+	sDateEditor = (DateTimeEditor)sEditWindow.getDescendantWithID(ID_DATE_EDITOR);
+	sDatePicker = (DatePicker)sEditWindow.getDescendantWithID(ID_DATE_PICKER);
+	sSetAlarmButton = (Button)sEditWindow.getDescendantWithID(ID_SET_ALARM_BUTTON);
 	sDiscardAlarmButton = (Button)sEditWindow.getDescendantWithID(ID_DISCARD_ALARM_BUTTON);
+	sInButton.setValue(1);
+	sDateEditor.limitToDangerEpoch();
 
 	super.onDecoded();
@@ -57,16 +77,56 @@
     }
 
-    void editAlarm(Alarm alarm, boolean asNew) {
+    protected void editDateOrPeriod(Alarm alarm) {
+        boolean usesPeriod = alarm.getUsesPeriod();
+	if (usesPeriod) {
+	    int period = alarm.getPeriod();
+	    int unitsPerSec = 1;
+	    DEBUG.p("period is " + period);
+	    for (int i = sPeriodUnitsPopup.itemCount() - 1 ; i >= 0 ; --i) {
+		unitsPerSec =
+		    sPeriodUnitsPopup.getIDOfItem(sPeriodUnitsPopup.getItem(i));
+		DEBUG.p("unitsPerSec = " + unitsPerSec);
+		if (period % unitsPerSec == 0) break;
+	    }
+	    sPeriodField.setValue(period / unitsPerSec);
+	    sPeriodUnitsPopup.setValueWithItemID(unitsPerSec);
+	    sRepeatCheckBox.setValue(alarm.getRepeating() ? 1 : 0);
+	}
+
+	Date date = alarm.getDate();
+	sTimeEditor.setDate(date);
+	sDateEditor.setDate(date);
+	sDatePicker.setDate(date);
+
+	sInButton.setValue(usesPeriod ? 1 : 0);
+	sAtButton.setValue(usesPeriod ? 0 : 1);
+    }
+
+    protected void editAlarm(Alarm alarm, boolean asNew) {
 	sEditingAlarm = alarm;
 	alarm.beginEditing();
-	sMessageField.setText(sEditingAlarm.getMessage());
+	sMessageField.setText(alarm.getMessage());
 	if (asNew) {
 	    sDiscardAlarmButton.hide();
 	} else {
 	    sDiscardAlarmButton.show();
-	}
-        boolean usesPeriod = sEditingAlarm.getUsesPeriod();
-	
+	    editDateOrPeriod(alarm);
+	}
+	constrainDate();
 	sEditWindow.show();
+    }
+
+    protected Date editingDate() {
+	Date date = sDateEditor.getDate();
+	date.setTime(sTimeEditor.getDate().getTime());
+	return date;
+    }
+
+    protected void constrainDate() {
+	// XXX schedule every minute (second?) if in AT mode
+	Date now = new Date();
+	sDateEditor.min(now);
+	sDatePicker.min(now);
+	sSetAlarmButton.setEnabled(editingDate().compareTo(now) > 0);
     }
 
@@ -77,10 +137,20 @@
 	    return true;
 	case EVENT_SET_ALARM:
+	    sEditingAlarm.setMessage(sMessageField.toString());
+	    if (sInButton.getValue() == 1) {
+		DEBUG.p("period: " + sPeriodField.getValue());
+		DEBUG.p(" units: " + sPeriodUnitsPopup.getValueAsItemID());
+		sEditingAlarm.setPeriod(sPeriodField.getValue() * 
+					sPeriodUnitsPopup.getValueAsItemID(),
+					sRepeatCheckBox.getValue() == 1);
+	    } else {
+		sEditingAlarm.setDate(editingDate());
+	    }
 	    if (sEditingAlarm != sFocusedAlarm) { // new alarm
 		sAlarmList.addItem(sEditingAlarm);
 		setFocusedItem(sEditingAlarm);
-	    }
-	    sEditingAlarm.setMessage(sMessageField.toString());
-	    sEditingAlarm.update();
+	    } else {
+		sEditingAlarm.update();
+	    }
 	case EVENT_CANCEL_ALARM:
 	    // XXX (re)schedule alarm
@@ -96,4 +166,24 @@
 	case EVENT_AT:
 	    sInButton.setValue(0);
+	    constrainDate();
+	    return true;
+	case EVENT_TIME_EDITOR:
+	    Date date = editingDate();
+	    // XXX factor this out (it's used twice)
+	    // XXX do this on exit from the field, not on change
+	    if (date.compareTo(new Date()) <= 0) {
+		date.addDays(1);
+		sDatePicker.setDate(date);
+		sDateEditor.setDate(date);
+	    }
+	    constrainDate();
+	    return true;
+        case EVENT_DATE_EDITOR:
+	    sDatePicker.setDate(sDateEditor.getDate());
+	    constrainDate();
+	    return true;
+        case EVENT_DATE_PICKER:
+	    sDateEditor.setDate((Date)e.argument);
+	    constrainDate();
 	    return true;
 	}
