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