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

No issues found

  1 /*
  2  * e-table-extras.c - Set of hash table sort of thingies.
  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  *		Chris Lahey <clahey@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 <stdlib.h>
 30 #include <string.h>
 31 
 32 #include <gtk/gtk.h>
 33 
 34 #include "e-util/e-util.h"
 35 
 36 #include "e-cell-checkbox.h"
 37 #include "e-cell-date.h"
 38 #include "e-cell-number.h"
 39 #include "e-cell-pixbuf.h"
 40 #include "e-cell-size.h"
 41 #include "e-cell-text.h"
 42 #include "e-cell-tree.h"
 43 #include "e-table-extras.h"
 44 #include "e-table-sorting-utils.h"
 45 
 46 #define E_TABLE_EXTRAS_GET_PRIVATE(obj) \
 47 	(G_TYPE_INSTANCE_GET_PRIVATE \
 48 	((obj), E_TYPE_TABLE_EXTRAS, ETableExtrasPrivate))
 49 
 50 struct _ETableExtrasPrivate {
 51 	GHashTable *cells;
 52 	GHashTable *compares;
 53 	GHashTable *icon_names;
 54 	GHashTable *searches;
 55 };
 56 
 57 /* workaround for avoiding API breakage */
 58 #define ete_get_type e_table_extras_get_type
 59 G_DEFINE_TYPE (ETableExtras, ete, G_TYPE_OBJECT)
 60 
 61 static void
 62 ete_finalize (GObject *object)
 63 {
 64 	ETableExtrasPrivate *priv;
 65 
 66 	priv = E_TABLE_EXTRAS_GET_PRIVATE (object);
 67 
 68 	if (priv->cells) {
 69 		g_hash_table_destroy (priv->cells);
 70 		priv->cells = NULL;
 71 	}
 72 
 73 	if (priv->compares) {
 74 		g_hash_table_destroy (priv->compares);
 75 		priv->compares = NULL;
 76 	}
 77 
 78 	if (priv->searches) {
 79 		g_hash_table_destroy (priv->searches);
 80 		priv->searches = NULL;
 81 	}
 82 
 83 	if (priv->icon_names) {
 84 		g_hash_table_destroy (priv->icon_names);
 85 		priv->icon_names = NULL;
 86 	}
 87 
 88 	G_OBJECT_CLASS (ete_parent_class)->finalize (object);
 89 }
 90 
 91 static void
 92 ete_class_init (ETableExtrasClass *class)
 93 {
 94 	GObjectClass *object_class;
 95 
 96 	g_type_class_add_private (class, sizeof (ETableExtrasPrivate));
 97 
 98 	object_class = G_OBJECT_CLASS (class);
 99 	object_class->finalize = ete_finalize;
100 }
101 
102 static gint
103 e_strint_compare (gconstpointer data1,
104                   gconstpointer data2)
105 {
106 	gint int1 = atoi (data1);
107 	gint int2 = atoi (data2);
108 
109 	return e_int_compare (GINT_TO_POINTER (int1), GINT_TO_POINTER (int2));
110 }
111 
112 /* UTF-8 strncasecmp - not optimized */
113 
114 static gint
115 g_utf8_strncasecmp (const gchar *s1,
116                     const gchar *s2,
117                     guint n)
118 {
119 	gunichar c1, c2;
120 
121 	g_return_val_if_fail (s1 != NULL && g_utf8_validate (s1, -1, NULL), 0);
122 	g_return_val_if_fail (s2 != NULL && g_utf8_validate (s2, -1, NULL), 0);
123 
124 	while (n && *s1 && *s2)
125 		{
126 
127 			n -= 1;
128 
129 			c1 = g_unichar_tolower (g_utf8_get_char (s1));
130 			c2 = g_unichar_tolower (g_utf8_get_char (s2));
131 
132 			/* Collation is locale-dependent, so this
133 			 * totally fails to do the right thing. */
134 			if (c1 != c2)
135 				return c1 < c2 ? -1 : 1;
136 
137 			s1 = g_utf8_next_char (s1);
138 			s2 = g_utf8_next_char (s2);
139 		}
140 
141 	if (n == 0 || (*s1 == '\0' && *s2 == '\0'))
142 		return 0;
143 
144 	return *s1 ? 1 : -1;
145 }
146 
147 static gboolean
148 e_string_search (gconstpointer haystack,
149                  const gchar *needle)
150 {
151 	gint length;
152 	if (haystack == NULL)
153 		return FALSE;
154 
155 	length = g_utf8_strlen (needle, -1);
156 	if (g_utf8_strncasecmp (haystack, needle, length) == 0)
157 		return TRUE;
158 	else
159 		return FALSE;
160 }
161 
162 static gint
163 e_table_str_case_compare (gconstpointer x,
164                           gconstpointer y,
165                           gpointer cmp_cache)
166 {
167 	const gchar *cx = NULL, *cy = NULL;
168 
169 	if (!cmp_cache)
170 		return e_str_case_compare (x, y);
171 
172 	if (x == NULL || y == NULL) {
173 		if (x == y)
174 			return 0;
175 		else
176 			return x ? -1 : 1;
177 	}
178 
179 	#define prepare_value(_z, _cz)						\
180 		_cz = e_table_sorting_utils_lookup_cmp_cache (cmp_cache, _z);	\
181 		if (!_cz) {							\
182 			gchar *tmp = g_utf8_casefold (_z, -1);			\
183 			_cz = g_utf8_collate_key (tmp, -1);			\
184 			g_free (tmp);						\
185 										\
186 			e_table_sorting_utils_add_to_cmp_cache (		\
187 				cmp_cache, _z, (gchar *) _cz);			\
188 		}
189 
190 	prepare_value (x, cx);
191 	prepare_value (y, cy);
192 
193 	#undef prepare_value
194 
195 	return strcmp (cx, cy);
196 }
197 
198 static gint
199 e_table_collate_compare (gconstpointer x,
200                          gconstpointer y,
201                          gpointer cmp_cache)
202 {
203 	const gchar *cx = NULL, *cy = NULL;
204 
205 	if (!cmp_cache)
206 		return e_collate_compare (x, y);
207 
208 	if (x == NULL || y == NULL) {
209 		if (x == y)
210 			return 0;
211 		else
212 			return x ? -1 : 1;
213 	}
214 
215 	#define prepare_value(_z, _cz)						\
216 		_cz = e_table_sorting_utils_lookup_cmp_cache (cmp_cache, _z);	\
217 		if (!_cz) {							\
218 			_cz = g_utf8_collate_key (_z, -1);			\
219 										\
220 			e_table_sorting_utils_add_to_cmp_cache (		\
221 				cmp_cache, _z, (gchar *) _cz);			\
222 		}
223 
224 	prepare_value (x, cx);
225 	prepare_value (y, cy);
226 
227 	#undef prepare_value
228 
229 	return strcmp (cx, cy);
230 }
231 
232 static void
233 safe_unref (gpointer object)
234 {
235 	if (object != NULL)
236 		g_object_unref (object);
237 }
238 
239 static void
240 ete_init (ETableExtras *extras)
241 {
242 	ECell *cell, *sub_cell;
243 
244 	extras->priv = E_TABLE_EXTRAS_GET_PRIVATE (extras);
245 
246 	extras->priv->cells = g_hash_table_new_full (
247 		g_str_hash, g_str_equal,
248 		(GDestroyNotify) g_free,
249 		(GDestroyNotify) safe_unref);
250 
251 	extras->priv->compares = g_hash_table_new_full (
252 		g_str_hash, g_str_equal,
253 		(GDestroyNotify) g_free,
254 		(GDestroyNotify) NULL);
255 
256 	extras->priv->icon_names = g_hash_table_new_full (
257 		g_str_hash, g_str_equal,
258 		(GDestroyNotify) g_free,
259 		(GDestroyNotify) g_free);
260 
261 	extras->priv->searches = g_hash_table_new_full (
262 		g_str_hash, g_str_equal,
263 		(GDestroyNotify) g_free,
264 		(GDestroyNotify) NULL);
265 
266 	e_table_extras_add_compare (
267 		extras, "string",
268 		(GCompareDataFunc) e_str_compare);
269 	e_table_extras_add_compare (
270 		extras, "stringcase",
271 		(GCompareDataFunc) e_table_str_case_compare);
272 	e_table_extras_add_compare (
273 		extras, "collate",
274 		(GCompareDataFunc) e_table_collate_compare);
275 	e_table_extras_add_compare (
276 		extras, "integer",
277 		(GCompareDataFunc) e_int_compare);
278 	e_table_extras_add_compare (
279 		extras, "string-integer",
280 		(GCompareDataFunc) e_strint_compare);
281 
282 	e_table_extras_add_search (extras, "string", e_string_search);
283 
284 	cell = e_cell_checkbox_new ();
285 	e_table_extras_add_cell (extras, "checkbox", cell);
286 	g_object_unref (cell);
287 
288 	cell = e_cell_date_new (NULL, GTK_JUSTIFY_LEFT);
289 	e_table_extras_add_cell (extras, "date", cell);
290 	g_object_unref (cell);
291 
292 	cell = e_cell_number_new (NULL, GTK_JUSTIFY_RIGHT);
293 	e_table_extras_add_cell (extras, "number", cell);
294 	g_object_unref (cell);
295 
296 	cell = e_cell_pixbuf_new ();
297 	e_table_extras_add_cell (extras, "pixbuf", cell);
298 	g_object_unref (cell);
299 
300 	cell = e_cell_size_new (NULL, GTK_JUSTIFY_RIGHT);
301 	e_table_extras_add_cell (extras, "size", cell);
302 	g_object_unref (cell);
303 
304 	cell = e_cell_text_new (NULL, GTK_JUSTIFY_LEFT);
305 	e_table_extras_add_cell (extras, "string", cell);
306 	g_object_unref (cell);
307 
308 	sub_cell = e_cell_text_new (NULL, GTK_JUSTIFY_LEFT);
309 	cell = e_cell_tree_new (TRUE, sub_cell);
310 	e_table_extras_add_cell (extras, "tree-string", cell);
311 	g_object_unref (sub_cell);
312 	g_object_unref (cell);
313 }
314 
315 ETableExtras *
316 e_table_extras_new (void)
317 {
318 	return g_object_new (E_TYPE_TABLE_EXTRAS, NULL);
319 }
320 
321 void
322 e_table_extras_add_cell (ETableExtras *extras,
323                          const gchar *id,
324                          ECell *cell)
325 {
326 	g_return_if_fail (E_IS_TABLE_EXTRAS (extras));
327 	g_return_if_fail (id != NULL);
328 
329 	if (cell != NULL)
330 		g_object_ref_sink (cell);
331 
332 	g_hash_table_insert (extras->priv->cells, g_strdup (id), cell);
333 }
334 
335 ECell *
336 e_table_extras_get_cell (ETableExtras *extras,
337                          const gchar *id)
338 {
339 	g_return_val_if_fail (E_IS_TABLE_EXTRAS (extras), NULL);
340 	g_return_val_if_fail (id != NULL, NULL);
341 
342 	return g_hash_table_lookup (extras->priv->cells, id);
343 }
344 
345 void
346 e_table_extras_add_compare (ETableExtras *extras,
347                             const gchar *id,
348                             GCompareDataFunc compare)
349 {
350 	g_return_if_fail (E_IS_TABLE_EXTRAS (extras));
351 	g_return_if_fail (id != NULL);
352 
353 	g_hash_table_insert (
354 		extras->priv->compares,
355 		g_strdup (id), (gpointer) compare);
356 }
357 
358 GCompareDataFunc
359 e_table_extras_get_compare (ETableExtras *extras,
360                             const gchar *id)
361 {
362 	g_return_val_if_fail (E_IS_TABLE_EXTRAS (extras), NULL);
363 	g_return_val_if_fail (id != NULL, NULL);
364 
365 	return g_hash_table_lookup (extras->priv->compares, id);
366 }
367 
368 void
369 e_table_extras_add_search (ETableExtras *extras,
370                            const gchar *id,
371                            ETableSearchFunc search)
372 {
373 	g_return_if_fail (E_IS_TABLE_EXTRAS (extras));
374 	g_return_if_fail (id != NULL);
375 
376 	g_hash_table_insert (
377 		extras->priv->searches,
378 		g_strdup (id), (gpointer) search);
379 }
380 
381 ETableSearchFunc
382 e_table_extras_get_search (ETableExtras *extras,
383                            const gchar *id)
384 {
385 	g_return_val_if_fail (E_IS_TABLE_EXTRAS (extras), NULL);
386 	g_return_val_if_fail (id != NULL, NULL);
387 
388 	return g_hash_table_lookup (extras->priv->searches, id);
389 }
390 
391 void
392 e_table_extras_add_icon_name (ETableExtras *extras,
393                               const gchar *id,
394                               const gchar *icon_name)
395 {
396 	g_return_if_fail (E_IS_TABLE_EXTRAS (extras));
397 	g_return_if_fail (id != NULL);
398 
399 	g_hash_table_insert (
400 		extras->priv->icon_names,
401 		g_strdup (id), g_strdup (icon_name));
402 }
403 
404 const gchar *
405 e_table_extras_get_icon_name (ETableExtras *extras,
406                               const gchar *id)
407 {
408 	g_return_val_if_fail (E_IS_TABLE_EXTRAS (extras), NULL);
409 	g_return_val_if_fail (id != NULL, NULL);
410 
411 	return g_hash_table_lookup (extras->priv->icon_names, id);
412 }