001 package biweekly.component;
002
003 import java.util.Arrays;
004 import java.util.Date;
005 import java.util.List;
006
007 import biweekly.Warning;
008 import biweekly.property.Attachment;
009 import biweekly.property.Attendee;
010 import biweekly.property.Categories;
011 import biweekly.property.Classification;
012 import biweekly.property.Comment;
013 import biweekly.property.Completed;
014 import biweekly.property.Contact;
015 import biweekly.property.Created;
016 import biweekly.property.DateDue;
017 import biweekly.property.DateStart;
018 import biweekly.property.DateTimeStamp;
019 import biweekly.property.Description;
020 import biweekly.property.DurationProperty;
021 import biweekly.property.ExceptionDates;
022 import biweekly.property.ExceptionRule;
023 import biweekly.property.Geo;
024 import biweekly.property.LastModified;
025 import biweekly.property.Location;
026 import biweekly.property.Method;
027 import biweekly.property.Organizer;
028 import biweekly.property.PercentComplete;
029 import biweekly.property.Priority;
030 import biweekly.property.RecurrenceDates;
031 import biweekly.property.RecurrenceId;
032 import biweekly.property.RecurrenceRule;
033 import biweekly.property.RelatedTo;
034 import biweekly.property.RequestStatus;
035 import biweekly.property.Resources;
036 import biweekly.property.Sequence;
037 import biweekly.property.Status;
038 import biweekly.property.Summary;
039 import biweekly.property.Uid;
040 import biweekly.property.Url;
041 import biweekly.util.Duration;
042 import biweekly.util.Recurrence;
043
044 /*
045 Copyright (c) 2013, Michael Angstadt
046 All rights reserved.
047
048 Redistribution and use in source and binary forms, with or without
049 modification, are permitted provided that the following conditions are met:
050
051 1. Redistributions of source code must retain the above copyright notice, this
052 list of conditions and the following disclaimer.
053 2. Redistributions in binary form must reproduce the above copyright notice,
054 this list of conditions and the following disclaimer in the documentation
055 and/or other materials provided with the distribution.
056
057 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
058 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
059 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
060 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
061 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
062 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
063 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
064 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
065 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
066 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
067 */
068
069 /**
070 * <p>
071 * Defines a task or assignment.
072 * </p>
073 * <p>
074 * <b>Examples:</b>
075 *
076 * <pre class="brush:java">
077 * VTodo todo = new VTodo();
078 * todo.setSummary("Complete report");
079 * Date due = ...
080 * todo.setDateDue(due);
081 * todo.setStatus(Status.confirmed());
082 * </pre>
083 *
084 * </p>
085 * @author Michael Angstadt
086 * @rfc 5545 p.55-7
087 */
088 public class VTodo extends ICalComponent {
089 /**
090 * <p>
091 * Creates a new to-do entry.
092 * </p>
093 * <p>
094 * The following properties are auto-generated on object creation. These
095 * properties <b>must</b> be present in order for the to-do to be valid:
096 * <ul>
097 * <li>{@link Uid} - Set to a UUID.</li>
098 * <li>{@link DateTimeStamp} - Set to the current date-time.</li>
099 * </ul>
100 * </p>
101 */
102 public VTodo() {
103 setUid(Uid.random());
104 setDateTimeStamp(new Date());
105 }
106
107 /**
108 * Gets the unique identifier for this to-do. This component object comes
109 * populated with a UID on creation. This is a <b>required</b> property.
110 * @return the UID or null if not set
111 * @rfc 5545 p.117-8
112 */
113 public Uid getUid() {
114 return getProperty(Uid.class);
115 }
116
117 /**
118 * Sets the unique identifier for this to-do. This component object comes
119 * populated with a UID on creation. This is a <b>required</b> property.
120 * @param uid the UID or null to remove
121 * @rfc 5545 p.117-8
122 */
123 public void setUid(Uid uid) {
124 setProperty(Uid.class, uid);
125 }
126
127 /**
128 * Sets the unique identifier for this to-do. This component object comes
129 * populated with a UID on creation. This is a <b>required</b> property.
130 * @param uid the UID or null to remove
131 * @return the property that was created
132 * @rfc 5545 p.117-8
133 */
134 public Uid setUid(String uid) {
135 Uid prop = (uid == null) ? null : new Uid(uid);
136 setUid(prop);
137 return prop;
138 }
139
140 /**
141 * Gets either (a) the creation date of the iCalendar object (if the
142 * {@link Method} property is defined) or (b) the date that the to-do was
143 * last modified (the {@link LastModified} property also holds this
144 * information). This to-do object comes populated with a
145 * {@link DateTimeStamp} property that is set to the current time. This is a
146 * <b>required</b> property.
147 * @return the date time stamp or null if not set
148 * @rfc 5545 p.137-8
149 */
150 public DateTimeStamp getDateTimeStamp() {
151 return getProperty(DateTimeStamp.class);
152 }
153
154 /**
155 * Sets either (a) the creation date of the iCalendar object (if the
156 * {@link Method} property is defined) or (b) the date that the to-do was
157 * last modified (the {@link LastModified} property also holds this
158 * information). This to-do object comes populated with a
159 * {@link DateTimeStamp} property that is set to the current time. This is a
160 * <b>required</b> property.
161 * @param dateTimeStamp the date time stamp or null to remove
162 * @rfc 5545 p.137-8
163 */
164 public void setDateTimeStamp(DateTimeStamp dateTimeStamp) {
165 setProperty(DateTimeStamp.class, dateTimeStamp);
166 }
167
168 /**
169 * Sets either (a) the creation date of the iCalendar object (if the
170 * {@link Method} property is defined) or (b) the date that the to-do was
171 * last modified (the {@link LastModified} property also holds this
172 * information). This to-do object comes populated with a
173 * {@link DateTimeStamp} property that is set to the current time. This is a
174 * <b>required</b> property.
175 * @param dateTimeStamp the date time stamp or null to remove
176 * @return the property that was created
177 * @rfc 5545 p.137-8
178 */
179 public DateTimeStamp setDateTimeStamp(Date dateTimeStamp) {
180 DateTimeStamp prop = (dateTimeStamp == null) ? null : new DateTimeStamp(dateTimeStamp);
181 setDateTimeStamp(prop);
182 return prop;
183 }
184
185 /**
186 * Gets the level of sensitivity of the to-do data. If not specified, the
187 * data within the to-do should be considered "public".
188 * @return the classification level or null if not set
189 * @rfc 5545 p.82-3
190 */
191 public Classification getClassification() {
192 return getProperty(Classification.class);
193 }
194
195 /**
196 * Sets the level of sensitivity of the to-do data. If not specified, the
197 * data within the to-do should be considered "public".
198 * @param classification the classification level or null to remove
199 * @rfc 5545 p.82-3
200 */
201 public void setClassification(Classification classification) {
202 setProperty(Classification.class, classification);
203 }
204
205 /**
206 * Sets the level of sensitivity of the to-do data. If not specified, the
207 * data within the to-do should be considered "public".
208 * @param classification the classification level (e.g. "CONFIDENTIAL") or
209 * null to remove
210 * @return the property that was created
211 * @rfc 5545 p.82-3
212 */
213 public Classification setClassification(String classification) {
214 Classification prop = (classification == null) ? null : new Classification(classification);
215 setClassification(prop);
216 return prop;
217 }
218
219 /**
220 * Gets the date and time that the to-do was completed.
221 * @return the completion date or null if not set
222 * @rfc 5545 p.94-5
223 */
224 public Completed getCompleted() {
225 return getProperty(Completed.class);
226 }
227
228 /**
229 * Sets the date and time that the to-do was completed.
230 * @param completed the completion date or null to remove
231 * @rfc 5545 p.94-5
232 */
233 public void setCompleted(Completed completed) {
234 setProperty(Completed.class, completed);
235 }
236
237 /**
238 * Sets the date and time that the to-do was completed.
239 * @param completed the completion date or null to remove
240 * @return the property that was created
241 * @rfc 5545 p.94-5
242 */
243 public Completed setCompleted(Date completed) {
244 Completed prop = (completed == null) ? null : new Completed(completed);
245 setCompleted(prop);
246 return prop;
247 }
248
249 /**
250 * Gets the date-time that the to-do was initially created.
251 * @return the creation date-time or null if not set
252 * @rfc 5545 p.136
253 */
254 public Created getCreated() {
255 return getProperty(Created.class);
256 }
257
258 /**
259 * Sets the date-time that the to-do was initially created.
260 * @param created the creation date-time or null to remove
261 * @rfc 5545 p.136
262 */
263 public void setCreated(Created created) {
264 setProperty(Created.class, created);
265 }
266
267 /**
268 * Sets the date-time that the to-do was initially created.
269 * @param created the creation date-time or null to remove
270 * @return the property that was created
271 * @rfc 5545 p.136
272 */
273 public Created setCreated(Date created) {
274 Created prop = (created == null) ? null : new Created(created);
275 setCreated(prop);
276 return prop;
277 }
278
279 /**
280 * Gets a detailed description of the to-do. The description should be more
281 * detailed than the one provided by the {@link Summary} property.
282 * @return the description or null if not set
283 * @rfc 5545 p.84-5
284 */
285 public Description getDescription() {
286 return getProperty(Description.class);
287 }
288
289 /**
290 * Sets a detailed description of the to-do. The description should be more
291 * detailed than the one provided by the {@link Summary} property.
292 * @param description the description or null to remove
293 * @rfc 5545 p.84-5
294 */
295 public void setDescription(Description description) {
296 setProperty(Description.class, description);
297 }
298
299 /**
300 * Sets a detailed description of the to-do. The description should be more
301 * detailed than the one provided by the {@link Summary} property.
302 * @param description the description or null to remove
303 * @return the property that was created
304 * @rfc 5545 p.84-5
305 */
306 public Description setDescription(String description) {
307 Description prop = (description == null) ? null : new Description(description);
308 setDescription(prop);
309 return prop;
310 }
311
312 /**
313 * Gets the date that the to-do starts.
314 * @return the start date or null if not set
315 * @rfc 5545 p.97-8
316 */
317 public DateStart getDateStart() {
318 return getProperty(DateStart.class);
319 }
320
321 /**
322 * Sets the date that the to-do starts.
323 * @param dateStart the start date or null to remove
324 * @rfc 5545 p.97-8
325 */
326 public void setDateStart(DateStart dateStart) {
327 setProperty(DateStart.class, dateStart);
328 }
329
330 /**
331 * Sets the date that the to-do starts.
332 * @param dateStart the start date or null to remove
333 * @return the property that was created
334 * @rfc 5545 p.97-8
335 */
336 public DateStart setDateStart(Date dateStart) {
337 DateStart prop = (dateStart == null) ? null : new DateStart(dateStart);
338 setDateStart(prop);
339 return prop;
340 }
341
342 /**
343 * Gets a set of geographical coordinates.
344 * @return the geographical coordinates or null if not set
345 * @rfc 5545 p.85-7
346 */
347 public Geo getGeo() {
348 return getProperty(Geo.class);
349 }
350
351 /**
352 * Sets a set of geographical coordinates.
353 * @param geo the geographical coordinates or null to remove
354 * @rfc 5545 p.85-7
355 */
356 public void setGeo(Geo geo) {
357 setProperty(Geo.class, geo);
358 }
359
360 /**
361 * Gets the date-time that the to-do was last changed.
362 * @return the last modified date or null if not set
363 * @rfc 5545 p.138
364 */
365 public LastModified getLastModified() {
366 return getProperty(LastModified.class);
367 }
368
369 /**
370 * Sets the date-time that the to-do was last changed.
371 * @param lastModified the last modified date or null to remove
372 * @rfc 5545 p.138
373 */
374 public void setLastModified(LastModified lastModified) {
375 setProperty(LastModified.class, lastModified);
376 }
377
378 /**
379 * Sets the date-time that the to-do was last changed.
380 * @param lastModified the last modified date or null to remove
381 * @return the property that was created
382 * @rfc 5545 p.138
383 */
384 public LastModified setLastModified(Date lastModified) {
385 LastModified prop = (lastModified == null) ? null : new LastModified(lastModified);
386 setLastModified(prop);
387 return prop;
388 }
389
390 /**
391 * Gets the physical location of the to-do.
392 * @return the location or null if not set
393 * @rfc 5545 p.87-8
394 */
395 public Location getLocation() {
396 return getProperty(Location.class);
397 }
398
399 /**
400 * Sets the physical location of the to-do.
401 * @param location the location or null to remove
402 * @rfc 5545 p.87-8
403 */
404 public void setLocation(Location location) {
405 setProperty(Location.class, location);
406 }
407
408 /**
409 * Sets the physical location of the to-do.
410 * @param location the location (e.g. "Room 101") or null to remove
411 * @return the property that was created
412 * @rfc 5545 p.87-8
413 */
414 public Location setLocation(String location) {
415 Location prop = (location == null) ? null : new Location(location);
416 setLocation(prop);
417 return prop;
418 }
419
420 /**
421 * Gets the organizer of the to-do.
422 * @return the organizer or null if not set
423 * @rfc 5545 p.111-2
424 */
425 public Organizer getOrganizer() {
426 return getProperty(Organizer.class);
427 }
428
429 /**
430 * Sets the organizer of the to-do.
431 * @param organizer the organizer or null to remove
432 * @rfc 5545 p.111-2
433 */
434 public void setOrganizer(Organizer organizer) {
435 setProperty(Organizer.class, organizer);
436 }
437
438 /**
439 * Sets the organizer of the to-do.
440 * @param email the organizer's email address (e.g. "johndoe@example.com")
441 * or null to remove
442 * @return the property that was created
443 * @rfc 5545 p.111-2
444 */
445 public Organizer setOrganizer(String email) {
446 Organizer prop = (email == null) ? null : Organizer.email(email);
447 setOrganizer(prop);
448 return prop;
449 }
450
451 /**
452 * Gets the amount that the to-do task has been completed.
453 * @return the percent complete or null if not set
454 * @rfc 5545 p.88-9
455 */
456 public PercentComplete getPercentComplete() {
457 return getProperty(PercentComplete.class);
458 }
459
460 /**
461 * Sets the amount that the to-do task has been completed.
462 * @param percentComplete the percent complete or null to remove
463 * @rfc 5545 p.88-9
464 */
465 public void setPercentComplete(PercentComplete percentComplete) {
466 setProperty(PercentComplete.class, percentComplete);
467 }
468
469 /**
470 * Sets the amount that the to-do task has been completed.
471 * @param percent the percent complete (e.g. "50" for 50%) or null to remove
472 * @return the property that was created
473 * @rfc 5545 p.88-9
474 */
475 public PercentComplete setPercentComplete(Integer percent) {
476 PercentComplete prop = (percent == null) ? null : new PercentComplete(percent);
477 setPercentComplete(prop);
478 return prop;
479 }
480
481 /**
482 * Gets the priority of the to-do.
483 * @return the priority or null if not set
484 * @rfc 5545 p.89-90
485 */
486 public Priority getPriority() {
487 return getProperty(Priority.class);
488 }
489
490 /**
491 * Sets the priority of the to-do.
492 * @param priority the priority or null to remove
493 * @rfc 5545 p.89-90
494 */
495 public void setPriority(Priority priority) {
496 setProperty(Priority.class, priority);
497 }
498
499 /**
500 * Sets the priority of the to-do.
501 * @param priority the priority ("0" is undefined, "1" is the highest, "9"
502 * is the lowest) or null to remove
503 * @return the property that was created
504 * @rfc 5545 p.89-90
505 */
506 public Priority setPriority(Integer priority) {
507 Priority prop = (priority == null) ? null : new Priority(priority);
508 setPriority(prop);
509 return prop;
510 }
511
512 /**
513 * Gets the original value of the {@link DateStart} property if the to-do is
514 * recurring and has been modified. Used in conjunction with the {@link Uid}
515 * and {@link Sequence} properties to uniquely identify a recurrence
516 * instance.
517 * @return the recurrence ID or null if not set
518 * @rfc 5545 p.112-4
519 */
520 public RecurrenceId getRecurrenceId() {
521 return getProperty(RecurrenceId.class);
522 }
523
524 /**
525 * Sets the original value of the {@link DateStart} property if the to-do is
526 * recurring and has been modified. Used in conjunction with the {@link Uid}
527 * and {@link Sequence} properties to uniquely identify a recurrence
528 * instance.
529 * @param recurrenceId the recurrence ID or null to remove
530 * @rfc 5545 p.112-4
531 */
532 public void setRecurrenceId(RecurrenceId recurrenceId) {
533 setProperty(RecurrenceId.class, recurrenceId);
534 }
535
536 /**
537 * Sets the original value of the {@link DateStart} property if the to-do is
538 * recurring and has been modified. Used in conjunction with the {@link Uid}
539 * and {@link Sequence} properties to uniquely identify a recurrence
540 * instance.
541 * @param originalStartDate the original start date or null to remove
542 * @return the property that was created
543 * @rfc 5545 p.112-4
544 */
545 public RecurrenceId setRecurrenceId(Date originalStartDate) {
546 RecurrenceId prop = (originalStartDate == null) ? null : new RecurrenceId(originalStartDate);
547 setRecurrenceId(prop);
548 return prop;
549 }
550
551 /**
552 * Gets the revision number of the to-do. The organizer can increment this
553 * number every time he or she makes a significant change.
554 * @return the sequence number
555 * @rfc 5545 p.138-9
556 */
557 public Sequence getSequence() {
558 return getProperty(Sequence.class);
559 }
560
561 /**
562 * Sets the revision number of the to-do. The organizer can increment this
563 * number every time he or she makes a significant change.
564 * @param sequence the sequence number
565 * @rfc 5545 p.138-9
566 */
567 public void setSequence(Sequence sequence) {
568 setProperty(Sequence.class, sequence);
569 }
570
571 /**
572 * Sets the revision number of the to-do. The organizer can increment this
573 * number every time he or she makes a significant change.
574 * @param sequence the sequence number
575 * @return the property that was created
576 * @rfc 5545 p.138-9
577 */
578 public Sequence setSequence(Integer sequence) {
579 Sequence prop = (sequence == null) ? null : new Sequence(sequence);
580 setSequence(prop);
581 return prop;
582 }
583
584 /**
585 * Increments the revision number of the to-do. The organizer can increment
586 * this number every time he or she makes a significant change.
587 * @rfc 5545 p.138-9
588 */
589 public void incrementSequence() {
590 Sequence sequence = getSequence();
591 if (sequence == null) {
592 setSequence(1);
593 } else {
594 sequence.increment();
595 }
596 }
597
598 /**
599 * Gets the status of the to-do.
600 * @return the status or null if not set
601 * @rfc 5545 p.92-3
602 */
603 public Status getStatus() {
604 return getProperty(Status.class);
605 }
606
607 /**
608 * Sets the status of the to-do.
609 * <p>
610 * Valid to-do status codes are:
611 * <ul>
612 * <li>NEEDS-ACTION</li>
613 * <li>COMPLETED</li>
614 * <li>IN-PROGRESS</li>
615 * <li>CANCELLED</li>
616 * </ul>
617 * </p>
618 * @param status the status or null to remove
619 * @rfc 5545 p.92-3
620 */
621 public void setStatus(Status status) {
622 setProperty(Status.class, status);
623 }
624
625 /**
626 * Gets the summary of the to-do.
627 * @return the summary or null if not set
628 * @rfc 5545 p.93-4
629 */
630 public Summary getSummary() {
631 return getProperty(Summary.class);
632 }
633
634 /**
635 * Sets the summary of the to-do.
636 * @param summary the summary or null to remove
637 * @rfc 5545 p.93-4
638 */
639 public void setSummary(Summary summary) {
640 setProperty(Summary.class, summary);
641 }
642
643 /**
644 * Sets the summary of the to-do.
645 * @param summary the summary or null to remove
646 * @return the property that was created
647 * @rfc 5545 p.93-4
648 */
649 public Summary setSummary(String summary) {
650 Summary prop = (summary == null) ? null : new Summary(summary);
651 setSummary(prop);
652 return prop;
653 }
654
655 /**
656 * Gets a URL to a resource that contains additional information about the
657 * to-do.
658 * @return the URL or null if not set
659 * @rfc 5545 p.116-7
660 */
661 public Url getUrl() {
662 return getProperty(Url.class);
663 }
664
665 /**
666 * Sets a URL to a resource that contains additional information about the
667 * to-do.
668 * @param url the URL or null to remove
669 * @rfc 5545 p.116-7
670 */
671 public void setUrl(Url url) {
672 setProperty(Url.class, url);
673 }
674
675 /**
676 * Sets a URL to a resource that contains additional information about the
677 * to-do.
678 * @param url the URL (e.g. "http://example.com/resource.ics") or null to
679 * remove
680 * @return the property that was created
681 * @rfc 5545 p.116-7
682 */
683 public Url setUrl(String url) {
684 Url prop = (url == null) ? null : new Url(url);
685 setUrl(prop);
686 return prop;
687 }
688
689 /**
690 * Gets how often the to-do repeats.
691 * @return the recurrence rule or null if not set
692 * @rfc 5545 p.122-32
693 */
694 public RecurrenceRule getRecurrenceRule() {
695 return getProperty(RecurrenceRule.class);
696 }
697
698 /**
699 * Sets how often the to-do repeats.
700 * @param recur the recurrence rule or null to remove
701 * @return the property that was created
702 * @rfc 5545 p.122-32
703 */
704 public RecurrenceRule setRecurrenceRule(Recurrence recur) {
705 RecurrenceRule prop = (recur == null) ? null : new RecurrenceRule(recur);
706 setRecurrenceRule(prop);
707 return prop;
708 }
709
710 /**
711 * Sets how often the to-do repeats.
712 * @param recurrenceRule the recurrence rule or null to remove
713 * @rfc 5545 p.122-32
714 */
715 public void setRecurrenceRule(RecurrenceRule recurrenceRule) {
716 setProperty(RecurrenceRule.class, recurrenceRule);
717 }
718
719 /**
720 * Gets the date that a to-do is due by.
721 * @return the due date or null if not set
722 * @rfc 5545 p.96-7
723 */
724 public DateDue getDateDue() {
725 return getProperty(DateDue.class);
726 }
727
728 /**
729 * Sets the date that a to-do is due by. This must NOT be set if a
730 * {@link DurationProperty} is defined.
731 * @param dateDue the due date or null to remove
732 * @rfc 5545 p.96-7
733 */
734 public void setDateDue(DateDue dateDue) {
735 setProperty(DateDue.class, dateDue);
736 }
737
738 /**
739 * Sets the date that a to-do is due by. This must NOT be set if a
740 * {@link DurationProperty} is defined.
741 * @param dateDue the due date or null to remove
742 * @return the property that was created
743 * @rfc 5545 p.96-7
744 */
745 public DateDue setDateDue(Date dateDue) {
746 DateDue prop = (dateDue == null) ? null : new DateDue(dateDue);
747 setDateDue(prop);
748 return prop;
749 }
750
751 /**
752 * Gets the duration of the to-do.
753 * @return the duration or null if not set
754 * @rfc 5545 p.99
755 */
756 public DurationProperty getDuration() {
757 return getProperty(DurationProperty.class);
758 }
759
760 /**
761 * Sets the duration of the to-do. This must NOT be set if a {@link DateDue}
762 * is defined.
763 * @param duration the duration or null to remove
764 * @rfc 5545 p.99
765 */
766 public void setDuration(DurationProperty duration) {
767 setProperty(DurationProperty.class, duration);
768 }
769
770 /**
771 * Sets the duration of the to-do. This must NOT be set if a {@link DateDue}
772 * is defined.
773 * @param duration the duration or null to remove
774 * @return the property that was created
775 * @rfc 5545 p.99
776 */
777 public DurationProperty setDuration(Duration duration) {
778 DurationProperty prop = (duration == null) ? null : new DurationProperty(duration);
779 setDuration(prop);
780 return prop;
781 }
782
783 /**
784 * Gets any attachments that are associated with the to-do.
785 * @return the attachments
786 * @rfc 5545 p.80-1
787 */
788 public List<Attachment> getAttachments() {
789 return getProperties(Attachment.class);
790 }
791
792 /**
793 * Adds an attachment to the to-do.
794 * @param attachment the attachment to add
795 * @rfc 5545 p.80-1
796 */
797 public void addAttachment(Attachment attachment) {
798 addProperty(attachment);
799 }
800
801 /**
802 * Gets the people who are involved in the to-do.
803 * @return the attendees
804 * @rfc 5545 p.107-9
805 */
806 public List<Attendee> getAttendees() {
807 return getProperties(Attendee.class);
808 }
809
810 /**
811 * Adds a person who is involved in the to-do.
812 * @param attendee the attendee
813 * @rfc 5545 p.107-9
814 */
815 public void addAttendee(Attendee attendee) {
816 addProperty(attendee);
817 }
818
819 /**
820 * Adds a person who is involved in the to-do.
821 * @param email the attendee's email address
822 * @return the property that was created
823 * @rfc 5545 p.107-9
824 */
825 public Attendee addAttendee(String email) {
826 Attendee prop = Attendee.email(email);
827 addAttendee(prop);
828 return prop;
829 }
830
831 /**
832 * Gets a list of "tags" or "keywords" that describe the to-do.
833 * @return the categories
834 * @rfc 5545 p.81-2
835 */
836 public List<Categories> getCategories() {
837 return getProperties(Categories.class);
838 }
839
840 /**
841 * Adds a list of "tags" or "keywords" that describe the to-do. Note that a
842 * single property can hold multiple keywords.
843 * @param categories the categories to add
844 * @rfc 5545 p.81-2
845 */
846 public void addCategories(Categories categories) {
847 addProperty(categories);
848 }
849
850 /**
851 * Adds a list of "tags" or "keywords" that describe the to-do.
852 * @param categories the categories to add
853 * @return the property that was created
854 * @rfc 5545 p.81-2
855 */
856 public Categories addCategories(String... categories) {
857 Categories prop = new Categories(categories);
858 addCategories(prop);
859 return prop;
860 }
861
862 /**
863 * Adds a list of "tags" or "keywords" that describe the to-do.
864 * @param categories the categories to add
865 * @return the property that was created
866 * @rfc 5545 p.81-2
867 */
868 public Categories addCategories(List<String> categories) {
869 Categories prop = new Categories(categories);
870 addCategories(prop);
871 return prop;
872 }
873
874 /**
875 * Gets the comments attached to the to-do.
876 * @return the comments
877 * @rfc 5545 p.83-4
878 */
879 public List<Comment> getComments() {
880 return getProperties(Comment.class);
881 }
882
883 /**
884 * Adds a comment to the to-do.
885 * @param comment the comment to add
886 * @rfc 5545 p.83-4
887 */
888 public void addComment(Comment comment) {
889 addProperty(comment);
890 }
891
892 /**
893 * Adds a comment to the to-do.
894 * @param comment the comment to add
895 * @return the property that was created
896 * @rfc 5545 p.83-4
897 */
898 public Comment addComment(String comment) {
899 Comment prop = new Comment(comment);
900 addComment(prop);
901 return prop;
902 }
903
904 /**
905 * Gets the contacts associated with the to-do.
906 * @return the contacts
907 * @rfc 5545 p.109-11
908 */
909 public List<Contact> getContacts() {
910 return getProperties(Contact.class);
911 }
912
913 /**
914 * Adds a contact to the to-do.
915 * @param contact the contact
916 * @rfc 5545 p.109-11
917 */
918 public void addContact(Contact contact) {
919 addProperty(contact);
920 }
921
922 /**
923 * Adds a contact to the to-do.
924 * @param contact the contact (e.g. "ACME Co - (123) 555-1234")
925 * @return the property that was created
926 * @rfc 5545 p.109-11
927 */
928 public Contact addContact(String contact) {
929 Contact prop = new Contact(contact);
930 addContact(prop);
931 return prop;
932 }
933
934 /**
935 * Gets the list of exceptions to the recurrence rule defined in the to-do
936 * (if one is defined).
937 * @return the list of exceptions
938 * @rfc 5545 p.118-20
939 */
940 public List<ExceptionDates> getExceptionDates() {
941 return getProperties(ExceptionDates.class);
942 }
943
944 /**
945 * Adds a list of exceptions to the recurrence rule defined in the to-do (if
946 * one is defined). Note that this property can contain multiple dates.
947 * @param exceptionDates the list of exceptions
948 * @rfc 5545 p.118-20
949 */
950 public void addExceptionDates(ExceptionDates exceptionDates) {
951 addProperty(exceptionDates);
952 }
953
954 /**
955 * Gets the response to a scheduling request.
956 * @return the response
957 * @rfc 5545 p.141-3
958 */
959 public RequestStatus getRequestStatus() {
960 return getProperty(RequestStatus.class);
961 }
962
963 /**
964 * Sets the response to a scheduling request.
965 * @param requestStatus the response
966 * @rfc 5545 p.141-3
967 */
968 public void setRequestStatus(RequestStatus requestStatus) {
969 setProperty(RequestStatus.class, requestStatus);
970 }
971
972 /**
973 * Gets the components that the to-do is related to.
974 * @return the relationships
975 * @rfc 5545 p.115-6
976 */
977 public List<RelatedTo> getRelatedTo() {
978 return getProperties(RelatedTo.class);
979 }
980
981 /**
982 * Adds a component that the to-do is related to.
983 * @param relatedTo the relationship
984 * @rfc 5545 p.115-6
985 */
986 public void addRelatedTo(RelatedTo relatedTo) {
987 //TODO create a method that accepts a component and make the RelatedTo property invisible to the user
988 //@formatter:off
989 /*
990 * addRelation(RelationshipType relType, ICalComponent component){
991 * RelatedTo prop = new RelatedTo(component.getUid().getValue());
992 * prop.setRelationshipType(relType);
993 * addProperty(prop);
994 * }
995 */
996 //@formatter:on
997 addProperty(relatedTo);
998 }
999
1000 /**
1001 * Adds a component that the to-do is related to.
1002 * @param uid the UID of the other component
1003 * @return the property that was created
1004 * @rfc 5545 p.115-6
1005 */
1006 public RelatedTo addRelatedTo(String uid) {
1007 RelatedTo prop = new RelatedTo(uid);
1008 addRelatedTo(prop);
1009 return prop;
1010 }
1011
1012 /**
1013 * Gets the resources that are needed for the to-do.
1014 * @return the resources
1015 * @rfc 5545 p.91
1016 */
1017 public List<Resources> getResources() {
1018 return getProperties(Resources.class);
1019 }
1020
1021 /**
1022 * Adds a list of resources that are needed for the to-do. Note that a
1023 * single property can hold multiple resources.
1024 * @param resources the resources to add
1025 * @rfc 5545 p.91
1026 */
1027 public void addResources(Resources resources) {
1028 addProperty(resources);
1029 }
1030
1031 /**
1032 * Adds a list of resources that are needed for the to-do.
1033 * @param resources the resources to add (e.g. "easel", "projector")
1034 * @return the property that was created
1035 * @rfc 5545 p.91
1036 */
1037 public Resources addResources(String... resources) {
1038 Resources prop = new Resources(resources);
1039 addResources(prop);
1040 return prop;
1041 }
1042
1043 /**
1044 * Adds a list of resources that are needed for the to-do.
1045 * @param resources the resources to add (e.g. "easel", "projector")
1046 * @return the property that was created
1047 * @rfc 5545 p.91
1048 */
1049 public Resources addResources(List<String> resources) {
1050 Resources prop = new Resources(resources);
1051 addResources(prop);
1052 return prop;
1053 }
1054
1055 /**
1056 * Gets the list of dates/periods that help define the recurrence rule of
1057 * this to-do (if one is defined).
1058 * @return the recurrence dates
1059 * @rfc 5545 p.120-2
1060 */
1061 public List<RecurrenceDates> getRecurrenceDates() {
1062 return getProperties(RecurrenceDates.class);
1063 }
1064
1065 /**
1066 * Adds a list of dates/periods that help define the recurrence rule of this
1067 * to-do (if one is defined).
1068 * @param recurrenceDates the recurrence dates
1069 * @rfc 5545 p.120-2
1070 */
1071 public void addRecurrenceDates(RecurrenceDates recurrenceDates) {
1072 addProperty(recurrenceDates);
1073 }
1074
1075 /**
1076 * Gets the alarms that are assigned to this to-do.
1077 * @return the alarms
1078 * @rfc 5545 p.71-6
1079 */
1080 public List<VAlarm> getAlarms() {
1081 return getComponents(VAlarm.class);
1082 }
1083
1084 /**
1085 * Adds an alarm to this to-do.
1086 * @param alarm the alarm
1087 * @rfc 5545 p.71-6
1088 */
1089 public void addAlarm(VAlarm alarm) {
1090 addComponent(alarm);
1091 }
1092
1093 /**
1094 * <p>
1095 * Gets the exceptions for the {@link RecurrenceRule} property.
1096 * </p>
1097 * <p>
1098 * Note that this property has been removed from the latest version of the
1099 * iCal specification. Its use should be avoided.
1100 * </p>
1101 * @return the exception rules
1102 * @rfc 2445 p.114-15
1103 */
1104 public List<ExceptionRule> getExceptionRules() {
1105 return getProperties(ExceptionRule.class);
1106 }
1107
1108 /**
1109 * <p>
1110 * Adds an exception for the {@link RecurrenceRule} property.
1111 * </p>
1112 * <p>
1113 * Note that this property has been removed from the latest version of the
1114 * iCal specification. Its use should be avoided.
1115 * </p>
1116 * @param recur the exception rule to add
1117 * @return the property that was created
1118 * @rfc 2445 p.114-15
1119 */
1120 public ExceptionRule addExceptionRule(Recurrence recur) {
1121 ExceptionRule prop = (recur == null) ? null : new ExceptionRule(recur);
1122 addExceptionRule(prop);
1123 return prop;
1124 }
1125
1126 /**
1127 * <p>
1128 * Adds an exception for the {@link RecurrenceRule} property.
1129 * </p>
1130 * <p>
1131 * Note that this property has been removed from the latest version of the
1132 * iCal specification. Its use should be avoided.
1133 * </p>
1134 * @param exceptionRule the exception rule to add
1135 * @rfc 2445 p.114-15
1136 */
1137 public void addExceptionRule(ExceptionRule exceptionRule) {
1138 addProperty(exceptionRule);
1139 }
1140
1141 @SuppressWarnings("unchecked")
1142 @Override
1143 protected void validate(List<ICalComponent> components, List<Warning> warnings) {
1144 checkRequiredCardinality(warnings, Uid.class, DateTimeStamp.class);
1145 checkOptionalCardinality(warnings, Classification.class, Completed.class, Created.class, Description.class, DateStart.class, Geo.class, LastModified.class, Location.class, Organizer.class, PercentComplete.class, Priority.class, RecurrenceId.class, Sequence.class, Status.class, Summary.class, Url.class);
1146
1147 Status status = getStatus();
1148 if (status != null && (status.isTentative() || status.isConfirmed() || status.isDraft() || status.isFinal())) {
1149 warnings.add(Warning.validate(13, status.getValue(), Arrays.asList(Status.needsAction().getValue(), Status.completed().getValue(), Status.inProgress().getValue(), Status.cancelled().getValue())));
1150 }
1151
1152 DateStart dateStart = getDateStart();
1153 DateDue dateDue = getDateDue();
1154 if (dateStart != null && dateDue != null) {
1155 Date start = dateStart.getValue();
1156 Date due = dateDue.getValue();
1157 if (start != null && due != null && start.compareTo(due) > 0) {
1158 warnings.add(Warning.validate(22));
1159 }
1160
1161 if (dateStart.hasTime() != dateDue.hasTime()) {
1162 warnings.add(Warning.validate(23));
1163 }
1164 }
1165
1166 DurationProperty duration = getDuration();
1167 if (dateDue != null && duration != null) {
1168 warnings.add(Warning.validate(24));
1169 }
1170 if (dateStart == null && duration != null) {
1171 warnings.add(Warning.validate(25));
1172 }
1173
1174 RecurrenceId recurrenceId = getRecurrenceId();
1175 if (recurrenceId != null && dateStart != null && dateStart.hasTime() != recurrenceId.hasTime()) {
1176 warnings.add(Warning.validate(19));
1177 }
1178
1179 //RFC 5545 p. 167
1180 RecurrenceRule rrule = getRecurrenceRule();
1181 if (dateStart != null && rrule != null) {
1182 Date start = dateStart.getValue();
1183 Recurrence recur = rrule.getValue();
1184 if (start != null && recur != null) {
1185 if (!dateStart.hasTime() && (!recur.getByHour().isEmpty() || !recur.getByMinute().isEmpty() || !recur.getBySecond().isEmpty())) {
1186 warnings.add(Warning.validate(5));
1187 }
1188 }
1189 }
1190
1191 //RFC 5545 p. 167
1192 if (getProperties(RecurrenceRule.class).size() > 1) {
1193 warnings.add(Warning.validate(6));
1194 }
1195 }
1196 }