evolution-3.6.4/calendar/gui/dialogs/event-editor.c

No issues found

  1 /*
  2  * Evolution calendar - Event editor dialog
  3  *
  4  * This program is free software; you can redistribute it and/or
  5  * modify it under the terms of the GNU Lesser General Public
  6  * License as published by the Free Software Foundation; either
  7  * version 2 of the License, or (at your option) version 3.
  8  *
  9  * This program is distributed in the hope that it will be useful,
 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 12  * Lesser General Public License for more details.
 13  *
 14  * You should have received a copy of the GNU Lesser General Public
 15  * License along with the program; if not, see <http://www.gnu.org/licenses/>
 16  *
 17  *
 18  * Authors:
 19  *		Miguel de Icaza <miguel@ximian.com>
 20  *      Federico Mena-Quintero <federico@ximian.com>
 21  *      Seth Alves <alves@hungry.com>
 22  *
 23  *
 24  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 25  *
 26  */
 27 
 28 #ifdef HAVE_CONFIG_H
 29 #include <config.h>
 30 #endif
 31 
 32 #include <string.h>
 33 #include <glib/gi18n.h>
 34 
 35 #include <misc/e-dateedit.h>
 36 #include <e-util/e-plugin-ui.h>
 37 #include <e-util/e-util-private.h>
 38 #include <e-util/e-ui-manager.h>
 39 
 40 #include "event-page.h"
 41 #include "recurrence-page.h"
 42 #include "schedule-page.h"
 43 #include "cancel-comp.h"
 44 #include "event-editor.h"
 45 
 46 #define EVENT_EDITOR_GET_PRIVATE(obj) \
 47 	(G_TYPE_INSTANCE_GET_PRIVATE \
 48 	((obj), TYPE_EVENT_EDITOR, EventEditorPrivate))
 49 
 50 struct _EventEditorPrivate {
 51 	EventPage *event_page;
 52 	RecurrencePage *recur_page;
 53 	GtkWidget *recur_window;
 54 	SchedulePage *sched_page;
 55 	GtkWidget *sched_window;
 56 
 57 	EMeetingStore *model;
 58 	gboolean meeting_shown;
 59 	gboolean updating;
 60 };
 61 
 62 /* Extends the UI definition in CompEditor */
 63 static const gchar *ui =
 64 "<ui>"
 65 "  <menubar action='main-menu'>"
 66 "    <menu action='view-menu'>"
 67 "      <menuitem action='view-type'/>"
 68 "      <menuitem action='view-status'/>"
 69 "      <menuitem action='view-role'/>"
 70 "      <menuitem action='view-rsvp'/>"
 71 "      <separator/>"
 72 "      <menuitem action='view-time-zone'/>"
 73 "      <menuitem action='view-categories'/>"
 74 "    </menu>"
 75 "    <menu action='insert-menu'>"
 76 "      <menuitem action='send-options'/>"
 77 "    </menu>"
 78 "    <menu action='options-menu'>"
 79 "      <menuitem action='alarms'/>"
 80 "      <menuitem action='show-time-busy'/>"
 81 "      <menuitem action='recurrence'/>"
 82 "      <menuitem action='all-day-event'/>"
 83 "      <menuitem action='free-busy'/>"
 84 "      <menu action='classification-menu'>"
 85 "        <menuitem action='classify-public'/>"
 86 "        <menuitem action='classify-private'/>"
 87 "        <menuitem action='classify-confidential'/>"
 88 "      </menu>"
 89 "    </menu>"
 90 "  </menubar>"
 91 "  <toolbar name='main-toolbar'>"
 92 "    <placeholder name='content'>\n"
 93 "#if !EXPRESS\n"
 94 "      <toolitem action='alarms'/>\n"
 95 "#endif\n"
 96 "      <toolitem action='show-time-busy'/>\n"
 97 "#if !EXPRESS\n"
 98 "      <toolitem action='recurrence'/>\n"
 99 "#endif\n"
