evolution-3.6.4/widgets/table/e-table-without.c

No issues found

  1 /*
  2  *
  3  * This program is free software; you can redistribute it and/or
  4  * modify it under the terms of the GNU Lesser General Public
  5  * License as published by the Free Software Foundation; either
  6  * version 2 of the License, or (at your option) version 3.
  7  *
  8  * This program is distributed in the hope that it will be useful,
  9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 11  * Lesser General Public License for more details.
 12  *
 13  * You should have received a copy of the GNU Lesser General Public
 14  * License along with the program; if not, see <http://www.gnu.org/licenses/>
 15  *
 16  *
 17  * Authors:
 18  *		Chris Lahey <clahey@ximian.com>
 19  *
 20  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 21  *
 22  */
 23 
 24 #ifdef HAVE_CONFIG_H
 25 #include <config.h>
 26 #endif
 27 
 28 #include <stdlib.h>
 29 #include <string.h>
 30 
 31 #include "e-util/e-util.h"
 32 
 33 #include "e-table-without.h"
 34 
 35 #define E_TABLE_WITHOUT_GET_PRIVATE(obj) \
 36 	(G_TYPE_INSTANCE_GET_PRIVATE \
 37 	((obj), E_TYPE_TABLE_WITHOUT, ETableWithoutPrivate))
 38 
 39 /* workaround for avoiding API breakage */
 40 #define etw_get_type e_table_without_get_type
 41 G_DEFINE_TYPE (ETableWithout, etw, E_TYPE_TABLE_SUBSET)
 42 
 43 #define INCREMENT_AMOUNT 10
 44 
 45 struct _ETableWithoutPrivate {
 46 	GHashTable *hash;
 47 
 48 	GHashFunc hash_func;
 49 	GCompareFunc compare_func;
 50 
 51 	ETableWithoutGetKeyFunc get_key_func;
 52 	ETableWithoutDuplicateKeyFunc duplicate_key_func;
 53 	ETableWithoutFreeKeyFunc free_gotten_key_func;
 54 	ETableWithoutFreeKeyFunc free_duplicated_key_func;
 55 
 56 	gpointer closure;
 57 };
 58 
 59 static gboolean
 60 check (ETableWithout *etw,
 61        gint model_row)
 62 {
 63 	gboolean ret_val;
 64 	gpointer key;
 65 	ETableSubset *etss = E_TABLE_SUBSET (etw);
 66 
 67 	if (etw->priv->get_key_func)
 68 		key = etw->priv->get_key_func (etss->source, model_row, etw->priv->closure);
 69 	else
 70 		key = GINT_TO_POINTER (model_row);
 71 	ret_val = (g_hash_table_lookup (etw->priv->hash, key) != NULL);
 72 	if (etw->priv->free_gotten_key_func)
 73 		etw->priv->free_gotten_key_func (key, etw->priv->closure);
 74 	return ret_val;
 75 }
 76 
 77 static gboolean
 78 check_with_key (ETableWithout *etw,
 79                 gpointer key,
 80                 gint model_row)
 81 {
 82 	gboolean ret_val;
 83 	gpointer key2;
 84 	ETableSubset *etss = E_TABLE_SUBSET (etw);
 85 
 86 	if (etw->priv->get_key_func)
 87 		key2 = etw->priv->get_key_func (etss->source, model_row, etw->priv->closure);
 88 	else
 89 		key2 = GINT_TO_POINTER (model_row);
 90 	if (etw->priv->compare_func)
 91 		ret_val = (etw->priv->compare_func (key, key2));
 92 	else
 93 		ret_val = (key == key2);
 94 	if (etw->priv->free_gotten_key_func)
 95 		etw->priv->free_gotten_key_func (key2, etw->priv->closure);
 96 	return ret_val;
 97 }
 98 
 99 static gint
