No issues found
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 |
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 }