100 "      <toolitem action='all-day-event'/>\n"
101 "#if !EXPRESS\n"
102 "      <toolitem action='free-busy'/>\n"
103 "#endif\n"
104 "    </placeholder>"
105 "  </toolbar>"
106 "</ui>";
107 
108 static void	event_editor_edit_comp		(CompEditor *editor,
109 						 ECalComponent *comp);
110 static gboolean	event_editor_send_comp		(CompEditor *editor,
111 						 ECalComponentItipMethod method,
112 						 gboolean strip_alarms);
113 
114 G_DEFINE_TYPE (EventEditor, event_editor, TYPE_COMP_EDITOR)
115 
116 static void
117 create_schedule_page (CompEditor *editor)
118 {
119 	EventEditorPrivate *priv;
120 	ENameSelector *name_selector;
121 	CompEditorPage *page;
122 	GtkWidget *content_area;
123 
124 	priv = EVENT_EDITOR_GET_PRIVATE (editor);
125 
126 	priv->sched_window = gtk_dialog_new_with_buttons (
127 		_("Free/Busy"), GTK_WINDOW (editor), GTK_DIALOG_DESTROY_WITH_PARENT,
128 		GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL);
129 
130 	content_area =
131 		gtk_dialog_get_content_area (GTK_DIALOG (priv->sched_window));
132 
133 	g_signal_connect (
134 		priv->sched_window, "response",
135 		G_CALLBACK (gtk_widget_hide), NULL);
136 	g_signal_connect (
137 		priv->sched_window, "delete-event",
138 		G_CALLBACK (gtk_widget_hide_on_delete), NULL);
139 
140 	priv->sched_page = schedule_page_new (priv->model, editor);
141 	page = COMP_EDITOR_PAGE (priv->sched_page);
142 	gtk_container_add (
143 		GTK_CONTAINER (content_area),
144 		comp_editor_page_get_widget (page));
145 
146 	name_selector = event_page_get_name_selector (priv->event_page);
147 	schedule_page_set_name_selector (priv->sched_page, name_selector);
148 
149 	comp_editor_append_page (editor, page, NULL, FALSE);
150 	schedule_page_update_free_busy (priv->sched_page);
151 
152 	gtk_widget_show_all (priv->sched_window);
153 }
154 
155 static void
156 action_alarms_cb (GtkAction *action,
157                   EventEditor *editor)
158 {
159 	event_page_show_alarm (editor->priv->event_page);
160 }
161 
162 static void
163 action_all_day_event_cb (GtkToggleAction *action,
164                          EventEditor *editor)
165 {
166 	gboolean active;
167 	GtkAction *action_show_busy;
168 	CompEditor *comp_editor = COMP_EDITOR (editor);
169 
170 	active = gtk_toggle_action_get_active (action);
171 	event_page_set_all_day_event (editor->priv->event_page, active);
172 
173 	action_show_busy = comp_editor_get_action (comp_editor, "show-time-busy");
174 	gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action_show_busy), !active);
175 	event_page_set_show_time_busy (editor->priv->event_page, !active);
176 }
177 
178 static void
179 action_free_busy_cb (GtkAction *action,
180                      EventEditor *editor)
181 {
182 	if (editor->priv->sched_window == NULL)
183 		create_schedule_page (COMP_EDITOR (editor));
184 	else
185 		gtk_window_present (GTK_WINDOW (editor->priv->sched_window));
186 }
187 
188 static void
189 action_recurrence_cb (GtkAction *action,
190                       EventEditor *editor)
191 {
192 	gtk_widget_show (editor->priv->recur_window);
193 }
194 
195 static void
196 action_send_options_cb (GtkAction *action,
197                         EventEditor *editor)
198 {
199 	event_page_send_options_clicked_cb (editor->priv->event_page);
200 }
201 
202 static void
203 action_show_time_busy_cb (GtkToggleAction *action,
204                           EventEditor *editor)
205 {
206 	gboolean active;
207 
208 	active = gtk_toggle_action_get_active (action);
209 	event_page_set_show_time_busy (editor->priv->event_page, active);
210 }
211 
212 static GtkActionEntry editable_entries[] = {
213 
214 	{ "alarms",
215 	  "appointment-soon",
216 	  N_("_Reminders"),
217 	  NULL,
218 	  N_("Set or unset reminders for this event"),
219 	  G_CALLBACK (action_alarms_cb) },
220 };
221 
222 static GtkToggleActionEntry editable_toggle_entries[] = {
223 
224 	{ "show-time-busy",
225 	  GTK_STOCK_DIALOG_ERROR,
226 	  N_("Show Time as _Busy"),
227 	  NULL,
228 	  N_("Toggles whether to show time as busy"),
229 	  G_CALLBACK (action_show_time_busy_cb),
230 	  FALSE }
231 };
232 
233 static GtkActionEntry event_entries[] = {
234 
235 	{ "recurrence",
236 	  "stock_task-recurring",
237 	  N_("_Recurrence"),
238 	  NULL,
239 	  N_("Make this a recurring event"),
240 	  G_CALLBACK (action_recurrence_cb) },
241 
242 	{ "send-options",
243 	  NULL,
244 	  N_("Send Options"),
245 	  NULL,
246 	  N_("Insert advanced send options"),
247 	  G_CALLBACK (action_send_options_cb) }
248 };
249 
250 static GtkToggleActionEntry event_toggle_entries[] = {
251 
252 	{ "all-day-event",
253 	  "stock_new-24h-appointment",
254 	  N_("All _Day Event"),
255 	  NULL,
256 	  N_("Toggles whether to have All Day Event"),
257 	  G_CALLBACK (action_all_day_event_cb),
258 	  FALSE },
259 };
260 
261 static GtkActionEntry meeting_entries[] = {
262 
263 	{ "free-busy",
264 	  "query-free-busy",
265 	  N_("_Free/Busy"),
266 	  NULL,
267 	  N_("Query free / busy information for the attendees"),
268 	  G_CALLBACK (action_free_busy_cb) }
269 };
270 
271 static void
272 event_editor_model_changed_cb (EventEditor *ee)
273 {
274 	if (!ee->priv->updating) {
275 		comp_editor_set_changed (COMP_EDITOR (ee), TRUE);
276 		comp_editor_set_needs_send (COMP_EDITOR (ee), TRUE);
277 	}
278 }
279 
280 static GObject *
281 event_editor_constructor (GType type,
282                           guint n_construct_properties,
283                           GObjectConstructParam *construct_properties)
284 {
285 	GObject *object;
286 	CompEditor *editor;
287 	CompEditorFlags flags;
288 	CompEditorPage *page;
289 	EventEditorPrivate *priv;
290 	GtkActionGroup *action_group;
291 	GtkWidget *content_area;
292 	EShell *shell;
293 	ECalClient *client;
294 	gboolean is_meeting;
295 	GtkWidget *alarm_page;
296 	GtkWidget *attendee_page;
297 
298 	/* Chain up to parent's constructor() method. */
299 	object = G_OBJECT_CLASS (event_editor_parent_class)->constructor (
300 		type, n_construct_properties, construct_properties);
301 
302 	editor = COMP_EDITOR (object);
303 	priv = EVENT_EDITOR_GET_PRIVATE (object);
304 
305 	shell = comp_editor_get_shell (editor);
306 
307 	client = comp_editor_get_client (editor);
308 	flags = comp_editor_get_flags (editor);
309 	action_group = comp_editor_get_action_group (editor, "coordinated");
310 
311 	is_meeting = flags & COMP_EDITOR_MEETING;
312 
313 	gtk_action_group_set_visible (action_group, is_meeting);
314 
315 	priv->event_page = event_page_new (priv->model, editor);
316 	comp_editor_append_page (
317 		editor, COMP_EDITOR_PAGE (priv->event_page),
318 		_("Appointment"), TRUE);
319 
320 	priv->recur_window = gtk_dialog_new_with_buttons (
321 		_("Recurrence"), GTK_WINDOW (editor), GTK_DIALOG_MODAL,
322 		GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, NULL);
323 	g_signal_connect (
324 		priv->recur_window, "response",
325 		G_CALLBACK (gtk_widget_hide), NULL);
326 	g_signal_connect (
327 		priv->recur_window, "delete-event",
328 		G_CALLBACK (gtk_widget_hide_on_delete), NULL);
329 
330 	content_area =
331 		gtk_dialog_get_content_area (GTK_DIALOG (priv->recur_window));
332 
333 	priv->recur_page = recurrence_page_new (priv->model, editor);
334 	page = COMP_EDITOR_PAGE (priv->recur_page);
335 	if (!e_shell_get_express_mode (shell)) {
336 		gtk_container_add (
337 			GTK_CONTAINER (content_area),
338 			comp_editor_page_get_widget (page));
339 		gtk_widget_show_all (gtk_bin_get_child (GTK_BIN (priv->recur_window)));
340 		comp_editor_append_page (editor, page, NULL, FALSE);
341 	} else {
342 		comp_editor_append_page (editor, page, _("Recurrence"), TRUE);
343 	}
344 
345 	if (e_shell_get_express_mode (shell)) {
346 		ENameSelector *name_selector;
347 
348 		priv->sched_page = schedule_page_new (priv->model, editor);
349 		page = COMP_EDITOR_PAGE (priv->sched_page);
350 
351 		name_selector = event_page_get_name_selector (priv->event_page);
352 		schedule_page_set_name_selector (priv->sched_page, name_selector);
353 
354 		comp_editor_append_page (editor, page, _("Free/Busy"), TRUE);
355 		schedule_page_update_free_busy (priv->sched_page);
356 
357 		g_object_bind_property (
358 			action_group, "visible",
359 			comp_editor_page_get_widget (page), "visible",
360 			G_BINDING_SYNC_CREATE);
361 
362 		/* Alarm page */
363 		alarm_page = event_page_get_alarm_page (priv->event_page);
364 		comp_editor_append_widget (editor, alarm_page, _("Reminder"), TRUE);
365 		g_object_unref (alarm_page);
366 	}
367 
368 	if (is_meeting) {
369 
370 		if (e_client_check_capability (E_CLIENT (client), CAL_STATIC_CAPABILITY_REQ_SEND_OPTIONS))
371 			event_page_show_options (priv->event_page);
372 
373 		comp_editor_set_group_item (editor, TRUE);
374 		if (!((flags & COMP_EDITOR_USER_ORG) ||
375 			(flags & COMP_EDITOR_DELEGATE) ||
376 			(flags & COMP_EDITOR_NEW_ITEM))) {
377 			GtkAction *action;
378 
379 			action = comp_editor_get_action (editor, "free-busy");
380 			gtk_action_set_visible (action, FALSE);
381 		}
382 
383 		event_page_set_meeting (priv->event_page, TRUE);
384 		priv->meeting_shown = TRUE;
385 
386 		if (e_shell_get_express_mode (shell)) {
387 			attendee_page = event_page_get_attendee_page (priv->event_page);
388 			comp_editor_append_widget (editor, attendee_page, _("Attendees"), TRUE);
389 			g_object_unref (attendee_page);
390 		}
391 	}
392 
393 	return object;
394 }
395 
396 static void
397 event_editor_dispose (GObject *object)
398 {
399 	EventEditorPrivate *priv;
400 
401 	priv = EVENT_EDITOR_GET_PRIVATE (object);
402 
403 	if (priv->event_page) {
404 		g_object_unref (priv->event_page);
405 		priv->event_page = NULL;
406 	}
407 
408 	if (priv->recur_page) {
409 		g_object_unref (priv->recur_page);
410 		priv->recur_page = NULL;
411 	}
412 
413 	if (priv->sched_page) {
414 		g_object_unref (priv->sched_page);
415 		priv->sched_page = NULL;
416 	}
417 
418 	if (priv->model) {
419 		g_signal_handlers_disconnect_by_func (
420 			priv->model, event_editor_model_changed_cb, object);
421 		g_object_unref (priv->model);
422 		priv->model = NULL;
423 	}
424 
425 	/* Chain up to parent's dispose() method. */
426 	G_OBJECT_CLASS (event_editor_parent_class)->dispose (object);
427 }
428 
429 static void
430 event_editor_constructed (GObject *object)
431 {
432 	EventEditorPrivate *priv;
433 
434 	priv = EVENT_EDITOR_GET_PRIVATE (object);
435 
436 	g_object_bind_property (
437 		object, "client",
438 		priv->model, "client",
439 		G_BINDING_SYNC_CREATE);
440 
441 	/* Chain up to parent's constructed() method. */
442 	G_OBJECT_CLASS (event_editor_parent_class)->constructed (object);
443 }
444 
445 static void
446 event_editor_show_categories (CompEditor *editor,
447                               gboolean visible)
448 {
449 	EventEditorPrivate *priv;
450 
451 	priv = EVENT_EDITOR_GET_PRIVATE (editor);
452 
453 	event_page_set_show_categories (priv->event_page, visible);
454 }
455 
456 static void
457 event_editor_show_role (CompEditor *editor,
458                         gboolean visible)
459 {
460 	EventEditorPrivate *priv;
461 
462 	priv = EVENT_EDITOR_GET_PRIVATE (editor);
463 
464 	event_page_set_view_role (priv->event_page, visible);
465 }
466 
467 static void
468 event_editor_show_rsvp (CompEditor *editor,
469                         gboolean visible)
470 {
471 	EventEditorPrivate *priv;
472 
473 	priv = EVENT_EDITOR_GET_PRIVATE (editor);
474 
475 	event_page_set_view_rsvp (priv->event_page, visible);
476 }
477 
478 static void
479 event_editor_show_status (CompEditor *editor,
480                           gboolean visible)
481 {
482 	EventEditorPrivate *priv;
483 
484 	priv = EVENT_EDITOR_GET_PRIVATE (editor);
485 
486 	event_page_set_view_status (priv->event_page, visible);
487 }
488 
489 static void
490 event_editor_show_time_zone (CompEditor *editor,
491                              gboolean visible)
492 {
493 	EventEditorPrivate *priv;
494 
495 	priv = EVENT_EDITOR_GET_PRIVATE (editor);
496 
497 	event_page_set_show_timezone (priv->event_page, visible);
498 }
499 
500 static void
501 event_editor_show_type (CompEditor *editor,
502                         gboolean visible)
503 {
504 	EventEditorPrivate *priv;
505 
506 	priv = EVENT_EDITOR_GET_PRIVATE (editor);
507 
508 	event_page_set_view_type (priv->event_page, visible);
509 }
510 
511 static void
512 event_editor_class_init (EventEditorClass *class)
513 {
514 	GObjectClass *object_class;
515 	CompEditorClass *editor_class;
516 
517 	g_type_class_add_private (class, sizeof (EventEditorPrivate));
518 
519 	object_class = G_OBJECT_CLASS (class);
520 	object_class->constructor = event_editor_constructor;
521 	object_class->dispose = event_editor_dispose;
522 	object_class->constructed = event_editor_constructed;
523 
524 	editor_class = COMP_EDITOR_CLASS (class);
525 	editor_class->help_section = "calendar-usage-add-appointment";
526 	editor_class->edit_comp = event_editor_edit_comp;
527 	editor_class->send_comp = event_editor_send_comp;
528 	editor_class->show_categories = event_editor_show_categories;
529 	editor_class->show_role = event_editor_show_role;
530 	editor_class->show_rsvp = event_editor_show_rsvp;
531 	editor_class->show_status = event_editor_show_status;;
532 	editor_class->show_time_zone = event_editor_show_time_zone;
533 	editor_class->show_type = event_editor_show_type;
534 }
535 
536 static void
537 event_editor_init (EventEditor *ee)
538 {
539 	CompEditor *editor = COMP_EDITOR (ee);
540 	GtkUIManager *ui_manager;
541 	GtkActionGroup *action_group;
542 	GtkAction *action;
543 	const gchar *id;
544 	GError *error = NULL;
545 
546 	ee->priv = EVENT_EDITOR_GET_PRIVATE (ee);
547 	ee->priv->model = E_MEETING_STORE (e_meeting_store_new ());
548 	ee->priv->meeting_shown = TRUE;
549 	ee->priv->updating = FALSE;
550 
551 	action_group = comp_editor_get_action_group (editor, "individual");
552 	gtk_action_group_add_actions (
553 		action_group, event_entries,
554 		G_N_ELEMENTS (event_entries), ee);
555 	gtk_action_group_add_toggle_actions (
556 		action_group, event_toggle_entries,
557 		G_N_ELEMENTS (event_toggle_entries), ee);
558 
559 	action_group = comp_editor_get_action_group (editor, "editable");
560 	gtk_action_group_add_actions (
561 		action_group, editable_entries,
562 		G_N_ELEMENTS (editable_entries), ee);
563 	gtk_action_group_add_toggle_actions (
564 		action_group, editable_toggle_entries,
565 		G_N_ELEMENTS (editable_toggle_entries), ee);
566 
567 	action_group = comp_editor_get_action_group (editor, "coordinated");
568 	gtk_action_group_add_actions (
569 		action_group, meeting_entries,
570 		G_N_ELEMENTS (meeting_entries), ee);
571 
572 	ui_manager = comp_editor_get_ui_manager (editor);
573 	e_ui_manager_add_ui_from_string (E_UI_MANAGER (ui_manager), ui, &error);
574 
575 	id = "org.gnome.evolution.event-editor";
576 	e_plugin_ui_register_manager (ui_manager, id, ee);
577 	e_plugin_ui_enable_manager (ui_manager, id);
578 
579 	if (error != NULL) {
580 		g_critical ("%s: %s", G_STRFUNC, error->message);
581 		g_error_free (error);
582 	}
583 
584 	action = comp_editor_get_action (editor, "print");
585 	gtk_action_set_tooltip (action, _("Print this event"));
586 
587 	/* Hide send options. */
588 	action = comp_editor_get_action (editor, "send-options");
589 	gtk_action_set_visible (action, FALSE);
590 
591 	g_signal_connect_swapped (
592 		ee->priv->model, "row_changed",
593 		G_CALLBACK (event_editor_model_changed_cb), ee);
594 	g_signal_connect_swapped (
595 		ee->priv->model, "row_inserted",
596 		G_CALLBACK (event_editor_model_changed_cb), ee);
597 	g_signal_connect_swapped (
598 		ee->priv->model, "row_deleted",
599 		G_CALLBACK (event_editor_model_changed_cb), ee);
600 }
601 
602 static void
603 event_editor_edit_comp (CompEditor *editor,
604                         ECalComponent *comp)
605 {
606 	EventEditorPrivate *priv;
607 	ECalComponentOrganizer organizer;
608 	gboolean delegate;
609 	ECalComponentDateTime dtstart, dtend;
610 	ECalClient *client;
611 	GSList *attendees = NULL;
612 	ESourceRegistry *registry;
613 	EShell *shell;
614 
615 	priv = EVENT_EDITOR_GET_PRIVATE (editor);
616 
617 	priv->updating = TRUE;
618 	delegate = (comp_editor_get_flags (COMP_EDITOR (editor)) & COMP_EDITOR_DELEGATE);
619 
620 	if (priv->sched_page) {
621 		e_cal_component_get_dtstart (comp, &dtstart);
622 		e_cal_component_get_dtend (comp, &dtend);
623 
624 		schedule_page_set_meeting_time (priv->sched_page, dtstart.value, dtend.value);
625 
626 		e_cal_component_free_datetime (&dtstart);
627 		e_cal_component_free_datetime (&dtend);
628 	}
629 
630 	if (COMP_EDITOR_CLASS (event_editor_parent_class)->edit_comp)
631 		COMP_EDITOR_CLASS (event_editor_parent_class)->edit_comp (editor, comp);
632 
633 	shell = comp_editor_get_shell (editor);
634 	client = comp_editor_get_client (editor);
635 
636 	registry = e_shell_get_registry (shell);
637 
638 	/* Get meeting related stuff */
639 	e_cal_component_get_organizer (comp, &organizer);
640 	e_cal_component_get_attendee_list (comp, &attendees);
641 
642 	/* Set up the attendees */
643 	if (attendees != NULL) {
644 		GSList *l;
645 		gint row;
646 		gchar *user_email;
647 
648 		user_email = itip_get_comp_attendee (
649 			registry, comp, client);
650 
651 		if (!priv->meeting_shown) {
652 			GtkAction *action;
653 
654 			action = comp_editor_get_action (editor, "free-busy");
655 			gtk_action_set_visible (action, TRUE);
656 		}
657 
658 		if (!(delegate && e_client_check_capability (
659 			E_CLIENT (client), CAL_STATIC_CAPABILITY_DELEGATE_TO_MANY))) {
660 			event_page_remove_all_attendees (priv->event_page);
661 
662 			for (l = attendees; l != NULL; l = l->next) {
663 				ECalComponentAttendee *ca = l->data;
664 				EMeetingAttendee *ia;
665 				gboolean addresses_match;
666 
667 				addresses_match = g_str_equal (
668 					user_email,
669 					itip_strip_mailto (ca->value));
670 
671 				if (delegate && !addresses_match)
672 					continue;
673 
674 				ia = E_MEETING_ATTENDEE (
675 					e_meeting_attendee_new_from_e_cal_component_attendee (ca));
676 
677 				/* If we aren't the organizer or the attendee
678 				 * is just delegated, don't allow editing. */
679 				if (!comp_editor_get_user_org (editor) ||
680 					e_meeting_attendee_is_set_delto (ia))
681 					e_meeting_attendee_set_edit_level (
682 						ia,  E_MEETING_ATTENDEE_EDIT_NONE);
683 
684 				comp_editor_page_add_attendee (
685 					COMP_EDITOR_PAGE (priv->event_page), ia);
686 
687 				g_object_unref (ia);
688 			}
689 
690 			/* If we aren't the organizer we can still change our own status */
691 			if (!comp_editor_get_user_org (editor)) {
692 				EMeetingAttendee *ia;
693 
694 				ia = e_meeting_store_find_self (priv->model, &row);
695 				if (ia != NULL)
696 					e_meeting_attendee_set_edit_level (
697 						ia, E_MEETING_ATTENDEE_EDIT_STATUS);
698 			} else if (e_cal_client_check_organizer_must_attend (client)) {
699 				EMeetingAttendee *ia;
700 
701 				ia = e_meeting_store_find_attendee (
702 					priv->model, organizer.value, &row);
703 				if (ia != NULL)
704 					e_meeting_attendee_set_edit_level (
705 						ia, E_MEETING_ATTENDEE_EDIT_NONE);
706 			}
707 		}
708 
709 		event_page_set_meeting (priv->event_page, TRUE);
710 		priv->meeting_shown = TRUE;
711 		g_free (user_email);
712 	}
713 	e_cal_component_free_attendee_list (attendees);
714 
715 	comp_editor_set_needs_send (
716 		editor, priv->meeting_shown && (itip_organizer_is_user (
717 		registry, comp, client) || itip_sentby_is_user (registry,
718 		comp, client)));
719 
720 	priv->updating = FALSE;
721 }
722 
723 static gboolean
724 event_editor_send_comp (CompEditor *editor,
725                         ECalComponentItipMethod method,
726                         gboolean strip_alarms)
727 {
728 	EventEditorPrivate *priv;
729 	EShell *shell;
730 	ESourceRegistry *registry;
731 	ECalComponent *comp = NULL;
732 
733 	priv = EVENT_EDITOR_GET_PRIVATE (editor);
734 
735 	/* Don't cancel more than once or when just publishing */
736 	if (method == E_CAL_COMPONENT_METHOD_PUBLISH ||
737 	    method == E_CAL_COMPONENT_METHOD_CANCEL)
738 		goto parent;
739 
740 	shell = comp_editor_get_shell (editor);
741 	registry = e_shell_get_registry (shell);
742 
743 	comp = event_page_get_cancel_comp (priv->event_page);
744 	if (comp != NULL) {
745 		ECalClient *client;
746 		gboolean result;
747 
748 		client = e_meeting_store_get_client (priv->model);
749 		result = itip_send_comp (
750 			registry, E_CAL_COMPONENT_METHOD_CANCEL, comp,
751 			client, NULL, NULL, NULL, strip_alarms, FALSE);
752 		g_object_unref (comp);
753 
754 		if (!result)
755 			return result;
756 	}
757 
758  parent:
759 	if (COMP_EDITOR_CLASS (event_editor_parent_class)->send_comp)
760 		return COMP_EDITOR_CLASS (event_editor_parent_class)->
761 			send_comp (editor, method, strip_alarms);
762 
763 	return FALSE;
764 }
765 
766 /**
767  * event_editor_new:
768  * @client: a ECalClient
769  *
770  * Creates a new event editor dialog.
771  *
772  * Return value: A newly-created event editor dialog, or NULL if the event
773  * editor could not be created.
774  **/
775 CompEditor *
776 event_editor_new (ECalClient *client,
777                   EShell *shell,
778                   CompEditorFlags flags)
779 {
780 	g_return_val_if_fail (E_IS_CAL_CLIENT (client), NULL);
781 	g_return_val_if_fail (E_IS_SHELL (shell), NULL);
782 
783 	return g_object_new (
784 		TYPE_EVENT_EDITOR,
785 		"client", client, "flags", flags, "shell", shell, NULL);
786 }
787 
788 void
789 event_editor_show_meeting (EventEditor *ee)
790 {
791 	CompEditor *editor;
792 	CompEditorFlags flags;
793 
794 	g_return_if_fail (IS_EVENT_EDITOR (ee));
795 
796 	editor = COMP_EDITOR (ee);
797 	flags = comp_editor_get_flags (editor);
798 
799 	event_page_set_meeting (ee->priv->event_page, TRUE);
800 	if (!ee->priv->meeting_shown) {
801 		GtkAction *action;
802 
803 		action = comp_editor_get_action (editor, "free-busy");
804 		gtk_action_set_visible (action, TRUE);
805 
806 		ee->priv->meeting_shown = TRUE;
807 
808 		comp_editor_set_changed (editor, FALSE);
809 		comp_editor_set_needs_send (editor, TRUE);
810 	}
811 
812 	if (!(flags & COMP_EDITOR_NEW_ITEM) && !(flags & COMP_EDITOR_USER_ORG))
813 		gtk_drag_dest_unset (GTK_WIDGET (editor));
814 }