]> Pileus Git - ~andy/gtk/blob - gtk/gtktexttagtable.c
Updated galician translations
[~andy/gtk] / gtk / gtktexttagtable.c
1 /* GTK - The GIMP Toolkit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library 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) any later version.
8  *
9  * This library 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 this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "config.h"
28 #include "gtktexttagtable.h"
29 #include "gtkmarshalers.h"
30 #include "gtktextbuffer.h" /* just for the lame notify_will_remove_tag hack */
31 #include "gtkintl.h"
32
33 #include <stdlib.h>
34
35
36 /**
37  * SECTION:gtktexttagtable
38  * @Short_description: Collection of tags that can be used together
39  * @Title: GtkTextTagTable
40  *
41  * You may wish to begin by reading the <link linkend="TextWidget">text widget
42  * conceptual overview</link> which gives an overview of all the objects and data
43  * types related to the text widget and how they work together.
44  */
45
46
47 struct _GtkTextTagTablePrivate
48 {
49   GHashTable *hash;
50   GSList     *anonymous;
51   GSList     *buffers;
52
53   gint anon_count;
54 };
55
56
57 enum {
58   TAG_CHANGED,
59   TAG_ADDED,
60   TAG_REMOVED,
61   LAST_SIGNAL
62 };
63
64 enum {
65   LAST_ARG
66 };
67
68 static void gtk_text_tag_table_finalize     (GObject              *object);
69 static void gtk_text_tag_table_set_property (GObject              *object,
70                                              guint                 prop_id,
71                                              const GValue         *value,
72                                              GParamSpec           *pspec);
73 static void gtk_text_tag_table_get_property (GObject              *object,
74                                              guint                 prop_id,
75                                              GValue               *value,
76                                              GParamSpec           *pspec);
77
78 static guint signals[LAST_SIGNAL] = { 0 };
79
80 G_DEFINE_TYPE (GtkTextTagTable, gtk_text_tag_table, G_TYPE_OBJECT)
81
82 static void
83 gtk_text_tag_table_class_init (GtkTextTagTableClass *klass)
84 {
85   GObjectClass *object_class = G_OBJECT_CLASS (klass);
86
87   object_class->set_property = gtk_text_tag_table_set_property;
88   object_class->get_property = gtk_text_tag_table_get_property;
89   
90   object_class->finalize = gtk_text_tag_table_finalize;
91
92   /**
93    * GtkTextTagTable::tag-changed:
94    * @texttagtable: the object which received the signal.
95    * @tag: the changed tag.
96    * @size_changed: whether the size has been changed.
97    */
98   signals[TAG_CHANGED] =
99     g_signal_new (I_("tag-changed"),
100                   G_OBJECT_CLASS_TYPE (object_class),
101                   G_SIGNAL_RUN_LAST,
102                   G_STRUCT_OFFSET (GtkTextTagTableClass, tag_changed),
103                   NULL, NULL,
104                   _gtk_marshal_VOID__OBJECT_BOOLEAN,
105                   G_TYPE_NONE,
106                   2,
107                   GTK_TYPE_TEXT_TAG,
108                   G_TYPE_BOOLEAN);  
109
110   /**
111    * GtkTextTagTable::tag-added:
112    * @texttagtable: the object which received the signal.
113    * @tag: the added tag.
114    */
115   signals[TAG_ADDED] =
116     g_signal_new (I_("tag-added"),
117                   G_OBJECT_CLASS_TYPE (object_class),
118                   G_SIGNAL_RUN_LAST,
119                   G_STRUCT_OFFSET (GtkTextTagTableClass, tag_added),
120                   NULL, NULL,
121                   _gtk_marshal_VOID__OBJECT,
122                   G_TYPE_NONE,
123                   1,
124                   GTK_TYPE_TEXT_TAG);
125
126   /**
127    * GtkTextTagTable::tag-removed:
128    * @texttagtable: the object which received the signal.
129    * @tag: the removed tag.
130    */
131   signals[TAG_REMOVED] =
132     g_signal_new (I_("tag-removed"),  
133                   G_OBJECT_CLASS_TYPE (object_class),
134                   G_SIGNAL_RUN_LAST,
135                   G_STRUCT_OFFSET (GtkTextTagTableClass, tag_removed),
136                   NULL, NULL,
137                   _gtk_marshal_VOID__OBJECT,
138                   G_TYPE_NONE,
139                   1,
140                   GTK_TYPE_TEXT_TAG);
141
142   g_type_class_add_private (klass, sizeof (GtkTextTagTablePrivate));
143 }
144
145 static void
146 gtk_text_tag_table_init (GtkTextTagTable *table)
147 {
148   GtkTextTagTablePrivate *priv;
149
150   table->priv = G_TYPE_INSTANCE_GET_PRIVATE (table,
151                                              GTK_TYPE_TEXT_TAG_TABLE,
152                                              GtkTextTagTablePrivate);
153   priv = table->priv;
154
155   priv->hash = g_hash_table_new (g_str_hash, g_str_equal);
156 }
157
158 /**
159  * gtk_text_tag_table_new:
160  * 
161  * Creates a new #GtkTextTagTable. The table contains no tags by
162  * default.
163  * 
164  * Return value: a new #GtkTextTagTable
165  **/
166 GtkTextTagTable*
167 gtk_text_tag_table_new (void)
168 {
169   GtkTextTagTable *table;
170
171   table = g_object_new (GTK_TYPE_TEXT_TAG_TABLE, NULL);
172
173   return table;
174 }
175
176 static void
177 foreach_unref (GtkTextTag *tag, gpointer data)
178 {
179   GtkTextTagTable *table = GTK_TEXT_TAG_TABLE (tag->table);
180   GtkTextTagTablePrivate *priv = table->priv;
181   GSList *tmp;
182   
183   /* We don't want to emit the remove signal here; so we just unparent
184    * and unref the tag.
185    */
186
187   tmp = priv->buffers;
188   while (tmp != NULL)
189     {
190       _gtk_text_buffer_notify_will_remove_tag (GTK_TEXT_BUFFER (tmp->data),
191                                                tag);
192       
193       tmp = tmp->next;
194     }
195   
196   tag->table = NULL;
197   g_object_unref (tag);
198 }
199
200 static void
201 gtk_text_tag_table_finalize (GObject *object)
202 {
203   GtkTextTagTable *table = GTK_TEXT_TAG_TABLE (object);
204   GtkTextTagTablePrivate *priv = table->priv;
205
206   gtk_text_tag_table_foreach (table, foreach_unref, NULL);
207
208   g_hash_table_destroy (priv->hash);
209   g_slist_free (priv->anonymous);
210
211   g_slist_free (priv->buffers);
212
213   G_OBJECT_CLASS (gtk_text_tag_table_parent_class)->finalize (object);
214 }
215 static void
216 gtk_text_tag_table_set_property (GObject      *object,
217                                  guint         prop_id,
218                                  const GValue *value,
219                                  GParamSpec   *pspec)
220 {
221   switch (prop_id)
222     {
223
224     default:
225       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
226       break;
227     }
228 }
229
230
231 static void
232 gtk_text_tag_table_get_property (GObject      *object,
233                                  guint         prop_id,
234                                  GValue       *value,
235                                  GParamSpec   *pspec)
236 {
237   switch (prop_id)
238     {
239
240     default:
241       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
242       break;
243     }
244 }
245
246 /**
247  * gtk_text_tag_table_add:
248  * @table: a #GtkTextTagTable
249  * @tag: a #GtkTextTag
250  *
251  * Add a tag to the table. The tag is assigned the highest priority
252  * in the table.
253  *
254  * @tag must not be in a tag table already, and may not have
255  * the same name as an already-added tag.
256  **/
257 void
258 gtk_text_tag_table_add (GtkTextTagTable *table,
259                         GtkTextTag      *tag)
260 {
261   GtkTextTagTablePrivate *priv;
262   guint size;
263
264   g_return_if_fail (GTK_IS_TEXT_TAG_TABLE (table));
265   g_return_if_fail (GTK_IS_TEXT_TAG (tag));
266   g_return_if_fail (tag->table == NULL);
267
268   priv = table->priv;
269
270   if (tag->name && g_hash_table_lookup (priv->hash, tag->name))
271     {
272       g_warning ("A tag named '%s' is already in the tag table.",
273                  tag->name);
274       return;
275     }
276   
277   g_object_ref (tag);
278
279   if (tag->name)
280     g_hash_table_insert (priv->hash, tag->name, tag);
281   else
282     {
283       priv->anonymous = g_slist_prepend (priv->anonymous, tag);
284       priv->anon_count += 1;
285     }
286
287   tag->table = table;
288
289   /* We get the highest tag priority, as the most-recently-added
290      tag. Note that we do NOT use gtk_text_tag_set_priority,
291      as it assumes the tag is already in the table. */
292   size = gtk_text_tag_table_get_size (table);
293   g_assert (size > 0);
294   tag->priority = size - 1;
295
296   g_signal_emit (table, signals[TAG_ADDED], 0, tag);
297 }
298
299 /**
300  * gtk_text_tag_table_lookup:
301  * @table: a #GtkTextTagTable 
302  * @name: name of a tag
303  * 
304  * Look up a named tag.
305  * 
306  * Return value: (transfer none): The tag, or %NULL if none by that name is in the table.
307  **/
308 GtkTextTag*
309 gtk_text_tag_table_lookup (GtkTextTagTable *table,
310                            const gchar     *name)
311 {
312   GtkTextTagTablePrivate *priv;
313
314   g_return_val_if_fail (GTK_IS_TEXT_TAG_TABLE (table), NULL);
315   g_return_val_if_fail (name != NULL, NULL);
316
317   priv = table->priv;
318
319   return g_hash_table_lookup (priv->hash, name);
320 }
321
322 /**
323  * gtk_text_tag_table_remove:
324  * @table: a #GtkTextTagTable
325  * @tag: a #GtkTextTag
326  * 
327  * Remove a tag from the table. This will remove the table's
328  * reference to the tag, so be careful - the tag will end
329  * up destroyed if you don't have a reference to it.
330  **/
331 void
332 gtk_text_tag_table_remove (GtkTextTagTable *table,
333                            GtkTextTag      *tag)
334 {
335   GtkTextTagTablePrivate *priv;
336   GSList *tmp;
337   
338   g_return_if_fail (GTK_IS_TEXT_TAG_TABLE (table));
339   g_return_if_fail (GTK_IS_TEXT_TAG (tag));
340   g_return_if_fail (tag->table == table);
341
342   priv = table->priv;
343
344   /* Our little bad hack to be sure buffers don't still have the tag
345    * applied to text in the buffer
346    */
347   tmp = priv->buffers;
348   while (tmp != NULL)
349     {
350       _gtk_text_buffer_notify_will_remove_tag (GTK_TEXT_BUFFER (tmp->data),
351                                                tag);
352       
353       tmp = tmp->next;
354     }
355   
356   /* Set ourselves to the highest priority; this means
357      when we're removed, there won't be any gaps in the
358      priorities of the tags in the table. */
359   gtk_text_tag_set_priority (tag, gtk_text_tag_table_get_size (table) - 1);
360
361   tag->table = NULL;
362
363   if (tag->name)
364     g_hash_table_remove (priv->hash, tag->name);
365   else
366     {
367       priv->anonymous = g_slist_remove (priv->anonymous, tag);
368       priv->anon_count -= 1;
369     }
370
371   g_signal_emit (table, signals[TAG_REMOVED], 0, tag);
372
373   g_object_unref (tag);
374 }
375
376 struct ForeachData
377 {
378   GtkTextTagTableForeach func;
379   gpointer data;
380 };
381
382 static void
383 hash_foreach (gpointer key, gpointer value, gpointer data)
384 {
385   struct ForeachData *fd = data;
386
387   g_return_if_fail (GTK_IS_TEXT_TAG (value));
388
389   (* fd->func) (value, fd->data);
390 }
391
392 static void
393 list_foreach (gpointer data, gpointer user_data)
394 {
395   struct ForeachData *fd = user_data;
396
397   g_return_if_fail (GTK_IS_TEXT_TAG (data));
398
399   (* fd->func) (data, fd->data);
400 }
401
402 /**
403  * gtk_text_tag_table_foreach:
404  * @table: a #GtkTextTagTable
405  * @func: (scope call): a function to call on each tag
406  * @data: user data
407  *
408  * Calls @func on each tag in @table, with user data @data.
409  * Note that the table may not be modified while iterating 
410  * over it (you can't add/remove tags).
411  **/
412 void
413 gtk_text_tag_table_foreach (GtkTextTagTable       *table,
414                             GtkTextTagTableForeach func,
415                             gpointer               data)
416 {
417   GtkTextTagTablePrivate *priv;
418   struct ForeachData d;
419
420   g_return_if_fail (GTK_IS_TEXT_TAG_TABLE (table));
421   g_return_if_fail (func != NULL);
422
423   priv = table->priv;
424
425   d.func = func;
426   d.data = data;
427
428   g_hash_table_foreach (priv->hash, hash_foreach, &d);
429   g_slist_foreach (priv->anonymous, list_foreach, &d);
430 }
431
432 /**
433  * gtk_text_tag_table_get_size:
434  * @table: a #GtkTextTagTable
435  * 
436  * Returns the size of the table (number of tags)
437  * 
438  * Return value: number of tags in @table
439  **/
440 gint
441 gtk_text_tag_table_get_size (GtkTextTagTable *table)
442 {
443   GtkTextTagTablePrivate *priv;
444
445   g_return_val_if_fail (GTK_IS_TEXT_TAG_TABLE (table), 0);
446
447   priv = table->priv;
448
449   return g_hash_table_size (priv->hash) + priv->anon_count;
450 }
451
452 void
453 _gtk_text_tag_table_add_buffer (GtkTextTagTable *table,
454                                 gpointer         buffer)
455 {
456   GtkTextTagTablePrivate *priv = table->priv;
457
458   priv->buffers = g_slist_prepend (priv->buffers, buffer);
459 }
460
461 static void
462 foreach_remove_tag (GtkTextTag *tag, gpointer data)
463 {
464   GtkTextBuffer *buffer;
465
466   buffer = GTK_TEXT_BUFFER (data);
467
468   _gtk_text_buffer_notify_will_remove_tag (buffer, tag);
469 }
470
471 void
472 _gtk_text_tag_table_remove_buffer (GtkTextTagTable *table,
473                                    gpointer         buffer)
474 {
475   GtkTextTagTablePrivate *priv = table->priv;
476
477   gtk_text_tag_table_foreach (table, foreach_remove_tag, buffer);
478
479   priv->buffers = g_slist_remove (priv->buffers, buffer);
480 }