evolution-3.6.4/addressbook/gui/widgets/e-addressbook-table-adapter.c

No issues found

  1 /*
  2  * This program is free software; you can redistribute it and/or
  3  * modify it under the terms of the GNU Lesser General Public
  4  * License as published by the Free Software Foundation; either
  5  * version 2 of the License, or (at your option) version 3.
  6  *
  7  * This program is distributed in the hope that it will be useful,
  8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 10  * Lesser General Public License for more details.
 11  *
 12  * You should have received a copy of the GNU Lesser General Public
 13  * License along with the program; if not, see <http://www.gnu.org/licenses/>
 14  *
 15  *
 16  * Authors:
 17  *
 18  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 19  *
 20  */
 21 
 22 #ifdef HAVE_CONFIG_H
 23 #include <config.h>
 24 #endif
 25 
 26 #include <gtk/gtk.h>
 27 #include <glib/gi18n.h>
 28 
 29 #include <libebook/libebook.h>
 30 
 31 #include "e-addressbook-model.h"
 32 #include "e-addressbook-table-adapter.h"
 33 #include "eab-contact-merging.h"
 34 #include "eab-gui-util.h"
 35 #include <libxml/tree.h>
 36 #include <libxml/parser.h>
 37 #include <libxml/xmlmemory.h>
 38 
 39 #define E_ADDRESSBOOK_TABLE_ADAPTER_GET_PRIVATE(obj) \
 40 	(G_TYPE_INSTANCE_GET_PRIVATE \
 41 	((obj), E_TYPE_ADDRESSBOOK_TABLE_ADAPTER, EAddressbookTableAdapterPrivate))
 42 
 43 struct _EAddressbookTableAdapterPrivate {
 44 	EAddressbookModel *model;
 45 
 46 	gint create_contact_id, remove_contact_id, modify_contact_id, model_changed_id;
 47 
 48 	GHashTable *emails;
 49 };
 50 
 51 #define COLS (E_CONTACT_FIELD_LAST)
 52 
 53 G_DEFINE_TYPE (
 54 	EAddressbookTableAdapter,
 55 	e_addressbook_table_adapter,
 56 	E_TYPE_TABLE_MODEL)
 57 
 58 static void
 59 unlink_model (EAddressbookTableAdapter *adapter)
 60 {
 61 	EAddressbookTableAdapterPrivate *priv = adapter->priv;
 62 
 63 	g_signal_handler_disconnect (priv->model, priv->create_contact_id);
 64 	g_signal_handler_disconnect (priv->model, priv->remove_contact_id);
 65 	g_signal_handler_disconnect (priv->model, priv->modify_contact_id);
 66 	g_signal_handler_disconnect (priv->model, priv->model_changed_id);
 67 
 68 	priv->create_contact_id = 0;
 69 	priv->remove_contact_id = 0;
 70 	priv->modify_contact_id = 0;
 71 	priv->model_changed_id = 0;
 72 
 73 	g_object_unref (priv->model);
 74 
 75 	priv->model = NULL;
 76 }
 77 
 78 static void
 79 addressbook_finalize (GObject *object)
 80 {
 81 	EAddressbookTableAdapter *adapter;
 82 
 83 	adapter = E_ADDRESSBOOK_TABLE_ADAPTER (object);
 84 
 85 	unlink_model (adapter);
 86 
 87 	g_hash_table_destroy (adapter->priv->emails);
 88 
 89 	/* Chain up to parent's finalize() method. */
 90 	G_OBJECT_CLASS (e_addressbook_table_adapter_parent_class)->finalize (object);
 91 }
 92 
 93 /* This function returns the number of columns in our ETableModel. */
 94 static gint
 95 addressbook_col_count (ETableModel *etc)
 96 {
 97 	return COLS;
 98 }
 99 