100 etw_view_to_model_row (ETableWithout *etw,
101                        gint view_row)
102 {
103 	ETableSubset *etss = E_TABLE_SUBSET (etw);
104 	return etss->map_table[view_row];
105 }
106 
107 static void
108 add_row (ETableWithout *etw,
109          gint model_row)
110 {
111 	ETableSubset *etss = E_TABLE_SUBSET (etw);
112 
113 	e_table_model_pre_change (E_TABLE_MODEL (etw));
114 
115 	etss->map_table = g_renew (int, etss->map_table, etss->n_map + 1);
116 
117 	etss->map_table[etss->n_map++] = model_row;
118 
119 	e_table_model_row_inserted (E_TABLE_MODEL (etw), etss->n_map - 1);
120 }
121 
122 static void
123 remove_row (ETableWithout *etw,
124             gint view_row)
125 {
126 	ETableSubset *etss = E_TABLE_SUBSET (etw);
127 
128 	e_table_model_pre_change (E_TABLE_MODEL (etw));
129 	memmove (
130 		etss->map_table + view_row,
131 		etss->map_table + view_row + 1,
132 		(etss->n_map - view_row - 1) * sizeof (gint));
133 	etss->n_map--;
134 	e_table_model_row_deleted (E_TABLE_MODEL (etw), view_row);
135 }
136 
137 static void
138 delete_hash_element (gpointer key,
139                      gpointer value,
140                      gpointer closure)
141 {
142 	ETableWithout *etw = closure;
143 	if (etw->priv->free_duplicated_key_func)
144 		etw->priv->free_duplicated_key_func (key, etw->priv->closure);
145 }
146 
147 static void
148 etw_dispose (GObject *object)
149 {
150 	ETableWithoutPrivate *priv;
151 
152 	priv = E_TABLE_WITHOUT_GET_PRIVATE (object);
153 
154 	if (priv->hash != NULL) {
155 		g_hash_table_foreach (priv->hash, delete_hash_element, object);
156 		g_hash_table_destroy (priv->hash);
157 		priv->hash = NULL;
158 	}
159 
160 	/* Chain up to parent's dispose() method. */
161 	G_OBJECT_CLASS (etw_parent_class)->dispose (object);
162 }
163 
164 static void
165 etw_proxy_model_rows_inserted (ETableSubset *etss,
166                                ETableModel *etm,
167                                gint model_row,
168                                gint count)
169 {
170 	gint i;
171 	ETableWithout *etw = E_TABLE_WITHOUT (etss);
172 	gboolean shift = FALSE;
173 
174 	/* i is View row */
175 	if (model_row != etss->n_map) {
176 		for (i = 0; i < etss->n_map; i++) {
177 			if (etss->map_table[i] > model_row)
178 				etss->map_table[i] += count;
179 		}
180 		shift = TRUE;
181 	}
182 
183 	/* i is Model row */
184 	for (i = model_row; i < model_row + count; i++) {
185 		if (!check (etw, i)) {
186 			add_row (etw, i);
187 		}
188 	}
189 	if (shift)
190 		e_table_model_changed (E_TABLE_MODEL (etw));
191 	else
192 		e_table_model_no_change (E_TABLE_MODEL (etw));
193 }
194 
195 static void
196 etw_proxy_model_rows_deleted (ETableSubset *etss,
197                               ETableModel *etm,
198                               gint model_row,
199                               gint count)
200 {
201 	gint i; /* View row */
202 	ETableWithout *etw = E_TABLE_WITHOUT (etss);
203 	gboolean shift = FALSE;
204 
205 	for (i = 0; i < etss->n_map; i++) {
206 		if (etss->map_table[i] >= model_row &&
207 		    etss->map_table[i] < model_row + count) {
208 			remove_row (etw, i);
209 			i--;
210 		} else if (etss->map_table[i] >= model_row + count) {
211 			etss->map_table[i] -= count;
212 			shift = TRUE;
213 		}
214 	}
215 	if (shift)
216 		e_table_model_changed (E_TABLE_MODEL (etw));
217 	else
218 		e_table_model_no_change (E_TABLE_MODEL (etw));
219 }
220 
221 static void
222 etw_proxy_model_changed (ETableSubset *etss,
223                          ETableModel *etm)
224 {
225 	gint i; /* Model row */
226 	gint j; /* View row */
227 	gint row_count;
228 	ETableWithout *etw = E_TABLE_WITHOUT (etss);
229 
230 	g_free (etss->map_table);
231 	row_count = e_table_model_row_count (etm);
232 	etss->map_table = g_new (int, row_count);
233 
234 	for (i = 0, j = 0; i < row_count; i++) {
235 		if (!check (etw, i)) {
236 			etss->map_table[j++] = i;
237 		}
238 	}
239 	etss->n_map = j;
240 
241 	if (E_TABLE_SUBSET_CLASS (etw_parent_class)->proxy_model_changed)
242 		E_TABLE_SUBSET_CLASS (etw_parent_class)->proxy_model_changed (etss, etm);
243 }
244 
245 static void
246 etw_class_init (ETableWithoutClass *class)
247 {
248 	GObjectClass *object_class;
249 	ETableSubsetClass *etss_class;
250 
251 	g_type_class_add_private (class, sizeof (ETableWithoutPrivate));
252 
253 	object_class = G_OBJECT_CLASS (class);
254 	object_class->dispose = etw_dispose;
255 
256 	etss_class = E_TABLE_SUBSET_CLASS (class);
257 	etss_class->proxy_model_rows_inserted = etw_proxy_model_rows_inserted;
258 	etss_class->proxy_model_rows_deleted  = etw_proxy_model_rows_deleted;
259 	etss_class->proxy_model_changed = etw_proxy_model_changed;
260 }
261 
262 static void
263 etw_init (ETableWithout *etw)
264 {
265 	etw->priv = E_TABLE_WITHOUT_GET_PRIVATE (etw);
266 }
267 
268 ETableModel *
269 e_table_without_construct (ETableWithout *etw,
270                            ETableModel *source,
271                            GHashFunc hash_func,
272                            GCompareFunc compare_func,
273                            ETableWithoutGetKeyFunc get_key_func,
274                            ETableWithoutDuplicateKeyFunc duplicate_key_func,
275                            ETableWithoutFreeKeyFunc free_gotten_key_func,
276                            ETableWithoutFreeKeyFunc free_duplicated_key_func,
277                            gpointer closure)
278 {
279 	if (e_table_subset_construct (E_TABLE_SUBSET (etw), source, 1) == NULL)
280 		return NULL;
281 	E_TABLE_SUBSET (etw)->n_map = 0;
282 
283 	etw->priv->hash_func                = hash_func;
284 	etw->priv->compare_func	    = compare_func;
285 	etw->priv->get_key_func	    = get_key_func;
286 	etw->priv->duplicate_key_func	    = duplicate_key_func;
287 	etw->priv->free_gotten_key_func     = free_gotten_key_func;
288 	etw->priv->free_duplicated_key_func = free_duplicated_key_func;
289 	etw->priv->closure                  = closure;
290 
291 	etw->priv->hash = g_hash_table_new (
292 		etw->priv->hash_func, etw->priv->compare_func);
293 
294 	return E_TABLE_MODEL (etw);
295 }
296 
297 ETableModel *
298 e_table_without_new (ETableModel *source,
299                      GHashFunc hash_func,
300                      GCompareFunc compare_func,
301                      ETableWithoutGetKeyFunc get_key_func,
302                      ETableWithoutDuplicateKeyFunc duplicate_key_func,
303                      ETableWithoutFreeKeyFunc free_gotten_key_func,
304                      ETableWithoutFreeKeyFunc free_duplicated_key_func,
305                      gpointer closure)
306 {
307 	ETableWithout *etw = g_object_new (E_TYPE_TABLE_WITHOUT, NULL);
308 
309 	if (e_table_without_construct (etw,
310 				       source,
311 				       hash_func,
312 				       compare_func,
313 				       get_key_func,
314 				       duplicate_key_func,
315 				       free_gotten_key_func,
316 				       free_duplicated_key_func,
317 				       closure)
318 	    == NULL) {
319 		g_object_unref (etw);
320 		return NULL;
321 	}
322 
323 	return (ETableModel *) etw;
324 }
325 
326 void
327 e_table_without_hide (ETableWithout *etw,
328                       gpointer key)
329 {
330 	gint i; /* View row */
331 	ETableSubset *etss = E_TABLE_SUBSET (etw);
332 
333 	if (etw->priv->duplicate_key_func)
334 		key = etw->priv->duplicate_key_func (key, etw->priv->closure);
335 
336 	g_hash_table_insert (etw->priv->hash, key, key);
337 	for (i = 0; i < etss->n_map; i++) {
338 		if (check_with_key (etw, key, etw_view_to_model_row (etw, i))) {
339 			remove_row (etw, i);
340 			i--;
341 		}
342 	}
343 }
344 
345 /* An adopted key will later be freed using the free_duplicated_key function. */
346 void
347 e_table_without_hide_adopt (ETableWithout *etw,
348                             gpointer key)
349 {
350 	gint i; /* View row */
351 	ETableSubset *etss = E_TABLE_SUBSET (etw);
352 
353 	g_hash_table_insert (etw->priv->hash, key, key);
354 	for (i = 0; i < etss->n_map; i++) {
355 		if (check_with_key (etw, key, etw_view_to_model_row (etw, i))) {
356 			remove_row (etw, i);
357 			i--;
358 		}
359 	}
360 }
361 
362 void
363 e_table_without_show (ETableWithout *etw,
364                       gpointer key)
365 {
366 	gint i; /* Model row */
367 	ETableSubset *etss = E_TABLE_SUBSET (etw);
368 	gint count;
369 	gpointer old_key;
370 
371 	count = e_table_model_row_count (etss->source);
372 
373 	for (i = 0; i < count; i++) {
374 		if (check_with_key (etw, key, i)) {
375 			add_row (etw, i);
376 		}
377 	}
378 	if (g_hash_table_lookup_extended (etw->priv->hash, key, &old_key, NULL)) {
379 #if 0
380 		if (etw->priv->free_duplicated_key_func)
381 			etw->priv->free_duplicated_key_func (key, etw->priv->closure);
382 #endif
383 		g_hash_table_remove (etw->priv->hash, key);
384 	}
385 }
386 
387 void
388 e_table_without_show_all (ETableWithout *etw)
389 {
390 	gint i; /* Model row */
391 	gint row_count;
392 	ETableSubset *etss = E_TABLE_SUBSET (etw);
393 
394 	e_table_model_pre_change (E_TABLE_MODEL (etw));
395 
396 	if (etw->priv->hash) {
397 		g_hash_table_foreach (etw->priv->hash, delete_hash_element, etw);
398 		g_hash_table_destroy (etw->priv->hash);
399 		etw->priv->hash = NULL;
400 	}
401 	etw->priv->hash = g_hash_table_new (
402 		etw->priv->hash_func, etw->priv->compare_func);
403 
404 	row_count = e_table_model_row_count (E_TABLE_MODEL (etss->source));
405 	g_free (etss->map_table);
406 	etss->map_table = g_new (int, row_count);
407 
408 	for (i = 0; i < row_count; i++) {
409 		etss->map_table[i] = i;
410 	}
411 	etss->n_map = row_count;
412 
413 	e_table_model_changed (E_TABLE_MODEL (etw));
414 }