evolution-3.6.4/calendar/gui/dialogs/memo-page.c

No issues found

   1 /*
   2  * Evolution calendar - Main page of the memo 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  *      Miguel de Icaza <miguel@ximian.com>
  21  *      Seth Alves <alves@hungry.com>
  22  *      JP Rosevear <jpr@ximian.com>
  23  *		Nathan Owens <pianocomp81@yahoo.com>
  24  *
  25  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
  26  *
  27  */
  28 
  29 #ifdef HAVE_CONFIG_H
  30 #include <config.h>
  31 #endif
  32 
  33 #include <string.h>
  34 #include <gtk/gtk.h>
  35 #include <glib/gi18n.h>
  36 
  37 #include <libedataserverui/libedataserverui.h>
  38 
  39 #include <e-util/e-util.h>
  40 #include <e-util/e-categories-config.h>
  41 #include <e-util/e-dialog-utils.h>
  42 #include <e-util/e-util-private.h>
  43 
  44 #include <misc/e-dateedit.h>
  45 #include <misc/e-spell-entry.h>
  46 #include <misc/e-buffer-tagger.h>
  47 
  48 #include "../calendar-config.h"
  49 #include "comp-editor.h"
  50 #include "comp-editor-util.h"
  51 #include "e-send-options-utils.h"
  52 #include "memo-page.h"
  53 
  54 #define MEMO_PAGE_GET_PRIVATE(obj) \
  55 	(G_TYPE_INSTANCE_GET_PRIVATE \
  56 	((obj), TYPE_MEMO_PAGE, MemoPagePrivate))
  57 
  58 /* Private part of the MemoPage structure */
  59 struct _MemoPagePrivate {
  60 	GtkBuilder *builder;
  61 
  62 	/* Widgets from the UI file */
  63 	GtkWidget *main;
  64 
  65 	GtkWidget *memo_content;
  66 
  67 	/* Generic informative messages placeholder */
  68 	GtkWidget *info_hbox;
  69 	GtkWidget *info_icon;
  70 	GtkWidget *info_string;
  71 
  72 	/* Organizer */
  73 	GtkWidget *org_label;
  74 	GtkWidget *org_combo;
  75 
  76 	/* To field */
  77 	GtkWidget *to_button;
  78 	GtkWidget *to_hbox;
  79 	GtkWidget *to_entry;
  80 
  81 	/* Summary */
  82 	GtkWidget *summary_label;
  83 	GtkWidget *summary_entry;
  84 
  85 	/* Start date */
  86 	GtkWidget *start_label;
  87 	GtkWidget *start_date;
  88 
  89 	GtkWidget *categories_btn;
  90 	GtkWidget *categories;
  91 
  92 	GtkWidget *source_combo_box;
  93 
  94 	gchar **address_strings;
  95 	gchar *fallback_address;
  96 
  97 	ENameSelector *name_selector;
  98 
  99 	GCancellable *open_cancellable;
 100 };
 101 
 102 static void set_subscriber_info_string (MemoPage *mpage, const gchar *backend_address);
 103 static const gchar * get_recipients (ECalComponent *comp);
 104 static void sensitize_widgets (MemoPage *mpage);
 105 static gboolean memo_page_fill_component (CompEditorPage *page, ECalComponent *comp);
 106 static void memo_page_select_organizer (MemoPage *mpage, const gchar *backend_address);
 107 
 108 G_DEFINE_TYPE (MemoPage, memo_page, TYPE_COMP_EDITOR_PAGE)
 109 
 110 static gboolean
 111 get_current_identity (MemoPage *page,
 112                       gchar **name,
 113                       gchar **mailto)
 114 {
 115 	EShell *shell;
 116 	CompEditor *editor;
 117 	ESourceRegistry *registry;
 118 	GList *list, *iter;
 119 	GtkWidget *entry;
 120 	const gchar *extension_name;
 121 	const gchar *text;
 122 	gboolean match = FALSE;
 123 
 124 	editor = comp_editor_page_get_editor (COMP_EDITOR_PAGE (page));
 125 	shell = comp_editor_get_shell (editor);
 126 
 127 	entry = gtk_bin_get_child (GTK_BIN (page->priv->org_combo));
 128 	text = gtk_entry_get_text (GTK_ENTRY (entry));
 129 
 130 	if (text == NULL || *text == '\0')
 131 		return FALSE;
 132 
 133 	registry = e_shell_get_registry (shell);
 134 	extension_name = E_SOURCE_EXTENSION_MAIL_IDENTITY;
 135 
 136 	list = e_source_registry_list_sources (registry, extension_name);
 137 
 138 	for (iter = list; !match && iter != NULL; iter = g_list_next (iter)) {
 139 		ESource *source = E_SOURCE (iter->data);
 140 		ESourceMailIdentity *extension;
 141 		const gchar *id_name;
 142 		const gchar *id_address;
 143 		gchar *identity;
 144 
 145 		extension = e_source_get_extension (source, extension_name);
 146 
 147 		id_name = e_source_mail_identity_get_name (extension);
 148 		id_address = e_source_mail_identity_get_address (extension);
 149 
 150 		if (id_name == NULL || id_address == NULL)
 151 			continue;
 152 
 153 		identity = g_strdup_printf ("%s <%s>", id_name, id_address);
 154 		match = (g_ascii_strcasecmp (text, identity) == 0);
 155 		g_free (identity);
 156 
 157 		if (match && name != NULL)
 158 			*name = g_strdup (id_name);
 159 
 160 		if (match && mailto != NULL)
 161 			*mailto = g_strdup_printf ("MAILTO:%s", id_address);
 162 	}
 163 
 164 	g_list_free_full (list, (GDestroyNotify) g_object_unref);
 165 
 166 	return match;
 167 }
 168 
 169 /* Fills the widgets with default values */
 170 static void
 171 clear_widgets (MemoPage *mpage)
 172 {
 173 	GtkTextBuffer *buffer;
 174 	GtkTextView *view;
 175 	CompEditor *editor;
 176 
 177 	/* Summary */
 178 	gtk_entry_set_text (GTK_ENTRY (mpage->priv->summary_entry), "");
 179 
 180 	/* Description */
 181 	view = GTK_TEXT_VIEW (mpage->priv->memo_content);
 182 	buffer = gtk_text_view_get_buffer (view);
 183 	gtk_text_buffer_set_text (buffer, "", 0);
 184 	e_buffer_tagger_update_tags (view);
 185 
 186 	/* Classification */
 187 	editor = comp_editor_page_get_editor (COMP_EDITOR_PAGE (mpage));
 188 	comp_editor_set_classification (editor, E_CAL_COMPONENT_CLASS_PRIVATE);
 189 
 190 	/* Categories */
 191 	gtk_entry_set_text (GTK_ENTRY (mpage->priv->categories), "");
 192 }
 193 
 194 static void
 195 memo_page_dispose (GObject *object)
 196 {
 197 	MemoPagePrivate *priv;
 198 
 199 	priv = MEMO_PAGE_GET_PRIVATE (object);
 200 
 201 	if (priv->open_cancellable) {
 202 		g_cancellable_cancel (priv->open_cancellable);
 203 		g_object_unref (priv->open_cancellable);
 204 		priv->open_cancellable = NULL;
 205 	}
 206 
 207 	g_strfreev (priv->address_strings);
 208 	priv->address_strings = NULL;
 209 
 210 	g_free (priv->fallback_address);
 211 	priv->fallback_address = NULL;
 212 
 213 	/* Chain up to parent's dispose() method. */
 214 	G_OBJECT_CLASS (memo_page_parent_class)->dispose (object);
 215 }
 216 
 217 static void
 218 memo_page_finalize (GObject *object)
 219 {
 220 	MemoPagePrivate *priv;
 221 
 222 	priv = MEMO_PAGE_GET_PRIVATE (object);
 223 
 224 	if (priv->name_selector) {
 225 		e_name_selector_cancel_loading (priv->name_selector);
 226 		g_object_unref (priv->name_selector);
 227 		priv->name_selector = NULL;
 228 	}
 229 
 230 	if (priv->main != NULL) {
 231 		g_object_unref (priv->main);
 232 		priv->main = NULL;
 233 	}
 234 
 235 	if (priv->builder) {
 236 		g_object_unref (priv->builder);
 237 		priv->builder = NULL;
 238 	}
 239 
 240 	/* Chain up to parent's finalize() method. */
 241 	G_OBJECT_CLASS (memo_page_parent_class)->finalize (object);
 242 }
 243 
 244 static GtkWidget *
 245 memo_page_get_widget (CompEditorPage *page)
 246 {
 247 	MemoPagePrivate *priv = MEMO_PAGE_GET_PRIVATE (page);
 248 
 249 	return priv->main;
 250 }
 251 
 252 static void
 253 memo_page_focus_main_widget (CompEditorPage *page)
 254 {
 255 	MemoPagePrivate *priv = MEMO_PAGE_GET_PRIVATE (page);
 256 
 257 	gtk_widget_grab_focus (priv->summary_entry);
 258 }
 259 
 260 static gboolean
 261 memo_page_fill_widgets (CompEditorPage *page,
 262                         ECalComponent *comp)
 263 {
 264 	MemoPage *mpage;
 265 	MemoPagePrivate *priv;
 266 	CompEditor *editor;
 267 	CompEditorFlags flags;
 268 	ECalClient *client;
 269 	ECalComponentClassification cl;
 270 	ECalComponentText text;
 271 	ECalComponentDateTime d;
 272 	ESourceRegistry *registry;
 273 	EShell *shell;
 274 	GSList *l;
 275 	const gchar *categories;
 276 	gchar *backend_addr = NULL;
 277 
 278 	mpage = MEMO_PAGE (page);
 279 	priv = mpage->priv;
 280 
 281 	editor = comp_editor_page_get_editor (page);
 282 	client = comp_editor_get_client (editor);
 283 	flags = comp_editor_get_flags (editor);
 284 	shell = comp_editor_get_shell (editor);
 285 
 286 	registry = e_shell_get_registry (shell);
 287 
 288 	/* Clean the screen */
 289 	clear_widgets (mpage);
 290 
 291         /* Summary */
 292 	e_cal_component_get_summary (comp, &text);
 293 	if (text.value != NULL)
 294 		gtk_entry_set_text (GTK_ENTRY (priv->summary_entry), text.value);
 295 	else
 296 		gtk_entry_set_text (GTK_ENTRY (priv->summary_entry), "");
 297 
 298 	e_cal_component_get_description_list (comp, &l);
 299 	if (l && l->data) {
 300 		ECalComponentText *dtext;
 301 
 302 		dtext = l->data;
 303 		gtk_text_buffer_set_text (
 304 			gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->memo_content)),
 305 			dtext->value ? dtext->value : "", -1);
 306 	} else {
 307 		gtk_text_buffer_set_text (
 308 			gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->memo_content)),
 309 			"", 0);
 310 	}
 311 	e_cal_component_free_text_list (l);
 312 	e_buffer_tagger_update_tags (GTK_TEXT_VIEW (priv->memo_content));
 313 
 314 	/* Start Date. */
 315 	e_cal_component_get_dtstart (comp, &d);
 316 	if (d.value) {
 317 		struct icaltimetype *start_tt = d.value;
 318 		e_date_edit_set_date (
 319 			E_DATE_EDIT (priv->start_date),
 320 			start_tt->year, start_tt->month,
 321 			start_tt->day);
 322 	} else if (!(flags & COMP_EDITOR_NEW_ITEM))
 323 		e_date_edit_set_time (E_DATE_EDIT (priv->start_date), -1);
 324 	e_cal_component_free_datetime (&d);
 325 
 326 	/* Classification. */
 327 	e_cal_component_get_classification (comp, &cl);
 328 	comp_editor_set_classification (editor, cl);
 329 
 330 	/* Categories */
 331 	e_cal_component_get_categories (comp, &categories);
 332 	if (categories != NULL)
 333 		gtk_entry_set_text (GTK_ENTRY (priv->categories), categories);
 334 	else
 335 		gtk_entry_set_text (GTK_ENTRY (priv->categories), "");
 336 
 337 	e_client_get_backend_property_sync (E_CLIENT (client), CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS, &backend_addr, NULL, NULL);
 338 	set_subscriber_info_string (mpage, backend_addr);
 339 
 340 	if (e_cal_component_has_organizer (comp)) {
 341 		ECalComponentOrganizer organizer;
 342 
 343 		e_cal_component_get_organizer (comp, &organizer);
 344 		if (organizer.value != NULL) {
 345 			const gchar *strip = itip_strip_mailto (organizer.value);
 346 			gchar *string;
 347 
 348 			if (organizer.cn != NULL)
 349 				string = g_strdup_printf ("%s <%s>", organizer.cn, strip);
 350 			else
 351 				string = g_strdup (strip);
 352 
 353 			if (itip_organizer_is_user (registry, comp, client) ||
 354 			    itip_sentby_is_user (registry, comp, client)) {
 355 				gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (priv->org_combo))), string);
 356 			} else {
 357 				GtkComboBox *combo_box;
 358 				GtkListStore *list_store;
 359 				GtkTreeModel *model;
 360 				GtkTreeIter iter;
 361 
 362 				combo_box = GTK_COMBO_BOX (priv->org_combo);
 363 				model = gtk_combo_box_get_model (combo_box);
 364 				list_store = GTK_LIST_STORE (model);
 365 
 366 				gtk_list_store_clear (list_store);
 367 				gtk_list_store_append (list_store, &iter);
 368 				gtk_list_store_set (list_store, &iter, 0, string, -1);
 369 				gtk_combo_box_set_active (combo_box, 0);
 370 				gtk_editable_set_editable (GTK_EDITABLE (gtk_bin_get_child (GTK_BIN (priv->org_combo))), FALSE);
 371 			}
 372 			g_free (string);
 373 		}
 374 	}
 375 
 376 	if (backend_addr)
 377 		g_free (backend_addr);
 378 
 379 	/* Source */
 380 	e_source_combo_box_set_active (
 381 		E_SOURCE_COMBO_BOX (priv->source_combo_box),
 382 		e_client_get_source (E_CLIENT (client)));
 383 
 384 	if (priv->to_entry && (flags & COMP_EDITOR_IS_SHARED) && !(flags & COMP_EDITOR_NEW_ITEM))
 385 		gtk_entry_set_text (GTK_ENTRY (priv->to_entry), get_recipients (comp));
 386 
 387 	sensitize_widgets (mpage);
 388 
 389 	return TRUE;
 390 }
 391 
 392 static void
 393 memo_page_class_init (MemoPageClass *class)
 394 {
 395 	CompEditorPageClass *editor_page_class;
 396 	GObjectClass *object_class;
 397 
 398 	g_type_class_add_private (class, sizeof (MemoPagePrivate));
 399 
 400 	object_class = G_OBJECT_CLASS (class);
 401 	object_class->dispose = memo_page_dispose;
 402 	object_class->finalize = memo_page_finalize;
 403 
 404 	editor_page_class = COMP_EDITOR_PAGE_CLASS (class);
 405 	editor_page_class->get_widget = memo_page_get_widget;
 406 	editor_page_class->focus_main_widget = memo_page_focus_main_widget;
 407 	editor_page_class->fill_widgets = memo_page_fill_widgets;
 408 	editor_page_class->fill_component = memo_page_fill_component;
 409 }
 410 
 411 static void
 412 memo_page_init (MemoPage *mpage)
 413 {
 414 	mpage->priv = MEMO_PAGE_GET_PRIVATE (mpage);
 415 }
 416 
 417 /* returns whether changed info text */
 418 static gboolean
 419 check_starts_in_the_past (MemoPage *mpage)
 420 {
 421 	MemoPagePrivate *priv;
 422 	struct icaltimetype start_tt = icaltime_null_time ();
 423 
 424 	if ((comp_editor_get_flags (comp_editor_page_get_editor (COMP_EDITOR_PAGE (mpage))) & COMP_EDITOR_NEW_ITEM) == 0)
 425 		return FALSE;
 426 
 427 	priv = mpage->priv;
 428 
 429 	start_tt.is_date = TRUE;
 430 	if (e_date_edit_get_date (E_DATE_EDIT (priv->start_date), &start_tt.year, &start_tt.month, &start_tt.day) &&
 431 	    comp_editor_test_time_in_the_past (start_tt)) {
 432 		gchar *tmp = g_strconcat ("<b>", _("Memo's start date is in the past"), "</b>", NULL);
 433 		memo_page_set_info_string (mpage, GTK_STOCK_DIALOG_WARNING, tmp);
 434 		g_free (tmp);
 435 	} else {
 436 		memo_page_set_info_string (mpage, NULL, NULL);
 437 	}
 438 
 439 	return TRUE;
 440 }
 441 
 442 static void
 443 sensitize_widgets (MemoPage *mpage)
 444 {
 445 	GtkActionGroup *action_group;
 446 	gboolean read_only, sens = FALSE, sensitize;
 447 	CompEditor *editor;
 448 	CompEditorFlags flags;
 449 	MemoPagePrivate *priv;
 450 	ECalClient *client;
 451 
 452 	priv = mpage->priv;
 453 
 454 	editor = comp_editor_page_get_editor (COMP_EDITOR_PAGE (mpage));
 455 	client = comp_editor_get_client (editor);
 456 	flags = comp_editor_get_flags (editor);
 457 
 458 	read_only = e_client_is_readonly (E_CLIENT (client));
 459 
 460 	if (flags & COMP_EDITOR_IS_SHARED)
 461 		sens = flags & COMP_EDITOR_USER_ORG;
 462 	else
 463 		sens = TRUE;
 464 
 465 	sensitize = (!read_only && sens);
 466 
 467 	if (read_only) {
 468 		gchar *tmp = g_strconcat ("<b>", _("Memo cannot be edited, because the selected memo list is read only"), "</b>", NULL);
 469 		memo_page_set_info_string (mpage, GTK_STOCK_DIALOG_INFO, tmp);
 470 		g_free (tmp);
 471 	} else if (!sens) {
 472 		gchar *tmp = g_strconcat ("<b>", _("Memo cannot be fully edited, because you are not the organizer"), "</b>", NULL);
 473 		memo_page_set_info_string (mpage, GTK_STOCK_DIALOG_INFO, tmp);
 474 		g_free (tmp);
 475 	} else if (!check_starts_in_the_past (mpage)) {
 476 		memo_page_set_info_string (mpage, NULL, NULL);
 477 	}
 478 
 479 	/* The list of organizers is set to be non-editable. Otherwise any
 480 	* change in the displayed list causes an 'Account not found' error.
 481 	*/
 482 	gtk_editable_set_editable (GTK_EDITABLE (gtk_bin_get_child (GTK_BIN (priv->org_combo))), FALSE);
 483 
 484 	gtk_text_view_set_editable (GTK_TEXT_VIEW (priv->memo_content), sensitize);
 485 	gtk_widget_set_sensitive (priv->start_date, sensitize);
 486 	gtk_widget_set_sensitive (priv->categories_btn, !read_only);
 487 	gtk_editable_set_editable (GTK_EDITABLE (priv->categories), !read_only);
 488 	gtk_editable_set_editable (GTK_EDITABLE (priv->summary_entry), sensitize);
 489 
 490 	if (flags & COMP_EDITOR_IS_SHARED) {
 491 		if (priv->to_entry) {
 492 			gtk_editable_set_editable (GTK_EDITABLE (priv->to_entry), !read_only);
 493 			gtk_widget_grab_focus (priv->to_entry);
 494 		}
 495 	}
 496 
 497 	action_group = comp_editor_get_action_group (editor, "editable");
 498 	gtk_action_group_set_sensitive (action_group, !read_only);
 499 
 500 	action_group = comp_editor_get_action_group (editor, "individual");
 501 	gtk_action_group_set_sensitive (action_group, sensitize);
 502 }
 503 
 504 /* returns empty string rather than NULL because of simplicity of usage */
 505 static const gchar *
 506 get_recipients (ECalComponent *comp)
 507 {
 508 	icalcomponent *icalcomp;
 509 	icalproperty *icalprop;
 510 
 511 	g_return_val_if_fail (comp != NULL, "");
 512 
 513 	icalcomp = e_cal_component_get_icalcomponent (comp);
 514 
 515 	/* first look if we have there such property */
 516 	for (icalprop = icalcomponent_get_first_property (icalcomp, ICAL_X_PROPERTY);
 517 	     icalprop;
 518 	     icalprop = icalcomponent_get_next_property (icalcomp, ICAL_X_PROPERTY)) {
 519 		const gchar *xname = icalproperty_get_x_name (icalprop);
 520 
 521 		if (xname && strcmp (xname, "X-EVOLUTION-RECIPIENTS") == 0)
 522 			break;
 523 	}
 524 
 525 	if (icalprop)
 526 		return icalproperty_get_x (icalprop);
 527 
 528 	return "";
 529 }
 530 
 531 static gboolean
 532 fill_comp_with_recipients (ENameSelector *name_selector,
 533                            ECalComponent *comp)
 534 {
 535 	EDestinationStore *destination_store;
 536 	GString *str = NULL;
 537 	GList *l, *destinations;
 538 	ENameSelectorModel *name_selector_model = e_name_selector_peek_model (name_selector);
 539 	icalcomponent *icalcomp;
 540 	icalproperty *icalprop;
 541 
 542 	e_name_selector_model_peek_section (
 543 		name_selector_model, "To",
 544 		NULL, &destination_store);
 545 
 546 	destinations = e_destination_store_list_destinations (destination_store);
 547 	for (l = destinations; l; l = g_list_next (l)) {
 548 		EDestination *destination = l->data, *des = NULL;
 549 		const GList *list_dests = NULL, *l;
 550 		GList card_dest;
 551 
 552 		if (e_destination_is_evolution_list (destination)) {
 553 			list_dests = e_destination_list_get_dests (destination);
 554 		} else {
 555 			EContact *contact = e_destination_get_contact (destination);
 556 			/* check if the contact is contact list which is not expanded yet */
 557 			/* we expand it by getting the list again from the server forming the query */
 558 			if (contact && e_contact_get (contact , E_CONTACT_IS_LIST)) {
 559 				EBookClient *book_client = NULL;
 560 				ENameSelectorDialog *dialog;
 561 				ENameSelectorModel *model;
 562 				EContactStore *c_store;
 563 				GSList *clients, *l;
 564 				gchar *uid = e_contact_get (contact, E_CONTACT_BOOK_UID);
 565 
 566 				dialog = e_name_selector_peek_dialog (name_selector);
 567 				model = e_name_selector_dialog_peek_model (dialog);
 568 				c_store = e_name_selector_model_peek_contact_store (model);
 569 				clients = e_contact_store_get_clients (c_store);
 570 
 571 				for (l = clients; l; l = l->next) {
 572 					EBookClient *b = l->data;
 573 					ESource *source;
 574 
 575 					source = e_client_get_source (E_CLIENT (b));
 576 
 577 					if (g_strcmp0 (uid, e_source_get_uid (source)) == 0) {
 578 						book_client = b;
 579 						break;
 580 					}
 581 				}
 582 
 583 				if (book_client) {
 584 					GSList *contacts = NULL;
 585 					EContact *n_con = NULL;
 586 					gchar *query;
 587 
 588 					query = g_strdup_printf (
 589 						"(is \"full_name\" \"%s\")",
 590 						(gchar *) e_contact_get (contact, E_CONTACT_FULL_NAME));
 591 
 592 					if (!e_book_client_get_contacts_sync (book_client, query, &contacts, NULL, NULL)) {
 593 						g_warning ("Could not get contact from the book \n");
 594 					} else {
 595 						des = e_destination_new ();
 596 						n_con = contacts->data;
 597 
 598 						e_destination_set_contact (des, n_con, 0);
 599 						e_destination_set_client (des, book_client);
 600 						list_dests = e_destination_list_get_dests (des);
 601 
 602 						g_slist_foreach (contacts, (GFunc) g_object_unref, NULL);
 603 						g_slist_free (contacts);
 604 					}
 605 
 606 					g_free (query);
 607 				}
 608 				g_slist_free (clients);
 609 			} else {
 610 				card_dest.next = NULL;
 611 				card_dest.prev = NULL;
 612 				card_dest.data = destination;
 613 				list_dests = &card_dest;
 614 			}
 615 		}
 616 
 617 		for (l = list_dests; l; l = l->next) {
 618 			EDestination *dest = l->data;
 619 			const gchar *attendee = NULL;
 620 
 621 			/* If we couldn't get the attendee prior,
 622 			 * get the email address as the default. */
 623 			if (attendee == NULL || *attendee == '\0')
 624 				attendee = e_destination_get_email (dest);
 625 
 626 			if (attendee == NULL || *attendee == '\0')
 627 				continue;
 628 
 629 			if (!str) {
 630 				str = g_string_new (NULL);
 631 				g_string_prepend (str, attendee);
 632 				continue;
 633 			}
 634 			g_string_prepend_c (str, ';');
 635 			g_string_prepend (str, attendee);
 636 		}
 637 	}
 638 
 639 	g_list_free (destinations);
 640 
 641 	if (str && *str->str) {
 642 		icalcomp = e_cal_component_get_icalcomponent (comp);
 643 		icalprop = icalproperty_new_x (str->str);
 644 		icalproperty_set_x_name (icalprop, "X-EVOLUTION-RECIPIENTS");
 645 		icalcomponent_add_property (icalcomp, icalprop);
 646 
 647 		g_string_free (str, FALSE);
 648 		return TRUE;
 649 	} else
 650 		return FALSE;
 651 }
 652 
 653 /* fill_component handler for the memo page */
 654 static gboolean
 655 memo_page_fill_component (CompEditorPage *page,
 656                           ECalComponent *comp)
 657 {
 658 	MemoPage *mpage;
 659 	MemoPagePrivate *priv;
 660 	CompEditor *editor;
 661 	CompEditorFlags flags;
 662 	ECalClient *client;
 663 	ECalComponentClassification classification;
 664 	ECalComponentDateTime start_date;
 665 	struct icaltimetype start_tt;
 666 	gchar *cat, *str;
 667 	gint i;
 668 	GtkTextBuffer *text_buffer;
 669 	GtkTextIter text_iter_start, text_iter_end;
 670 
 671 	mpage = MEMO_PAGE (page);
 672 	priv = mpage->priv;
 673 
 674 	editor = comp_editor_page_get_editor (page);
 675 	client = comp_editor_get_client (editor);
 676 	flags = comp_editor_get_flags (editor);
 677 
 678 	text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->memo_content));
 679 
 680 	/* Summary */
 681 	str = gtk_editable_get_chars (GTK_EDITABLE (priv->summary_entry), 0, -1);
 682 	if (str == NULL || *str == '\0')
 683 		e_cal_component_set_summary (comp, NULL);
 684 	else {
 685 		ECalComponentText text;
 686 
 687 		text.value = str;
 688 		text.altrep = NULL;
 689 
 690 		e_cal_component_set_summary (comp, &text);
 691 	}
 692 
 693 	g_free (str);
 694 	str = NULL;
 695 
 696 	/* Memo Content */
 697 
 698 	gtk_text_buffer_get_start_iter (text_buffer, &text_iter_start);
 699 	gtk_text_buffer_get_end_iter   (text_buffer, &text_iter_end);
 700 	str = gtk_text_buffer_get_text (text_buffer, &text_iter_start, &text_iter_end, FALSE);
 701 
 702 	if (!str || strlen (str) == 0) {
 703 		e_cal_component_set_description_list (comp, NULL);
 704 	}
 705 	else {
 706 		GSList l;
 707 		ECalComponentText text;
 708 		gchar *p;
 709 		gunichar uc;
 710 
 711 		for (i = 0, p = str, uc = g_utf8_get_char_validated (p, -1);
 712 		    i < 50 && p && uc < (gunichar) - 2;
 713 		    i++, p = g_utf8_next_char (p), uc = g_utf8_get_char_validated (p, -1)) {
 714 			if (uc == '\n' || !uc) {
 715 				p = NULL;
 716 				break;
 717 			}
 718 		}
 719 
 720 		text.value = str;
 721 		text.altrep = NULL;
 722 		l.data = &text;
 723 		l.next = NULL;
 724 
 725 		e_cal_component_set_description_list (comp, &l);
 726 	}
 727 
 728 	g_free (str);
 729 
 730 	/* Dates */
 731 	start_tt = icaltime_null_time ();
 732 	start_tt.is_date = 1;
 733 	start_date.value = &start_tt;
 734 	start_date.tzid = NULL;
 735 
 736 	if (!e_date_edit_date_is_valid (E_DATE_EDIT (priv->start_date))) {
 737 		comp_editor_page_display_validation_error (page, _("Start date is wrong"), priv->start_date);
 738 		return FALSE;
 739 	}
 740 	if (e_date_edit_get_date (E_DATE_EDIT (priv->start_date),
 741 					       &start_tt.year,
 742 					       &start_tt.month,
 743 					       &start_tt.day))
 744 		e_cal_component_set_dtstart (comp, &start_date);
 745 	else
 746 		e_cal_component_set_dtstart (comp, NULL);
 747 
 748 	/* Classification. */
 749 	classification = comp_editor_get_classification (editor);
 750 	e_cal_component_set_classification (comp, classification);
 751 
 752 	/* Categories */
 753 	cat = gtk_editable_get_chars (GTK_EDITABLE (priv->categories), 0, -1);
 754 	str = comp_editor_strip_categories (cat);
 755 	g_free (cat);
 756 
 757 	e_cal_component_set_categories (comp, str);
 758 
 759 	g_free (str);
 760 
 761 	/* change recipients only when creating new item, after that no such action is available */
 762 	if ((flags & COMP_EDITOR_IS_SHARED) && (flags & COMP_EDITOR_NEW_ITEM) && fill_comp_with_recipients (priv->name_selector, comp)) {
 763 		ECalComponentOrganizer organizer = {NULL, NULL, NULL, NULL};
 764 
 765 		gchar *backend_addr = NULL;
 766 		gchar *backend_mailto = NULL;
 767 		gchar *name = NULL;
 768 		gchar *mailto = NULL;
 769 
 770 		e_client_get_backend_property_sync (E_CLIENT (client), CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS, &backend_addr, NULL, NULL);
 771 
 772 		/* Find the identity for the organizer or sentby field */
 773 		if (!get_current_identity (mpage, &name, &mailto)) {
 774 			e_notice (
 775 				priv->main, GTK_MESSAGE_ERROR,
 776 				_("An organizer is required."));
 777 			return FALSE;
 778 		}
 779 
 780 		/* Prefer the backend addres if we have one. */
 781 		if (backend_addr != NULL && *backend_addr != '\0') {
 782 			backend_mailto = g_strdup_printf (
 783 				"MAILTO:%s", backend_addr);
 784 			if (g_ascii_strcasecmp (backend_mailto, mailto) == 0) {
 785 				g_free (backend_mailto);
 786 				backend_mailto = NULL;
 787 			}
 788 		}
 789 
 790 		if (backend_mailto == NULL) {
 791 			organizer.cn = name;
 792 			organizer.value = mailto;
 793 			name = mailto = NULL;
 794 		} else {
 795 			organizer.value = backend_mailto;
 796 			organizer.sentby = mailto;
 797 			backend_mailto = mailto = NULL;
 798 		}
 799 
 800 		e_cal_component_set_organizer (comp, &organizer);
 801 
 802 		if (flags & COMP_EDITOR_NEW_ITEM)
 803 			comp_editor_set_needs_send (editor, TRUE);
 804 
 805 		g_free (backend_addr);
 806 		g_free (backend_mailto);
 807 		g_free (name);
 808 		g_free (mailto);
 809 	}
 810 
 811 	comp_editor_set_needs_send (editor, (flags & COMP_EDITOR_IS_SHARED) != 0 &&
 812 		itip_organizer_is_user (e_shell_get_registry (comp_editor_get_shell (editor)), comp, client));
 813 
 814 	return TRUE;
 815 }
 816 
 817 void
 818 memo_page_set_show_categories (MemoPage *page,
 819                                gboolean state)
 820 {
 821 	if (state) {
 822 		gtk_widget_show (page->priv->categories_btn);
 823 		gtk_widget_show (page->priv->categories);
 824 	} else {
 825 		gtk_widget_hide (page->priv->categories_btn);
 826 		gtk_widget_hide (page->priv->categories);
 827 	}
 828 }
 829 
 830 /*If the msg has some value set, the icon should always be set */
 831 void
 832 memo_page_set_info_string (MemoPage *mpage,
 833                            const gchar *icon,
 834                            const gchar *msg)
 835 {
 836 	MemoPagePrivate *priv;
 837 
 838 	priv = mpage->priv;
 839 
 840 	gtk_image_set_from_stock (GTK_IMAGE (priv->info_icon), icon, GTK_ICON_SIZE_BUTTON);
 841 	gtk_label_set_markup (GTK_LABEL (priv->info_string), msg);
 842 
 843 	if (msg && icon)
 844 		gtk_widget_show (priv->info_hbox);
 845 	else
 846 		gtk_widget_hide (priv->info_hbox);
 847 }
 848 
 849 /* Gets the widgets from the XML file and returns if they are all available. */
 850 static gboolean
 851 get_widgets (MemoPage *mpage)
 852 {
 853 	EShell *shell;
 854 	ESourceRegistry *registry;
 855 	CompEditor *editor;
 856 	CompEditorPage *page = COMP_EDITOR_PAGE (mpage);
 857 	GtkEntryCompletion *completion;
 858 	MemoPagePrivate *priv;
 859 	GSList *accel_groups;
 860 	GtkWidget *toplevel;
 861 	GtkWidget *parent;
 862 
 863 	priv = mpage->priv;
 864 
 865 #define GW(name) e_builder_get_widget (priv->builder, name)
 866 
 867 	editor = comp_editor_page_get_editor (page);
 868 	shell = comp_editor_get_shell (editor);
 869 	registry = e_shell_get_registry (shell);
 870 
 871 	priv->main = GW ("memo-page");
 872 	if (!priv->main) {
 873 		g_warning ("couldn't find memo-page!");
 874 		return FALSE;
 875 	}
 876 
 877 	/* Get the GtkAccelGroup from the toplevel window, so we can install
 878 	 * it when the notebook page is mapped. */
 879 	toplevel = gtk_widget_get_toplevel (priv->main);
 880 	accel_groups = gtk_accel_groups_from_object (G_OBJECT (toplevel));
 881 	if (accel_groups)
 882 		page->accel_group = g_object_ref (accel_groups->data);
 883 
 884 	g_object_ref (priv->main);
 885 	parent = gtk_widget_get_parent (priv->main);
 886 	gtk_container_remove (GTK_CONTAINER (parent), priv->main);
 887 
 888 	priv->info_hbox = GW ("generic-info");
 889 	priv->info_icon = GW ("generic-info-image");
 890 	priv->info_string = GW ("generic-info-msgs");
 891 
 892 	priv->org_label = GW ("org-label");
 893 	priv->org_combo = GW ("org-combo");
 894 	gtk_list_store_clear (GTK_LIST_STORE (gtk_combo_box_get_model (GTK_COMBO_BOX (priv->org_combo))));
 895 	gtk_combo_box_set_entry_text_column (GTK_COMBO_BOX (priv->org_combo), 0);
 896 
 897 	priv->to_button = GW ("to-button");
 898 	priv->to_hbox = GW ("to-hbox");
 899 
 900 	priv->summary_label = GW ("sum-label");
 901 	priv->summary_entry = GW ("sum-entry");
 902 
 903 	priv->start_label = GW ("start-label");
 904 	priv->start_date = GW ("start-date");
 905 
 906 	priv->memo_content = GW ("memo_content");
 907 
 908 	priv->categories_btn = GW ("categories-button");
 909 	priv->categories = GW ("categories");
 910 
 911 	priv->source_combo_box = GW ("source");
 912 	e_source_combo_box_set_registry (
 913 		E_SOURCE_COMBO_BOX (priv->source_combo_box), registry);
 914 #undef GW
 915 
 916 	completion = e_category_completion_new ();
 917 	gtk_entry_set_completion (GTK_ENTRY (priv->categories), completion);
 918 	g_object_unref (completion);
 919 
 920 	if (priv->summary_entry) {
 921 		EShell *shell;
 922 		EShellSettings *shell_settings;
 923 		CompEditor *editor;
 924 
 925 		editor = comp_editor_page_get_editor (page);
 926 		shell = comp_editor_get_shell (editor);
 927 		shell_settings = e_shell_get_shell_settings (shell);
 928 
 929 		g_object_bind_property (
 930 			shell_settings, "composer-inline-spelling",
 931 			priv->summary_entry, "checking-enabled",
 932 			G_BINDING_SYNC_CREATE);
 933 	}
 934 
 935 	return (priv->memo_content
 936 		&& priv->categories_btn
 937 		&& priv->categories
 938 		&& priv->start_date);
 939 }
 940 
 941 /* Callback used when the categories button is clicked; we must bring up the
 942  * category list dialog.
 943  */
 944 static void
 945 categories_clicked_cb (GtkWidget *button,
 946                        MemoPage *mpage)
 947 {
 948 	GtkEntry *entry;
 949 
 950 	entry = GTK_ENTRY (mpage->priv->categories);
 951 	e_categories_config_open_dialog_for_entry (entry);
 952 }
 953 
 954 static void
 955 mpage_client_opened_cb (GObject *source_object,
 956                         GAsyncResult *result,
 957                         gpointer user_data)
 958 {
 959 	ESource *source = E_SOURCE (source_object);
 960 	EClient *client = NULL;
 961 	MemoPage *mpage = user_data;
 962 	MemoPagePrivate *priv;
 963 	CompEditor *editor;
 964 	GError *error = NULL;
 965 
 966 	if (!e_client_utils_open_new_finish (source, result, &client, &error)) {
 967 		if (g_error_matches (error, E_CLIENT_ERROR, E_CLIENT_ERROR_CANCELLED) ||
 968 		    g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
 969 			g_clear_error (&error);
 970 			return;
 971 		}
 972 	}
 973 
 974 	editor = comp_editor_page_get_editor (COMP_EDITOR_PAGE (mpage));
 975 	priv = mpage->priv;
 976 
 977 	if (error != NULL) {
 978 		GtkWidget *dialog;
 979 		ECalClient *old_client;
 980 
 981 		old_client = comp_editor_get_client (editor);
 982 
 983 		e_source_combo_box_set_active (
 984 			E_SOURCE_COMBO_BOX (priv->source_combo_box),
 985 			e_client_get_source (E_CLIENT (old_client)));
 986 
 987 		dialog = gtk_message_dialog_new (
 988 			NULL, GTK_DIALOG_MODAL,
 989 			GTK_MESSAGE_WARNING, GTK_BUTTONS_OK,
 990 			_("Unable to open memos in '%s': %s"),
 991 			e_source_get_display_name (source),
 992 			error->message);
 993 		gtk_dialog_run (GTK_DIALOG (dialog));
 994 		gtk_widget_destroy (dialog);
 995 
 996 		g_clear_error (&error);
 997 	} else {
 998 		icaltimezone *zone;
 999 		CompEditorFlags flags;
1000 		ECalClient *cal_client = E_CAL_CLIENT (client);
1001 
1002 		g_return_if_fail (cal_client != NULL);
1003 
1004 		flags = comp_editor_get_flags (editor);
1005 		zone = comp_editor_get_timezone (editor);
1006 		e_cal_client_set_default_timezone (cal_client, zone);
1007 
1008 		comp_editor_set_client (editor, cal_client);
1009 
1010 		if (client) {
1011 			gchar *backend_addr = NULL;
1012 
1013 			e_client_get_backend_property_sync (client, CAL_BACKEND_PROPERTY_CAL_EMAIL_ADDRESS, &backend_addr, NULL, NULL);
1014 
1015 			if (flags & COMP_EDITOR_IS_SHARED)
1016 				memo_page_select_organizer (mpage, backend_addr);
1017 
1018 			set_subscriber_info_string (mpage, backend_addr);
1019 			g_free (backend_addr);
1020 		}
1021 
1022 		sensitize_widgets (mpage);
1023 	}
1024 }
1025 
1026 static void
1027 source_changed_cb (ESourceComboBox *source_combo_box,
1028                    MemoPage *mpage)
1029 {
1030 	MemoPagePrivate *priv = mpage->priv;
1031 	ESource *source;
1032 
1033 	if (comp_editor_page_get_updating (COMP_EDITOR_PAGE (mpage)))
1034 		return;
1035 
1036 	source = e_source_combo_box_ref_active (source_combo_box);
1037 	g_return_if_fail (source != NULL);
1038 
1039 	if (priv->open_cancellable) {
1040 		g_cancellable_cancel (priv->open_cancellable);
1041 		g_object_unref (priv->open_cancellable);
1042 	}
1043 	priv->open_cancellable = g_cancellable_new ();
1044 
1045 	e_client_utils_open_new (
1046 		source, E_CLIENT_SOURCE_TYPE_MEMOS,
1047 		FALSE, priv->open_cancellable,
1048 		mpage_client_opened_cb, mpage);
1049 
1050 	g_object_unref (source);
1051 }
1052 
1053 static void
1054 set_subscriber_info_string (MemoPage *mpage,
1055                             const gchar *backend_address)
1056 {
1057 	if (!check_starts_in_the_past (mpage))
1058 		memo_page_set_info_string (mpage, NULL, NULL);
1059 }
1060 
1061 static void
1062 summary_changed_cb (GtkEntry *entry,
1063                     CompEditorPage *page)
1064 {
1065 	CompEditor *editor;
1066 	const gchar *text;
1067 
1068 	if (comp_editor_page_get_updating (page))
1069 		return;
1070 
1071 	editor = comp_editor_page_get_editor (page);
1072 	text = gtk_entry_get_text (entry);
1073 	comp_editor_set_summary (editor, text);
1074 }
1075 
1076 static void
1077 to_button_clicked_cb (GtkButton *button,
1078                       MemoPage *mpage)
1079 {
1080 	e_name_selector_show_dialog (
1081 		mpage->priv->name_selector,
1082 		mpage->priv->main);
1083 }
1084 
1085 static void
1086 memo_page_start_date_changed_cb (MemoPage *mpage)
1087 {
1088 	check_starts_in_the_past (mpage);
1089 	comp_editor_page_changed (COMP_EDITOR_PAGE (mpage));
1090 }
1091 
1092 /* Hooks the widget signals */
1093 static gboolean
1094 init_widgets (MemoPage *mpage)
1095 {
1096 	CompEditor *editor;
1097 	MemoPagePrivate *priv = mpage->priv;
1098 	GtkTextBuffer *buffer;
1099 	GtkTextView *view;
1100 	GtkAction *action;
1101 	gboolean active;
1102 
1103 	editor = comp_editor_page_get_editor (COMP_EDITOR_PAGE (mpage));
1104 
1105 	/* Generic informative messages */
1106 	gtk_widget_hide (priv->info_hbox);
1107 
1108 	/* Summary */
1109 	g_signal_connect (
1110 		priv->summary_entry, "changed",
1111 		G_CALLBACK (summary_changed_cb), mpage);
1112 
1113 	/* Memo Content */
1114 	view = GTK_TEXT_VIEW (priv->memo_content);
1115 	buffer = gtk_text_view_get_buffer (view);
1116 	gtk_text_view_set_wrap_mode (view, GTK_WRAP_WORD);
1117 	e_buffer_tagger_connect (view);
1118 
1119 	/* Categories button */
1120 	g_signal_connect (
1121 		priv->categories_btn, "clicked",
1122 		G_CALLBACK (categories_clicked_cb), mpage);
1123 
1124 	/* Source selector */
1125 	g_signal_connect (
1126 		priv->source_combo_box, "changed",
1127 		G_CALLBACK (source_changed_cb), mpage);
1128 
1129 	/* Connect the default signal handler to use to make sure the "changed"
1130 	 * field gets set whenever a field is changed. */
1131 
1132 	/* Belongs to priv->memo_content */
1133 	g_signal_connect_swapped (
1134 		buffer, "changed",
1135 		G_CALLBACK (comp_editor_page_changed), mpage);
1136 
1137 	g_signal_connect_swapped (
1138 		priv->categories, "changed",
1139 		G_CALLBACK (comp_editor_page_changed), mpage);
1140 
1141 	g_signal_connect_swapped (
1142 		priv->summary_entry, "changed",
1143 		G_CALLBACK (comp_editor_page_changed), mpage);
1144 
1145 	g_signal_connect_swapped (
1146 		priv->source_combo_box, "changed",
1147 		G_CALLBACK (comp_editor_page_changed), mpage);
1148 
1149 	g_signal_connect_swapped (
1150 		priv->start_date, "changed",
1151 		G_CALLBACK (memo_page_start_date_changed_cb), mpage);
1152 
1153 	if (priv->name_selector) {
1154 		ENameSelectorDialog *name_selector_dialog;
1155 
1156 		name_selector_dialog = e_name_selector_peek_dialog (priv->name_selector);
1157 
1158 		g_signal_connect (
1159 			name_selector_dialog, "response",
1160 			G_CALLBACK (gtk_widget_hide), NULL);
1161 		g_signal_connect (
1162 			priv->to_button, "clicked",
1163 			G_CALLBACK (to_button_clicked_cb), mpage);
1164 		g_signal_connect_swapped (
1165 			priv->to_entry, "changed",
1166 			G_CALLBACK (comp_editor_page_changed), mpage);
1167 	}
1168 
1169 	action = comp_editor_get_action (editor, "view-categories");
1170 	active = gtk_toggle_action_get_active (GTK_TOGGLE_ACTION (action));
1171 	memo_page_set_show_categories (mpage, active);
1172 
1173 	return TRUE;
1174 }
1175 
1176 static GtkWidget *
1177 get_to_entry (ENameSelector *name_selector)
1178 {
1179 	ENameSelectorModel *name_selector_model;
1180 	ENameSelectorEntry *name_selector_entry;
1181 
1182 	name_selector_model = e_name_selector_peek_model (name_selector);
1183 	e_name_selector_model_add_section (name_selector_model, "To", _("To"), NULL);
1184 	name_selector_entry = (ENameSelectorEntry *) e_name_selector_peek_section_list (name_selector, "To");
1185 
1186 	return GTK_WIDGET (name_selector_entry);
1187 }
1188 
1189 static void
1190 memo_page_select_organizer (MemoPage *mpage,
1191                             const gchar *backend_address)
1192 {
1193 	MemoPagePrivate *priv = mpage->priv;
1194 	CompEditor *editor;
1195 	CompEditorFlags flags;
1196 	const gchar *default_address;
1197 	gint ii;
1198 
1199 	/* Treat an empty backend address as NULL. */
1200 	if (backend_address != NULL && *backend_address == '\0')
1201 		backend_address = NULL;
1202 
1203 	editor = comp_editor_page_get_editor (COMP_EDITOR_PAGE (mpage));
1204 	flags = comp_editor_get_flags (editor);
1205 
1206 	default_address = priv->fallback_address;
1207 
1208 	if (backend_address != NULL) {
1209 		for (ii = 0; priv->address_strings[ii] != NULL; ii++) {
1210 			if (g_strrstr (priv->address_strings[ii], backend_address) != NULL) {
1211 				default_address = priv->address_strings[ii];
1212 				break;
1213 			}
1214 		}
1215 	}
1216 
1217 	if (default_address != NULL) {
1218 		if (flags & COMP_EDITOR_NEW_ITEM) {
1219 			gtk_entry_set_text (GTK_ENTRY (gtk_bin_get_child (GTK_BIN (priv->org_combo))), default_address);
1220 		}
1221 	} else
1222 		g_warning ("No potential organizers!");
1223 }
1224 
1225 /**
1226  * memo_page_construct:
1227  * @mpage: An memo page.
1228  *
1229  * Constructs an memo page by loading its Glade data.
1230  *
1231  * Return value: The same object as @mpage, or NULL if the widgets could not be
1232  * created.
1233  **/
1234 MemoPage *
1235 memo_page_construct (MemoPage *mpage)
1236 {
1237 	MemoPagePrivate *priv;
1238 	EShell *shell;
1239 	CompEditor *editor;
1240 	CompEditorFlags flags;
1241 	ESourceRegistry *registry;
1242 
1243 	priv = mpage->priv;
1244 
1245 	editor = comp_editor_page_get_editor (COMP_EDITOR_PAGE (mpage));
1246 
1247 	flags = comp_editor_get_flags (editor);
1248 	shell = comp_editor_get_shell (editor);
1249 
1250 	registry = e_shell_get_registry (shell);
1251 
1252 	/* Make sure our custom widget classes are registered with
1253 	 * GType before we load the GtkBuilder definition file. */
1254 	E_TYPE_DATE_EDIT;
1255 	E_TYPE_SPELL_ENTRY;
1256 
1257 	priv->builder = gtk_builder_new ();
1258 	e_load_ui_builder_definition (priv->builder, "memo-page.ui");
1259 
1260 	if (!get_widgets (mpage)) {
1261 		g_message (
1262 			"memo_page_construct(): "
1263 			"Could not find all widgets in the XML file!");
1264 		return NULL;
1265 	}
1266 
1267 	if (flags & COMP_EDITOR_IS_SHARED) {
1268 		GtkComboBox *combo_box;
1269 		GtkListStore *list_store;
1270 		GtkTreeModel *model;
1271 		GtkTreeIter iter;
1272 		gint ii;
1273 
1274 		combo_box = GTK_COMBO_BOX (priv->org_combo);
1275 		model = gtk_combo_box_get_model (combo_box);
1276 		list_store = GTK_LIST_STORE (model);
1277 
1278 		priv->address_strings = itip_get_user_identities (registry);
1279 		priv->fallback_address = itip_get_fallback_identity (registry);
1280 
1281 		/* FIXME Could we just use a GtkComboBoxText? */
1282 		for (ii = 0; priv->address_strings[ii] != NULL; ii++) {
1283 			gtk_list_store_append (list_store, &iter);
1284 			gtk_list_store_set (
1285 				list_store, &iter,
1286 				0, priv->address_strings[ii], -1);
1287 		}
1288 
1289 		gtk_combo_box_set_active (combo_box, 0);
1290 
1291 		gtk_widget_show (priv->org_label);
1292 		gtk_widget_show (priv->org_combo);
1293 
1294 		priv->name_selector = e_name_selector_new (registry);
1295 		priv->to_entry = get_to_entry (priv->name_selector);
1296 		gtk_container_add ((GtkContainer *) priv->to_hbox, priv->to_entry);
1297 		gtk_widget_show (priv->to_hbox);
1298 		gtk_widget_show (priv->to_entry);
1299 		gtk_widget_show (priv->to_button);
1300 
1301 		if (!(flags & COMP_EDITOR_NEW_ITEM)) {
1302 			gtk_widget_set_sensitive (priv->to_button, FALSE);
1303 			gtk_widget_set_sensitive (priv->to_entry, FALSE);
1304 		}
1305 	}
1306 
1307 	if (!init_widgets (mpage)) {
1308 		g_message ("memo_page_construct(): "
1309 			"Could not initialize the widgets!");
1310 		return NULL;
1311 	}
1312 
1313 	return mpage;
1314 }
1315 
1316 /**
1317  * memo_page_new:
1318  *
1319  * Creates a new memo page.
1320  *
1321  * Return value: A newly-created task page, or NULL if the page could
1322  * not be created.
1323  **/
1324 MemoPage *
1325 memo_page_new (CompEditor *editor)
1326 {
1327 	MemoPage *mpage;
1328 
1329 	g_return_val_if_fail (IS_COMP_EDITOR (editor), NULL);
1330 
1331 	mpage = g_object_new (TYPE_MEMO_PAGE, "editor", editor, NULL);
1332 
1333 	if (!memo_page_construct (mpage)) {
1334 		g_object_unref (mpage);
1335 		g_return_val_if_reached (NULL);
1336 	}
1337 
1338 	return mpage;
1339 }