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

No issues found

   1 /*
   2  * Evolution calendar - Framework for a calendar component 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  *		Federico Mena-Quintero <federico@ximian.com>
  20  *
  21  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
  22  *
  23  */
  24 
  25 #ifdef HAVE_CONFIG_H
  26 #include <config.h>
  27 #endif
  28 
  29 #include <errno.h>
  30 #include <stdio.h>
  31 #include <sys/types.h>
  32 #include <sys/stat.h>
  33 #include <fcntl.h>
  34 #include <unistd.h>
  35 #include <glib/gi18n-lib.h>
  36 #include <glib/gstdio.h>
  37 #include <gio/gio.h>
  38 #include <gdk/gdkkeysyms.h>
  39 #include <libebackend/libebackend.h>
  40 
  41 #include <e-util/e-util.h>
  42 #include <libevolution-utils/e-alert-sink.h>
  43 #include <e-util/e-dialog-utils.h>
  44 #include <e-util/e-util-private.h>
  45 #include <shell/e-shell.h>
  46 
  47 #include "../print.h"
  48 #include "../comp-util.h"
  49 #include "save-comp.h"
  50 #include "delete-comp.h"
  51 #include "send-comp.h"
  52 #include "changed-comp.h"
  53 #include "cancel-comp.h"
  54 #include "recur-comp.h"
  55 #include "comp-editor.h"
  56 #include "comp-editor-util.h"
  57 #include "../calendar-config-keys.h"
  58 #include "widgets/misc/e-attachment-view.h"
  59 #include "widgets/misc/e-attachment-paned.h"
  60 
  61 #include "libevolution-utils/e-alert-dialog.h"
  62 #include "e-util/e-ui-manager.h"
  63 
  64 #define COMP_EDITOR_GET_PRIVATE(obj) \
  65 	(G_TYPE_INSTANCE_GET_PRIVATE \
  66 	((obj), TYPE_COMP_EDITOR, CompEditorPrivate))
  67 
  68 #define d(x)
  69 
  70 /* Private part of the CompEditor structure */
  71 struct _CompEditorPrivate {
  72 
  73 	gpointer shell;  /* weak pointer */
  74 
  75 	GSettings *calendar_settings;
  76 
  77 	/* EFocusTracker keeps selection actions up-to-date. */
  78 	EFocusTracker *focus_tracker;
  79 
  80 	/* Each CompEditor window gets its own GtkWindowGroup, so it
  81 	 * doesn't block the main window or other CompEditor windows. */
  82 	GtkWindowGroup *window_group;
  83 
  84 	/* Client to use */
  85 	ECalClient *cal_client;
  86 
  87 	/* Source client (where comp lives currently) */
  88 	ECalClient *source_client;
  89 
  90 	/* View to listen for changes */
  91 	ECalClientView *view;
  92 	GCancellable *view_cancellable;
  93 
  94 	/* Calendar object/uid we are editing; this is an internal copy */
  95 	ECalComponent *comp;
  96 
  97 	/* The pages we have */
  98 	GList *pages;
  99 
 100 	/* Notebook to hold the pages */
 101 	GtkNotebook *notebook;
 102 
 103 	/* Attachment handling */
 104 	GtkWidget *attachment_view;
 105 
 106 	/* Manages menus and toolbars */
 107 	GtkUIManager *ui_manager;
 108 
 109 	gchar *summary;
 110 
 111 	guint32 attachment_bar_visible : 1;
 112 
 113 	/* TODO use this flags for setting all the boolean variables
 114 	 * below */
 115 	CompEditorFlags flags;
 116 
 117 	icaltimezone *zone;
 118 	gboolean use_24_hour_format;
 119 
 120 	gint work_day_end_hour;
 121 	gint work_day_end_minute;
 122 	gint work_day_start_hour;
 123 	gint work_day_start_minute;
 124 
 125 	gboolean changed;
 126 	gboolean needs_send;
 127 
 128 	gboolean saved;
 129 
 130 	CalObjModType mod;
 131 
 132 	gboolean existing_org;
 133 	gboolean user_org;
 134 	gboolean is_group_item;
 135 
 136 	gboolean warned;
 137 };
 138 
 139 enum {
 140 	PROP_0,
 141 	PROP_CHANGED,
 142 	PROP_CLIENT,
 143 	PROP_FLAGS,
 144 	PROP_FOCUS_TRACKER,
 145 	PROP_SHELL,
 146 	PROP_SUMMARY,
 147 	PROP_TIMEZONE,
 148 	PROP_USE_24_HOUR_FORMAT,
 149 	PROP_WORK_DAY_END_HOUR,
 150 	PROP_WORK_DAY_END_MINUTE,
 151 	PROP_WORK_DAY_START_HOUR,
 152 	PROP_WORK_DAY_START_MINUTE
 153 };
 154 
 155 static const gchar *ui =
 156 "<ui>"
 157 "  <menubar action='main-menu'>"
 158 "    <menu action='file-menu'>"
 159 "      <menuitem action='save'/>"
 160 "      <menuitem action='save-and-close'/>"
 161 "      <separator/>"
 162 "      <menuitem action='print-preview'/>"
 163 "      <menuitem action='print'/>"
 164 "      <separator/>"
 165 "      <menuitem action='close'/>"
 166 "    </menu>"
 167 "    <menu action='edit-menu'>"
 168 "      <menuitem action='cut-clipboard'/>"
 169 "      <menuitem action='copy-clipboard'/>"
 170 "      <menuitem action='paste-clipboard'/>"
 171 "      <menuitem action='delete-selection'/>"
 172 "      <separator/>"
 173 "      <menuitem action='select-all'/>"
 174 "    </menu>"
 175 "    <menu action='view-menu'/>"
 176 "    <menu action='insert-menu'>"
 177 "      <menuitem action='attach'/>"
 178 "    </menu>"
 179 "    <menu action='options-menu'/>"
 180 "    <menu action='help-menu'>"
 181 "      <menuitem action='help'/>"
 182 "    </menu>"
 183 "  </menubar>"
 184 "  <toolbar name='main-toolbar'>"
 185 "    <toolitem action='save-and-close'/>\n"
 186 "    <toolitem action='save'/>\n"
 187 "#if !EXPRESS\n"
 188 "    <toolitem action='print'/>\n"
 189 "#endif\n"
 190 "    <separator/>"
 191 "    <placeholder name='content'/>\n"
 192 "#if EXPRESS\n"
 193 "    <separator expand='true'/>\n"
 194 "    <toolitem action='close'/>\n"
 195 "#endif\n"
 196 "  </toolbar>"
 197 "</ui>";
 198 
 199 static void	comp_editor_show_help		(CompEditor *editor);
 200 
 201 static void	real_edit_comp			(CompEditor *editor,
 202 						 ECalComponent *comp);
 203 static gboolean	real_send_comp			(CompEditor *editor,
 204 						 ECalComponentItipMethod method,
 205 						 gboolean strip_alarms);
 206 static gboolean	prompt_and_save_changes		(CompEditor *editor,
 207 						 gboolean send);
 208 static void	close_dialog			(CompEditor *editor);
 209 
 210 static void	page_dates_changed_cb		(CompEditor *editor,
 211 						 CompEditorPageDates *dates,
 212 						 CompEditorPage *page);
 213 
 214 static void	obj_modified_cb			(ECalClientView *view,
 215 						 const GSList *objs,
 216 						 CompEditor *editor);
 217 static void	obj_removed_cb			(ECalClientView *view,
 218 						 const GSList *uids,
 219 						 CompEditor *editor);
 220 
 221 G_DEFINE_TYPE_WITH_CODE (
 222 	CompEditor, comp_editor, GTK_TYPE_WINDOW,
 223 	G_IMPLEMENT_INTERFACE (E_TYPE_ALERT_SINK, NULL)
 224 	G_IMPLEMENT_INTERFACE (E_TYPE_EXTENSIBLE, NULL))
 225 
 226 enum {
 227 	OBJECT_CREATED,
 228 	COMP_CLOSED,
 229 	LAST_SIGNAL
 230 };
 231 
 232 static guint signals[LAST_SIGNAL];
 233 static GList *active_editors;
 234 
 235 static void
 236 comp_editor_weak_notify_cb (gpointer unused,
 237                             GObject *where_the_object_was)
 238 {
 239 	active_editors = g_list_remove (active_editors, where_the_object_was);
 240 }
 241 
 242 static void
 243 attachment_store_changed_cb (CompEditor *editor)
 244 {
 245 	/* Mark the editor as changed so it prompts about unsaved
 246 	 * changes on close */
 247 	comp_editor_set_changed (editor, TRUE);
 248 }
 249 
 250 static void
 251 attachment_save_finished (EAttachmentStore *store,
 252                           GAsyncResult *result,
 253                           gpointer user_data)
 254 {
 255 	GtkWidget *dialog;
 256 	const gchar *primary_text;
 257 	gchar **uris;
 258 	GError *error = NULL;
 259 
 260 	struct {
 261 		gchar **uris;
 262 		gboolean done;
 263 		GtkWindow *parent;
 264 	} *status = user_data;
 265 
 266 	uris = e_attachment_store_save_finish (store, result, &error);
 267 
 268 	status->uris = uris;
 269 	status->done = TRUE;
 270 
 271 	if (uris != NULL)
 272 		goto exit;
 273 
 274 	/* Ignore cancellations. */
 275 	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
 276 		goto exit;
 277 
 278 	primary_text = _("Could not save attachments");
 279 
 280 	dialog = gtk_message_dialog_new_with_markup (
 281 		status->parent, GTK_DIALOG_DESTROY_WITH_PARENT,
 282 		GTK_MESSAGE_ERROR, GTK_BUTTONS_OK,
 283 		"<big><b>%s</b></big>", primary_text);
 284 
 285 	gtk_message_dialog_format_secondary_text (
 286 		GTK_MESSAGE_DIALOG (dialog), "%s", error->message);
 287 
 288 	gtk_dialog_run (GTK_DIALOG (dialog));
 289 
 290 	gtk_widget_destroy (dialog);
 291 
 292 exit:
 293 	if (error != NULL)
 294 		g_error_free (error);
 295 
 296 	g_object_unref (status->parent);
 297 }
 298 
 299 static GSList *
 300 get_attachment_list (CompEditor *editor)
 301 {
 302 	EAttachmentStore *store;
 303 	EAttachmentView *view;
 304 	GFile *destination;
 305 	GSList *list = NULL;
 306 	const gchar *comp_uid = NULL;
 307 	const gchar *local_store;
 308 	gchar *filename_prefix, *tmp;
 309 	gint ii;
 310 
 311 	struct {
 312 		gchar **uris;
 313 		gboolean done;
 314 		GtkWindow *parent;
 315 	} status;
 316 
 317 	e_cal_component_get_uid (editor->priv->comp, &comp_uid);
 318 	g_return_val_if_fail (comp_uid != NULL, NULL);
 319 
 320 	status.uris = NULL;
 321 	status.done = FALSE;
 322 	status.parent = g_object_ref (editor);
 323 
 324 	view = E_ATTACHMENT_VIEW (editor->priv->attachment_view);
 325 	store = e_attachment_view_get_store (view);
 326 
 327 	tmp = g_strdup (comp_uid);
 328 	e_filename_make_safe (tmp);
 329 	filename_prefix = g_strconcat (tmp, "-", NULL);
 330 	g_free (tmp);
 331 
 332 	local_store = e_cal_client_get_local_attachment_store (editor->priv->cal_client);
 333 	destination = g_file_new_for_path (local_store);
 334 
 335 	e_attachment_store_save_async (
 336 		store, destination, filename_prefix,
 337 		(GAsyncReadyCallback) attachment_save_finished, &status);
 338 
 339 	g_object_unref (destination);
 340 	g_free (filename_prefix);
 341 
 342 	/* We can't return until we have results, so crank
 343 	 * the main loop until the callback gets triggered. */
 344 	while (!status.done)
 345 		gtk_main_iteration ();
 346 
 347 	if (status.uris == NULL)
 348 		return NULL;
 349 
 350 	/* Transfer the URI strings to the GSList. */
 351 	for (ii = 0; status.uris[ii] != NULL; ii++) {
 352 		list = g_slist_prepend (list, status.uris[ii]);
 353 		status.uris[ii] = NULL;
 354 	}
 355 
 356 	g_free (status.uris);
 357 
 358 	return g_slist_reverse (list);
 359 }
 360 
 361 /* This sets the focus to the toplevel, so any field being edited is committed.
 362  * FIXME: In future we may also want to check some of the fields are valid,
 363  * e.g. the EDateEdit fields. */
 364 static void
 365 commit_all_fields (CompEditor *editor)
 366 {
 367 	gtk_window_set_focus (GTK_WINDOW (editor), NULL);
 368 }
 369 
 370 static void
 371 changes_view_ready_cb (GObject *source_object,
 372                        GAsyncResult *result,
 373                        gpointer user_data)
 374 {
 375 	CompEditor *editor = user_data;
 376 	ECalClientView *view = NULL;
 377 	gboolean success;
 378 	GError *error = NULL;
 379 
 380 	g_return_if_fail (editor != NULL);
 381 
 382 	success = e_cal_client_get_view_finish (
 383 		E_CAL_CLIENT (source_object), result, &view, &error);
 384 
 385 	if (!success)
 386 		view = NULL;
 387 
 388 	if (view) {
 389 		editor->priv->view = view;
 390 		g_signal_connect (
 391 			view, "objects_modified",
 392 			G_CALLBACK (obj_modified_cb), editor);
 393 		g_signal_connect (
 394 			view, "objects_removed",
 395 			G_CALLBACK (obj_removed_cb), editor);
 396 
 397 		e_cal_client_view_start (view, &error);
 398 
 399 		if (error != NULL) {
 400 			g_warning (
 401 				"%s: Failed to start view: %s",
 402 				G_STRFUNC, error->message);
 403 			g_error_free (error);
 404 		}
 405 	} else if (error) {
 406 		if (!g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) &&
 407 		    !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
 408 			g_warning (
 409 				"%s: Failed to get view: %s",
 410 				G_STRFUNC, error->message);
 411 		g_error_free (error);
 412 	}
 413 }
 414 
 415 static void
 416 listen_for_changes (CompEditor *editor)
 417 {
 418 	CompEditorPrivate *priv;
 419 	const gchar *uid = NULL;
 420 
 421 	priv = editor->priv;
 422 
 423 	/* Discard change listener */
 424 	if (priv->view_cancellable) {
 425 		g_cancellable_cancel (priv->view_cancellable);
 426 		g_object_unref (priv->view_cancellable);
 427 		priv->view_cancellable = NULL;
 428 	}
 429 
 430 	if (priv->view) {
 431 		g_signal_handlers_disconnect_matched (
 432 			priv->view, G_SIGNAL_MATCH_DATA,
 433 			0, 0, NULL, NULL, editor);
 434 
 435 		g_object_unref (priv->view);
 436 		priv->view = NULL;
 437 	}
 438 
 439 	/* Listen for changes */
 440 	if (priv->comp)
 441 		e_cal_component_get_uid (priv->comp, &uid);
 442 
 443 	if (uid) {
 444 		gchar *query;
 445 
 446 		priv->view_cancellable = g_cancellable_new ();
 447 		query = g_strdup_printf ("(uid? \"%s\")", uid);
 448 		e_cal_client_get_view (
 449 			priv->source_client,
 450 			query, priv->view_cancellable,
 451 			changes_view_ready_cb, editor);
 452 		g_free (query);
 453 	}
 454 }
 455 
 456 static void
 457 send_timezone (gpointer key,
 458                gpointer value,
 459                gpointer user_data)
 460 {
 461 	icaltimezone *zone = value;
 462 	CompEditor *editor = user_data;
 463 	GError *error = NULL;
 464 
 465 	e_cal_client_add_timezone_sync (editor->priv->cal_client, zone, NULL, &error);
 466 
 467 	if (error != NULL) {
 468 		g_warning (
 469 			"%s: Failed to add timezone: %s",
 470 			G_STRFUNC, error->message);
 471 		g_error_free (error);
 472 	}
 473 }
 474 
 475 static gboolean
 476 save_comp (CompEditor *editor)
 477 {
 478 	CompEditorPrivate *priv;
 479 	CompEditorFlags flags;
 480 	ECalComponent *clone;
 481 	ESourceRegistry *registry;
 482 	EShell *shell;
 483 	GList *l;
 484 	gboolean result;
 485 	GError *error = NULL;
 486 	GHashTable *timezones;
 487 	const gchar *orig_uid = NULL;
 488 	gchar *orig_uid_copy;
 489 	icalcomponent *icalcomp;
 490 
 491 	priv = editor->priv;
 492 
 493 	if (!priv->changed)
 494 		return TRUE;
 495 
 496 	flags = comp_editor_get_flags (editor);
 497 	shell = comp_editor_get_shell (editor);
 498 
 499 	registry = e_shell_get_registry (shell);
 500 
 501 	/* Stop listening because we are about to change things */
 502 	if (priv->view) {
 503 		g_signal_handlers_disconnect_matched (
 504 			priv->view,
 505 			G_SIGNAL_MATCH_DATA,
 506 			0, 0, NULL, NULL,
 507 			editor);
 508 
 509 		g_object_unref (priv->view);
 510 		priv->view = NULL;
 511 	}
 512 
 513 	/* Update on the server */
 514 	timezones = g_hash_table_new (g_str_hash, g_str_equal);
 515 
 516 	clone = e_cal_component_clone (priv->comp);
 517 	comp_editor_copy_new_attendees (clone, priv->comp);
 518 	for (l = priv->pages; l != NULL; l = l->next) {
 519 		if (IS_COMP_EDITOR_PAGE (l->data) &&
 520 			!comp_editor_page_fill_component (l->data, clone)) {
 521 			g_object_unref (clone);
 522 			g_hash_table_destroy (timezones);
 523 			comp_editor_show_page (editor, COMP_EDITOR_PAGE (l->data));
 524 			return FALSE;
 525 		}
 526 
 527 		/* retrieve all timezones */
 528 		if (IS_COMP_EDITOR_PAGE (l->data))
 529 			comp_editor_page_fill_timezones (l->data, timezones);
 530 	}
 531 
 532 	/* If we are not the organizer, we don't update the sequence number */
 533 	if (!e_cal_component_has_organizer (clone) ||
 534 		itip_organizer_is_user (registry, clone, priv->cal_client) ||
 535 		itip_sentby_is_user (registry, clone, priv->cal_client))
 536 		e_cal_component_commit_sequence (clone);
 537 	else
 538 		e_cal_component_abort_sequence (clone);
 539 
 540 	g_object_unref (priv->comp);
 541 	priv->comp = clone;
 542 
 543 	e_cal_component_get_uid (priv->comp, &orig_uid);
 544 	/* Make a copy of it, because call of e_cal_create_object()
 545 	 * rewrites the internal uid. */
 546 	orig_uid_copy = g_strdup (orig_uid);
 547 
 548 	/* send timezones */
 549 	g_hash_table_foreach (timezones, (GHFunc) send_timezone, editor);
 550 	g_hash_table_destroy (timezones);
 551 
 552 	/* Attachments*/
 553 
 554 	e_cal_component_set_attachment_list (
 555 		priv->comp, get_attachment_list (editor));
 556 	icalcomp = e_cal_component_get_icalcomponent (priv->comp);
 557 	/* send the component to the server */
 558 	if (!cal_comp_is_on_server (priv->comp, priv->cal_client)) {
 559 		gchar *uid = NULL;
 560 		result = e_cal_client_create_object_sync (
 561 			priv->cal_client, icalcomp, &uid, NULL, &error);
 562 		if (result) {
 563 			icalcomponent_set_uid (icalcomp, uid);
 564 			g_free (uid);
 565 			g_signal_emit_by_name (editor, "object_created");
 566 		}
 567 	} else {
 568 		gboolean has_recurrences;
 569 
 570 		has_recurrences =
 571 			e_cal_component_has_recurrences (priv->comp);
 572 
 573 		if (has_recurrences && priv->mod == CALOBJ_MOD_ALL)
 574 			comp_util_sanitize_recurrence_master (
 575 				priv->comp, priv->cal_client);
 576 
 577 		if (priv->mod == CALOBJ_MOD_THIS) {
 578 			e_cal_component_set_rdate_list (priv->comp, NULL);
 579 			e_cal_component_set_rrule_list (priv->comp, NULL);
 580 			e_cal_component_set_exdate_list (priv->comp, NULL);
 581 			e_cal_component_set_exrule_list (priv->comp, NULL);
 582 		}
 583 		result = e_cal_client_modify_object_sync (
 584 			priv->cal_client, icalcomp, priv->mod, NULL, &error);
 585 
 586 		if (priv->mod == CALOBJ_MOD_THIS) {
 587 			if (result && ((flags & COMP_EDITOR_DELEGATE) ||
 588 				!e_cal_component_has_organizer (clone) ||
 589 				itip_organizer_is_user (registry, clone, priv->cal_client) ||
 590 				itip_sentby_is_user (registry, clone, priv->cal_client)))
 591 				e_cal_component_commit_sequence (clone);
 592 			else
 593 				e_cal_component_abort_sequence (clone);
 594 		}
 595 	}
 596 
 597 	/* If the delay delivery is set, the items will not be created in
 598 	 * the server immediately, so we need not show them in the view.
 599 	 * They will appear as soon as the server creates it after the
 600 	 * delay period. */
 601 	if (result && e_cal_component_has_attendees (priv->comp)) {
 602 		gboolean delay_set = FALSE;
 603 		icalproperty *icalprop;
 604 		icalprop = icalcomponent_get_first_property (icalcomp, ICAL_X_PROPERTY);
 605 		while (icalprop) {
 606 			const gchar *x_name;
 607 
 608 			x_name = icalproperty_get_x_name (icalprop);
 609 			if (!strcmp (x_name, "X-EVOLUTION-OPTIONS-DELAY")) {
 610 				delay_set = TRUE;
 611 				break;
 612 			}
 613 
 614 			icalprop = icalcomponent_get_next_property (icalcomp, ICAL_X_PROPERTY);
 615 		}
 616 		if (delay_set) {
 617 			g_free (orig_uid_copy);
 618 			return TRUE;
 619 		}
 620 	}
 621 
 622 	if (!result) {
 623 		GtkWidget *dialog;
 624 
 625 		dialog = gtk_message_dialog_new (
 626 			NULL, 0,
 627 			GTK_MESSAGE_ERROR,
 628 			GTK_BUTTONS_OK,
 629 			"%s", (error != NULL) ? error->message :
 630 			_("Could not update object"));
 631 		gtk_dialog_run (GTK_DIALOG (dialog));
 632 		gtk_widget_destroy (dialog);
 633 
 634 		if (error)
 635 			g_error_free (error);
 636 
 637 		g_free (orig_uid_copy);
 638 
 639 		return FALSE;
 640 	} else {
 641 		if (priv->source_client &&
 642 		    !e_source_equal (e_client_get_source (E_CLIENT (priv->cal_client)),
 643 				     e_client_get_source (E_CLIENT (priv->source_client))) &&
 644 		    cal_comp_is_on_server (priv->comp, priv->source_client)) {
 645 			/* Comp found a new home. Remove it from old one. */
 646 			GError *error = NULL;
 647 
 648 			if (e_cal_component_is_instance (priv->comp) ||
 649 				e_cal_component_has_recurrences (priv->comp))
 650 				e_cal_client_remove_object_sync (
 651 					priv->source_client, orig_uid_copy,
 652 					NULL, CALOBJ_MOD_ALL, NULL, &error);
 653 			else
 654 				e_cal_client_remove_object_sync (
 655 					priv->source_client,
 656 					orig_uid_copy, NULL, CALOBJ_MOD_THIS, NULL, &error);
 657 
 658 			if (error != NULL) {
 659 				g_warning (
 660 					"%s: Failed to remove object: %s",
 661 					G_STRFUNC, error->message);
 662 				g_error_free (error);
 663 			}
 664 
 665 			/* Let priv->source_client point to new home,
 666 			 * so we can move it again this session. */
 667 			g_object_unref (priv->source_client);
 668 			priv->source_client = g_object_ref (priv->cal_client);
 669 
 670 			listen_for_changes (editor);
 671 		}
 672 
 673 		comp_editor_set_changed (editor, FALSE);
 674 		priv->saved = TRUE;
 675 	}
 676 
 677 	g_free (orig_uid_copy);
 678 
 679 	return TRUE;
 680 }
 681 
 682 static gboolean
 683 save_comp_with_send (CompEditor *editor)
 684 {
 685 	CompEditorPrivate *priv;
 686 	CompEditorFlags flags;
 687 	ESourceRegistry *registry;
 688 	EShell *shell;
 689 	gboolean send, delegated, only_new_attendees = FALSE;
 690 	gboolean delegate;
 691 	gboolean strip_alarms = TRUE;
 692 
 693 	priv = editor->priv;
 694 
 695 	flags = comp_editor_get_flags (editor);
 696 	shell = comp_editor_get_shell (editor);
 697 
 698 	registry = e_shell_get_registry (shell);
 699 
 700 	send = priv->changed && priv->needs_send;
 701 	delegate = flags & COMP_EDITOR_DELEGATE;
 702 
 703 	if (delegate) {
 704 		icalcomponent *icalcomp = e_cal_component_get_icalcomponent (priv->comp);
 705 		icalproperty *icalprop;
 706 
 707 		icalprop = icalproperty_new_x ("1");
 708 		icalproperty_set_x_name (icalprop, "X-EVOLUTION-DELEGATED");
 709 		icalcomponent_add_property (icalcomp, icalprop);
 710 	}
 711 
 712 	if (!save_comp (editor))
 713 		return FALSE;
 714 
 715 	delegated = delegate && !e_cal_client_check_save_schedules (priv->cal_client);
 716 	if (delegated || (send && send_component_dialog (
 717 		(GtkWindow *) editor, priv->cal_client, priv->comp,
 718 		!priv->existing_org, &strip_alarms, !priv->existing_org ?
 719 		NULL : &only_new_attendees))) {
 720 		if (delegated)
 721 			only_new_attendees = FALSE;
 722 
 723 		comp_editor_set_flags (
 724 			editor, (comp_editor_get_flags (editor) &
 725 			(~COMP_EDITOR_SEND_TO_NEW_ATTENDEES_ONLY)) |
 726 			(only_new_attendees ?
 727 			COMP_EDITOR_SEND_TO_NEW_ATTENDEES_ONLY : 0));
 728 
 729 		if ((itip_organizer_is_user (registry, priv->comp, priv->cal_client) ||
 730 			itip_sentby_is_user (registry, priv->comp, priv->cal_client))) {
 731 			if (e_cal_component_get_vtype (priv->comp) == E_CAL_COMPONENT_JOURNAL)
 732 				return comp_editor_send_comp (
 733 					editor, E_CAL_COMPONENT_METHOD_PUBLISH,
 734 					strip_alarms);
 735 			else
 736 				return comp_editor_send_comp (
 737 					editor, E_CAL_COMPONENT_METHOD_REQUEST,
 738 					strip_alarms);
 739 		} else {
 740 			if (!comp_editor_send_comp (
 741 				editor, E_CAL_COMPONENT_METHOD_REQUEST,
 742 				strip_alarms))
 743 				return FALSE;
 744 
 745 			if (delegate)
 746 				return comp_editor_send_comp (
 747 					editor, E_CAL_COMPONENT_METHOD_REPLY,
 748 					strip_alarms);
 749 		}
 750 	}
 751 
 752 	return TRUE;
 753 }
 754 
 755 static void
 756 update_window_border (CompEditor *editor,
 757                       const gchar *description)
 758 {
 759 	const gchar *icon_name;
 760 	const gchar *format;
 761 	gchar *title;
 762 
 763 	if (editor->priv->comp == NULL) {
 764 		title = g_strdup (_("Edit Appointment"));
 765 		icon_name = "x-office-calendar";
 766 		goto exit;
 767 
 768 	} else switch (e_cal_component_get_vtype (editor->priv->comp)) {
 769 		case E_CAL_COMPONENT_EVENT:
 770 			if (editor->priv->is_group_item)
 771 				format = _("Meeting - %s");
 772 			else
 773 				format = _("Appointment - %s");
 774 			icon_name = "appointment-new";
 775 			break;
 776 
 777 		case E_CAL_COMPONENT_TODO:
 778 			if (editor->priv->is_group_item)
 779 				format = _("Assigned Task - %s");
 780 			else
 781 				format = _("Task - %s");
 782 			icon_name = "stock_task";
 783 			break;
 784 
 785 		case E_CAL_COMPONENT_JOURNAL:
 786 			format = _("Memo - %s");
 787 			icon_name = "stock_insert-note";
 788 			break;
 789 
 790 		default:
 791 			g_return_if_reached ();
 792 	}
 793 
 794 	if (description == NULL || *description == '\0') {
 795 		ECalComponentText text;
 796 
 797 		e_cal_component_get_summary (editor->priv->comp, &text);
 798 		description = text.value;
 799 	}
 800 
 801 	if (description == NULL || *description == '\0')
 802 		description = _("No Summary");
 803 
 804 	title = g_strdup_printf (format, description);
 805 
 806 exit:
 807 	gtk_window_set_icon_name (GTK_WINDOW (editor), icon_name);
 808 	gtk_window_set_title (GTK_WINDOW (editor), title);
 809 
 810 	g_free (title);
 811 }
 812 
 813 static void
 814 action_attach_cb (GtkAction *action,
 815                   CompEditor *editor)
 816 {
 817 	EAttachmentStore *store;
 818 	EAttachmentView *view;
 819 
 820 	view = E_ATTACHMENT_VIEW (editor->priv->attachment_view);
 821 	store = e_attachment_view_get_store (view);
 822 
 823 	e_attachment_store_run_load_dialog (store, GTK_WINDOW (editor));
 824 }
 825 
 826 static void
 827 action_classification_cb (GtkRadioAction *action,
 828                           GtkRadioAction *current,
 829                           CompEditor *editor)
 830 {
 831 	comp_editor_set_changed (editor, TRUE);
 832 }
 833 
 834 static void
 835 action_close_cb (GtkAction *action,
 836                  CompEditor *editor)
 837 {
 838 	commit_all_fields (editor);
 839 
 840 	if (prompt_and_save_changes (editor, TRUE))
 841 		close_dialog (editor);
 842 }
 843 
 844 static void
 845 action_help_cb (GtkAction *action,
 846                 CompEditor *editor)
 847 {
 848 	comp_editor_show_help (editor);
 849 }
 850 
 851 static void
 852 action_print_cb (GtkAction *action,
 853                  CompEditor *editor)
 854 {
 855 	CompEditorPrivate *priv = editor->priv;
 856 	ECalComponent *comp;
 857 	GList *l;
 858 	icalcomponent *component;
 859 	icalcomponent *clone;
 860 	icaltimezone *zone;
 861 	gboolean use_24_hour_format;
 862 
 863 	comp = e_cal_component_new ();
 864 	component = e_cal_component_get_icalcomponent (priv->comp);
 865 	clone = icalcomponent_new_clone (component);
 866 	e_cal_component_set_icalcomponent (comp, clone);
 867 
 868 	for (l = priv->pages; l != NULL; l = l->next)
 869 		 comp_editor_page_fill_component (l->data, comp);
 870 
 871 	zone = comp_editor_get_timezone (editor);
 872 	use_24_hour_format = comp_editor_get_use_24_hour_format (editor);
 873 
 874 	print_comp (
 875 		comp, priv->cal_client, zone, use_24_hour_format,
 876 		GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG);
 877 
 878 	g_object_unref (comp);
 879 }
 880 
 881 static void
 882 action_print_preview_cb (GtkAction *action,
 883                          CompEditor *editor)
 884 {
 885 	CompEditorPrivate *priv = editor->priv;
 886 	ECalComponent *comp;
 887 	GList *l;
 888 	icalcomponent *component;
 889 	icalcomponent *clone;
 890 	icaltimezone *zone;
 891 	gboolean use_24_hour_format;
 892 
 893 	comp = e_cal_component_new ();
 894 	component = e_cal_component_get_icalcomponent (priv->comp);
 895 	clone = icalcomponent_new_clone (component);
 896 	e_cal_component_set_icalcomponent (comp, clone);
 897 
 898 	for (l = priv->pages; l != NULL; l = l->next)
 899 		 comp_editor_page_fill_component (l->data, comp);
 900 
 901 	zone = comp_editor_get_timezone (editor);
 902 	use_24_hour_format = comp_editor_get_use_24_hour_format (editor);
 903 
 904 	print_comp (
 905 		comp, priv->cal_client, zone, use_24_hour_format,
 906 		GTK_PRINT_OPERATION_ACTION_PREVIEW);
 907 
 908 	g_object_unref (comp);
 909 }
 910 
 911 static gboolean
 912 remove_event_dialog (ECalClient *client,
 913                      ECalComponent *comp,
 914                      GtkWindow *parent)
 915 {
 916 	GtkWidget *dialog;
 917 	gboolean ret;
 918 
 919 	g_return_val_if_fail (E_IS_CAL_COMPONENT (comp), TRUE);
 920 
 921 	dialog = gtk_message_dialog_new (
 922 		parent, 0, GTK_MESSAGE_QUESTION,
 923 		GTK_BUTTONS_YES_NO, "%s", _("Keep original item?"));
 924 	gtk_window_set_resizable (GTK_WINDOW (dialog), TRUE);
 925 	ret = gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_YES;
 926 	gtk_widget_destroy (dialog);
 927 
 928 	return ret;
 929 }
 930 
 931 static void
 932 save_and_close_editor (CompEditor *editor,
 933                        gboolean can_close)
 934 {
 935 	CompEditorPrivate *priv = editor->priv;
 936 	EAttachmentStore *store;
 937 	EAttachmentView *view;
 938 	ECalComponentText text;
 939 	gboolean delegated = FALSE;
 940 	gboolean correct = FALSE;
 941 	ECalComponent *comp;
 942 
 943 	view = E_ATTACHMENT_VIEW (priv->attachment_view);
 944 	store = e_attachment_view_get_store (view);
 945 
 946 	if (e_attachment_store_get_num_loading (store) > 0) {
 947 		gboolean response = 1;
 948 	/*FIXME: Cannot use mail functions from calendar!!!! */
 949 #if 0
 950 		ECalComponentVType vtype = e_cal_component_get_vtype (editor->priv->comp);
 951 
 952 		if (vtype == E_CAL_COMPONENT_EVENT)
 953 			response = em_utils_prompt_user (
 954 				(GtkWindow *) widget,
 955 				NULL,
 956 				"calendar:ask-send-event-pending-download",
 957 				NULL);
 958 		else
 959 			response = em_utils_prompt_user (
 960 				(GtkWindow *) widget,
 961 				NULL,
 962 				"calendar:ask-send-task-pending-download",
 963 				NULL);
 964 #endif
 965 	if (!response)
 966 		return;
 967 	}
 968 
 969 	if (e_client_is_readonly (E_CLIENT (priv->cal_client))) {
 970 		e_alert_submit (
 971 			E_ALERT_SINK (editor),
 972 			"calendar:prompt-read-only-cal-editor",
 973 			e_source_get_display_name (
 974 				e_client_get_source (E_CLIENT (priv->cal_client))),
 975 			NULL);
 976 		return;
 977 	}
 978 
 979 	if ((comp_editor_get_flags (editor) & COMP_EDITOR_IS_ASSIGNED) != 0
 980 	    && e_cal_component_get_vtype (priv->comp) == E_CAL_COMPONENT_TODO
 981 	    && e_client_check_capability (E_CLIENT (priv->cal_client), CAL_STATIC_CAPABILITY_NO_TASK_ASSIGNMENT)) {
 982 		e_alert_submit (
 983 			E_ALERT_SINK (editor),
 984 			"calendar:prompt-no-task-assignment-editor",
 985 			e_source_get_display_name (
 986 				e_client_get_source (E_CLIENT (priv->cal_client))),
 987 			NULL);
 988 		return;
 989 	}
 990 
 991 	commit_all_fields (editor);
 992 	if (e_cal_component_has_recurrences (priv->comp)) {
 993 		if (!recur_component_dialog (
 994 			priv->cal_client, priv->comp, &priv->mod,
 995 			GTK_WINDOW (editor), delegated))
 996 			return;
 997 	} else if (e_cal_component_is_instance (priv->comp))
 998 		priv->mod = CALOBJ_MOD_THIS;
 999 
1000 	comp = comp_editor_get_current_comp (editor, &correct);
1001 	e_cal_component_get_summary (comp, &text);
1002 	g_object_unref (comp);
1003 
1004 	if (!correct)
1005 		return;
1006 
1007 	if (!text.value)
1008 		if (!send_component_prompt_subject (
1009 			(GtkWindow *) editor, priv->cal_client, priv->comp))
1010 			return;
1011 
1012 	gtk_widget_set_sensitive (GTK_WIDGET (editor), FALSE);
1013 
1014 	if (save_comp_with_send (editor)) {
1015 		CompEditorFlags flags;
1016 		gboolean delegate;
1017 
1018 		flags = comp_editor_get_flags (editor);
1019 		delegate = flags & COMP_EDITOR_DELEGATE;
1020 
1021 		if (delegate && !remove_event_dialog (
1022 			priv->cal_client, priv->comp, GTK_WINDOW (editor))) {
1023 			const gchar *uid = NULL;
1024 			GError *error = NULL;
1025 
1026 			e_cal_component_get_uid (priv->comp, &uid);
1027 
1028 			if (e_cal_component_is_instance (priv->comp) ||
1029 				e_cal_component_has_recurrences (priv->comp)) {
1030 				gchar *rid;
1031 				rid = e_cal_component_get_recurid_as_string (priv->comp);
1032 				e_cal_client_remove_object_sync (
1033 					priv->cal_client, uid, rid,
1034 					priv->mod, NULL, &error);
1035 				g_free (rid);
1036 			} else
1037 				e_cal_client_remove_object_sync (
1038 					priv->cal_client, uid, NULL,
1039 					CALOBJ_MOD_THIS, NULL, &error);
1040 
1041 			g_clear_error (&error);
1042 		}
1043 	} else
1044 		correct = FALSE;
1045 
1046 	gtk_widget_set_sensitive (GTK_WIDGET (editor), TRUE);
1047 
1048 	if (correct) {
1049 		if (can_close)
1050 			close_dialog (editor);
1051 		else
1052 			comp_editor_set_changed (editor, FALSE);
1053 	}
1054 }
1055 
1056 static void
1057 action_save_cb (GtkAction *action,
1058                 CompEditor *editor)
1059 {
1060 	save_and_close_editor (editor, FALSE);
1061 }
1062 
1063 static void
1064 action_save_and_close_cb (GtkAction *action,
1065                           CompEditor *editor)
1066 {
1067 	save_and_close_editor (editor, TRUE);
1068 }
1069 
1070 static void
1071 action_view_categories_cb (GtkToggleAction *action,
1072                            CompEditor *editor)
1073 {
1074 	CompEditorClass *class;
1075 	gboolean active;
1076 
1077 	class = COMP_EDITOR_GET_CLASS (editor);
1078 	active = gtk_toggle_action_get_active (action);
1079 
1080 	if (class->show_categories != NULL)
1081 		class->show_categories (editor, active);
1082 }
1083 
1084 static void
1085 action_view_role_cb (GtkToggleAction *action,
1086                      CompEditor *editor)
1087 {
1088 	CompEditorClass *class;
1089 	gboolean active;
1090 
1091 	class = COMP_EDITOR_GET_CLASS (editor);
1092 	active = gtk_toggle_action_get_active (action);
1093 
1094 	if (class->show_role != NULL)
1095 		class->show_role (editor, active);
1096 }
1097 
1098 static void
1099 action_view_rsvp_cb (GtkToggleAction *action,
1100                      CompEditor *editor)
1101 {
1102 	CompEditorClass *class;
1103 	gboolean active;
1104 
1105 	class = COMP_EDITOR_GET_CLASS (editor);
1106 	active = gtk_toggle_action_get_active (action);
1107 
1108 	if (class->show_rsvp != NULL)
1109 		class->show_rsvp (editor, active);
1110 }
1111 
1112 static void
1113 action_view_status_cb (GtkToggleAction *action,
1114                        CompEditor *editor)
1115 {
1116 	CompEditorClass *class;
1117 	gboolean active;
1118 
1119 	class = COMP_EDITOR_GET_CLASS (editor);
1120 	active = gtk_toggle_action_get_active (action);
1121 
1122 	if (class->show_status != NULL)
1123 		class->show_status (editor, active);
1124 }
1125 
1126 static void
1127 action_view_time_zone_cb (GtkToggleAction *action,
1128                           CompEditor *editor)
1129 {
1130 	CompEditorClass *class;
1131 	gboolean active;
1132 
1133 	class = COMP_EDITOR_GET_CLASS (editor);
1134 	active = gtk_toggle_action_get_active (action);
1135 
1136 	if (class->show_time_zone != NULL)
1137 		class->show_time_zone (editor, active);
1138 }
1139 
1140 static void
1141 action_view_type_cb (GtkToggleAction *action,
1142                      CompEditor *editor)
1143 {
1144 	CompEditorClass *class;
1145 	gboolean active;
1146 
1147 	class = COMP_EDITOR_GET_CLASS (editor);
1148 	active = gtk_toggle_action_get_active (action);
1149 
1150 	if (class->show_type != NULL)
1151 		class->show_type (editor, active);
1152 }
1153 
1154 static GtkActionEntry core_entries[] = {
1155 
1156 	{ "close",
1157 	  GTK_STOCK_CLOSE,
1158 	  NULL,
1159 	  NULL,
1160 	  N_("Close the current window"),
1161 	  G_CALLBACK (action_close_cb) },
1162 
1163 	{ "copy-clipboard",
1164 	  GTK_STOCK_COPY,
1165 	  NULL,
1166 	  NULL,
1167 	  N_("Copy the selection"),
1168 	  NULL },  /* Handled by EFocusTracker */
1169 
1170 	{ "cut-clipboard",
1171 	  GTK_STOCK_CUT,
1172 	  NULL,
1173 	  NULL,
1174 	  N_("Cut the selection"),
1175 	  NULL },  /* Handled by EFocusTracker */
1176 
1177 	{ "delete-selection",
1178 	  GTK_STOCK_DELETE,
1179 	  NULL,
1180 	  NULL,
1181 	  N_("Delete the selection"),
1182 	  NULL },  /* Handled by EFocusTracker */
1183 
1184 	{ "help",
1185 	  GTK_STOCK_HELP,
1186 	  NULL,
1187 	  NULL,
1188 	  N_("View help"),
1189 	  G_CALLBACK (action_help_cb) },
1190 
1191 	{ "paste-clipboard",
1192 	  GTK_STOCK_PASTE,
1193 	  NULL,
1194 	  NULL,
1195 	  N_("Paste the clipboard"),
1196 	  NULL },  /* Handled by EFocusTracker */
1197 
1198 	{ "print",
1199 	  GTK_STOCK_PRINT,
1200 	  NULL,
1201 	  "<Control>p",
1202 	  NULL,
1203 	  G_CALLBACK (action_print_cb) },
1204 
1205 	{ "print-preview",
1206 	  GTK_STOCK_PRINT_PREVIEW,
1207 	  NULL,
1208 	  NULL,
1209 	  NULL,
1210 	  G_CALLBACK (action_print_preview_cb) },
1211 
1212 	{ "save",
1213 	  GTK_STOCK_SAVE,
1214 	  NULL,
1215 	  NULL,
1216 	  N_("Save current changes"),
1217 	  G_CALLBACK (action_save_cb) },
1218 
1219 	{ "save-and-close",
1220 	  NULL,
1221 	  N_("Save and Close"),
1222 	  NULL,
1223 	  N_("Save current changes and close editor"),
1224 	  G_CALLBACK (action_save_and_close_cb) },
1225 
1226 	{ "select-all",
1227 	  GTK_STOCK_SELECT_ALL,
1228 	  NULL,
1229 	  "<Control>a",
1230 	  N_("Select all text"),
1231 	  NULL },  /* Handled by EFocusTracker */
1232 
1233 	/* Menus */
1234 
1235 	{ "classification-menu",
1236 	  NULL,
1237 	  N_("_Classification"),
1238 	  NULL,
1239 	  NULL,
1240 	  NULL },
1241 
1242 	{ "edit-menu",
1243 	  NULL,
1244 	  N_("_Edit"),
1245 	  NULL,
1246 	  NULL,
1247 	  NULL },
1248 
1249 	{ "file-menu",
1250 	  NULL,
1251 	  N_("_File"),
1252 	  NULL,
1253 	  NULL,
1254 	  NULL },
1255 
1256 	{ "help-menu",
1257 	  NULL,
1258 	  N_("_Help"),
1259 	  NULL,
1260 	  NULL,
1261 	  NULL },
1262 
1263 	{ "insert-menu",
1264 	  NULL,
1265 	  N_("_Insert"),
1266 	  NULL,
1267 	  NULL,
1268 	  NULL },
1269 
1270 	{ "options-menu",
1271 	  NULL,
1272 	  N_("_Options"),
1273 	  NULL,
1274 	  NULL,
1275 	  NULL },
1276 
1277 	{ "view-menu",
1278 	  NULL,
1279 	  N_("_View"),
1280 	  NULL,
1281 	  NULL,
1282 	  NULL }
1283 };
1284 
1285 static GtkActionEntry individual_entries[] = {
1286 
1287 	{ "attach",
1288 	  "mail-attachment",
1289 	  N_("_Attachment..."),
1290 	  "<Control>m",
1291 	  N_("Attach a file"),
1292 	  G_CALLBACK (action_attach_cb) }
1293 };
1294 
1295 static GtkToggleActionEntry core_toggle_entries[] = {
1296 
1297 	{ "view-categories",
1298 	  NULL,
1299 	  N_("_Categories"),
1300 	  NULL,
1301 	  N_("Toggles whether to display categories"),
1302 	  G_CALLBACK (action_view_categories_cb),
1303 	  FALSE },
1304 
1305 	{ "view-time-zone",
1306 	  "stock_timezone",
1307 	  N_("Time _Zone"),
1308 	  NULL,
1309 	  N_("Toggles whether the time zone is displayed"),
1310 	  G_CALLBACK (action_view_time_zone_cb),
1311 	  FALSE }
1312 };
1313 
1314 static GtkRadioActionEntry classification_radio_entries[] = {
1315 
1316 	{ "classify-public",
1317 	  NULL,
1318 	  N_("Pu_blic"),
1319 	  NULL,
1320 	  N_("Classify as public"),
1321 	  E_CAL_COMPONENT_CLASS_PUBLIC },
1322 
1323 	{ "classify-private",
1324 	  NULL,
1325 	  N_("_Private"),
1326 	  NULL,
1327 	  N_("Classify as private"),
1328 	  E_CAL_COMPONENT_CLASS_PRIVATE },
1329 
1330 	{ "classify-confidential",
1331 	  NULL,
1332 	  N_("_Confidential"),
1333 	  NULL,
1334 	  N_("Classify as confidential"),
1335 	  E_CAL_COMPONENT_CLASS_CONFIDENTIAL }
1336 };
1337 
1338 static GtkToggleActionEntry coordinated_toggle_entries[] = {
1339 
1340 	{ "view-role",
1341 	  NULL,
1342 	  N_("R_ole Field"),
1343 	  NULL,
1344 	  N_("Toggles whether the Role field is displayed"),
1345 	  G_CALLBACK (action_view_role_cb),
1346 	  FALSE },
1347 
1348 	{ "view-rsvp",
1349 	  NULL,
1350 	  N_("_RSVP"),
1351 	  NULL,
1352 	  N_("Toggles whether the RSVP field is displayed"),
1353 	  G_CALLBACK (action_view_rsvp_cb),
1354 	  FALSE },
1355 
1356 	{ "view-status",
1357 	  NULL,
1358 	  N_("_Status Field"),
1359 	  NULL,
1360 	  N_("Toggles whether the Status field is displayed"),
1361 	  G_CALLBACK (action_view_status_cb),
1362 	  FALSE },
1363 
1364 	{ "view-type",
1365 	  NULL,
1366 	  N_("_Type Field"),
1367 	  NULL,
1368 	  N_("Toggles whether the Attendee Type is displayed"),
1369 	  G_CALLBACK (action_view_type_cb),
1370 	  FALSE }
1371 };
1372 
1373 static void
1374 comp_editor_set_shell (CompEditor *editor,
1375                        EShell *shell)
1376 {
1377 	g_return_if_fail (E_IS_SHELL (shell));
1378 	g_return_if_fail (editor->priv->shell == NULL);
1379 
1380 	editor->priv->shell = shell;
1381 
1382 	g_object_add_weak_pointer (G_OBJECT (shell), &editor->priv->shell);
1383 }
1384 
1385 static void
1386 comp_editor_set_property (GObject *object,
1387                           guint property_id,
1388                           const GValue *value,
1389                           GParamSpec *pspec)
1390 {
1391 	switch (property_id) {
1392 		case PROP_CHANGED:
1393 			comp_editor_set_changed (
1394 				COMP_EDITOR (object),
1395 				g_value_get_boolean (value));
1396 			return;
1397 
1398 		case PROP_CLIENT:
1399 			comp_editor_set_client (
1400 				COMP_EDITOR (object),
1401 				g_value_get_object (value));
1402 			return;
1403 
1404 		case PROP_FLAGS:
1405 			comp_editor_set_flags (
1406 				COMP_EDITOR (object),
1407 				g_value_get_int (value));
1408 			return;
1409 
1410 		case PROP_SHELL:
1411 			comp_editor_set_shell (
1412 				COMP_EDITOR (object),
1413 				g_value_get_object (value));
1414 			return;
1415 
1416 		case PROP_SUMMARY:
1417 			comp_editor_set_summary (
1418 				COMP_EDITOR (object),
1419 				g_value_get_string (value));
1420 			return;
1421 
1422 		case PROP_TIMEZONE:
1423 			comp_editor_set_timezone (
1424 				COMP_EDITOR (object),
1425 				g_value_get_pointer (value));
1426 			return;
1427 
1428 		case PROP_USE_24_HOUR_FORMAT:
1429 			comp_editor_set_use_24_hour_format (
1430 				COMP_EDITOR (object),
1431 				g_value_get_boolean (value));
1432 			return;
1433 
1434 		case PROP_WORK_DAY_END_HOUR:
1435 			comp_editor_set_work_day_end_hour (
1436 				COMP_EDITOR (object),
1437 				g_value_get_int (value));
1438 			return;
1439 
1440 		case PROP_WORK_DAY_END_MINUTE:
1441 			comp_editor_set_work_day_end_minute (
1442 				COMP_EDITOR (object),
1443 				g_value_get_int (value));
1444 			return;
1445 
1446 		case PROP_WORK_DAY_START_HOUR:
1447 			comp_editor_set_work_day_start_hour (
1448 				COMP_EDITOR (object),
1449 				g_value_get_int (value));
1450 			return;
1451 
1452 		case PROP_WORK_DAY_START_MINUTE:
1453 			comp_editor_set_work_day_start_minute (
1454 				COMP_EDITOR (object),
1455 				g_value_get_int (value));
1456 			return;
1457 	}
1458 
1459 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1460 }
1461 
1462 static void
1463 comp_editor_get_property (GObject *object,
1464                           guint property_id,
1465                           GValue *value,
1466                           GParamSpec *pspec)
1467 {
1468 	switch (property_id) {
1469 		case PROP_CHANGED:
1470 			g_value_set_boolean (
1471 				value, comp_editor_get_changed (
1472 				COMP_EDITOR (object)));
1473 			return;
1474 
1475 		case PROP_CLIENT:
1476 			g_value_set_object (
1477 				value, comp_editor_get_client (
1478 				COMP_EDITOR (object)));
1479 			return;
1480 
1481 		case PROP_FLAGS:
1482 			g_value_set_int (
1483 				value, comp_editor_get_flags (
1484 				COMP_EDITOR (object)));
1485 			return;
1486 
1487 		case PROP_FOCUS_TRACKER:
1488 			g_value_set_object (
1489 				value, comp_editor_get_focus_tracker (
1490 				COMP_EDITOR (object)));
1491 			return;
1492 
1493 		case PROP_SHELL:
1494 			g_value_set_object (
1495 				value, comp_editor_get_shell (
1496 				COMP_EDITOR (object)));
1497 			return;
1498 
1499 		case PROP_SUMMARY:
1500 			g_value_set_string (
1501 				value, comp_editor_get_summary (
1502 				COMP_EDITOR (object)));
1503 			return;
1504 
1505 		case PROP_TIMEZONE:
1506 			g_value_set_pointer (
1507 				value, comp_editor_get_timezone (
1508 				COMP_EDITOR (object)));
1509 			return;
1510 
1511 		case PROP_USE_24_HOUR_FORMAT:
1512 			g_value_set_boolean (
1513 				value, comp_editor_get_use_24_hour_format (
1514 				COMP_EDITOR (object)));
1515 			return;
1516 
1517 		case PROP_WORK_DAY_END_HOUR:
1518 			g_value_set_int (
1519 				value, comp_editor_get_work_day_end_hour (
1520 				COMP_EDITOR (object)));
1521 			return;
1522 
1523 		case PROP_WORK_DAY_END_MINUTE:
1524 			g_value_set_int (
1525 				value, comp_editor_get_work_day_end_minute (
1526 				COMP_EDITOR (object)));
1527 			return;
1528 
1529 		case PROP_WORK_DAY_START_HOUR:
1530 			g_value_set_int (
1531 				value, comp_editor_get_work_day_start_hour (
1532 				COMP_EDITOR (object)));
1533 			return;
1534 
1535 		case PROP_WORK_DAY_START_MINUTE:
1536 			g_value_set_int (
1537 				value, comp_editor_get_work_day_start_minute (
1538 				COMP_EDITOR (object)));
1539 			return;
1540 	}
1541 
1542 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
1543 }
1544 
1545 static void
1546 unref_page_cb (gpointer editor_page,
1547                gpointer comp_editor)
1548 {
1549 	if (IS_COMP_EDITOR_PAGE (editor_page)) {
1550 		GtkWidget *page_widget;
1551 		CompEditorPage *page = COMP_EDITOR_PAGE (editor_page);
1552 		CompEditor *editor = COMP_EDITOR (comp_editor);
1553 
1554 		g_return_if_fail (page != NULL);
1555 		g_return_if_fail (editor != NULL);
1556 
1557 		page_widget = comp_editor_page_get_widget (page);
1558 		g_signal_handlers_disconnect_matched (
1559 			page_widget, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, page);
1560 	}
1561 
1562 	g_signal_handlers_disconnect_matched (
1563 		editor_page, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, comp_editor);
1564 	g_object_unref (editor_page);
1565 }
1566 
1567 static void
1568 comp_editor_dispose (GObject *object)
1569 {
1570 	CompEditorPrivate *priv;
1571 
1572 	priv = COMP_EDITOR_GET_PRIVATE (object);
1573 
1574 	if (priv->shell != NULL) {
1575 		g_object_remove_weak_pointer (
1576 			G_OBJECT (priv->shell), &priv->shell);
1577 		priv->shell = NULL;
1578 	}
1579 
1580 	if (priv->focus_tracker != NULL) {
1581 		g_object_unref (priv->focus_tracker);
1582 		priv->focus_tracker = NULL;
1583 	}
1584 
1585 	if (priv->window_group != NULL) {
1586 		g_object_unref (priv->window_group);
1587 		priv->window_group = NULL;
1588 	}
1589 
1590 	if (priv->cal_client) {
1591 		g_object_unref (priv->cal_client);
1592 		priv->cal_client = NULL;
1593 	}
1594 
1595 	if (priv->source_client) {
1596 		g_object_unref (priv->source_client);
1597 		priv->source_client = NULL;
1598 	}
1599 
1600 	if (priv->view_cancellable) {
1601 		g_cancellable_cancel (priv->view_cancellable);
1602 		g_object_unref (priv->view_cancellable);
1603 		priv->view_cancellable = NULL;
1604 	}
1605 
1606 	if (priv->view) {
1607 		g_signal_handlers_disconnect_matched (
1608 			priv->view, G_SIGNAL_MATCH_DATA,
1609 			0, 0, NULL, NULL, object);
1610 		g_object_unref (priv->view);
1611 		priv->view = NULL;
1612 	}
1613 
1614 	if (priv->attachment_view) {
1615 		EAttachmentStore *store;
1616 
1617 		store = e_attachment_view_get_store (
1618 			E_ATTACHMENT_VIEW (priv->attachment_view));
1619 		g_signal_handlers_disconnect_matched (
1620 			store, G_SIGNAL_MATCH_DATA,
1621 			0, 0, NULL, NULL, object);
1622 		g_object_unref (priv->attachment_view);
1623 		priv->attachment_view = NULL;
1624 	}
1625 
1626 	/* We want to destroy the pages after the widgets get destroyed,
1627 	 * since they have lots of signal handlers connected to the widgets
1628 	 * with the pages as the data. */
1629 	g_list_foreach (priv->pages, (GFunc) unref_page_cb, object);
1630 	g_list_free (priv->pages);
1631 	priv->pages = NULL;
1632 
1633 	if (priv->comp) {
1634 		g_object_unref (priv->comp);
1635 		priv->comp = NULL;
1636 	}
1637 
1638 	if (priv->ui_manager != NULL) {
1639 		g_object_unref (priv->ui_manager);
1640 		priv->ui_manager = NULL;
1641 	}
1642 
1643 	/* Chain up to parent's dispose() method. */
1644 	G_OBJECT_CLASS (comp_editor_parent_class)->dispose (object);
1645 }
1646 
1647 static void
1648 comp_editor_finalize (GObject *object)
1649 {
1650 	CompEditorPrivate *priv;
1651 
1652 	priv = COMP_EDITOR_GET_PRIVATE (object);
1653 
1654 	g_object_unref (priv->calendar_settings);
1655 	g_free (priv->summary);
1656 
1657 	/* Chain up to parent's finalize() method. */
1658 	G_OBJECT_CLASS (comp_editor_parent_class)->finalize (object);
1659 }
1660 
1661 static void
1662 comp_editor_constructed (GObject *object)
1663 {
1664 	e_extensible_load_extensions (E_EXTENSIBLE (object));
1665 
1666 	/* Chain up to parent's constructed() method. */
1667 	G_OBJECT_CLASS (comp_editor_parent_class)->constructed (object);
1668 }
1669 
1670 static void
1671 comp_editor_bind_settings (CompEditor *editor)
1672 {
1673 	GtkAction *action;
1674 
1675 	g_return_if_fail (editor != NULL);
1676 
1677 	action = comp_editor_get_action (editor, "view-categories");
1678 	g_settings_bind (
1679 		editor->priv->calendar_settings, "editor-show-categories",
1680 		action, "active",
1681 		G_SETTINGS_BIND_DEFAULT);
1682 
1683 	action = comp_editor_get_action (editor, "view-role");
1684 	g_settings_bind (
1685 		editor->priv->calendar_settings, "editor-show-role",
1686 		action, "active",
1687 		G_SETTINGS_BIND_DEFAULT);
1688 
1689 	action = comp_editor_get_action (editor, "view-rsvp");
1690 	g_settings_bind (
1691 		editor->priv->calendar_settings, "editor-show-rsvp",
1692 		action, "active",
1693 		G_SETTINGS_BIND_DEFAULT);
1694 
1695 	action = comp_editor_get_action (editor, "view-status");
1696 	g_settings_bind (
1697 		editor->priv->calendar_settings, "editor-show-status",
1698 		action, "active",
1699 		G_SETTINGS_BIND_DEFAULT);
1700 
1701 	action = comp_editor_get_action (editor, "view-time-zone");
1702 	g_settings_bind (
1703 		editor->priv->calendar_settings, "editor-show-timezone",
1704 		action, "active",
1705 		G_SETTINGS_BIND_DEFAULT);
1706 
1707 	action = comp_editor_get_action (editor, "view-type");
1708 	g_settings_bind (
1709 		editor->priv->calendar_settings, "editor-show-type",
1710 		action, "active",
1711 		G_SETTINGS_BIND_DEFAULT);
1712 }
1713 
1714 static gboolean
1715 comp_editor_delete_event (GtkWidget *widget,
1716                           GdkEventAny *event)
1717 {
1718 	CompEditor *editor;
1719 
1720 	editor = COMP_EDITOR (widget);
1721 
1722 	commit_all_fields (editor);
1723 
1724 	if (prompt_and_save_changes (editor, TRUE))
1725 		close_dialog (editor);
1726 
1727 	return TRUE;
1728 }
1729 
1730 static gboolean
1731 comp_editor_key_press_event (GtkWidget *widget,
1732                              GdkEventKey *event)
1733 {
1734 	CompEditor *editor;
1735 
1736 	editor = COMP_EDITOR (widget);
1737 
1738 	if (event->keyval == GDK_KEY_Escape) {
1739 		commit_all_fields (editor);
1740 
1741 		if (prompt_and_save_changes (editor, TRUE))
1742 			close_dialog (editor);
1743 
1744 		return TRUE;
1745 	}
1746 
1747 	/* Chain up to parent's key_press_event() method. */
1748 	return GTK_WIDGET_CLASS (comp_editor_parent_class)->
1749 		key_press_event (widget, event);
1750 }
1751 
1752 static gboolean
1753 comp_editor_drag_motion (GtkWidget *widget,
1754                          GdkDragContext *context,
1755                          gint x,
1756                          gint y,
1757                          guint time)
1758 {
1759 	CompEditorPrivate *priv;
1760 	EAttachmentView *view;
1761 
1762 	priv = COMP_EDITOR_GET_PRIVATE (widget);
1763 	view = E_ATTACHMENT_VIEW (priv->attachment_view);
1764 
1765 	return e_attachment_view_drag_motion (view, context, x, y, time);
1766 }
1767 
1768 static void
1769 comp_editor_drag_data_received (GtkWidget *widget,
1770                                 GdkDragContext *context,
1771                                 gint x,
1772                                 gint y,
1773                                 GtkSelectionData *selection,
1774                                 guint info,
1775                                 guint time)
1776 {
1777 	CompEditorPrivate *priv;
1778 	EAttachmentView *view;
1779 
1780 	priv = COMP_EDITOR_GET_PRIVATE (widget);
1781 	view = E_ATTACHMENT_VIEW (priv->attachment_view);
1782 
1783 	/* Forward the data to the attachment view.  Note that calling
1784 	 * e_attachment_view_drag_data_received() will not work because
1785 	 * that function only handles the case where all the other drag
1786 	 * handlers have failed. */
1787 	e_attachment_paned_drag_data_received (
1788 		E_ATTACHMENT_PANED (view),
1789 		context, x, y, selection, info, time);
1790 }
1791 
1792 static void
1793 comp_editor_class_init (CompEditorClass *class)
1794 {
1795 	GObjectClass *object_class;
1796 	GtkWidgetClass *widget_class;
1797 
1798 	g_type_class_add_private (class, sizeof (CompEditorPrivate));
1799 
1800 	object_class = G_OBJECT_CLASS (class);
1801 	object_class->set_property = comp_editor_set_property;
1802 	object_class->get_property = comp_editor_get_property;
1803 	object_class->dispose = comp_editor_dispose;
1804 	object_class->finalize = comp_editor_finalize;
1805 	object_class->constructed = comp_editor_constructed;
1806 
1807 	widget_class = GTK_WIDGET_CLASS (class);
1808 	widget_class->delete_event = comp_editor_delete_event;
1809 	widget_class->key_press_event = comp_editor_key_press_event;
1810 	widget_class->drag_motion = comp_editor_drag_motion;
1811 	widget_class->drag_data_received = comp_editor_drag_data_received;
1812 
1813 	class->help_section = "memos-usage";
1814 	class->edit_comp = real_edit_comp;
1815 	class->send_comp = real_send_comp;
1816 	class->object_created = NULL;
1817 
1818 	g_object_class_install_property (
1819 		object_class,
1820 		PROP_CHANGED,
1821 		g_param_spec_boolean (
1822 			"changed",
1823 			NULL,
1824 			NULL,
1825 			FALSE,
1826 			G_PARAM_READWRITE));
1827 
1828 	g_object_class_install_property (
1829 		object_class,
1830 		PROP_CLIENT,
1831 		g_param_spec_object (
1832 			"client",
1833 			NULL,
1834 			NULL,
1835 			E_TYPE_CAL_CLIENT,
1836 			G_PARAM_READWRITE |
1837 			G_PARAM_CONSTRUCT));
1838 
1839 	/* FIXME: Use a proper flags type instead of int. */
1840 	g_object_class_install_property (
1841 		object_class,
1842 		PROP_FLAGS,
1843 		g_param_spec_int (
1844 			"flags",
1845 			NULL,
1846 			NULL,
1847 			G_MININT,
1848 			G_MAXINT,
1849 			0,
1850 			G_PARAM_READWRITE |
1851 			G_PARAM_CONSTRUCT));
1852 
1853 	g_object_class_install_property (
1854 		object_class,
1855 		PROP_FOCUS_TRACKER,
1856 		g_param_spec_object (
1857 			"focus-tracker",
1858 			NULL,
1859 			NULL,
1860 			E_TYPE_FOCUS_TRACKER,
1861 			G_PARAM_READABLE));
1862 
1863 	g_object_class_install_property (
1864 		object_class,
1865 		PROP_SHELL,
1866 		g_param_spec_object (
1867 			"shell",
1868 			NULL,
1869 			NULL,
1870 			E_TYPE_SHELL,
1871 			G_PARAM_READWRITE |
1872 			G_PARAM_CONSTRUCT_ONLY));
1873 
1874 	g_object_class_install_property (
1875 		object_class,
1876 		PROP_SUMMARY,
1877 		g_param_spec_string (
1878 			"summary",
1879 			NULL,
1880 			NULL,
1881 			NULL,
1882 			G_PARAM_READWRITE));
1883 
1884 	g_object_class_install_property (
1885 		object_class,
1886 		PROP_TIMEZONE,
1887 		g_param_spec_pointer (
1888 			"timezone",
1889 			"Time Zone",
1890 			NULL,
1891 			G_PARAM_READWRITE));
1892 
1893 	g_object_class_install_property (
1894 		object_class,
1895 		PROP_USE_24_HOUR_FORMAT,
1896 		g_param_spec_boolean (
1897 			"use-24-hour-format",
1898 			"Use 24-hour Format",
1899 			NULL,
1900 			FALSE,
1901 			G_PARAM_READWRITE));
1902 
1903 	g_object_class_install_property (
1904 		object_class,
1905 		PROP_WORK_DAY_END_HOUR,
1906 		g_param_spec_int (
1907 			"work-day-end-hour",
1908 			"Work Day End Hour",
1909 			NULL,
1910 			0,
1911 			23,
1912 			0,
1913 			G_PARAM_READWRITE));
1914 
1915 	g_object_class_install_property (
1916 		object_class,
1917 		PROP_WORK_DAY_END_MINUTE,
1918 		g_param_spec_int (
1919 			"work-day-end-minute",
1920 			"Work Day End Minute",
1921 			NULL,
1922 			0,
1923 			59,
1924 			0,
1925 			G_PARAM_READWRITE));
1926 
1927 	g_object_class_install_property (
1928 		object_class,
1929 		PROP_WORK_DAY_START_HOUR,
1930 		g_param_spec_int (
1931 			"work-day-start-hour",
1932 			"Work Day Start Hour",
1933 			NULL,
1934 			0,
1935 			23,
1936 			0,
1937 			G_PARAM_READWRITE));
1938 
1939 	g_object_class_install_property (
1940 		object_class,
1941 		PROP_WORK_DAY_START_MINUTE,
1942 		g_param_spec_int (
1943 			"work-day-start-minute",
1944 			"Work Day Start Minute",
1945 			NULL,
1946 			0,
1947 			59,
1948 			0,
1949 			G_PARAM_READWRITE));
1950 
1951 	signals[OBJECT_CREATED] = g_signal_new (
1952 		"object_created",
1953 		G_TYPE_FROM_CLASS (class),
1954 		G_SIGNAL_RUN_LAST,
1955 		G_STRUCT_OFFSET (CompEditorClass, object_created),
1956 		NULL, NULL,
1957 		g_cclosure_marshal_VOID__VOID,
1958 		G_TYPE_NONE, 0);
1959 
1960 	signals[COMP_CLOSED] = g_signal_new (
1961 		"comp_closed",
1962 		G_TYPE_FROM_CLASS (class),
1963 		G_SIGNAL_RUN_LAST,
1964 		G_STRUCT_OFFSET (CompEditorClass, comp_closed),
1965 		NULL, NULL,
1966 		g_cclosure_marshal_VOID__BOOLEAN,
1967 		G_TYPE_NONE, 1, G_TYPE_BOOLEAN);
1968 }
1969 
1970 static void
1971 comp_editor_init (CompEditor *editor)
1972 {
1973 	CompEditorPrivate *priv;
1974 	EAttachmentView *view;
1975 	EAttachmentStore *store;
1976 	EFocusTracker *focus_tracker;
1977 	GdkDragAction drag_actions;
1978 	GtkTargetList *target_list;
1979 	GtkTargetEntry *targets;
1980 	GtkActionGroup *action_group;
1981 	GtkActionGroup *action_group_2;
1982 	GtkAction *action;
1983 	GtkWidget *container;
1984 	GtkWidget *widget;
1985 	GtkWindow *window;
1986 	EShell *shell;
1987 	gboolean express_mode;
1988 	gboolean meego_mode;
1989 	gint n_targets;
1990 	GError *error = NULL;
1991 
1992 	/* FIXME We already have a 'shell' property.  Move stuff
1993 	 *       that depends on it to a constructed() method. */
1994 	shell = e_shell_get_default ();
1995 	express_mode = e_shell_get_express_mode (shell);
1996 	meego_mode = e_shell_get_meego_mode (shell);
1997 
1998 	editor->priv = priv = COMP_EDITOR_GET_PRIVATE (editor);
1999 
2000 	g_object_weak_ref (
2001 		G_OBJECT (editor), (GWeakNotify)
2002 		comp_editor_weak_notify_cb, NULL);
2003 
2004 	active_editors = g_list_prepend (active_editors, editor);
2005 
2006 	priv->calendar_settings = g_settings_new ("org.gnome.evolution.calendar");
2007 
2008 	/* Each editor window gets its own window group. */
2009 	window = GTK_WINDOW (editor);
2010 	priv->window_group = gtk_window_group_new ();
2011 	gtk_window_group_add_window (priv->window_group, window);
2012 
2013 	priv->pages = NULL;
2014 	priv->changed = FALSE;
2015 	priv->needs_send = FALSE;
2016 	priv->mod = CALOBJ_MOD_ALL;
2017 	priv->existing_org = FALSE;
2018 	priv->user_org = FALSE;
2019 	priv->warned = FALSE;
2020 	priv->is_group_item = FALSE;
2021 	priv->saved = FALSE;
2022 
2023 	priv->ui_manager = e_ui_manager_new ();
2024 	e_ui_manager_set_express_mode (
2025 		E_UI_MANAGER (priv->ui_manager), express_mode);
2026 
2027 	gtk_window_add_accel_group (
2028 		GTK_WINDOW (editor),
2029 		gtk_ui_manager_get_accel_group (priv->ui_manager));
2030 
2031 	/* Setup Action Groups */
2032 
2033 	action_group = gtk_action_group_new ("core");
2034 	gtk_action_group_set_translation_domain (
2035 		action_group, GETTEXT_PACKAGE);
2036 	gtk_action_group_add_actions (
2037 		action_group, core_entries,
2038 		G_N_ELEMENTS (core_entries), editor);
2039 	gtk_action_group_add_toggle_actions (
2040 		action_group, core_toggle_entries,
2041 		G_N_ELEMENTS (core_toggle_entries), editor);
2042 	gtk_ui_manager_insert_action_group (
2043 		priv->ui_manager, action_group, 0);
2044 	g_object_unref (action_group);
2045 
2046 	action = gtk_action_group_get_action (action_group, "save-and-close");
2047 	if (action) {
2048 		GtkAction *save_action;
2049 		GIcon *icon;
2050 		GIcon *emblemed_icon;
2051 		GEmblem *emblem;
2052 
2053 		icon = g_themed_icon_new (GTK_STOCK_CLOSE);
2054 		emblemed_icon = g_themed_icon_new (GTK_STOCK_SAVE);
2055 		emblem = g_emblem_new (emblemed_icon);
2056 		g_object_unref (emblemed_icon);
2057 
2058 		emblemed_icon = g_emblemed_icon_new (icon, emblem);
2059 		g_object_unref (emblem);
2060 		g_object_unref (icon);
2061 
2062 		gtk_action_set_gicon (action, emblemed_icon);
2063 
2064 		g_object_unref (emblemed_icon);
2065 
2066 		save_action = gtk_action_group_get_action (action_group, "save");
2067 		g_object_bind_property (
2068 			save_action, "sensitive",
2069 			action, "sensitive",
2070 			G_BINDING_SYNC_CREATE);
2071 	}
2072 
2073 	action_group = gtk_action_group_new ("individual");
2074 	gtk_action_group_set_translation_domain (
2075 		action_group, GETTEXT_PACKAGE);
2076 	gtk_action_group_add_actions (
2077 		action_group, individual_entries,
2078 		G_N_ELEMENTS (individual_entries), editor);
2079 	gtk_action_group_add_radio_actions (
2080 		action_group, classification_radio_entries,
2081 		G_N_ELEMENTS (classification_radio_entries),
2082 		E_CAL_COMPONENT_CLASS_PUBLIC,
2083 		G_CALLBACK (action_classification_cb), editor);
2084 	gtk_ui_manager_insert_action_group (
2085 		priv->ui_manager, action_group, 0);
2086 	g_object_unref (action_group);
2087 
2088 	action_group = gtk_action_group_new ("editable");
2089 	gtk_action_group_set_translation_domain (
2090 		action_group, GETTEXT_PACKAGE);
2091 	gtk_ui_manager_insert_action_group (
2092 		priv->ui_manager, action_group, 0);
2093 	g_object_unref (action_group);
2094 
2095 	action_group = gtk_action_group_new ("coordinated");
2096 	gtk_action_group_set_translation_domain (
2097 		action_group, GETTEXT_PACKAGE);
2098 	gtk_action_group_add_toggle_actions (
2099 		action_group, coordinated_toggle_entries,
2100 		G_N_ELEMENTS (coordinated_toggle_entries), editor);
2101 	gtk_ui_manager_insert_action_group (
2102 		priv->ui_manager, action_group, 0);
2103 	g_object_unref (action_group);
2104 
2105 	/* Configure an EFocusTracker to manage selection actions. */
2106 
2107 	focus_tracker = e_focus_tracker_new (GTK_WINDOW (editor));
2108 
2109 	action = comp_editor_get_action (editor, "cut-clipboard");
2110 	e_focus_tracker_set_cut_clipboard_action (focus_tracker, action);
2111 
2112 	action = comp_editor_get_action (editor, "copy-clipboard");
2113 	e_focus_tracker_set_copy_clipboard_action (focus_tracker, action);
2114 
2115 	action = comp_editor_get_action (editor, "paste-clipboard");
2116 	e_focus_tracker_set_paste_clipboard_action (focus_tracker, action);
2117 
2118 	action = comp_editor_get_action (editor, "delete-selection");
2119 	e_focus_tracker_set_delete_selection_action (focus_tracker, action);
2120 
2121 	action = comp_editor_get_action (editor, "select-all");
2122 	e_focus_tracker_set_select_all_action (focus_tracker, action);
2123 
2124 	priv->focus_tracker = focus_tracker;
2125 
2126 	/* Fine Tuning */
2127 
2128 	action = comp_editor_get_action (editor, "attach");
2129 	g_object_set (action, "short-label", _("Attach"), NULL);
2130 
2131 	/* Desensitize the "save" action. */
2132 	action = comp_editor_get_action (editor, "save");
2133 	gtk_action_set_sensitive (action, FALSE);
2134 
2135 	e_ui_manager_add_ui_from_string (E_UI_MANAGER (priv->ui_manager), ui, &error);
2136 	if (error != NULL) {
2137 		g_warning ("%s: %s", G_STRFUNC, error->message);
2138 		g_error_free (error);
2139 	}
2140 
2141 	/* Setup Widgets */
2142 
2143 	container = GTK_WIDGET (editor);
2144 
2145 	widget = gtk_vbox_new (FALSE, 0);
2146 	gtk_container_add (GTK_CONTAINER (container), widget);
2147 	gtk_widget_show (widget);
2148 
2149 	container = widget;
2150 
2151 	if (!express_mode) {
2152 		widget = comp_editor_get_managed_widget (editor, "/main-menu");
2153 		gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
2154 		gtk_widget_set_visible (widget, !meego_mode);
2155 	}
2156 
2157 	widget = comp_editor_get_managed_widget (editor, "/main-toolbar");
2158 	gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0);
2159 	gtk_widget_show (widget);
2160 
2161 	gtk_style_context_add_class (
2162 		gtk_widget_get_style_context (widget),
2163 		GTK_STYLE_CLASS_PRIMARY_TOOLBAR);
2164 
2165 	widget = e_attachment_paned_new ();
2166 	e_attachment_paned_set_resize_toplevel (
2167 		E_ATTACHMENT_PANED (widget), TRUE);
2168 	gtk_container_set_border_width (GTK_CONTAINER (widget), 6);
2169 	gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
2170 	priv->attachment_view = g_object_ref (widget);
2171 	gtk_widget_show (widget);
2172 
2173 	if (express_mode) {
2174 		widget = e_attachment_paned_get_view_combo (
2175 			E_ATTACHMENT_PANED (widget));
2176 		gtk_widget_hide (widget);
2177 	}
2178 
2179 	container = e_attachment_paned_get_content_area (
2180 		E_ATTACHMENT_PANED (priv->attachment_view));
2181 
2182 	if (meego_mode) {
2183 		widget = gtk_scrolled_window_new (NULL, NULL);
2184 		gtk_scrolled_window_set_policy (
2185 			GTK_SCROLLED_WINDOW (widget),
2186 			GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2187 		gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0);
2188 		gtk_widget_set_size_request (widget, 300, -1);
2189 		gtk_widget_show (widget);
2190 
2191 		container = widget;
2192 	}
2193 
2194 	widget = gtk_notebook_new ();
2195 	gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), express_mode);
2196 	if (!meego_mode)
2197 		gtk_box_pack_start (
2198 			GTK_BOX (container), widget, TRUE, TRUE, 0);
2199 	else
2200 		gtk_scrolled_window_add_with_viewport (
2201 			GTK_SCROLLED_WINDOW (container), widget);
2202 	priv->notebook = GTK_NOTEBOOK (widget);
2203 	gtk_widget_show (widget);
2204 
2205 	/* Drag-and-Drop Support */
2206 
2207 	view = E_ATTACHMENT_VIEW (priv->attachment_view);
2208 	target_list = e_attachment_view_get_target_list (view);
2209 	drag_actions = e_attachment_view_get_drag_actions (view);
2210 
2211 	targets = gtk_target_table_new_from_list (target_list, &n_targets);
2212 
2213 	gtk_drag_dest_set (
2214 		GTK_WIDGET (editor), GTK_DEST_DEFAULT_ALL,
2215 		targets, n_targets, drag_actions);
2216 
2217 	gtk_target_table_free (targets, n_targets);
2218 
2219 	gtk_window_set_type_hint (
2220 		GTK_WINDOW (editor), GDK_WINDOW_TYPE_HINT_NORMAL);
2221 
2222 	action_group = comp_editor_get_action_group (editor, "individual");
2223 	action_group_2 = e_attachment_view_get_action_group (view, "editable");
2224 
2225 	g_object_bind_property (
2226 		action_group, "sensitive",
2227 		action_group_2, "sensitive",
2228 		G_BINDING_SYNC_CREATE);
2229 
2230 	/* Listen for attachment store changes. */
2231 
2232 	store = e_attachment_view_get_store (view);
2233 
2234 	g_signal_connect_swapped (
2235 		store, "row-deleted",
2236 		G_CALLBACK (attachment_store_changed_cb), editor);
2237 
2238 	g_signal_connect_swapped (
2239 		store, "row-inserted",
2240 		G_CALLBACK (attachment_store_changed_cb), editor);
2241 
2242 	comp_editor_bind_settings (editor);
2243 
2244 	gtk_application_add_window (
2245 		GTK_APPLICATION (shell), GTK_WINDOW (editor));
2246 	e_shell_adapt_window_size (shell, GTK_WINDOW (editor));
2247 }
2248 
2249 static gboolean
2250 prompt_and_save_changes (CompEditor *editor,
2251                          gboolean send)
2252 {
2253 	CompEditorPrivate *priv;
2254 	gboolean correct = FALSE;
2255 	ECalComponent *comp;
2256 	ECalComponentText text;
2257 
2258 	priv = editor->priv;
2259 
2260 	if (!priv->changed)
2261 		return TRUE;
2262 
2263 	switch (save_component_dialog (GTK_WINDOW (editor), priv->comp)) {
2264 	case GTK_RESPONSE_YES: /* Save */
2265 		if (e_client_is_readonly (E_CLIENT (priv->cal_client))) {
2266 			e_alert_submit (
2267 				E_ALERT_SINK (editor),
2268 				"calendar:prompt-read-only-cal-editor",
2269 				e_source_get_display_name (
2270 					e_client_get_source (E_CLIENT (priv->cal_client))),
2271 				NULL);
2272 			/* don't discard changes when selected readonly calendar */
2273 			return FALSE;
2274 		}
2275 
2276 		if ((comp_editor_get_flags (editor) & COMP_EDITOR_IS_ASSIGNED) != 0
2277 		    && e_cal_component_get_vtype (priv->comp) == E_CAL_COMPONENT_TODO
2278 		    && e_client_check_capability (E_CLIENT (priv->cal_client), CAL_STATIC_CAPABILITY_NO_TASK_ASSIGNMENT)) {
2279 			e_alert_submit (
2280 				E_ALERT_SINK (editor),
2281 				"calendar:prompt-no-task-assignment-editor",
2282 				e_source_get_display_name (
2283 					e_client_get_source (E_CLIENT (priv->cal_client))),
2284 				NULL);
2285 			return FALSE;
2286 		}
2287 
2288 		comp = comp_editor_get_current_comp (editor, &correct);
2289 		e_cal_component_get_summary (comp, &text);
2290 		g_object_unref (comp);
2291 
2292 		if (!correct)
2293 			return FALSE;
2294 
2295 		if (!text.value)
2296 			if (!send_component_prompt_subject (
2297 				(GtkWindow *) editor, priv->cal_client, priv->comp))
2298 				return FALSE;
2299 
2300 		if (e_cal_component_is_instance (priv->comp))
2301 			if (!recur_component_dialog (
2302 				priv->cal_client, priv->comp, &priv->mod,
2303 				GTK_WINDOW (editor), FALSE))
2304 				return FALSE;
2305 
2306 		if (send && save_comp_with_send (editor))
2307 			return TRUE;
2308 		else if (!send && save_comp (editor))
2309 			return TRUE;
2310 		else
2311 			return FALSE;
2312 	case GTK_RESPONSE_NO: /* Discard */
2313 		return TRUE;
2314 	case GTK_RESPONSE_CANCEL: /* Cancel */
2315 	default:
2316 		return FALSE;
2317 	}
2318 }
2319 
2320 /* Menu callbacks */
2321 
2322 static void
2323 comp_editor_show_help (CompEditor *editor)
2324 {
2325 	CompEditorClass *class;
2326 
2327 	class = COMP_EDITOR_GET_CLASS (editor);
2328 	g_return_if_fail (class->help_section != NULL);
2329 
2330 	e_display_help (GTK_WINDOW (editor), class->help_section);
2331 }
2332 
2333 /* Closes the dialog box and emits the appropriate signals */
2334 static void
2335 close_dialog (CompEditor *editor)
2336 {
2337 	CompEditorPrivate *priv = editor->priv;
2338 
2339 	g_signal_emit_by_name (editor, "comp_closed", priv->saved);
2340 
2341 	/* FIXME Unfortunately we do this here because otherwise corba
2342 	 * calls happen during destruction and we might get a change
2343 	 * notification back when we are in an inconsistent state */
2344 	if (priv->view)
2345 		g_signal_handlers_disconnect_matched (
2346 			priv->view, G_SIGNAL_MATCH_DATA,
2347 			0, 0, NULL, NULL, editor);
2348 
2349 	gtk_widget_destroy (GTK_WIDGET (editor));
2350 }
2351 
2352 static gint
2353 comp_editor_compare (CompEditor *editor_a,
2354                      const gchar *uid_b)
2355 {
2356 	const gchar *uid_a = NULL;
2357 
2358 	e_cal_component_get_uid (editor_a->priv->comp, &uid_a);
2359 
2360 	return g_strcmp0 (uid_a, uid_b);
2361 }
2362 
2363 void
2364 comp_editor_set_existing_org (CompEditor *editor,
2365                               gboolean existing_org)
2366 {
2367 	g_return_if_fail (IS_COMP_EDITOR (editor));
2368 
2369 	editor->priv->existing_org = existing_org;
2370 }
2371 
2372 gboolean
2373 comp_editor_get_existing_org (CompEditor *editor)
2374 {
2375 	g_return_val_if_fail (IS_COMP_EDITOR (editor), FALSE);
2376 
2377 	return editor->priv->existing_org;
2378 }
2379 
2380 void
2381 comp_editor_set_user_org (CompEditor *editor,
2382                           gboolean user_org)
2383 {
2384 	g_return_if_fail (IS_COMP_EDITOR (editor));
2385 
2386 	editor->priv->user_org = user_org;
2387 }
2388 
2389 gboolean
2390 comp_editor_get_user_org (CompEditor *editor)
2391 {
2392 	g_return_val_if_fail (IS_COMP_EDITOR (editor), FALSE);
2393 
2394 	return editor->priv->user_org;
2395 }
2396 
2397 void
2398 comp_editor_set_group_item (CompEditor *editor,
2399                             gboolean group_item)
2400 {
2401 	g_return_if_fail (IS_COMP_EDITOR (editor));
2402 
2403 	editor->priv->is_group_item = group_item;
2404 }
2405 
2406 gboolean
2407 comp_editor_get_group_item (CompEditor *editor)
2408 {
2409 	g_return_val_if_fail (IS_COMP_EDITOR (editor), FALSE);
2410 
2411 	return editor->priv->is_group_item;
2412 }
2413 
2414 void
2415 comp_editor_set_classification (CompEditor *editor,
2416                                 ECalComponentClassification classification)
2417 {
2418 	GtkAction *action;
2419 
2420 	g_return_if_fail (IS_COMP_EDITOR (editor));
2421 
2422 	switch (classification) {
2423 		case E_CAL_COMPONENT_CLASS_PUBLIC:
2424 		case E_CAL_COMPONENT_CLASS_PRIVATE:
2425 		case E_CAL_COMPONENT_CLASS_CONFIDENTIAL:
2426 			break;
2427 		default:
2428 			classification = E_CAL_COMPONENT_CLASS_PUBLIC;
2429 			break;
2430 	}
2431 
2432 	action = comp_editor_get_action (editor, "classify-public");
2433 	gtk_radio_action_set_current_value (
2434 		GTK_RADIO_ACTION (action), classification);
2435 }
2436 
2437 ECalComponentClassification
2438 comp_editor_get_classification (CompEditor *editor)
2439 {
2440 	GtkAction *action;
2441 
2442 	g_return_val_if_fail (IS_COMP_EDITOR (editor), 0);
2443 
2444 	action = comp_editor_get_action (editor, "classify-public");
2445 	return gtk_radio_action_get_current_value (GTK_RADIO_ACTION (action));
2446 }
2447 
2448 EShell *
2449 comp_editor_get_shell (CompEditor *editor)
2450 {
2451 	g_return_val_if_fail (IS_COMP_EDITOR (editor), NULL);
2452 
2453 	return editor->priv->shell;
2454 }
2455 
2456 void
2457 comp_editor_set_summary (CompEditor *editor,
2458                          const gchar *summary)
2459 {
2460 	gboolean show_warning;
2461 
2462 	g_return_if_fail (IS_COMP_EDITOR (editor));
2463 
2464 	if (g_strcmp0 (editor->priv->summary, summary) == 0)
2465 		return;
2466 
2467 	g_free (editor->priv->summary);
2468 	editor->priv->summary = g_strdup (summary);
2469 
2470 	show_warning =
2471 		!editor->priv->warned &&
2472 		!(editor->priv->flags & COMP_EDITOR_DELEGATE) &&
2473 		editor->priv->existing_org &&
2474 		!editor->priv->user_org && !(editor->priv->flags & COMP_EDITOR_NEW_ITEM);
2475 
2476 	if (show_warning) {
2477 		e_notice (
2478 			editor->priv->notebook, GTK_MESSAGE_INFO,
2479 			_("Changes made to this item may be "
2480 			"discarded if an update arrives"));
2481 		editor->priv->warned = TRUE;
2482 	}
2483 
2484 	update_window_border (editor, summary);
2485 
2486 	g_object_notify (G_OBJECT (editor), "summary");
2487 }
2488 
2489 const gchar *
2490 comp_editor_get_summary (CompEditor *editor)
2491 {
2492 	g_return_val_if_fail (IS_COMP_EDITOR (editor), NULL);
2493 
2494 	return editor->priv->summary;
2495 }
2496 
2497 icaltimezone *
2498 comp_editor_get_timezone (CompEditor *editor)
2499 {
2500 	g_return_val_if_fail (IS_COMP_EDITOR (editor), NULL);
2501 
2502 	return editor->priv->zone;
2503 }
2504 
2505 void
2506 comp_editor_set_timezone (CompEditor *editor,
2507                           icaltimezone *zone)
2508 {
2509 	g_return_if_fail (IS_COMP_EDITOR (editor));
2510 
2511 	if (editor->priv->zone == zone)
2512 		return;
2513 
2514 	editor->priv->zone = zone;
2515 
2516 	g_object_notify (G_OBJECT (editor), "timezone");
2517 }
2518 
2519 gboolean
2520 comp_editor_get_use_24_hour_format (CompEditor *editor)
2521 {
2522 	g_return_val_if_fail (IS_COMP_EDITOR (editor), FALSE);
2523 
2524 	return editor->priv->use_24_hour_format;
2525 }
2526 
2527 void
2528 comp_editor_set_use_24_hour_format (CompEditor *editor,
2529                                     gboolean use_24_hour_format)
2530 {
2531 	g_return_if_fail (IS_COMP_EDITOR (editor));
2532 
2533 	if (editor->priv->use_24_hour_format == use_24_hour_format)
2534 		return;
2535 
2536 	editor->priv->use_24_hour_format = use_24_hour_format;
2537 
2538 	g_object_notify (G_OBJECT (editor), "use-24-hour-format");
2539 }
2540 
2541 gint
2542 comp_editor_get_work_day_end_hour (CompEditor *editor)
2543 {
2544 	g_return_val_if_fail (IS_COMP_EDITOR (editor), 0);
2545 
2546 	return editor->priv->work_day_end_hour;
2547 }
2548 
2549 void
2550 comp_editor_set_work_day_end_hour (CompEditor *editor,
2551                                    gint work_day_end_hour)
2552 {
2553 	g_return_if_fail (IS_COMP_EDITOR (editor));
2554 
2555 	if (editor->priv->work_day_end_hour == work_day_end_hour)
2556 		return;
2557 
2558 	editor->priv->work_day_end_hour = work_day_end_hour;
2559 
2560 	g_object_notify (G_OBJECT (editor), "work-day-end-hour");
2561 }
2562 
2563 gint
2564 comp_editor_get_work_day_end_minute (CompEditor *editor)
2565 {
2566 	g_return_val_if_fail (IS_COMP_EDITOR (editor), 0);
2567 
2568 	return editor->priv->work_day_end_minute;
2569 }
2570 
2571 void
2572 comp_editor_set_work_day_end_minute (CompEditor *editor,
2573                                      gint work_day_end_minute)
2574 {
2575 	g_return_if_fail (IS_COMP_EDITOR (editor));
2576 
2577 	if (editor->priv->work_day_end_minute == work_day_end_minute)
2578 		return;
2579 
2580 	editor->priv->work_day_end_minute = work_day_end_minute;
2581 
2582 	g_object_notify (G_OBJECT (editor), "work-day-end-minute");
2583 }
2584 
2585 gint
2586 comp_editor_get_work_day_start_hour (CompEditor *editor)
2587 {
2588 	g_return_val_if_fail (IS_COMP_EDITOR (editor), 0);
2589 
2590 	return editor->priv->work_day_start_hour;
2591 }
2592 
2593 void
2594 comp_editor_set_work_day_start_hour (CompEditor *editor,
2595                                      gint work_day_start_hour)
2596 {
2597 	g_return_if_fail (IS_COMP_EDITOR (editor));
2598 
2599 	if (editor->priv->work_day_start_hour == work_day_start_hour)
2600 		return;
2601 
2602 	editor->priv->work_day_start_hour = work_day_start_hour;
2603 
2604 	g_object_notify (G_OBJECT (editor), "work-day-start-hour");
2605 }
2606 
2607 gint
2608 comp_editor_get_work_day_start_minute (CompEditor *editor)
2609 {
2610 	g_return_val_if_fail (IS_COMP_EDITOR (editor), 0);
2611 
2612 	return editor->priv->work_day_start_minute;
2613 }
2614 
2615 void
2616 comp_editor_set_work_day_start_minute (CompEditor *editor,
2617                                        gint work_day_start_minute)
2618 {
2619 	g_return_if_fail (IS_COMP_EDITOR (editor));
2620 
2621 	if (editor->priv->work_day_start_minute == work_day_start_minute)
2622 		return;
2623 
2624 	editor->priv->work_day_start_minute = work_day_start_minute;
2625 
2626 	g_object_notify (G_OBJECT (editor), "work-day-start-minute");
2627 }
2628 
2629 /**
2630  * comp_editor_set_changed:
2631  * @editor: A component editor
2632  * @changed: Value to set the changed state to
2633  *
2634  * Set the dialog changed state to the given value
2635  **/
2636 void
2637 comp_editor_set_changed (CompEditor *editor,
2638                          gboolean changed)
2639 {
2640 	GtkAction *action;
2641 	gboolean show_warning;
2642 
2643 	g_return_if_fail (IS_COMP_EDITOR (editor));
2644 
2645 	/* always process below changes, because other parts of
2646 	 * the editor listen for 'changed' notifications to update
2647 	 * its widgets, thus do it even the value actually didn't change
2648 	 */
2649 	if (editor->priv->changed != changed) {
2650 		editor->priv->changed = changed;
2651 
2652 		action = comp_editor_get_action (editor, "save");
2653 		g_return_if_fail (action != NULL);
2654 		gtk_action_set_sensitive (action, changed);
2655 	}
2656 
2657 	show_warning =
2658 		changed && !editor->priv->warned &&
2659 		!(editor->priv->flags & COMP_EDITOR_DELEGATE) &&
2660 		editor->priv->existing_org && !editor->priv->user_org
2661 		&& !(editor->priv->flags & COMP_EDITOR_NEW_ITEM);
2662 
2663 	if (show_warning) {
2664 		e_notice (
2665 			editor->priv->notebook, GTK_MESSAGE_INFO,
2666 			_("Changes made to this item may be "
2667 			"discarded if an update arrives"));
2668 		editor->priv->warned = TRUE;
2669 	}
2670 
2671 	g_object_notify (G_OBJECT (editor), "changed");
2672 }
2673 
2674 /**
2675  * comp_editor_get_changed:
2676  * @editor: A component editor
2677  *
2678  * Gets the changed state of the dialog
2679  *
2680  * Return value: A boolean indicating if the dialog is in a changed
2681  * state
2682  **/
2683 gboolean
2684 comp_editor_get_changed (CompEditor *editor)
2685 {
2686 	g_return_val_if_fail (IS_COMP_EDITOR (editor), FALSE);
2687 
2688 	return editor->priv->changed;
2689 }
2690 
2691 EFocusTracker *
2692 comp_editor_get_focus_tracker (CompEditor *editor)
2693 {
2694 	g_return_val_if_fail (IS_COMP_EDITOR (editor), NULL);
2695 
2696 	return editor->priv->focus_tracker;
2697 }
2698 
2699 void
2700 comp_editor_set_flags (CompEditor *editor,
2701                        CompEditorFlags flags)
2702 {
2703 	g_return_if_fail (IS_COMP_EDITOR (editor));
2704 
2705 	if (editor->priv->flags == flags)
2706 		return;
2707 
2708 	editor->priv->flags = flags;
2709 	editor->priv->user_org = flags & COMP_EDITOR_USER_ORG;
2710 
2711 	g_object_notify (G_OBJECT (editor), "flags");
2712 }
2713 
2714 CompEditorFlags
2715 comp_editor_get_flags (CompEditor *editor)
2716 {
2717 	g_return_val_if_fail (IS_COMP_EDITOR (editor), 0);
2718 
2719 	return editor->priv->flags;
2720 }
2721 
2722 GtkUIManager *
2723 comp_editor_get_ui_manager (CompEditor *editor)
2724 {
2725 	g_return_val_if_fail (IS_COMP_EDITOR (editor), NULL);
2726 
2727 	return editor->priv->ui_manager;
2728 }
2729 
2730 GtkAction *
2731 comp_editor_get_action (CompEditor *editor,
2732                         const gchar *action_name)
2733 {
2734 	GtkUIManager *ui_manager;
2735 
2736 	g_return_val_if_fail (IS_COMP_EDITOR (editor), NULL);
2737 	g_return_val_if_fail (action_name != NULL, NULL);
2738 
2739 	ui_manager = comp_editor_get_ui_manager (editor);
2740 
2741 	return e_lookup_action (ui_manager, action_name);
2742 }
2743 
2744 GtkActionGroup *
2745 comp_editor_get_action_group (CompEditor *editor,
2746                               const gchar *group_name)
2747 {
2748 	GtkUIManager *ui_manager;
2749 
2750 	g_return_val_if_fail (IS_COMP_EDITOR (editor), NULL);
2751 	g_return_val_if_fail (group_name != NULL, NULL);
2752 
2753 	ui_manager = comp_editor_get_ui_manager (editor);
2754 
2755 	return e_lookup_action_group (ui_manager, group_name);
2756 }
2757 
2758 GtkWidget *
2759 comp_editor_get_managed_widget (CompEditor *editor,
2760                                 const gchar *widget_path)
2761 {
2762 	GtkUIManager *ui_manager;
2763 	GtkWidget *widget;
2764 
2765 	g_return_val_if_fail (IS_COMP_EDITOR (editor), NULL);
2766 	g_return_val_if_fail (widget_path != NULL, NULL);
2767 
2768 	ui_manager = comp_editor_get_ui_manager (editor);
2769 	widget = gtk_ui_manager_get_widget (ui_manager, widget_path);
2770 	g_return_val_if_fail (widget != NULL, NULL);
2771 
2772 	return widget;
2773 }
2774 
2775 CompEditor *
2776 comp_editor_find_instance (const gchar *uid)
2777 {
2778 	GList *link;
2779 
2780 	g_return_val_if_fail (uid != NULL, NULL);
2781 
2782 	link = g_list_find_custom (
2783 		active_editors, uid,
2784 		(GCompareFunc) comp_editor_compare);
2785 
2786 	return (link != NULL) ? link->data : NULL;
2787 }
2788 
2789 /**
2790  * comp_editor_set_needs_send:
2791  * @editor: A component editor
2792  * @needs_send: Value to set the needs send state to
2793  *
2794  * Set the dialog needs send state to the given value
2795  **/
2796 void
2797 comp_editor_set_needs_send (CompEditor *editor,
2798                             gboolean needs_send)
2799 {
2800 	g_return_if_fail (IS_COMP_EDITOR (editor));
2801 
2802 	editor->priv->needs_send = needs_send;
2803 }
2804 
2805 /**
2806  * comp_editor_get_needs_send:
2807  * @editor: A component editor
2808  *
2809  * Gets the needs send state of the dialog
2810  *
2811  * Return value: A boolean indicating if the dialog is in a needs send
2812  * state
2813  **/
2814 gboolean
2815 comp_editor_get_needs_send (CompEditor *editor)
2816 {
2817 	g_return_val_if_fail (IS_COMP_EDITOR (editor), FALSE);
2818 
2819 	return editor->priv->needs_send;
2820 }
2821 
2822 static void
2823 page_mapped_cb (GtkWidget *page_widget,
2824                 CompEditorPage *page)
2825 {
2826 	GtkWidget *toplevel;
2827 
2828 	toplevel = gtk_widget_get_toplevel (page_widget);
2829 	if (!GTK_IS_WINDOW (toplevel))
2830 		return;
2831 
2832 	if (page->accel_group) {
2833 		gtk_window_add_accel_group (
2834 			GTK_WINDOW (toplevel),
2835 			page->accel_group);
2836 	}
2837 }
2838 
2839 static void
2840 page_unmapped_cb (GtkWidget *page_widget,
2841                   CompEditorPage *page)
2842 {
2843 	GtkWidget *toplevel;
2844 
2845 	toplevel = gtk_widget_get_toplevel (page_widget);
2846 	if (!GTK_IS_WINDOW (toplevel))
2847 		return;
2848 
2849 	if (page->accel_group) {
2850 		gtk_window_remove_accel_group (GTK_WINDOW (toplevel), page->accel_group);
2851 	}
2852 }
2853 
2854 /**
2855  * comp_editor_append_widget:
2856  * @editor: A component editor
2857  * @page: A component editor page
2858  * @label: Label of the page. Should be NULL if add is FALSE.
2859  * @add: Add's the page into the notebook if TRUE
2860  *
2861  * Appends a page to the notebook if add is TRUE else
2862  * just adds it to the list of pages.
2863  **/
2864 void
2865 comp_editor_append_widget (CompEditor *editor,
2866                          GtkWidget *page,
2867                          const gchar *label,
2868                          gboolean add)
2869 {
2870 	CompEditorPrivate *priv;
2871 	GtkWidget *label_widget = NULL;
2872 
2873 	g_return_if_fail (IS_COMP_EDITOR (editor));
2874 
2875 	priv = editor->priv;
2876 
2877 	g_object_ref (page);
2878 
2879 	if (label)
2880 		label_widget = gtk_label_new_with_mnemonic (label);
2881 
2882 	priv->pages = g_list_append (priv->pages, page);
2883 
2884 	if (add) {
2885 		gtk_notebook_append_page (priv->notebook, page, label_widget);
2886 		gtk_container_child_set (
2887 			GTK_CONTAINER (priv->notebook), page,
2888 			"tab-fill", FALSE, "tab-expand", FALSE, NULL);
2889 	}
2890 
2891 	/* Listen for when the page is mapped/unmapped so we can
2892 	 * install/uninstall the appropriate GtkAccelGroup.
2893 	g_signal_connect (
2894 		page, "map",
2895 		G_CALLBACK (page_mapped_cb), page);
2896 	g_signal_connect (
2897 		page, "unmap",
2898 		G_CALLBACK (page_unmapped_cb), page);
2899 		*/
2900 
2901 }
2902 
2903 /**
2904  * comp_editor_append_page:
2905  * @editor: A component editor
2906  * @page: A component editor page
2907  * @label: Label of the page. Should be NULL if add is FALSE.
2908  * @add: Add's the page into the notebook if TRUE
2909  *
2910  * Appends a page to the notebook if add is TRUE else
2911  * just adds it to the list of pages.
2912  **/
2913 void
2914 comp_editor_append_page (CompEditor *editor,
2915                          CompEditorPage *page,
2916                          const gchar *label,
2917                          gboolean add)
2918 {
2919 	CompEditorPrivate *priv;
2920 	GtkWidget *page_widget;
2921 	GtkWidget *label_widget = NULL;
2922 	gboolean is_first_page;
2923 
2924 	g_return_if_fail (IS_COMP_EDITOR (editor));
2925 	g_return_if_fail (IS_COMP_EDITOR_PAGE (page));
2926 
2927 	priv = editor->priv;
2928 
2929 	g_object_ref (page);
2930 
2931 	/* If we are editing something, fill the widgets with current info */
2932 	if (priv->comp != NULL) {
2933 		ECalComponent *comp;
2934 
2935 		comp = comp_editor_get_current_comp (editor, NULL);
2936 		comp_editor_page_fill_widgets (page, comp);
2937 		g_object_unref (comp);
2938 	}
2939 
2940 	page_widget = comp_editor_page_get_widget (page);
2941 	g_return_if_fail (page_widget != NULL);
2942 
2943 	if (label)
2944 		label_widget = gtk_label_new_with_mnemonic (label);
2945 
2946 	is_first_page = (priv->pages == NULL);
2947 
2948 	priv->pages = g_list_append (priv->pages, page);
2949 
2950 	if (add) {
2951 		gtk_notebook_append_page (
2952 			priv->notebook, page_widget, label_widget);
2953 		gtk_container_child_set (
2954 			GTK_CONTAINER (priv->notebook), page_widget,
2955 			"tab-fill", FALSE, "tab-expand", FALSE, NULL);
2956 	}
2957 
2958 	/* Listen for things happening on the page */
2959 	g_signal_connect_swapped (
2960 		page, "dates_changed",
2961 		G_CALLBACK (page_dates_changed_cb), editor);
2962 
2963 	/* Listen for when the page is mapped/unmapped so we can
2964 	 * install/uninstall the appropriate GtkAccelGroup. */
2965 	g_signal_connect (
2966 		page_widget, "map",
2967 		G_CALLBACK (page_mapped_cb), page);
2968 	g_signal_connect (
2969 		page_widget, "unmap",
2970 		G_CALLBACK (page_unmapped_cb), page);
2971 
2972 	/* The first page is the main page of the editor, so we ask it to focus
2973 	 * its main widget.
2974 	 */
2975 	if (is_first_page)
2976 		comp_editor_page_focus_main_widget (page);
2977 }
2978 
2979 /**
2980  * comp_editor_remove_page:
2981  * @editor: A component editor
2982  * @page: A component editor page
2983  *
2984  * Removes the page from the component editor
2985  **/
2986 void
2987 comp_editor_remove_page (CompEditor *editor,
2988                          CompEditorPage *page)
2989 {
2990 	CompEditorPrivate *priv;
2991 	GtkWidget *page_widget;
2992 	gint page_num;
2993 
2994 	g_return_if_fail (IS_COMP_EDITOR (editor));
2995 	g_return_if_fail (IS_COMP_EDITOR_PAGE (page));
2996 
2997 	priv = editor->priv;
2998 
2999 	page_widget = comp_editor_page_get_widget (page);
3000 	page_num = gtk_notebook_page_num (priv->notebook, page_widget);
3001 	if (page_num == -1)
3002 		return;
3003 
3004 	/* Disconnect all the signals added in append_page(). */
3005 	g_signal_handlers_disconnect_matched (
3006 		page, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, editor);
3007 	g_signal_handlers_disconnect_matched (
3008 		page_widget, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, page);
3009 
3010 	gtk_notebook_remove_page (priv->notebook, page_num);
3011 
3012 	priv->pages = g_list_remove (priv->pages, page);
3013 	g_object_unref (page);
3014 }
3015 
3016 /**
3017  * comp_editor_show_page:
3018  * @editor:
3019  * @page:
3020  *
3021  *
3022  **/
3023 void
3024 comp_editor_show_page (CompEditor *editor,
3025                        CompEditorPage *page)
3026 {
3027 	CompEditorPrivate *priv;
3028 	GtkWidget *page_widget;
3029 	gint page_num;
3030 
3031 	g_return_if_fail (IS_COMP_EDITOR (editor));
3032 	g_return_if_fail (IS_COMP_EDITOR_PAGE (page));
3033 
3034 	priv = editor->priv;
3035 
3036 	page_widget = comp_editor_page_get_widget (page);
3037 	page_num = gtk_notebook_page_num (priv->notebook, page_widget);
3038 	gtk_notebook_set_current_page (priv->notebook, page_num);
3039 }
3040 
3041 /**
3042  * comp_editor_set_client:
3043  * @editor: A component editor
3044  * @cal_client: The calendar client to use
3045  *
3046  * Sets the calendar client used by the editor to update components
3047  **/
3048 void
3049 comp_editor_set_client (CompEditor *editor,
3050                         ECalClient *cal_client)
3051 {
3052 	g_return_if_fail (IS_COMP_EDITOR (editor));
3053 	g_return_if_fail (cal_client == NULL || E_IS_CAL_CLIENT (cal_client));
3054 
3055 	if (editor->priv->cal_client == cal_client)
3056 		return;
3057 
3058 	if (cal_client != NULL)
3059 		g_object_ref (cal_client);
3060 
3061 	if (editor->priv->cal_client != NULL)
3062 		g_object_unref (editor->priv->cal_client);
3063 
3064 	editor->priv->cal_client = cal_client;
3065 
3066 	if (editor->priv->source_client == NULL && cal_client != NULL)
3067 		editor->priv->source_client = g_object_ref (cal_client);
3068 
3069 	g_object_notify (G_OBJECT (editor), "client");
3070 }
3071 
3072 /**
3073  * comp_editor_get_client:
3074  * @editor: A component editor
3075  *
3076  * Returns the calendar client of the editor
3077  *
3078  * Return value: The calendar client of the editor
3079  **/
3080 ECalClient *
3081 comp_editor_get_client (CompEditor *editor)
3082 {
3083 	g_return_val_if_fail (IS_COMP_EDITOR (editor), NULL);
3084 
3085 	return editor->priv->cal_client;
3086 }
3087 
3088 static void
3089 attachment_loaded_cb (EAttachment *attachment,
3090                       GAsyncResult *result,
3091                       GtkWindow *parent)
3092 {
3093 	GFileInfo *file_info;
3094 	const gchar *display_name;
3095 	const gchar *uid;
3096 	gchar *new_name;
3097 
3098 	/* Prior to 2.27.2, attachment files were named:
3099 	 *
3100 	 *     <component-uid> '-' <actual-filename>
3101 	 *     -------------------------------------
3102 	 *              (one long filename)
3103 	 *
3104 	 * Here we fix the display name if this form is detected so we
3105 	 * don't show the component UID in the user interface.  If the
3106 	 * user saves changes in the editor, the attachment will be
3107 	 * written to disk as:
3108 	 *
3109 	 *     <component-uid> / <actual-filename>
3110 	 *     ---------------   -----------------
3111 	 *       (directory)      (original name)
3112 	 *
3113 	 * So this is a lazy migration from the old form to the new.
3114 	 */
3115 
3116 	file_info = e_attachment_get_file_info (attachment);
3117 	if (!file_info) {
3118 		/* failed to load an attachment file */
3119 		e_attachment_load_handle_error (attachment, result, parent);
3120 		return;
3121 	}
3122 
3123 	display_name = g_file_info_get_display_name (file_info);
3124 	uid = g_object_get_data (G_OBJECT (attachment), "uid");
3125 
3126 	if (g_str_has_prefix (display_name, uid)) {
3127 		new_name = g_strdup (display_name + strlen (uid) + 1);
3128 		g_file_info_set_display_name (file_info, new_name);
3129 		g_object_notify (G_OBJECT (attachment), "file-info");
3130 		g_free (new_name);
3131 	}
3132 
3133 	e_attachment_load_handle_error (attachment, result, parent);
3134 }
3135 
3136 static void
3137 set_attachment_list (CompEditor *editor,
3138                      GSList *uri_list)
3139 {
3140 	EAttachmentStore *store;
3141 	EAttachmentView *view;
3142 	const gchar *uid = NULL;
3143 	GSList *iter;
3144 
3145 	view = E_ATTACHMENT_VIEW (editor->priv->attachment_view);
3146 	store = e_attachment_view_get_store (view);
3147 
3148 	if (e_attachment_store_get_num_attachments (store) > 0) {
3149 		/* To prevent repopulating the
3150 		 * bar due to redraw functions in fill_widget.
3151 		 * Assumes it can be set only once.
3152 		 */
3153 		return;
3154 	}
3155 
3156 	/* XXX What an awkward API this is.  Takes a return location
3157 	 *     for a constant string instead of just returning it. */
3158 	e_cal_component_get_uid (editor->priv->comp, &uid);
3159 
3160 	for (iter = uri_list; iter != NULL; iter = iter->next) {
3161 		EAttachment *attachment;
3162 
3163 		attachment = e_attachment_new_for_uri (iter->data);
3164 		e_attachment_store_add_attachment (store, attachment);
3165 		g_object_set_data_full (
3166 			G_OBJECT (attachment),
3167 			"uid", g_strdup (uid),
3168 			(GDestroyNotify) g_free);
3169 		e_attachment_load_async (
3170 			attachment, (GAsyncReadyCallback)
3171 			attachment_loaded_cb, editor);
3172 		g_object_unref (attachment);
3173 	}
3174 }
3175 
3176 static void
3177 fill_widgets (CompEditor *editor)
3178 {
3179 	EAttachmentStore *store;
3180 	EAttachmentView *view;
3181 	CompEditorPrivate *priv;
3182 	GtkAction *action;
3183 	GList *iter;
3184 
3185 	view = E_ATTACHMENT_VIEW (editor->priv->attachment_view);
3186 	store = e_attachment_view_get_store (view);
3187 
3188 	priv = editor->priv;
3189 
3190 	/*Check if attachments are available here and set them*/
3191 	if (e_cal_component_has_attachments (priv->comp)) {
3192 		GSList *attachment_list = NULL;
3193 		e_cal_component_get_attachment_list (priv->comp, &attachment_list);
3194 		g_signal_handlers_block_by_func (
3195 			store, G_CALLBACK (attachment_store_changed_cb),
3196 			editor);
3197 		set_attachment_list (editor, attachment_list);
3198 		g_signal_handlers_unblock_by_func (
3199 			store, G_CALLBACK (attachment_store_changed_cb),
3200 			editor);
3201 		g_slist_foreach (attachment_list, (GFunc) g_free, NULL);
3202 		g_slist_free (attachment_list);
3203 	}
3204 
3205 	action = comp_editor_get_action (editor, "classify-public");
3206 	g_signal_handlers_block_by_func (
3207 		action, G_CALLBACK (action_classification_cb), editor);
3208 
3209 	for (iter = priv->pages; iter != NULL; iter = iter->next) {
3210 		if (IS_COMP_EDITOR_PAGE (iter->data))
3211 			comp_editor_page_fill_widgets (iter->data, priv->comp);
3212 	}
3213 
3214 	g_signal_handlers_unblock_by_func (
3215 		action, G_CALLBACK (action_classification_cb), editor);
3216 }
3217 
3218 static void
3219 real_edit_comp (CompEditor *editor,
3220                 ECalComponent *comp)
3221 {
3222 	CompEditorPrivate *priv;
3223 
3224 	g_return_if_fail (IS_COMP_EDITOR (editor));
3225 
3226 	priv = editor->priv;
3227 
3228 	if (priv->comp) {
3229 		g_object_unref (priv->comp);
3230 		priv->comp = NULL;
3231 	}
3232 
3233 	if (comp) {
3234 		priv->comp = e_cal_component_clone (comp);
3235 		comp_editor_copy_new_attendees (priv->comp, comp);
3236 	}
3237 
3238 	priv->existing_org = e_cal_component_has_organizer (comp);
3239 	priv->warned = FALSE;
3240 
3241 	update_window_border (editor, NULL);
3242 
3243 	fill_widgets (editor);
3244 
3245 	comp_editor_set_changed (editor, FALSE);
3246 
3247 	listen_for_changes (editor);
3248 }
3249 
3250 /* TODO These functions should be available in e-cal-component.c */
3251 static void
3252 set_attendees_for_delegation (ECalComponent *comp,
3253                               const gchar *address,
3254                               ECalComponentItipMethod method)
3255 {
3256 	icalproperty *prop;
3257 	icalparameter *param;
3258 	icalcomponent *icalcomp;
3259 
3260 	icalcomp = e_cal_component_get_icalcomponent (comp);
3261 
3262 	for (prop = icalcomponent_get_first_property (icalcomp, ICAL_ATTENDEE_PROPERTY);
3263 	     prop;
3264 	     prop = icalcomponent_get_next_property (icalcomp, ICAL_ATTENDEE_PROPERTY)) {
3265 		const gchar *attendee = icalproperty_get_attendee (prop);
3266 		const gchar *delfrom = NULL;
3267 
3268 		param = icalproperty_get_first_parameter (prop, ICAL_DELEGATEDFROM_PARAMETER);
3269 		if (param)
3270 			delfrom = icalparameter_get_delegatedfrom (param);
3271 		if (!(g_str_equal (itip_strip_mailto (attendee), address) ||
3272 				((delfrom && *delfrom) &&
3273 				 g_str_equal (itip_strip_mailto (delfrom), address)))) {
3274 			icalcomponent_remove_property (icalcomp, prop);
3275 		}
3276 
3277 	}
3278 
3279 }
3280 
3281 static void
3282 get_users_from_memo_comp (ECalComponent *comp,
3283                           GSList **users)
3284 {
3285 	icalcomponent *icalcomp;
3286 	icalproperty *icalprop;
3287 	const gchar *attendees = NULL;
3288 	gchar **emails, **iter;
3289 
3290 	icalcomp = e_cal_component_get_icalcomponent (comp);
3291 
3292 	for (icalprop = icalcomponent_get_first_property (icalcomp, ICAL_X_PROPERTY);
3293 	     icalprop != NULL;
3294 	     icalprop = icalcomponent_get_next_property (icalcomp, ICAL_X_PROPERTY)) {
3295 		const gchar *x_name;
3296 
3297 		x_name = icalproperty_get_x_name (icalprop);
3298 
3299 		if (g_str_equal (x_name, "X-EVOLUTION-RECIPIENTS"))
3300 			break;
3301 	}
3302 
3303 	if (icalprop) {
3304 		attendees = icalproperty_get_x (icalprop);
3305 		emails = g_strsplit (attendees, ";", -1);
3306 
3307 		iter = emails;
3308 		while (*iter) {
3309 			*users = g_slist_append (*users, g_strdup (*iter));
3310 			iter++;
3311 		}
3312 		g_strfreev (emails);
3313 	}
3314 }
3315 
3316 static gboolean
3317 real_send_comp (CompEditor *editor,
3318                 ECalComponentItipMethod method,
3319                 gboolean strip_alarms)
3320 {
3321 	CompEditorPrivate *priv;
3322 	CompEditorFlags flags;
3323 	EShell *shell;
3324 	ESourceRegistry *registry;
3325 	ECalComponent *send_comp = NULL;
3326 	gchar *address = NULL;
3327 	GSList *users = NULL;
3328 
3329 	g_return_val_if_fail (IS_COMP_EDITOR (editor), FALSE);
3330 
3331 	priv = editor->priv;
3332 
3333 	flags = comp_editor_get_flags (editor);
3334 	shell = comp_editor_get_shell (editor);
3335 
3336 	registry = e_shell_get_registry (shell);
3337 
3338 	if (priv->mod == CALOBJ_MOD_ALL && e_cal_component_is_instance (priv->comp)) {
3339 		/* Ensure we send the master object, not the instance only */
3340 		icalcomponent *icalcomp = NULL;
3341 		const gchar *uid = NULL;
3342 
3343 		e_cal_component_get_uid (priv->comp, &uid);
3344 		if (e_cal_client_get_object_sync (priv->cal_client, uid, NULL, &icalcomp, NULL, NULL) && icalcomp) {
3345 			send_comp = e_cal_component_new ();
3346 			if (!e_cal_component_set_icalcomponent (send_comp, icalcomp)) {
3347 				icalcomponent_free (icalcomp);
3348 				g_object_unref (send_comp);
3349 				send_comp = NULL;
3350 			}
3351 		}
3352 	}
3353 
3354 	if (!send_comp)
3355 		send_comp = e_cal_component_clone (priv->comp);
3356 
3357 	comp_editor_copy_new_attendees (send_comp, priv->comp);
3358 
3359 	if (e_cal_component_get_vtype (send_comp) == E_CAL_COMPONENT_JOURNAL)
3360 		get_users_from_memo_comp (send_comp, &users);
3361 
3362 	/* The user updates the delegated status to the Organizer,
3363 	 * so remove all other attendees. */
3364 	if (flags & COMP_EDITOR_DELEGATE) {
3365 		address = itip_get_comp_attendee (
3366 			registry, send_comp, priv->cal_client);
3367 
3368 		if (address)
3369 			set_attendees_for_delegation (send_comp, address, method);
3370 	}
3371 
3372 	if (!e_cal_component_has_attachments (priv->comp) ||
3373 		e_client_check_capability (
3374 			E_CLIENT (priv->cal_client),
3375 			CAL_STATIC_CAPABILITY_CREATE_MESSAGES)) {
3376 		if (itip_send_comp (
3377 			registry, method, send_comp, priv->cal_client,
3378 			NULL, NULL, users, strip_alarms,
3379 			priv->flags & COMP_EDITOR_SEND_TO_NEW_ATTENDEES_ONLY)) {
3380 			g_object_unref (send_comp);
3381 			return TRUE;
3382 		}
3383 	} else {
3384 		/* Clone the component with attachments set to CID:...  */
3385 		GSList *attach_list = NULL;
3386 		GSList *mime_attach_list, *attach;
3387 
3388 		/* mime_attach_list is freed by itip_send_comp */
3389 		mime_attach_list = comp_editor_get_mime_attach_list (editor);
3390 
3391 		for (attach = mime_attach_list; attach; attach = attach->next) {
3392 			struct CalMimeAttach *cma = (struct CalMimeAttach *) attach->data;
3393 
3394 			attach_list = g_slist_append (
3395 				attach_list, g_strconcat (
3396 				"cid:", cma->content_id, NULL));
3397 		}
3398 
3399 		if (attach_list) {
3400 			e_cal_component_set_attachment_list (send_comp, attach_list);
3401 
3402 			g_slist_foreach (attach_list, (GFunc) g_free, NULL);
3403 			g_slist_free (attach_list);
3404 		}
3405 
3406 		if (itip_send_comp (
3407 			registry, method, send_comp, priv->cal_client,
3408 			NULL, mime_attach_list, users, strip_alarms,
3409 			priv->flags & COMP_EDITOR_SEND_TO_NEW_ATTENDEES_ONLY)) {
3410 			gboolean saved = save_comp (editor);
3411 
3412 			g_object_unref (send_comp);
3413 
3414 			if (!saved)
3415 				comp_editor_set_changed (editor, TRUE);
3416 
3417 			return saved;
3418 		}
3419 	}
3420 
3421 	g_object_unref (send_comp);
3422 	g_free (address);
3423 	comp_editor_set_changed (editor, TRUE);
3424 
3425 	return FALSE;
3426 
3427 }
3428 
3429 /**
3430  * comp_editor_edit_comp:
3431  * @editor: A component editor
3432  * @comp: A calendar component
3433  *
3434  * Starts the editor editing the given component
3435  **/
3436 void
3437 comp_editor_edit_comp (CompEditor *editor,
3438                        ECalComponent *comp)
3439 {
3440 	CompEditorClass *class;
3441 
3442 	g_return_if_fail (IS_COMP_EDITOR (editor));
3443 	g_return_if_fail (E_IS_CAL_COMPONENT (comp));
3444 
3445 	class = COMP_EDITOR_GET_CLASS (editor);
3446 
3447 	if (class->edit_comp)
3448 		class->edit_comp (editor, comp);
3449 }
3450 
3451 ECalComponent *
3452 comp_editor_get_comp (CompEditor *editor)
3453 {
3454 	g_return_val_if_fail (IS_COMP_EDITOR (editor), NULL);
3455 
3456 	return editor->priv->comp;
3457 }
3458 
3459 /**
3460  * comp_editor_get_current_comp
3461  * @editor: a #CompEditor
3462  * @correct: Set this no non-%NULL if you are interested to know if all
3463  * pages reported success when filling component.
3464  *
3465  * Returns: Newly allocated component, should be unref-ed by g_object_unref().
3466  **/
3467 ECalComponent *
3468 comp_editor_get_current_comp (CompEditor *editor,
3469                               gboolean *correct)
3470 {
3471 	CompEditorPrivate *priv;
3472 	ECalComponent *comp;
3473 	GList *l;
3474 	gboolean all_ok = TRUE;
3475 
3476 	g_return_val_if_fail (IS_COMP_EDITOR (editor), NULL);
3477 
3478 	priv = editor->priv;
3479 
3480 	comp = e_cal_component_clone (priv->comp);
3481 	comp_editor_copy_new_attendees (comp, priv->comp);
3482 	if (priv->changed) {
3483 		for (l = priv->pages; l != NULL; l = l->next) {
3484 			if (IS_COMP_EDITOR_PAGE (l->data))
3485 				all_ok = comp_editor_page_fill_component (l->data, comp) && all_ok;
3486 		}
3487 	}
3488 
3489 	if (correct)
3490 		*correct = all_ok;
3491 
3492 	return comp;
3493 }
3494 
3495 /**
3496  * comp_editor_save_comp:
3497  * @editor:
3498  *
3499  *
3500  **/
3501 gboolean
3502 comp_editor_save_comp (CompEditor *editor,
3503                        gboolean send)
3504 {
3505 	return prompt_and_save_changes (editor, send);
3506 }
3507 
3508 /**
3509  * comp_editor_delete_comp:
3510  * @editor:
3511  *
3512  *
3513  **/
3514 void
3515 comp_editor_delete_comp (CompEditor *editor)
3516 {
3517 	CompEditorPrivate *priv;
3518 	const gchar *uid;
3519 
3520 	g_return_if_fail (IS_COMP_EDITOR (editor));
3521 
3522 	priv = editor->priv;
3523 
3524 	e_cal_component_get_uid (priv->comp, &uid);
3525 	if (e_cal_component_is_instance (priv->comp) ||
3526 		e_cal_component_has_recurrences (priv->comp))
3527 		e_cal_client_remove_object_sync (
3528 			priv->cal_client, uid, NULL,
3529 			CALOBJ_MOD_ALL, NULL, NULL);
3530 	else
3531 		e_cal_client_remove_object_sync (
3532 			priv->cal_client, uid, NULL,
3533 			CALOBJ_MOD_THIS, NULL, NULL);
3534 	close_dialog (editor);
3535 }
3536 
3537 /**
3538  * comp_editor_send_comp:
3539  * @editor:
3540  * @method:
3541  *
3542  *
3543  **/
3544 gboolean
3545 comp_editor_send_comp (CompEditor *editor,
3546                        ECalComponentItipMethod method,
3547                        gboolean strip_alarms)
3548 {
3549 	CompEditorClass *class;
3550 
3551 	g_return_val_if_fail (IS_COMP_EDITOR (editor), FALSE);
3552 
3553 	class = COMP_EDITOR_GET_CLASS (editor);
3554 
3555 	if (class->send_comp)
3556 		return class->send_comp (editor, method, strip_alarms);
3557 
3558 	return FALSE;
3559 }
3560 
3561 gboolean
3562 comp_editor_close (CompEditor *editor)
3563 {
3564 	gboolean close;
3565 
3566 	g_return_val_if_fail (IS_COMP_EDITOR (editor), FALSE);
3567 
3568 	commit_all_fields (editor);
3569 
3570 	close = prompt_and_save_changes (editor, TRUE);
3571 	if (close)
3572 		close_dialog (editor);
3573 
3574 	return close;
3575 }
3576 
3577 /* Utility function to get the mime-attachment list from the attachment
3578  * bar for sending the comp via itip. The list and its contents must
3579  * be freed by the caller.
3580  */
3581 GSList *
3582 comp_editor_get_mime_attach_list (CompEditor *editor)
3583 {
3584 	EAttachmentStore *store;
3585 	EAttachmentView *view;
3586 	GtkTreeModel *model;
3587 	GtkTreeIter iter;
3588 	struct CalMimeAttach *cal_mime_attach;
3589 	GSList *attach_list = NULL;
3590 	gboolean valid;
3591 
3592 	view = E_ATTACHMENT_VIEW (editor->priv->attachment_view);
3593 	store = e_attachment_view_get_store (view);
3594 
3595 	model = GTK_TREE_MODEL (store);
3596 	valid = gtk_tree_model_get_iter_first (model, &iter);
3597 
3598 	while (valid) {
3599 		EAttachment *attachment;
3600 		CamelDataWrapper *wrapper;
3601 		CamelMimePart *mime_part;
3602 		CamelStream *stream;
3603 		GByteArray *byte_array;
3604 		guchar *buffer = NULL;
3605 		const gchar *desc, *disp;
3606 		gint column_id;
3607 
3608 		column_id = E_ATTACHMENT_STORE_COLUMN_ATTACHMENT;
3609 		gtk_tree_model_get (model, &iter, column_id, &attachment, -1);
3610 		mime_part = e_attachment_get_mime_part (attachment);
3611 		g_object_unref (attachment);
3612 
3613 		valid = gtk_tree_model_iter_next (model, &iter);
3614 
3615 		if (mime_part == NULL)
3616 			continue;
3617 
3618 		cal_mime_attach = g_malloc0 (sizeof (struct CalMimeAttach));
3619 		wrapper = camel_medium_get_content (CAMEL_MEDIUM (mime_part));
3620 
3621 		byte_array = g_byte_array_new ();
3622 		stream = camel_stream_mem_new_with_byte_array (byte_array);
3623 
3624 		camel_data_wrapper_decode_to_stream_sync (
3625 			wrapper, stream, NULL, NULL);
3626 		buffer = g_memdup (byte_array->data, byte_array->len);
3627 
3628 		camel_mime_part_set_content_id (mime_part, NULL);
3629 
3630 		cal_mime_attach->encoded_data = (gchar *) buffer;
3631 		cal_mime_attach->length = byte_array->len;
3632 		cal_mime_attach->filename =
3633 			g_strdup (camel_mime_part_get_filename (mime_part));
3634 		desc = camel_mime_part_get_description (mime_part);
3635 		if (!desc || *desc == '\0')
3636 			desc = _("attachment");
3637 		cal_mime_attach->description = g_strdup (desc);
3638 		cal_mime_attach->content_type = g_strdup (
3639 			camel_data_wrapper_get_mime_type (wrapper));
3640 		cal_mime_attach->content_id = g_strdup (
3641 			camel_mime_part_get_content_id (mime_part));
3642 
3643 		disp = camel_mime_part_get_disposition (mime_part);
3644 		if (disp && !g_ascii_strcasecmp (disp, "inline"))
3645 			cal_mime_attach->disposition = TRUE;
3646 
3647 		attach_list = g_slist_append (attach_list, cal_mime_attach);
3648 
3649 		g_object_unref (stream);
3650 
3651 	}
3652 
3653 	return attach_list;
3654 }
3655 
3656 static void
3657 page_dates_changed_cb (CompEditor *editor,
3658                        CompEditorPageDates *dates,
3659                        CompEditorPage *page)
3660 {
3661 	CompEditorPrivate *priv = editor->priv;
3662 	GList *l;
3663 
3664 	for (l = priv->pages; l != NULL; l = l->next)
3665 		if (page != (CompEditorPage *) l->data && IS_COMP_EDITOR_PAGE (l->data))
3666 			comp_editor_page_set_dates (l->data, dates);
3667 
3668 	if (!priv->warned && priv->existing_org && !priv->user_org &&
3669 		!(editor->priv->flags & COMP_EDITOR_NEW_ITEM)) {
3670 		e_notice (
3671 			priv->notebook, GTK_MESSAGE_INFO,
3672 			_("Changes made to this item may be discarded "
3673 			"if an update arrives"));
3674 		priv->warned = TRUE;
3675 	}
3676 }
3677 
3678 static void
3679 obj_modified_cb (ECalClientView *view,
3680                  const GSList *objects,
3681                  CompEditor *editor)
3682 {
3683 	CompEditorPrivate *priv;
3684 	ECalComponent *comp = NULL;
3685 
3686 	priv = editor->priv;
3687 
3688 	/* We queried based on a specific UID so we definitely changed */
3689 	if (changed_component_dialog (
3690 		(GtkWindow *) editor, priv->comp, FALSE, priv->changed)) {
3691 		icalcomponent *icalcomp = icalcomponent_new_clone (objects->data);
3692 
3693 		comp = e_cal_component_new ();
3694 		if (e_cal_component_set_icalcomponent (comp, icalcomp)) {
3695 			comp_editor_edit_comp (editor, comp);
3696 		} else {
3697 			GtkWidget *dialog;
3698 
3699 			dialog = gtk_message_dialog_new (
3700 				NULL, 0,
3701 				GTK_MESSAGE_ERROR,
3702 				GTK_BUTTONS_OK,
3703 				"%s",
3704 				_("Unable to use current version!"));
3705 			gtk_dialog_run (GTK_DIALOG (dialog));
3706 			gtk_widget_destroy (dialog);
3707 
3708 			icalcomponent_free (icalcomp);
3709 		}
3710 
3711 		g_object_unref (comp);
3712 	}
3713 }
3714 
3715 static void
3716 obj_removed_cb (ECalClientView *view,
3717                 const GSList *uids,
3718                 CompEditor *editor)
3719 {
3720 	CompEditorPrivate *priv = editor->priv;
3721 
3722 	if (changed_component_dialog (
3723 		GTK_WINDOW (editor), priv->comp, TRUE, priv->changed))
3724 		close_dialog (editor);
3725 }