100 /* This function returns the number of rows in our ETableModel. */
101 static gint
102 addressbook_row_count (ETableModel *etc)
103 {
104 	EAddressbookTableAdapter *adapter = E_ADDRESSBOOK_TABLE_ADAPTER (etc);
105 	EAddressbookTableAdapterPrivate *priv = adapter->priv;
106 
107 	return e_addressbook_model_contact_count (priv->model);
108 }
109 
110 /* This function returns the value at a particular point in our ETableModel. */
111 static gpointer
112 addressbook_value_at (ETableModel *etc,
113                       gint col,
114                       gint row)
115 {
116 	EAddressbookTableAdapter *adapter = E_ADDRESSBOOK_TABLE_ADAPTER (etc);
117 	EAddressbookTableAdapterPrivate *priv = adapter->priv;
118 	EContact *contact;
119 	const gchar *value;
120 
121 	if (col >= COLS || row >= e_addressbook_model_contact_count (priv->model))
122 		return NULL;
123 
124 	contact = e_addressbook_model_contact_at (priv->model, row);
125 	value = e_contact_get_const (contact, col);
126 
127 	if (value && *value && (col == E_CONTACT_EMAIL_1 ||
128 	    col == E_CONTACT_EMAIL_2 || col == E_CONTACT_EMAIL_3)) {
129 		gchar *val = g_hash_table_lookup (priv->emails, value);
130 
131 		if (val) {
132 			/* we have this already cached, so use value from the cache */
133 			value = val;
134 		} else {
135 			gchar *name = NULL, *mail = NULL;
136 
137 			if (eab_parse_qp_email (value, &name, &mail))
138 				val = g_strdup_printf ("%s <%s>", name, mail);
139 			else
140 				val = g_strdup (value);
141 
142 			g_free (name);
143 			g_free (mail);
144 
145 			g_hash_table_insert (priv->emails, g_strdup (value), val);
146 			value = val;
147 		}
148 	}
149 
150 	return (gpointer)(value ? value : "");
151 }
152 
153 /* This function sets the value at a particular point in our ETableModel. */
154 static void
155 contact_modified_cb (EBookClient *book_client,
156                      const GError *error,
157                      gpointer user_data)
158 {
159 	if (error)
160 		eab_error_dialog (NULL, _("Error modifying card"), error);
161 }
162 
163 static void
164 addressbook_set_value_at (ETableModel *etc,
165                           gint col,
166                           gint row,
167                           gconstpointer val)
168 {
169 	EAddressbookTableAdapter *adapter = E_ADDRESSBOOK_TABLE_ADAPTER (etc);
170 	EAddressbookTableAdapterPrivate *priv = adapter->priv;
171 
172 	if (e_addressbook_model_get_editable (priv->model)) {
173 		ESourceRegistry *registry;
174 		EBookClient *book_client;
175 		EContact *contact;
176 
177 		registry = e_addressbook_model_get_registry (priv->model);
178 		book_client = e_addressbook_model_get_client (priv->model);
179 
180 		if (col >= COLS || row >= e_addressbook_model_contact_count (priv->model))
181 			return;
182 
183 		contact = e_addressbook_model_get_contact (priv->model, row);
184 		if (!contact)
185 			return;
186 
187 		e_table_model_pre_change (etc);
188 
189 		if (col == E_CONTACT_EMAIL_1 ||
190 		    col == E_CONTACT_EMAIL_2 ||
191 		    col == E_CONTACT_EMAIL_3) {
192 			const gchar *old_value = e_contact_get_const (contact, col);
193 
194 			/* remove old value from cache and use new one */
195 			if (old_value && *old_value)
196 				g_hash_table_remove (priv->emails, old_value);
197 		}
198 
199 		e_contact_set (contact, col, (gpointer) val);
200 		eab_merging_book_modify_contact (
201 			registry, book_client,
202 			contact, contact_modified_cb, etc);
203 
204 		g_object_unref (contact);
205 
206 		/* XXX Do we need this?  Shouldn't the commit_contact
207 		 *     generate a changed signal? */
208 		e_table_model_cell_changed (etc, col, row);
209 	}
210 }
211 
212 /* This function returns whether a particular cell is editable. */
213 static gboolean
214 addressbook_is_cell_editable (ETableModel *etc,
215                               gint col,
216                               gint row)
217 {
218 	return FALSE;
219 }
220 
221 static void
222 addressbook_append_row (ETableModel *etm,
223                         ETableModel *source,
224                         gint row)
225 {
226 	EAddressbookTableAdapter *adapter = E_ADDRESSBOOK_TABLE_ADAPTER (etm);
227 	EAddressbookTableAdapterPrivate *priv = adapter->priv;
228 	ESourceRegistry *registry;
229 	EBookClient *book_client;
230 	EContact *contact;
231 	gint col;
232 
233 	contact = e_contact_new ();
234 
235 	for (col = 1; col < E_CONTACT_LAST_SIMPLE_STRING; col++) {
236 		gconstpointer val = e_table_model_value_at (source, col, row);
237 		e_contact_set (contact, col, (gpointer) val);
238 	}
239 
240 	registry = e_addressbook_model_get_registry (priv->model);
241 	book_client = e_addressbook_model_get_client (priv->model);
242 
243 	eab_merging_book_add_contact (
244 		registry, book_client, contact, NULL, NULL);
245 
246 	g_object_unref (contact);
247 }
248 
249 /* This function duplicates the value passed to it. */
250 static gpointer
251 addressbook_duplicate_value (ETableModel *etc,
252                              gint col,
253                              gconstpointer value)
254 {
255 	return g_strdup (value);
256 }
257 
258 /* This function frees the value passed to it. */
259 static void
260 addressbook_free_value (ETableModel *etc,
261                         gint col,
262                         gpointer value)
263 {
264 	g_free (value);
265 }
266 
267 static gpointer
268 addressbook_initialize_value (ETableModel *etc,
269                               gint col)
270 {
271 	return g_strdup ("");
272 }
273 
274 static gboolean
275 addressbook_value_is_empty (ETableModel *etc,
276                             gint col,
277                             gconstpointer value)
278 {
279 	return !(value && *(gchar *) value);
280 }
281 
282 static gchar *
283 addressbook_value_to_string (ETableModel *etc,
284                              gint col,
285                              gconstpointer value)
286 {
287 	return g_strdup (value);
288 }
289 
290 static void
291 e_addressbook_table_adapter_class_init (EAddressbookTableAdapterClass *class)
292 {
293 	GObjectClass *object_class;
294 	ETableModelClass *model_class;
295 
296 	g_type_class_add_private (
297 		class, sizeof (EAddressbookTableAdapterPrivate));
298 
299 	object_class = G_OBJECT_CLASS (class);
300 	object_class->finalize = addressbook_finalize;
301 
302 	model_class = E_TABLE_MODEL_CLASS (class);
303 	model_class->column_count = addressbook_col_count;
304 	model_class->row_count = addressbook_row_count;
305 	model_class->value_at = addressbook_value_at;
306 	model_class->set_value_at = addressbook_set_value_at;
307 	model_class->is_cell_editable = addressbook_is_cell_editable;
308 	model_class->append_row = addressbook_append_row;
309 	model_class->duplicate_value = addressbook_duplicate_value;
310 	model_class->free_value = addressbook_free_value;
311 	model_class->initialize_value = addressbook_initialize_value;
312 	model_class->value_is_empty = addressbook_value_is_empty;
313 	model_class->value_to_string = addressbook_value_to_string;
314 }
315 
316 static void
317 e_addressbook_table_adapter_init (EAddressbookTableAdapter *adapter)
318 {
319 	adapter->priv = E_ADDRESSBOOK_TABLE_ADAPTER_GET_PRIVATE (adapter);
320 }
321 
322 static void
323 create_contact (EAddressbookModel *model,
324                 gint index,
325                 gint count,
326                 EAddressbookTableAdapter *adapter)
327 {
328 	e_table_model_pre_change (E_TABLE_MODEL (adapter));
329 	e_table_model_rows_inserted (E_TABLE_MODEL (adapter), index, count);
330 }
331 
332 static void
333 remove_contacts (EAddressbookModel *model,
334                 gpointer data,
335                 EAddressbookTableAdapter *adapter)
336 {
337 	GArray *indices = (GArray *) data;
338 	gint count = indices->len;
339 
340 	/* clear whole cache */
341 	g_hash_table_remove_all (adapter->priv->emails);
342 
343 	e_table_model_pre_change (E_TABLE_MODEL (adapter));
344 	if (count == 1)
345 		e_table_model_rows_deleted (
346 			E_TABLE_MODEL (adapter),
347 			g_array_index (indices, gint, 0), 1);
348 	else
349 		e_table_model_changed (E_TABLE_MODEL (adapter));
350 }
351 
352 static void
353 modify_contact (EAddressbookModel *model,
354                 gint index,
355                 EAddressbookTableAdapter *adapter)
356 {
357 	/* clear whole cache */
358 	g_hash_table_remove_all (adapter->priv->emails);
359 
360 	e_table_model_pre_change (E_TABLE_MODEL (adapter));
361 	e_table_model_row_changed (E_TABLE_MODEL (adapter), index);
362 }
363 
364 static void
365 model_changed (EAddressbookModel *model,
366                EAddressbookTableAdapter *adapter)
367 {
368 	/* clear whole cache */
369 	g_hash_table_remove_all (adapter->priv->emails);
370 
371 	e_table_model_pre_change (E_TABLE_MODEL (adapter));
372 	e_table_model_changed (E_TABLE_MODEL (adapter));
373 }
374 
375 void
376 e_addressbook_table_adapter_construct (EAddressbookTableAdapter *adapter,
377                                        EAddressbookModel *model)
378 {
379 	EAddressbookTableAdapterPrivate *priv = adapter->priv;
380 
381 	priv->model = model;
382 	g_object_ref (priv->model);
383 
384 	priv->create_contact_id = g_signal_connect (
385 		priv->model, "contact_added",
386 		G_CALLBACK (create_contact), adapter);
387 
388 	priv->remove_contact_id = g_signal_connect (
389 		priv->model, "contacts_removed",
390 		G_CALLBACK (remove_contacts), adapter);
391 
392 	priv->modify_contact_id = g_signal_connect (
393 		priv->model, "contact_changed",
394 		G_CALLBACK (modify_contact), adapter);
395 
396 	priv->model_changed_id = g_signal_connect (
397 		priv->model, "model_changed",
398 		G_CALLBACK (model_changed), adapter);
399 
400 	priv->emails = g_hash_table_new_full (
401 		g_str_hash, g_str_equal,
402 		(GDestroyNotify) g_free,
403 		(GDestroyNotify) g_free);
404 }
405 
406 ETableModel *
407 e_addressbook_table_adapter_new (EAddressbookModel *model)
408 {
409 	EAddressbookTableAdapter *et;
410 
411 	et = g_object_new (E_TYPE_ADDRESSBOOK_TABLE_ADAPTER, NULL);
412 
413 	e_addressbook_table_adapter_construct (et, model);
414 
415 	return E_TABLE_MODEL (et);
416 }