Bug 793125 - Crash due to popup menus left attached too long
[evolution.git] / src / calendar / gui / e-meeting-attendee.c
blobabca018ee75e1cda428ced1c8e63035dbfb6108d
1 /*
2 * This program is free software; you can redistribute it and/or modify it
3 * under the terms of the GNU Lesser General Public License as published by
4 * the Free Software Foundation.
6 * This program is distributed in the hope that it will be useful, but
7 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
8 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
9 * for more details.
11 * You should have received a copy of the GNU Lesser General Public License
12 * along with this program; if not, see <http://www.gnu.org/licenses/>.
15 * Authors:
16 * JP Rosevear <jpr@ximian.com>
18 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
22 #include "evolution-config.h"
24 #include <stdlib.h>
25 #include <gtk/gtk.h>
26 #include "e-meeting-utils.h"
27 #include "e-meeting-attendee.h"
29 #define E_MEETING_ATTENDEE_GET_PRIVATE(obj) \
30 (G_TYPE_INSTANCE_GET_PRIVATE \
31 ((obj), E_TYPE_MEETING_ATTENDEE, EMeetingAttendeePrivate))
33 struct _EMeetingAttendeePrivate {
34 gchar *address;
35 gchar *member;
36 gchar *fburi;
38 icalparameter_cutype cutype;
39 icalparameter_role role;
41 gboolean rsvp;
43 gchar *delto;
44 gchar *delfrom;
46 icalparameter_partstat status;
48 gchar *sentby;
49 gchar *cn;
50 gchar *language;
52 EMeetingAttendeeEditLevel edit_level;
54 gboolean has_calendar_info;
56 GArray *busy_periods;
57 gboolean busy_periods_sorted;
59 EMeetingTime busy_periods_start;
60 EMeetingTime busy_periods_end;
61 gboolean start_busy_range_set;
62 gboolean end_busy_range_set;
64 gint longest_period_in_days;
67 enum {
68 CHANGED,
69 LAST_SIGNAL
71 static guint signals[LAST_SIGNAL];
73 static void e_meeting_attendee_finalize (GObject *obj);
75 G_DEFINE_TYPE (EMeetingAttendee, e_meeting_attendee, G_TYPE_OBJECT)
77 static gchar *
78 string_test (gchar *string)
80 return string != NULL ? string : g_strdup ("");
83 static gboolean
84 string_is_set (gchar *string)
86 if (string != NULL && *string != '\0')
87 return TRUE;
89 return FALSE;
92 static void
93 busy_periods_array_clear_func (gpointer data)
95 EMeetingFreeBusyPeriod *period = (EMeetingFreeBusyPeriod *) data;
97 /* We're expected to clear the data segment,
98 * but not deallocate the segment itself. The
99 * XFB data possibly attached to the
100 * EMeetingFreeBusyPeriod requires special
101 * care when removing elements from the GArray
103 e_meeting_xfb_data_clear (&(period->xfb));
106 static void
107 notify_changed (EMeetingAttendee *ia)
109 g_signal_emit_by_name (ia, "changed");
112 static void
113 e_meeting_attendee_finalize (GObject *object)
115 EMeetingAttendeePrivate *priv;
117 priv = E_MEETING_ATTENDEE_GET_PRIVATE (object);
119 g_free (priv->address);
120 g_free (priv->member);
121 g_free (priv->fburi);
123 g_free (priv->delto);
124 g_free (priv->delfrom);
126 g_free (priv->sentby);
127 g_free (priv->cn);
128 g_free (priv->language);
130 g_array_free (priv->busy_periods, TRUE);
132 /* Chain up to parent's finalize() method. */
133 G_OBJECT_CLASS (e_meeting_attendee_parent_class)->finalize (object);
136 static void
137 e_meeting_attendee_class_init (EMeetingAttendeeClass *class)
139 GObjectClass *object_class;
141 g_type_class_add_private (class, sizeof (EMeetingAttendeePrivate));
143 object_class = G_OBJECT_CLASS (class);
144 object_class->finalize = e_meeting_attendee_finalize;
146 signals[CHANGED] = g_signal_new (
147 "changed",
148 G_TYPE_FROM_CLASS (class),
149 G_SIGNAL_RUN_FIRST,
150 G_STRUCT_OFFSET (EMeetingAttendeeClass, changed),
151 NULL, NULL,
152 g_cclosure_marshal_VOID__VOID,
153 G_TYPE_NONE, 0);
156 static void
157 e_meeting_attendee_init (EMeetingAttendee *ia)
159 ia->priv = E_MEETING_ATTENDEE_GET_PRIVATE (ia);
161 ia->priv->address = string_test (NULL);
162 ia->priv->member = string_test (NULL);
164 ia->priv->cutype = ICAL_CUTYPE_NONE;
165 ia->priv->role = ICAL_ROLE_NONE;
167 ia->priv->rsvp = FALSE;
169 ia->priv->delto = string_test (NULL);
170 ia->priv->delfrom = string_test (NULL);
172 ia->priv->status = ICAL_PARTSTAT_NONE;
174 ia->priv->sentby = string_test (NULL);
175 ia->priv->cn = string_test (NULL);
176 ia->priv->language = string_test (NULL);
178 ia->priv->edit_level = E_MEETING_ATTENDEE_EDIT_FULL;
179 ia->priv->has_calendar_info = FALSE;
181 ia->priv->busy_periods = g_array_new (FALSE, FALSE, sizeof (EMeetingFreeBusyPeriod));
182 g_array_set_clear_func (ia->priv->busy_periods, busy_periods_array_clear_func);
183 ia->priv->busy_periods_sorted = FALSE;
185 g_date_clear (&ia->priv->busy_periods_start.date, 1);
186 ia->priv->busy_periods_start.hour = 0;
187 ia->priv->busy_periods_start.minute = 0;
189 g_date_clear (&ia->priv->busy_periods_end.date, 1);
190 ia->priv->busy_periods_end.hour = 0;
191 ia->priv->busy_periods_end.minute = 0;
193 ia->priv->start_busy_range_set = FALSE;
194 ia->priv->end_busy_range_set = FALSE;
196 ia->priv->longest_period_in_days = 0;
199 GObject *
200 e_meeting_attendee_new (void)
202 return g_object_new (E_TYPE_MEETING_ATTENDEE, NULL);
205 GObject *
206 e_meeting_attendee_new_from_e_cal_component_attendee (ECalComponentAttendee *ca)
208 EMeetingAttendee *ia;
210 ia = E_MEETING_ATTENDEE (g_object_new (E_TYPE_MEETING_ATTENDEE, NULL));
212 e_meeting_attendee_set_address (ia, g_strdup (ca->value));
213 e_meeting_attendee_set_member (ia, g_strdup (ca->member));
214 e_meeting_attendee_set_cutype (ia, ca->cutype);
215 e_meeting_attendee_set_role (ia, ca->role);
216 e_meeting_attendee_set_status (ia, ca->status);
217 e_meeting_attendee_set_rsvp (ia, ca->rsvp);
218 e_meeting_attendee_set_delto (ia, g_strdup (ca->delto));
219 e_meeting_attendee_set_delfrom (ia, g_strdup (ca->delfrom));
220 e_meeting_attendee_set_sentby (ia, g_strdup (ca->sentby));
221 e_meeting_attendee_set_cn (ia, g_strdup (ca->cn));
222 e_meeting_attendee_set_language (ia, g_strdup (ca->language));
224 return G_OBJECT (ia);
227 ECalComponentAttendee *
228 e_meeting_attendee_as_e_cal_component_attendee (EMeetingAttendee *ia)
230 EMeetingAttendeePrivate *priv;
231 ECalComponentAttendee *ca;
233 priv = ia->priv;
235 ca = g_new0 (ECalComponentAttendee, 1);
237 ca->value = priv->address;
238 ca->member = string_is_set (priv->member) ? priv->member : NULL;
239 ca->cutype= priv->cutype;
240 ca->role = priv->role;
241 ca->status = priv->status;
242 ca->rsvp = priv->rsvp;
243 ca->delto = string_is_set (priv->delto) ? priv->delto : NULL;
244 ca->delfrom = string_is_set (priv->delfrom) ? priv->delfrom : NULL;
245 ca->sentby = string_is_set (priv->sentby) ? priv->sentby : NULL;
246 ca->cn = string_is_set (priv->cn) ? priv->cn : NULL;
247 ca->language = string_is_set (priv->language) ? priv->language : NULL;
249 return ca;
252 const gchar *
253 e_meeting_attendee_get_fburi (EMeetingAttendee *ia)
255 EMeetingAttendeePrivate *priv;
257 priv = ia->priv;
259 return priv->fburi;
262 void
263 e_meeting_attendee_set_fburi (EMeetingAttendee *ia,
264 gchar *fburi)
266 EMeetingAttendeePrivate *priv;
268 priv = ia->priv;
270 if (priv->fburi != NULL)
271 g_free (priv->fburi);
273 priv->fburi = string_test (fburi);
275 notify_changed (ia);
278 const gchar *
279 e_meeting_attendee_get_address (EMeetingAttendee *ia)
281 EMeetingAttendeePrivate *priv;
283 priv = ia->priv;
285 return priv->address;
288 void
289 e_meeting_attendee_set_address (EMeetingAttendee *ia,
290 gchar *address)
292 EMeetingAttendeePrivate *priv;
294 priv = ia->priv;
296 if (priv->address != NULL)
297 g_free (priv->address);
299 priv->address = string_test (address);
301 notify_changed (ia);
304 gboolean
305 e_meeting_attendee_is_set_address (EMeetingAttendee *ia)
307 EMeetingAttendeePrivate *priv;
309 priv = ia->priv;
311 return string_is_set (priv->address);
314 const gchar *
315 e_meeting_attendee_get_member (EMeetingAttendee *ia)
317 EMeetingAttendeePrivate *priv;
319 priv = ia->priv;
321 return priv->member;
324 void
325 e_meeting_attendee_set_member (EMeetingAttendee *ia,
326 gchar *member)
328 EMeetingAttendeePrivate *priv;
330 priv = ia->priv;
332 if (priv->member != NULL)
333 g_free (priv->member);
335 priv->member = string_test (member);
337 notify_changed (ia);
340 gboolean
341 e_meeting_attendee_is_set_member (EMeetingAttendee *ia)
343 EMeetingAttendeePrivate *priv;
345 priv = ia->priv;
347 return string_is_set (priv->member);
350 icalparameter_cutype
351 e_meeting_attendee_get_cutype (EMeetingAttendee *ia)
353 EMeetingAttendeePrivate *priv;
355 priv = ia->priv;
357 return priv->cutype;
360 void
361 e_meeting_attendee_set_cutype (EMeetingAttendee *ia,
362 icalparameter_cutype cutype)
364 EMeetingAttendeePrivate *priv;
366 priv = ia->priv;
368 priv->cutype = cutype;
370 notify_changed (ia);
373 icalparameter_role
374 e_meeting_attendee_get_role (EMeetingAttendee *ia)
376 EMeetingAttendeePrivate *priv;
378 priv = ia->priv;
380 return priv->role;
383 void
384 e_meeting_attendee_set_role (EMeetingAttendee *ia,
385 icalparameter_role role)
387 EMeetingAttendeePrivate *priv;
389 priv = ia->priv;
391 priv->role = role;
393 notify_changed (ia);
396 gboolean
397 e_meeting_attendee_get_rsvp (EMeetingAttendee *ia)
399 EMeetingAttendeePrivate *priv;
401 priv = ia->priv;
403 return priv->rsvp;
406 void
407 e_meeting_attendee_set_rsvp (EMeetingAttendee *ia,
408 gboolean rsvp)
410 EMeetingAttendeePrivate *priv;
412 priv = ia->priv;
414 priv->rsvp = rsvp;
416 notify_changed (ia);
419 const gchar *
420 e_meeting_attendee_get_delto (EMeetingAttendee *ia)
422 EMeetingAttendeePrivate *priv;
424 priv = ia->priv;
426 return priv->delto;
429 void
430 e_meeting_attendee_set_delto (EMeetingAttendee *ia,
431 gchar *delto)
433 EMeetingAttendeePrivate *priv;
435 priv = ia->priv;
437 if (priv->delto != NULL)
438 g_free (priv->delto);
440 priv->delto = string_test (delto);
442 notify_changed (ia);
445 gboolean
446 e_meeting_attendee_is_set_delto (EMeetingAttendee *ia)
448 EMeetingAttendeePrivate *priv;
450 priv = ia->priv;
452 return string_is_set (priv->delto);
455 const gchar *
456 e_meeting_attendee_get_delfrom (EMeetingAttendee *ia)
458 EMeetingAttendeePrivate *priv;
460 priv = ia->priv;
462 return priv->delfrom;
465 void
466 e_meeting_attendee_set_delfrom (EMeetingAttendee *ia,
467 gchar *delfrom)
469 EMeetingAttendeePrivate *priv;
471 priv = ia->priv;
473 if (priv->delfrom != NULL)
474 g_free (priv->delfrom);
476 priv->delfrom = string_test (delfrom);
478 notify_changed (ia);
481 gboolean
482 e_meeting_attendee_is_set_delfrom (EMeetingAttendee *ia)
484 EMeetingAttendeePrivate *priv;
486 priv = ia->priv;
488 return string_is_set (priv->delfrom);
491 icalparameter_partstat
492 e_meeting_attendee_get_status (EMeetingAttendee *ia)
494 EMeetingAttendeePrivate *priv;
496 priv = ia->priv;
498 return priv->status;
501 void
502 e_meeting_attendee_set_status (EMeetingAttendee *ia,
503 icalparameter_partstat status)
505 EMeetingAttendeePrivate *priv;
507 priv = ia->priv;
509 priv->status = status;
511 notify_changed (ia);
514 const gchar *
515 e_meeting_attendee_get_sentby (EMeetingAttendee *ia)
517 EMeetingAttendeePrivate *priv;
519 priv = ia->priv;
521 return priv->sentby;
524 void
525 e_meeting_attendee_set_sentby (EMeetingAttendee *ia,
526 gchar *sentby)
528 EMeetingAttendeePrivate *priv;
530 priv = ia->priv;
532 if (priv->sentby != NULL)
533 g_free (priv->sentby);
535 priv->sentby = string_test (sentby);
537 notify_changed (ia);
540 gboolean
541 e_meeting_attendee_is_set_sentby (EMeetingAttendee *ia)
543 EMeetingAttendeePrivate *priv;
545 priv = ia->priv;
547 return string_is_set (priv->sentby);
550 const gchar *
551 e_meeting_attendee_get_cn (EMeetingAttendee *ia)
553 EMeetingAttendeePrivate *priv;
555 priv = ia->priv;
557 return priv->cn;
560 void
561 e_meeting_attendee_set_cn (EMeetingAttendee *ia,
562 gchar *cn)
564 EMeetingAttendeePrivate *priv;
566 priv = ia->priv;
568 if (priv->cn != NULL)
569 g_free (priv->cn);
571 priv->cn = string_test (cn);
573 notify_changed (ia);
576 gboolean
577 e_meeting_attendee_is_set_cn (EMeetingAttendee *ia)
579 EMeetingAttendeePrivate *priv;
581 priv = ia->priv;
583 return string_is_set (priv->cn);
586 const gchar *
587 e_meeting_attendee_get_language (EMeetingAttendee *ia)
589 EMeetingAttendeePrivate *priv;
591 priv = ia->priv;
593 return priv->language;
596 void
597 e_meeting_attendee_set_language (EMeetingAttendee *ia,
598 gchar *language)
600 EMeetingAttendeePrivate *priv;
602 priv = ia->priv;
604 if (priv->language != NULL)
605 g_free (priv->language);
607 priv->language = string_test (language);
609 notify_changed (ia);
612 gboolean
613 e_meeting_attendee_is_set_language (EMeetingAttendee *ia)
615 EMeetingAttendeePrivate *priv;
617 priv = ia->priv;
619 return string_is_set (priv->language);
622 EMeetingAttendeeType
623 e_meeting_attendee_get_atype (EMeetingAttendee *ia)
625 EMeetingAttendeePrivate *priv;
627 priv = ia->priv;
629 if (priv->cutype == ICAL_CUTYPE_ROOM
630 || priv->cutype == ICAL_CUTYPE_RESOURCE)
631 return E_MEETING_ATTENDEE_RESOURCE;
633 if (priv->role == ICAL_ROLE_CHAIR
634 || priv->role == ICAL_ROLE_REQPARTICIPANT)
635 return E_MEETING_ATTENDEE_REQUIRED_PERSON;
637 return E_MEETING_ATTENDEE_OPTIONAL_PERSON;
640 EMeetingAttendeeEditLevel
641 e_meeting_attendee_get_edit_level (EMeetingAttendee *ia)
643 EMeetingAttendeePrivate *priv;
645 g_return_val_if_fail (ia != NULL, E_MEETING_ATTENDEE_EDIT_NONE);
646 g_return_val_if_fail (E_IS_MEETING_ATTENDEE (ia), E_MEETING_ATTENDEE_EDIT_NONE);
648 priv = ia->priv;
650 return priv->edit_level;
653 void
654 e_meeting_attendee_set_edit_level (EMeetingAttendee *ia,
655 EMeetingAttendeeEditLevel level)
657 EMeetingAttendeePrivate *priv;
659 g_return_if_fail (ia != NULL);
660 g_return_if_fail (E_IS_MEETING_ATTENDEE (ia));
662 priv = ia->priv;
664 priv->edit_level = level;
667 static gint
668 compare_times (EMeetingTime *time1,
669 EMeetingTime *time2)
671 gint day_comparison;
673 day_comparison = g_date_compare (
674 &time1->date,
675 &time2->date);
676 if (day_comparison != 0)
677 return day_comparison;
679 if (time1->hour < time2->hour)
680 return -1;
681 if (time1->hour > time2->hour)
682 return 1;
684 if (time1->minute < time2->minute)
685 return -1;
686 if (time1->minute > time2->minute)
687 return 1;
689 /* The start times are exactly the same. */
690 return 0;
693 static gint
694 compare_period_starts (gconstpointer arg1,
695 gconstpointer arg2)
697 EMeetingFreeBusyPeriod *period1, *period2;
699 period1 = (EMeetingFreeBusyPeriod *) arg1;
700 period2 = (EMeetingFreeBusyPeriod *) arg2;
702 return compare_times (&period1->start, &period2->start);
705 static void
706 ensure_periods_sorted (EMeetingAttendee *ia)
708 EMeetingAttendeePrivate *priv;
710 priv = ia->priv;
712 if (priv->busy_periods_sorted)
713 return;
715 qsort (
716 priv->busy_periods->data, priv->busy_periods->len,
717 sizeof (EMeetingFreeBusyPeriod),
718 compare_period_starts);
720 priv->busy_periods_sorted = TRUE;
723 gboolean
724 e_meeting_attendee_get_has_calendar_info (EMeetingAttendee *ia)
726 EMeetingAttendeePrivate *priv;
728 priv = ia->priv;
730 return priv->has_calendar_info;
733 void
734 e_meeting_attendee_set_has_calendar_info (EMeetingAttendee *ia,
735 gboolean has_calendar_info)
737 EMeetingAttendeePrivate *priv;
739 priv = ia->priv;
741 priv->has_calendar_info = has_calendar_info;
744 const GArray *
745 e_meeting_attendee_get_busy_periods (EMeetingAttendee *ia)
747 EMeetingAttendeePrivate *priv;
749 priv = ia->priv;
751 ensure_periods_sorted (ia);
753 return priv->busy_periods;
756 gint
757 e_meeting_attendee_find_first_busy_period (EMeetingAttendee *ia,
758 GDate *date)
760 EMeetingAttendeePrivate *priv;
761 EMeetingFreeBusyPeriod *period;
762 gint lower, upper, middle = 0, cmp = 0;
763 GDate tmp_date;
765 priv = ia->priv;
767 /* Make sure the busy periods have been sorted. */
768 ensure_periods_sorted (ia);
770 /* Calculate the first day which could have a busy period which
771 * continues onto our given date. */
772 tmp_date = *date;
773 g_date_subtract_days (&tmp_date, priv->longest_period_in_days);
775 /* We want the first busy period which starts on tmp_date. */
776 lower = 0;
777 upper = priv->busy_periods->len;
779 if (upper == 0)
780 return -1;
782 while (lower < upper) {
783 middle = (lower + upper) >> 1;
785 period = &g_array_index (priv->busy_periods,
786 EMeetingFreeBusyPeriod, middle);
788 cmp = g_date_compare (&tmp_date, &period->start.date);
790 if (cmp == 0)
791 break;
792 else if (cmp < 0)
793 upper = middle;
794 else
795 lower = middle + 1;
798 /* There may be several busy periods on the same day so we step
799 * backwards to the first one. */
800 if (cmp == 0) {
801 while (middle > 0) {
802 period = &g_array_index (priv->busy_periods,
803 EMeetingFreeBusyPeriod, middle - 1);
804 if (g_date_compare (&tmp_date, &period->start.date) != 0)
805 break;
806 middle--;
808 } else if (cmp > 0) {
809 /* This means we couldn't find a period on the given day, and
810 * the last one we looked at was before it, so if there are
811 * any more periods after this one we return it. */
812 middle++;
813 if (priv->busy_periods->len <= middle)
814 return -1;
817 return middle;
820 gboolean
821 e_meeting_attendee_add_busy_period (EMeetingAttendee *ia,
822 gint start_year,
823 gint start_month,
824 gint start_day,
825 gint start_hour,
826 gint start_minute,
827 gint end_year,
828 gint end_month,
829 gint end_day,
830 gint end_hour,
831 gint end_minute,
832 EMeetingFreeBusyType busy_type,
833 const gchar *summary,
834 const gchar *location)
836 EMeetingAttendeePrivate *priv;
837 EMeetingFreeBusyPeriod period;
838 gint period_in_days;
840 g_return_val_if_fail (ia != NULL, FALSE);
841 g_return_val_if_fail (E_IS_MEETING_ATTENDEE (ia), FALSE);
842 g_return_val_if_fail (busy_type < E_MEETING_FREE_BUSY_LAST, FALSE);
843 /* summary may be NULL (optional XFB data) */
844 /* location may be NULL (optional XFB data) */
846 priv = ia->priv;
848 /* Check the dates are valid. */
849 if (!g_date_valid_dmy (start_day, start_month, start_year))
850 return FALSE;
851 if (!g_date_valid_dmy (end_day, end_month, end_year))
852 return FALSE;
853 if (start_hour < 0 || start_hour > 23)
854 return FALSE;
855 if (end_hour < 0 || end_hour > 23)
856 return FALSE;
857 if (start_minute < 0 || start_minute > 59)
858 return FALSE;
859 if (end_minute < 0 || end_minute > 59)
860 return FALSE;
862 g_date_clear (&period.start.date, 1);
863 g_date_clear (&period.end.date, 1);
864 g_date_set_dmy (&period.start.date, start_day, start_month, start_year);
865 g_date_set_dmy (&period.end.date, end_day, end_month, end_year);
866 period.start.hour = start_hour;
867 period.start.minute = start_minute;
868 period.end.hour = end_hour;
869 period.end.minute = end_minute;
870 period.busy_type = busy_type;
872 /* Check that the start time is before or equal to the end time. */
873 if (compare_times (&period.start, &period.end) > 0)
874 return FALSE;
876 /* If the busy_type is FREE, then there is no need to render it in UI */
877 if (busy_type == E_MEETING_FREE_BUSY_FREE)
878 goto done;
880 /* If the busy range is not set elsewhere, track it as best we can */
881 if (!priv->start_busy_range_set) {
882 if (!g_date_valid (&priv->busy_periods_start.date)) {
883 priv->busy_periods_start.date = period.start.date;
884 priv->busy_periods_start.hour = period.start.hour;
885 priv->busy_periods_start.minute = period.start.minute;
886 } else {
887 gint compare;
889 compare = g_date_compare (
890 &period.start.date,
891 &priv->busy_periods_start.date);
893 switch (compare) {
894 case -1:
895 priv->busy_periods_start.date = period.start.date;
896 priv->busy_periods_start.hour = period.start.hour;
897 priv->busy_periods_start.minute = period.start.minute;
898 break;
899 case 0:
900 if (period.start.hour < priv->busy_periods_start.hour
901 || (period.start.hour == priv->busy_periods_start.hour
902 && period.start.minute < priv->busy_periods_start.minute)) {
903 priv->busy_periods_start.date = period.start.date;
904 priv->busy_periods_start.hour = period.start.hour;
905 priv->busy_periods_start.minute = period.start.minute;
906 break;
908 break;
913 if (!priv->end_busy_range_set) {
914 if (!g_date_valid (&priv->busy_periods_end.date)) {
915 priv->busy_periods_end.date = period.end.date;
916 priv->busy_periods_end.hour = period.end.hour;
917 priv->busy_periods_end.minute = period.end.minute;
918 } else {
919 gint compare;
921 compare = g_date_compare (
922 &period.end.date,
923 &priv->busy_periods_end.date);
925 switch (compare) {
926 case 0:
927 if (period.end.hour > priv->busy_periods_end.hour
928 || (period.end.hour == priv->busy_periods_end.hour
929 && period.end.minute > priv->busy_periods_end.minute)) {
930 priv->busy_periods_end.date = period.end.date;
931 priv->busy_periods_end.hour = period.end.hour;
932 priv->busy_periods_end.minute = period.end.minute;
933 break;
935 break;
936 case 1:
937 priv->busy_periods_end.date = period.end.date;
938 priv->busy_periods_end.hour = period.end.hour;
939 priv->busy_periods_end.minute = period.end.minute;
940 break;
945 /* Setting of extended free/busy (XFB) data, if we have any. */
946 e_meeting_xfb_data_init (&(period.xfb));
947 e_meeting_xfb_data_set (&(period.xfb), summary, location);
949 g_array_append_val (priv->busy_periods, period);
951 period_in_days =
952 g_date_get_julian (&period.end.date) -
953 g_date_get_julian (&period.start.date) + 1;
954 priv->longest_period_in_days =
955 MAX (priv->longest_period_in_days, period_in_days);
957 done:
958 priv->has_calendar_info = TRUE;
959 priv->busy_periods_sorted = FALSE;
961 return TRUE;
964 EMeetingTime
965 e_meeting_attendee_get_start_busy_range (EMeetingAttendee *ia)
967 EMeetingAttendeePrivate *priv;
969 priv = ia->priv;
971 return priv->busy_periods_start;
974 EMeetingTime
975 e_meeting_attendee_get_end_busy_range (EMeetingAttendee *ia)
977 EMeetingAttendeePrivate *priv;
979 priv = ia->priv;
981 return priv->busy_periods_end;
984 gboolean
985 e_meeting_attendee_set_start_busy_range (EMeetingAttendee *ia,
986 gint start_year,
987 gint start_month,
988 gint start_day,
989 gint start_hour,
990 gint start_minute)
992 EMeetingAttendeePrivate *priv;
994 g_return_val_if_fail (E_IS_MEETING_ATTENDEE (ia), FALSE);
996 priv = ia->priv;
998 /* Check the dates are valid. */
999 if (!g_date_valid_dmy (start_day, start_month, start_year))
1000 return FALSE;
1001 if (start_hour < 0 || start_hour > 23)
1002 return FALSE;
1003 if (start_minute < 0 || start_minute > 59)
1004 return FALSE;
1006 g_date_clear (&priv->busy_periods_start.date, 1);
1007 g_date_set_dmy (
1008 &priv->busy_periods_start.date,
1009 start_day, start_month, start_year);
1010 priv->busy_periods_start.hour = start_hour;
1011 priv->busy_periods_start.minute = start_minute;
1013 priv->start_busy_range_set = TRUE;
1015 return TRUE;
1018 gboolean
1019 e_meeting_attendee_set_end_busy_range (EMeetingAttendee *ia,
1020 gint end_year,
1021 gint end_month,
1022 gint end_day,
1023 gint end_hour,
1024 gint end_minute)
1026 EMeetingAttendeePrivate *priv;
1028 g_return_val_if_fail (E_IS_MEETING_ATTENDEE (ia), FALSE);
1030 priv = ia->priv;
1032 /* Check the dates are valid. */
1033 if (!g_date_valid_dmy (end_day, end_month, end_year))
1034 return FALSE;
1035 if (end_hour < 0 || end_hour > 23)
1036 return FALSE;
1037 if (end_minute < 0 || end_minute > 59)
1038 return FALSE;
1040 g_date_clear (&priv->busy_periods_end.date, 1);
1041 g_date_set_dmy (
1042 &priv->busy_periods_end.date,
1043 end_day, end_month, end_year);
1044 priv->busy_periods_end.hour = end_hour;
1045 priv->busy_periods_end.minute = end_minute;
1047 priv->end_busy_range_set = TRUE;
1049 return TRUE;
1052 /* Clears all busy times for the given attendee. */
1053 void
1054 e_meeting_attendee_clear_busy_periods (EMeetingAttendee *ia)
1056 EMeetingAttendeePrivate *priv;
1058 g_return_if_fail (E_IS_MEETING_ATTENDEE (ia));
1060 priv = ia->priv;
1062 g_array_set_size (priv->busy_periods, 0);
1063 priv->busy_periods_sorted = TRUE;
1065 g_date_clear (&priv->busy_periods_start.date, 1);
1066 priv->busy_periods_start.hour = 0;
1067 priv->busy_periods_start.minute = 0;
1069 g_date_clear (&priv->busy_periods_end.date, 1);
1070 priv->busy_periods_end.hour = 0;
1071 priv->busy_periods_end.minute = 0;
1073 priv->longest_period_in_days = 0;