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 }