evolution-3.6.4/widgets/text/e-text-model.c

No issues found

Incomplete coverage

Tool Failure ID Location Function Message Data
clang-analyzer no-output-found e-text-model.c Message(text='Unable to locate XML output from invoke-clang-analyzer') None
clang-analyzer no-output-found e-text-model.c Message(text='Unable to locate XML output from invoke-clang-analyzer') None
Failure running clang-analyzer ('no-output-found')
Message
Unable to locate XML output from invoke-clang-analyzer
Failure running clang-analyzer ('no-output-found')
Message
Unable to locate XML output from invoke-clang-analyzer
  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  *		Chris Lahey <clahey@ximian.com>
 18  *
 19  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
 20  *
 21  */
 22 
 23 #undef  PARANOID_DEBUGGING
 24 
 25 #ifdef HAVE_CONFIG_H
 26 #include <config.h>
 27 #endif
 28 
 29 #include <ctype.h>
 30 #include <string.h>
 31 
 32 #include <gtk/gtk.h>
 33 
 34 #include "e-util/e-util.h"
 35 
 36 #include "e-text-model.h"
 37 #include "e-text-model-repos.h"
 38 
 39 #define E_TEXT_MODEL_GET_PRIVATE(obj) \
 40 	(G_TYPE_INSTANCE_GET_PRIVATE \
 41 	((obj), E_TYPE_TEXT_MODEL, ETextModelPrivate))
 42 
 43 enum {
 44 	E_TEXT_MODEL_CHANGED,
 45 	E_TEXT_MODEL_REPOSITION,
 46 	E_TEXT_MODEL_OBJECT_ACTIVATED,
 47 	E_TEXT_MODEL_CANCEL_COMPLETION,
 48 	E_TEXT_MODEL_LAST_SIGNAL
 49 };
 50 
 51 static guint signals[E_TEXT_MODEL_LAST_SIGNAL] = { 0 };
 52 
 53 struct _ETextModelPrivate {
 54 	GString *text;
 55 };
 56 
 57 static gint	e_text_model_real_validate_position
 58 						(ETextModel *, gint pos);
 59 static const gchar *
 60 		e_text_model_real_get_text	(ETextModel *model);
 61 static gint	e_text_model_real_get_text_length
 62 						(ETextModel *model);
 63 static void	e_text_model_real_set_text	(ETextModel *model,
 64 						 const gchar *text);
 65 static void	e_text_model_real_insert	(ETextModel *model,
 66 						 gint postion,
 67 						 const gchar *text);
 68 static void	e_text_model_real_insert_length	(ETextModel *model,
 69 						 gint postion,
 70 						 const gchar *text,
 71 						 gint length);
 72 static void	e_text_model_real_delete	(ETextModel *model,
 73 						 gint postion,
 74 						 gint length);
 75 
 76 G_DEFINE_TYPE (ETextModel, e_text_model, G_TYPE_OBJECT)
 77 
 78 static void
 79 e_text_model_finalize (GObject *object)
 80 {
 81 	ETextModelPrivate *priv;
 82 
 83 	priv = E_TEXT_MODEL_GET_PRIVATE (object);
 84 
 85 	g_string_free (priv->text, TRUE);
 86 
 87 	/* Chain up to parent's finalize() method. */
 88 	G_OBJECT_CLASS (e_text_model_parent_class)->finalize (object);
 89 }
 90 
 91 static void
 92 e_text_model_class_init (ETextModelClass *class)
 93 {
 94 	GObjectClass *object_class;
 95 
 96 	g_type_class_add_private (class, sizeof (ETextModelPrivate));
 97 
 98 	object_class = G_OBJECT_CLASS (class);
 99 	object_class->finalize = e_text_model_finalize;
100 
101 	signals[E_TEXT_MODEL_CHANGED] = g_signal_new (
102 		"changed",
103 		G_OBJECT_CLASS_TYPE (object_class),
104 		G_SIGNAL_RUN_LAST,
105 		G_STRUCT_OFFSET (ETextModelClass, changed),
106 		NULL, NULL,
107 		g_cclosure_marshal_VOID__VOID,
108 		G_TYPE_NONE, 0);
109 
110 	signals[E_TEXT_MODEL_REPOSITION] = g_signal_new (
111 		"reposition",
112 		G_OBJECT_CLASS_TYPE (object_class),
113 		G_SIGNAL_RUN_LAST,
114 		G_STRUCT_OFFSET (ETextModelClass, reposition),
115 		NULL, NULL,
116 		e_marshal_NONE__POINTER_POINTER,
117 		G_TYPE_NONE, 2,
118 		G_TYPE_POINTER,
119 		G_TYPE_POINTER);
120 
121 	signals[E_TEXT_MODEL_OBJECT_ACTIVATED] = g_signal_new (
122 		"object_activated",
123 		G_OBJECT_CLASS_TYPE (object_class),
124 		G_SIGNAL_RUN_LAST,
125 		G_STRUCT_OFFSET (ETextModelClass, object_activated),
126 		NULL, NULL,
127 		g_cclosure_marshal_VOID__INT,
128 		G_TYPE_NONE, 1,
129 		G_TYPE_INT);
130 
131 	signals[E_TEXT_MODEL_CANCEL_COMPLETION] = g_signal_new (
132 		"cancel_completion",
133 		G_OBJECT_CLASS_TYPE (object_class),
134 		G_SIGNAL_RUN_LAST,
135 		G_STRUCT_OFFSET (ETextModelClass, cancel_completion),
136 		NULL, NULL,
137 		g_cclosure_marshal_VOID__VOID,
138 		G_TYPE_NONE, 0);
139 
140 	/* No default signal handlers. */
141 	class->changed          = NULL;
142 	class->reposition       = NULL;
143 	class->object_activated = NULL;
144 
145 	class->validate_pos  = e_text_model_real_validate_position;
146 
147 	class->get_text      = e_text_model_real_get_text;
148 	class->get_text_len  = e_text_model_real_get_text_length;
149 	class->set_text      = e_text_model_real_set_text;
150 	class->insert        = e_text_model_real_insert;
151 	class->insert_length = e_text_model_real_insert_length;
152 	class->delete        = e_text_model_real_delete;
153 
154 	/* We explicitly don't define default handlers for these. */
155 	class->objectify        = NULL;
156 	class->obj_count        = NULL;
157 	class->get_nth_obj      = NULL;
158 }
159 
160 static void
161 e_text_model_init (ETextModel *model)
162 {
163 	model->priv = E_TEXT_MODEL_GET_PRIVATE (model);
164 	model->priv->text = g_string_new ("");
165 }
166 
167 static gint
168 e_text_model_real_validate_position (ETextModel *model,
169                                      gint pos)
170 {
171 	gint len = e_text_model_get_text_length (model);
172 
173 	if (pos < 0)
174 		pos = 0;
175 	else if (pos > len)
176 		pos = len;
177 
178 	return pos;
179 }
180 
181 static const gchar *
182 e_text_model_real_get_text (ETextModel *model)
183 {
184 	if (model->priv->text)
185 		return model->priv->text->str;
186 	else
187 		return "";
188 }
189 
190 static gint
191 e_text_model_real_get_text_length (ETextModel *model)
192 {
193 	return g_utf8_strlen (model->priv->text->str, -1);
194 }
195 
196 static void
197 e_text_model_real_set_text (ETextModel *model,
198                             const gchar *text)
199 {
200 	EReposAbsolute repos;
201 	gboolean changed = FALSE;
202 
203 	if (text == NULL) {
204 		changed = (*model->priv->text->str != '\0');
205 
206 		g_string_set_size (model->priv->text, 0);
207 
208 	} else if (*model->priv->text->str == '\0' ||
209 		strcmp (model->priv->text->str, text)) {
210 
211 		g_string_assign (model->priv->text, text);
212 
213 		changed = TRUE;
214 	}
215 
216 	if (changed) {
217 		e_text_model_changed (model);
218 		repos.model = model;
219 		repos.pos = -1;
220 		e_text_model_reposition (model, e_repos_absolute, &repos);
221 	}
222 }
223 
224 static void
225 e_text_model_real_insert (ETextModel *model,
226                           gint position,
227                           const gchar *text)
228 {
229 	e_text_model_insert_length (model, position, text, strlen (text));
230 }
231 
232 static void
233 e_text_model_real_insert_length (ETextModel *model,
234                                  gint position,
235                                  const gchar *text,
236                                  gint length)
237 {
238 	EReposInsertShift repos;
239 	gint model_len = e_text_model_real_get_text_length (model);
240 	gchar *offs;
241 	const gchar *p;
242 	gint byte_length, l;
243 
244 	if (position > model_len)
245 		return;
246 
247 	offs = g_utf8_offset_to_pointer (model->priv->text->str, position);
248 
249 	for (p = text, l = 0;
250 	     l < length;
251 	     p = g_utf8_next_char (p), l++);
252 
253 	byte_length = p - text;
254 
255 	g_string_insert_len (
256 		model->priv->text,
257 		offs - model->priv->text->str,
258 		text, byte_length);
259 
260 	e_text_model_changed (model);
261 
262 	repos.model = model;
263 	repos.pos = position;
264 	repos.len = length;
265 
266 	e_text_model_reposition (model, e_repos_insert_shift, &repos);
267 }
268 
269 static void
270 e_text_model_real_delete (ETextModel *model,
271                           gint position,
272                           gint length)
273 {
274 	EReposDeleteShift repos;
275 	gint byte_position, byte_length;
276 	gchar *offs, *p;
277 	gint l;
278 
279 	offs = g_utf8_offset_to_pointer (model->priv->text->str, position);
280 	byte_position = offs - model->priv->text->str;
281 
282 	for (p = offs, l = 0;
283 	     l < length;
284 	     p = g_utf8_next_char (p), l++);
285 
286 	byte_length = p - offs;
287 
288 	g_string_erase (
289 		model->priv->text,
290 		byte_position, byte_length);
291 
292 	e_text_model_changed (model);
293 
294 	repos.model = model;
295 	repos.pos   = position;
296 	repos.len   = length;
297 
298 	e_text_model_reposition (model, e_repos_delete_shift, &repos);
299 }
300 
301 void
302 e_text_model_changed (ETextModel *model)
303 {
304 	ETextModelClass *class;
305 
306 	g_return_if_fail (E_IS_TEXT_MODEL (model));
307 
308 	class = E_TEXT_MODEL_GET_CLASS (model);
309 
310 	/*
311 	  Objectify before emitting any signal.
312 	  While this method could, in theory, do pretty much anything, it is meant
313 	  for scanning objects and converting substrings into embedded objects.
314 	*/
315 	if (class->objectify != NULL)
316 		class->objectify (model);
317 
318 	g_signal_emit (model, signals[E_TEXT_MODEL_CHANGED], 0);
319 }
320 
321 void
322 e_text_model_cancel_completion (ETextModel *model)
323 {
324 	g_return_if_fail (E_IS_TEXT_MODEL (model));
325 
326 	g_signal_emit (model, signals[E_TEXT_MODEL_CANCEL_COMPLETION], 0);
327 }
328 
329 void
330 e_text_model_reposition (ETextModel *model,
331                          ETextModelReposFn fn,
332                          gpointer repos_data)
333 {
334 	g_return_if_fail (E_IS_TEXT_MODEL (model));
335 	g_return_if_fail (fn != NULL);
336 
337 	g_signal_emit (
338 		model, signals[E_TEXT_MODEL_REPOSITION], 0, fn, repos_data);
339 }
340 
341 gint
342 e_text_model_validate_position (ETextModel *model,
343                                 gint pos)
344 {
345 	ETextModelClass *class;
346 
347 	g_return_val_if_fail (E_IS_TEXT_MODEL (model), 0);
348 
349 	class = E_TEXT_MODEL_GET_CLASS (model);
350 
351 	if (class->validate_pos != NULL)
352 		pos = class->validate_pos (model, pos);
353 
354 	return pos;
355 }
356 
357 const gchar *
358 e_text_model_get_text (ETextModel *model)
359 {
360 	ETextModelClass *class;
361 
362 	g_return_val_if_fail (E_IS_TEXT_MODEL (model), NULL);
363 
364 	class = E_TEXT_MODEL_GET_CLASS (model);
365 
366 	if (class->get_text == NULL)
367 		return "";
368 
369 	return class->get_text (model);
370 }
371 
372 gint
373 e_text_model_get_text_length (ETextModel *model)
374 {
375 	ETextModelClass *class;
376 
377 	g_return_val_if_fail (E_IS_TEXT_MODEL (model), 0);
378 
379 	class = E_TEXT_MODEL_GET_CLASS (model);
380 
381 	if (class->get_text_len (model)) {
382 
383 		gint len = class->get_text_len (model);
384 
385 #ifdef PARANOID_DEBUGGING
386 		const gchar *str = e_text_model_get_text (model);
387 		gint len2 = str ? g_utf8_strlen (str, -1) : 0;
388 		if (len != len)
389 			g_error ("\"%s\" length reported as %d, not %d.", str, len, len2);
390 #endif
391 
392 		return len;
393 
394 	} else {
395 		/* Calculate length the old-fashioned way... */
396 		const gchar *str = e_text_model_get_text (model);
397 		return str ? g_utf8_strlen (str, -1) : 0;
398 	}
399 }
400 
401 void
402 e_text_model_set_text (ETextModel *model,
403                        const gchar *text)
404 {
405 	ETextModelClass *class;
406 
407 	g_return_if_fail (E_IS_TEXT_MODEL (model));
408 
409 	class = E_TEXT_MODEL_GET_CLASS (model);
410 
411 	if (class->set_text != NULL)
412 		class->set_text (model, text);
413 }
414 
415 void
416 e_text_model_insert (ETextModel *model,
417                      gint position,
418                      const gchar *text)
419 {
420 	ETextModelClass *class;
421 
422 	g_return_if_fail (E_IS_TEXT_MODEL (model));
423 
424 	if (text == NULL)
425 		return;
426 
427 	class = E_TEXT_MODEL_GET_CLASS (model);
428 
429 	if (class->insert != NULL)
430 		class->insert (model, position, text);
431 }
432 
433 void
434 e_text_model_insert_length (ETextModel *model,
435                             gint position,
436                             const gchar *text,
437                             gint length)
438 {
439 	ETextModelClass *class;
440 
441 	g_return_if_fail (E_IS_TEXT_MODEL (model));
442 	g_return_if_fail (length >= 0);
443 
444 	if (text == NULL || length == 0)
445 		return;
446 
447 	class = E_TEXT_MODEL_GET_CLASS (model);
448 
449 	if (class->insert_length != NULL)
450 		class->insert_length (model, position, text, length);
451 }
452 
453 void
454 e_text_model_prepend (ETextModel *model,
455                       const gchar *text)
456 {
457 	g_return_if_fail (E_IS_TEXT_MODEL (model));
458 
459 	if (text == NULL)
460 		return;
461 
462 	e_text_model_insert (model, 0, text);
463 }
464 
465 void
466 e_text_model_append (ETextModel *model,
467                      const gchar *text)
468 {
469 	g_return_if_fail (E_IS_TEXT_MODEL (model));
470 
471 	if (text == NULL)
472 		return;
473 
474 	e_text_model_insert (model, e_text_model_get_text_length (model), text);
475 }
476 
477 void
478 e_text_model_delete (ETextModel *model,
479                      gint position,
480                      gint length)
481 {
482 	ETextModelClass *class;
483 	gint txt_len;
484 
485 	g_return_if_fail (E_IS_TEXT_MODEL (model));
486 	g_return_if_fail (length >= 0);
487 
488 	txt_len = e_text_model_get_text_length (model);
489 	if (position + length > txt_len)
490 		length = txt_len - position;
491 
492 	if (length <= 0)
493 		return;
494 
495 	class = E_TEXT_MODEL_GET_CLASS (model);
496 
497 	if (class->delete != NULL)
498 		class->delete (model, position, length);
499 }
500 
501 gint
502 e_text_model_object_count (ETextModel *model)
503 {
504 	ETextModelClass *class;
505 
506 	g_return_val_if_fail (E_IS_TEXT_MODEL (model), 0);
507 
508 	class = E_TEXT_MODEL_GET_CLASS (model);
509 
510 	if (class->obj_count == NULL)
511 		return 0;
512 
513 	return class->obj_count (model);
514 }
515 
516 const gchar *
517 e_text_model_get_nth_object (ETextModel *model,
518                              gint n,
519                              gint *len)
520 {
521 	ETextModelClass *class;
522 
523 	g_return_val_if_fail (E_IS_TEXT_MODEL (model), NULL);
524 
525 	if (n < 0 || n >= e_text_model_object_count (model))
526 		return NULL;
527 
528 	class = E_TEXT_MODEL_GET_CLASS (model);
529 
530 	if (class->get_nth_obj == NULL)
531 		return NULL;
532 
533 	return class->get_nth_obj (model, n, len);
534 }
535 
536 gchar *
537 e_text_model_strdup_nth_object (ETextModel *model,
538                                 gint n)
539 {
540 	const gchar *obj;
541 	gint len = 0;
542 
543 	g_return_val_if_fail (E_IS_TEXT_MODEL (model), NULL);
544 
545 	obj = e_text_model_get_nth_object (model, n, &len);
546 
547 	if (obj) {
548 		gint byte_len;
549 		byte_len = g_utf8_offset_to_pointer (obj, len) - obj;
550 		return g_strndup (obj, byte_len);
551 	}
552 	else {
553 		return NULL;
554 	}
555 }
556 
557 void
558 e_text_model_get_nth_object_bounds (ETextModel *model,
559                                     gint n,
560                                     gint *start,
561                                     gint *end)
562 {
563 	const gchar *txt = NULL, *obj = NULL;
564 	gint len = 0;
565 
566 	g_return_if_fail (E_IS_TEXT_MODEL (model));
567 
568 	txt = e_text_model_get_text (model);
569 	obj = e_text_model_get_nth_object (model, n, &len);
570 
571 	g_return_if_fail (obj != NULL);
572 
573 	if (start)
574 		*start = g_utf8_pointer_to_offset (txt, obj);
575 	if (end)
576 		*end = *start + len;
577 }
578 
579 gint
580 e_text_model_get_object_at_offset (ETextModel *model,
581                                    gint offset)
582 {
583 	ETextModelClass *class;
584 
585 	g_return_val_if_fail (E_IS_TEXT_MODEL (model), -1);
586 
587 	if (offset < 0 || offset >= e_text_model_get_text_length (model))
588 		return -1;
589 
590 	class = E_TEXT_MODEL_GET_CLASS (model);
591 
592 	/* If an optimized version has been provided, we use it. */
593 	if (class->obj_at_offset != NULL) {
594 		return class->obj_at_offset (model, offset);
595 
596 	} else {
597 		/* If not, we fake it.*/
598 
599 		gint i, N, pos0, pos1;
600 
601 		N = e_text_model_object_count (model);
602 
603 		for (i = 0; i < N; ++i) {
604 			e_text_model_get_nth_object_bounds (model, i, &pos0, &pos1);
605 			if (pos0 <= offset && offset < pos1)
606 				return i;
607 		}
608 
609 	}
610 
611 	return -1;
612 }
613 
614 gint
615 e_text_model_get_object_at_pointer (ETextModel *model,
616                                     const gchar *s)
617 {
618 	g_return_val_if_fail (E_IS_TEXT_MODEL (model), -1);
619 	g_return_val_if_fail (s != NULL, -1);
620 
621 	return e_text_model_get_object_at_offset (
622 		model, s - e_text_model_get_text (model));
623 }
624 
625 void
626 e_text_model_activate_nth_object (ETextModel *model,
627                                   gint n)
628 {
629 	g_return_if_fail (model != NULL);
630 	g_return_if_fail (E_IS_TEXT_MODEL (model));
631 	g_return_if_fail (n >= 0);
632 	g_return_if_fail (n < e_text_model_object_count (model));
633 
634 	g_signal_emit (model, signals[E_TEXT_MODEL_OBJECT_ACTIVATED], 0, n);
635 }
636 
637 ETextModel *
638 e_text_model_new (void)
639 {
640 	ETextModel *model = g_object_new (E_TYPE_TEXT_MODEL, NULL);
641 	return model;
642 }