jfxtras.icalendarfx.components.VEvent Maven / Gradle / Ivy
package jfxtras.icalendarfx.components;
import java.time.Duration;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAmount;
import java.util.Collections;
import java.util.List;
import jfxtras.icalendarfx.VCalendar;
import jfxtras.icalendarfx.components.VDateTimeEnd;
import jfxtras.icalendarfx.components.VDescribable2;
import jfxtras.icalendarfx.components.VEvent;
import jfxtras.icalendarfx.components.VLocatable;
import jfxtras.icalendarfx.components.VRepeatable;
import jfxtras.icalendarfx.properties.component.time.DateTimeEnd;
import jfxtras.icalendarfx.properties.component.time.TimeTransparency;
import jfxtras.icalendarfx.properties.component.time.TimeTransparency.TimeTransparencyType;
import jfxtras.icalendarfx.utilities.DateTimeUtilities;
/**
* VEVENT
* Event Component
* RFC 5545, 3.6.1, page 52
*
* Description: A "VEVENT" calendar component is a grouping of
component properties, possibly including "VALARM" calendar
components, that represents a scheduled amount of time on a
calendar. For example, it can be an activity; such as a one-hour
long, department meeting from 8:00 AM to 9:00 AM, tomorrow.
Generally, an event will take up time on an individual calendar.
Hence, the event will appear as an opaque interval in a search for
busy time. Alternately, the event can have its Time Transparency
set to "TRANSPARENT" in order to prevent blocking of the event in
searches for busy time.
The "VEVENT" is also the calendar component used to specify an
anniversary or daily reminder within a calendar. These events
have a DATE value type for the "DTSTART" property instead of the
default value type of DATE-TIME. If such a "VEVENT" has a "DTEND"
property, it MUST be specified as a DATE value also. The
anniversary type of "VEVENT" can span more than one date (i.e.,
"DTEND" property value is set to a calendar date after the
"DTSTART" property value). If such a "VEVENT" has a "DURATION"
property, it MUST be specified as a "dur-day" or "dur-week" value.
The "DTSTART" property for a "VEVENT" specifies the inclusive
start of the event. For recurring events, it also specifies the
very first instance in the recurrence set. The "DTEND" property
for a "VEVENT" calendar component specifies the non-inclusive end
of the event. For cases where a "VEVENT" calendar component
specifies a "DTSTART" property with a DATE value type but no
"DTEND" nor "DURATION" property, the event's duration is taken to
be one day. For cases where a "VEVENT" calendar component
specifies a "DTSTART" property with a DATE-TIME value type but no
"DTEND" property, the event ends on the same calendar date and
time of day specified by the "DTSTART" property.
The "VEVENT" calendar component cannot be nested within another
calendar component. However, "VEVENT" calendar components can be
related to each other or to a "VTODO" or to a "VJOURNAL" calendar
component with the "RELATED-TO" property.
Example: The following is an example of the "VEVENT" calendar
component used to represent a meeting that will also be opaque to
searches for busy time:
BEGIN:VEVENT
UID:[email protected]
DTSTAMP:19970901T130000Z
DTSTART:19970903T163000Z
DTEND:19970903T190000Z
SUMMARY:Annual Employee Review
CLASS:PRIVATE
CATEGORIES:BUSINESS,HUMAN RESOURCES
END:VEVENT
*
* @author David Bal
*
*/
public class VEvent extends VLocatable implements VDateTimeEnd,
VDescribable2, VRepeatable
{
/**
* DTEND
* Date-Time End
* RFC 5545, 3.8.2.2, page 95
*
* This property specifies when the calendar component ends.
*
* The value type of this property MUST be the same as the "DTSTART" property, and
* its value MUST be later in time than the value of the "DTSTART" property.
*
* Example:
* DTEND;VALUE=DATE:19980704
*/
@Override
public DateTimeEnd getDateTimeEnd() { return dateTimeEnd; }
private DateTimeEnd dateTimeEnd;
@Override
public void setDateTimeEnd(DateTimeEnd dateTimeEnd)
{
orderChild(this.dateTimeEnd, dateTimeEnd);
this.dateTimeEnd = dateTimeEnd;
}
/** add listener to Duration to ensure both DURATION and DTEND are not both set */
/**
* TRANSP
* Time Transparency
* RFC 5545 iCalendar 3.8.2.7. page 101
*
* This property defines whether or not an event is transparent to busy time searches.
* Events that consume actual time SHOULD be recorded as OPAQUE. Other
* events, which do not take up time SHOULD be recorded as TRANSPARENT.
*
* Example:
* TRANSP:TRANSPARENT
*/
private TimeTransparency timeTransparency;
public TimeTransparency getTimeTransparency() { return timeTransparency; }
public void setTimeTransparency(String timeTransparency) { setTimeTransparency(TimeTransparency.parse(timeTransparency)); }
public void setTimeTransparency(TimeTransparency timeTransparency)
{
orderChild(this.timeTransparency, timeTransparency);
this.timeTransparency = timeTransparency;
}
public void setTimeTransparency(TimeTransparencyType timeTransparency) { setTimeTransparency(new TimeTransparency(timeTransparency)); }
public VEvent withTimeTransparency(TimeTransparency timeTransparency)
{
setTimeTransparency(timeTransparency);
return this;
}
public VEvent withTimeTransparency(TimeTransparencyType timeTransparencyType)
{
setTimeTransparency(timeTransparencyType);
return this;
}
public VEvent withTimeTransparency(String timeTransparency)
{
setTimeTransparency(TimeTransparency.parse(timeTransparency));
return this;
}
/*
* CONSTRUCTORS
*/
public VEvent()
{
super();
}
/** Copy constructor */
public VEvent(VEvent source)
{
super(source);
}
@Override
public TemporalAmount getActualDuration()
{
final TemporalAmount duration;
if (getDuration() != null)
{
duration = getDuration().getValue();
} else if (getDateTimeEnd() != null)
{
Temporal dtstart = getDateTimeStart().getValue();
Temporal dtend = getDateTimeEnd().getValue();
duration = DateTimeUtilities.temporalAmountBetween(dtstart, dtend);
} else
{
return Duration.ZERO;
}
return duration;
}
@Override
public void setEndOrDuration(Temporal startRecurrence, Temporal endRecurrence)
{
TemporalAmount duration = DateTimeUtilities.temporalAmountBetween(startRecurrence, endRecurrence);
if (getDuration() != null)
{
setDuration(duration);
} else if (getDateTimeEnd() != null)
{
Temporal dtend = getDateTimeStart().getValue().plus(duration);
setDateTimeEnd(dtend);
} else
{
throw new RuntimeException("Either DTEND or DURATION must be set");
}
}
@Override
public List errors()
{
List errors = super.errors();
List dtendError = VDateTimeEnd.errorsDateTimeEnd(this);
errors.addAll(dtendError);
if (getDateTimeStart() == null)
{
errors.add("DTSTART is not present. DTSTART is REQUIRED and MUST NOT occur more than once");
}
boolean isDateTimeEndPresent = getDateTimeEnd() != null;
boolean isDurationPresent = getDuration() != null;
if (! isDateTimeEndPresent && ! isDurationPresent)
{
// errors.add("Neither DTEND or DURATION is present. DTEND or DURATION is REQUIRED and MUST NOT occur more than once"); // not required
} else if (isDateTimeEndPresent && isDurationPresent)
{
errors.add("Both DTEND and DURATION are present. DTEND or DURATION MAY exist, but both MUST NOT occur in the same " + name());
}
return Collections.unmodifiableList(errors);
}
@Override
public List calendarList()
{
if (getParent() != null)
{
VCalendar cal = (VCalendar) getParent();
return cal.getVEvents();
} else
{
throw new RuntimeException("Parent isn't set");
}
}
@Override
@Deprecated // is this necessary?
public void eraseDateTimeProperties()
{
super.eraseDateTimeProperties();
setDateTimeEnd((DateTimeEnd) null);
}
/**
* Creates a new VEvent calendar component by parsing a String of iCalendar content lines
*
* @param content the text to parse, not null
* @return the parsed VEvent
*/
public static VEvent parse(String content)
{
return VEvent.parse(new VEvent(), content);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy