All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jfxtras.icalendarfx.components.VEvent Maven / Gradle / Ivy

There is a newer version: 17-r1
Show newest version
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