evolution-3.6.4/widgets/table/e-cell-text.c

Location Tool Test ID Function Issue
e-cell-text.c:892:17 clang-analyzer Access to field 'preedit_length' results in a dereference of a null pointer (loaded from variable 'edit')
e-cell-text.c:892:17 clang-analyzer Access to field 'preedit_length' results in a dereference of a null pointer (loaded from variable 'edit')
e-cell-text.c:1989:41 clang-analyzer Access to field 'text_view' results in a dereference of a null pointer (loaded from variable 'edit')
e-cell-text.c:1989:41 clang-analyzer Access to field 'text_view' results in a dereference of a null pointer (loaded from variable 'edit')
e-cell-text.c:2567:7 clang-analyzer Access to field 'tep' results in a dereference of a null pointer (loaded from variable 'edit')
e-cell-text.c:2567:7 clang-analyzer Access to field 'tep' results in a dereference of a null pointer (loaded from variable 'edit')
   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  *		Miguel de Icaza <miguel@ximian.com>
  18  *      Chris Lahey <clahey@ximian.com>
  19  *
  20  * A lot of code taken from:
  21  *
  22  * Text item type for GnomeCanvas widget
  23  *
  24  * GnomeCanvas is basically a port of the Tk toolkit's most excellent
  25  * canvas widget.  Tk is copyrighted by the Regents of the University
  26  * of California, Sun Microsystems, and other parties.
  27  *
  28  * Copyright (C) 1998 The Free Software Foundation
  29  *
  30  * Author: Federico Mena <federico@nuclecu.unam.mx>
  31  *
  32  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
  33  *
  34  */
  35 
  36 #ifdef HAVE_CONFIG_H
  37 #include <config.h>
  38 #endif
  39 
  40 #include <stdio.h>
  41 #include <ctype.h>
  42 #include <math.h>
  43 #include <string.h>
  44 
  45 #include <gdk/gdkkeysyms.h>
  46 #include <gtk/gtk.h>
  47 #include <libgnomecanvas/libgnomecanvas.h>
  48 
  49 #include "text/e-text.h"
  50 #include <glib/gi18n.h>
  51 #include "e-util/e-text-event-processor.h"
  52 #include "e-util/e-text-event-processor-emacs-like.h"
  53 #include "e-util/e-util.h"
  54 #include "misc/e-canvas.h"
  55 #include "e-util/e-unicode.h"
  56 
  57 #include "e-table.h"
  58 #include "e-cell-text.h"
  59 #include "e-table-item.h"
  60 
  61 #define d(x)
  62 #define DO_SELECTION 1
  63 #define VIEW_TO_CELL(view) E_CELL_TEXT (((ECellView *)view)->ecell)
  64 
  65 #if d(!)0
  66 #define e_table_item_leave_edit_(x) (e_table_item_leave_edit((x)), g_print ("%s: e_table_item_leave_edit\n", __FUNCTION__))
  67 #else
  68 #define e_table_item_leave_edit_(x) (e_table_item_leave_edit((x)))
  69 #endif
  70 
  71 /* This defines a line of text */
  72 struct line {
  73 	gchar *text;	/* Line's text UTF-8, it is a pointer into the text->text string */
  74 	gint length;	/* Line's length in BYTES */
  75 	gint width;	/* Line's width in pixels */
  76 	gint ellipsis_length;  /* Length before adding ellipsis in BYTES */
  77 };
  78 
  79 /* Object argument IDs */
  80 enum {
  81 	PROP_0,
  82 
  83 	PROP_STRIKEOUT_COLUMN,
  84 	PROP_UNDERLINE_COLUMN,
  85 	PROP_BOLD_COLUMN,
  86 	PROP_COLOR_COLUMN,
  87 	PROP_EDITABLE,
  88 	PROP_BG_COLOR_COLUMN
  89 };
  90 
  91 enum {
  92 	E_SELECTION_PRIMARY,
  93 	E_SELECTION_CLIPBOARD
  94 };
  95 
  96 /* signals */
  97 enum {
  98 	TEXT_INSERTED,
  99 	TEXT_DELETED,
 100 	LAST_SIGNAL
 101 };
 102 
 103 static guint signals[LAST_SIGNAL] = { 0 };
 104 
 105 static GdkAtom clipboard_atom = GDK_NONE;
 106 
 107 G_DEFINE_TYPE (ECellText, e_cell_text, E_TYPE_CELL)
 108 
 109 #define UTF8_ATOM  gdk_atom_intern ("UTF8_STRING", FALSE)
 110 
 111 #define TEXT_PAD 4
 112 
 113 typedef struct {
 114 	gpointer lines;			/* Text split into lines (private field) */
 115 	gint num_lines;			/* Number of lines of text */
 116 	gint max_width;
 117 	gint ref_count;
 118 } ECellTextLineBreaks;
 119 
 120 typedef struct _CellEdit CellEdit;
 121 
 122 typedef struct {
 123 	ECellView    cell_view;
 124 	GdkCursor *i_cursor;
 125 
 126 	GnomeCanvas *canvas;
 127 
 128 	/*
 129 	 * During editing.
 130 	 */
 131 	CellEdit    *edit;
 132 
 133 	gint xofs, yofs;                 /* This gets added to the x
 134                                            and y for the cell text. */
 135 	gdouble ellipsis_width[2];      /* The width of the ellipsis. */
 136 } ECellTextView;
 137 
 138 struct _CellEdit {
 139 
 140 	ECellTextView *text_view;
 141 
 142 	gint model_col, view_col, row;
 143 	gint cell_width;
 144 
 145 	PangoLayout *layout;
 146 
 147 	gchar *text;
 148 
 149 	gchar         *old_text;
 150 
 151 	/*
 152 	 * Where the editing is taking place
 153 	 */
 154 
 155 	gint xofs_edit, yofs_edit;       /* Offset because of editing.
 156                                            This is negative compared
 157                                            to the other offsets. */
 158 
 159 	/* This needs to be reworked a bit once we get line wrapping. */
 160 	gint selection_start;            /* Start of selection - IN BYTES */
 161 	gint selection_end;              /* End of selection - IN BYTES */
 162 	gboolean select_by_word;        /* Current selection is by word */
 163 
 164 	/* This section is for drag scrolling and blinking cursor. */
 165 	/* Cursor handling. */
 166 	gint timeout_id;                /* Current timeout id for scrolling */
 167 	GTimer *timer;                  /* Timer for blinking cursor and scrolling */
 168 
 169 	gint lastx, lasty;              /* Last x and y motion events */
 170 	gint last_state;                /* Last state */
 171 	gulong scroll_start;            /* Starting time for scroll (microseconds) */
 172 
 173 	gint show_cursor;               /* Is cursor currently shown */
 174 	gboolean button_down;           /* Is mouse button 1 down */
 175 
 176 	ETextEventProcessor *tep;       /* Text Event Processor */
 177 
 178 	gboolean has_selection;         /* TRUE if we have the selection */
 179 
 180 	guint pointer_in : 1;
 181 	guint default_cursor_shown : 1;
 182 	GtkIMContext *im_context;
 183 	gboolean need_im_reset;
 184 	gboolean im_context_signals_registered;
 185 
 186 	guint16 preedit_length;       /* length of preedit string, in bytes */
 187 	gint preedit_pos;             /* position of preedit cursor */
 188 
 189 	ECellActions actions;
 190 };
 191 
 192 static void e_cell_text_view_command (ETextEventProcessor *tep, ETextEventProcessorCommand *command, gpointer data);
 193 
 194 static void e_cell_text_view_get_selection (CellEdit *edit, GdkAtom selection, guint32 time);
 195 static void e_cell_text_view_supply_selection (CellEdit *edit, guint time, GdkAtom selection, gchar *data, gint length);
 196 
 197 static void _get_tep (CellEdit *edit);
 198 
 199 static gint get_position_from_xy (CellEdit *edit, gint x, gint y);
 200 static gboolean _blink_scroll_timeout (gpointer data);
 201 
 202 static void e_cell_text_preedit_changed_cb (GtkIMContext *context, ECellTextView *text_view);
 203 static void e_cell_text_commit_cb (GtkIMContext *context, const gchar  *str, ECellTextView *text_view);
 204 static gboolean e_cell_text_retrieve_surrounding_cb (GtkIMContext *context, ECellTextView *text_view);
 205 static gboolean e_cell_text_delete_surrounding_cb   (GtkIMContext *context, gint          offset, gint          n_chars, ECellTextView        *text_view);
 206 static void _insert (ECellTextView *text_view, const gchar *string, gint value);
 207 static void _delete_selection (ECellTextView *text_view);
 208 static PangoAttrList * build_attr_list (ECellTextView *text_view, gint row, gint text_length);
 209 static void update_im_cursor_location (ECellTextView *tv);
 210 
 211 static gchar *
 212 ect_real_get_text (ECellText *cell,
 213                    ETableModel *model,
 214                    gint col,
 215                    gint row)
 216 {
 217 	return e_table_model_value_at (model, col, row);
 218 }
 219 
 220 static void
 221 ect_real_free_text (ECellText *cell,
 222                     gchar *text)
 223 {
 224 }
 225 
 226 /* This is the default method for setting the ETableModel value based on
 227  * the text in the ECellText. This simply uses the text as it is - it assumes
 228  * the value in the model is a gchar *. Subclasses may parse the text into
 229  * data structures to pass to the model. */
 230 static void
 231 ect_real_set_value (ECellText *cell,
 232                     ETableModel *model,
 233                     gint col,
 234                     gint row,
 235                     const gchar *text)
 236 {
 237 	e_table_model_set_value_at (model, col, row, text);
 238 }
 239 
 240 static void
 241 ect_queue_redraw (ECellTextView *text_view,
 242                   gint view_col,
 243                   gint view_row)
 244 {
 245 	e_table_item_redraw_range (
 246 		text_view->cell_view.e_table_item_view,
 247 		view_col, view_row, view_col, view_row);
 248 }
 249 
 250 /*
 251  * Shuts down the editing process
 252  */
 253 static void
 254 ect_stop_editing (ECellTextView *text_view,
 255                   gboolean commit)
 256 {
 257 	GdkWindow *window;
 258 	CellEdit *edit = text_view->edit;
 259 	gint row, view_col, model_col;
 260 	gchar *old_text, *text;
 261 
 262 	if (!edit)
 263 		return;
 264 
 265 	window = gtk_widget_get_window (GTK_WIDGET (text_view->canvas));
 266 
 267 	row = edit->row;
 268 	view_col = edit->view_col;
 269 	model_col = edit->model_col;
 270 
 271 	old_text = edit->old_text;
 272 	text = edit->text;
 273 	if (edit->tep)
 274 		g_object_unref (edit->tep);
 275 	if (!edit->default_cursor_shown) {
 276 		gdk_window_set_cursor (window, NULL);
 277 		edit->default_cursor_shown = TRUE;
 278 	}
 279 	if (edit->timeout_id) {
 280 		g_source_remove (edit->timeout_id);
 281 		edit->timeout_id = 0;
 282 	}
 283 	if (edit->timer) {
 284 		g_timer_stop (edit->timer);
 285 		g_timer_destroy (edit->timer);
 286 		edit->timer = NULL;
 287 	}
 288 
 289 	g_signal_handlers_disconnect_matched (
 290 		edit->im_context,
 291 		G_SIGNAL_MATCH_DATA, 0, 0,
 292 		NULL, NULL, text_view);
 293 
 294 	if (edit->layout)
 295 		g_object_unref (edit->layout);
 296 
 297 	g_free (edit);
 298 
 299 	text_view->edit = NULL;
 300 	if (commit) {
 301 		/*
 302 		 * Accept the currently edited text.  if it's the same as what's in the cell, do nothing.
 303 		 */
 304 		ECellView *ecell_view = (ECellView *) text_view;
 305 		ECellText *ect = (ECellText *) ecell_view->ecell;
 306 
 307 		if (strcmp (old_text, text)) {
 308 			e_cell_text_set_value (
 309 				ect, ecell_view->e_table_model,
 310 				model_col, row, text);
 311 		}
 312 	}
 313 	g_free (text);
 314 	g_free (old_text);
 315 
 316 	ect_queue_redraw (text_view, view_col, row);
 317 }
 318 
 319 /*
 320  * Cancels the edits
 321  */
 322 static void
 323 ect_cancel_edit (ECellTextView *text_view)
 324 {
 325 	ect_stop_editing (text_view, FALSE);
 326 	e_table_item_leave_edit_ (text_view->cell_view.e_table_item_view);
 327 }
 328 
 329 /*
 330  * ECell::new_view method
 331  */
 332 static ECellView *
 333 ect_new_view (ECell *ecell,
 334               ETableModel *table_model,
 335               gpointer e_table_item_view)
 336 {
 337 	ECellTextView *text_view = g_new0 (ECellTextView, 1);
 338 	GnomeCanvas *canvas = GNOME_CANVAS_ITEM (e_table_item_view)->canvas;
 339 
 340 	text_view->cell_view.ecell = ecell;
 341 	text_view->cell_view.e_table_model = table_model;
 342 	text_view->cell_view.e_table_item_view = e_table_item_view;
 343 	text_view->cell_view.kill_view_cb = NULL;
 344 	text_view->cell_view.kill_view_cb_data = NULL;
 345 
 346 	text_view->canvas = canvas;
 347 
 348 	text_view->xofs = 0.0;
 349 	text_view->yofs = 0.0;
 350 
 351 	return (ECellView *) text_view;
 352 }
 353 
 354 /*
 355  * ECell::kill_view method
 356  */
 357 static void
 358 ect_kill_view (ECellView *ecv)
 359 {
 360 	ECellTextView *text_view = (ECellTextView *) ecv;
 361 
 362 	if (text_view->cell_view.kill_view_cb)
 363 	    (text_view->cell_view.kill_view_cb)(ecv, text_view->cell_view.kill_view_cb_data);
 364 
 365 	if (text_view->cell_view.kill_view_cb_data)
 366 	    g_list_free (text_view->cell_view.kill_view_cb_data);
 367 
 368 	g_free (text_view);
 369 }
 370 
 371 /*
 372  * ECell::realize method
 373  */
 374 static void
 375 ect_realize (ECellView *ecell_view)
 376 {
 377 	ECellTextView *text_view = (ECellTextView *) ecell_view;
 378 
 379 	text_view->i_cursor = gdk_cursor_new (GDK_XTERM);
 380 
 381 	if (E_CELL_CLASS (e_cell_text_parent_class)->realize)
 382 		(* E_CELL_CLASS (e_cell_text_parent_class)->realize) (ecell_view);
 383 }
 384 
 385 /*
 386  * ECell::unrealize method
 387  */
 388 static void
 389 ect_unrealize (ECellView *ecv)
 390 {
 391 	ECellTextView *text_view = (ECellTextView *) ecv;
 392 
 393 	if (text_view->edit) {
 394 		ect_cancel_edit (text_view);
 395 	}
 396 
 397 	g_object_unref (text_view->i_cursor);
 398 
 399 	if (E_CELL_CLASS (e_cell_text_parent_class)->unrealize)
 400 		(* E_CELL_CLASS (e_cell_text_parent_class)->unrealize) (ecv);
 401 
 402 }
 403 
 404 static PangoAttrList *
 405 build_attr_list (ECellTextView *text_view,
 406                  gint row,
 407                  gint text_length)
 408 {
 409 
 410 	ECellView *ecell_view = (ECellView *) text_view;
 411 	ECellText *ect = E_CELL_TEXT (ecell_view->ecell);
 412 	PangoAttrList *attrs = pango_attr_list_new ();
 413 	gboolean bold, strikeout, underline;
 414 
 415 	bold = ect->bold_column >= 0 &&
 416 		row >= 0 &&
 417 		e_table_model_value_at (ecell_view->e_table_model, ect->bold_column, row);
 418 	strikeout = ect->strikeout_column >= 0 &&
 419 		row >= 0 &&
 420 		e_table_model_value_at (ecell_view->e_table_model, ect->strikeout_column, row);
 421 	underline = ect->underline_column >= 0 &&
 422 		row >= 0 &&
 423 		e_table_model_value_at (ecell_view->e_table_model, ect->underline_column, row);
 424 
 425 	if (bold || strikeout || underline) {
 426 		if (bold) {
 427 			PangoAttribute *attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD);
 428 			attr->start_index = 0;
 429 			attr->end_index = text_length;
 430 
 431 			pango_attr_list_insert_before (attrs, attr);
 432 		}
 433 		if (strikeout) {
 434 			PangoAttribute *attr = pango_attr_strikethrough_new (TRUE);
 435 			attr->start_index = 0;
 436 			attr->end_index = text_length;
 437 
 438 			pango_attr_list_insert_before (attrs, attr);
 439 		}
 440 		if (underline) {
 441 			PangoAttribute *attr = pango_attr_underline_new (TRUE);
 442 			attr->start_index = 0;
 443 			attr->end_index = text_length;
 444 
 445 			pango_attr_list_insert_before (attrs, attr);
 446 		}
 447 	}
 448 	return attrs;
 449 }
 450 
 451 static PangoLayout *
 452 layout_with_preedit (ECellTextView *text_view,
 453                      gint row,
 454                      const gchar *text,
 455                      gint width)
 456 {
 457 	CellEdit *edit = text_view->edit;
 458 	PangoAttrList *attrs;
 459 	PangoLayout *layout;
 460 	GString *tmp_string = g_string_new (NULL);
 461 	PangoAttrList *preedit_attrs = NULL;
 462 	gchar *preedit_string = NULL;
 463 	gint preedit_length = 0;
 464 	gint text_length = strlen (text);
 465 	gint mlen = MIN (edit->selection_start,text_length);
 466 
 467 	gtk_im_context_get_preedit_string (
 468 		edit->im_context,
 469 		&preedit_string,&preedit_attrs,
 470 		NULL);
 471 	preedit_length = edit->preedit_length = strlen (preedit_string);;
 472 
 473 	layout = edit->layout;
 474 
 475 	g_string_prepend_len (tmp_string, text,text_length);
 476 
 477 	if (preedit_length) {
 478 
 479 		/* mlen is the text_length in bytes, not chars
 480 		 * check whether we are not inserting into
 481 		 * the middle of a utf8 character
 482 		 */
 483 
 484 		if (mlen < text_length) {
 485 			if (!g_utf8_validate (text + mlen, -1, NULL)) {
 486 				gchar *tc;
 487 				tc = g_utf8_find_next_char (text + mlen,NULL);
 488 				if (tc) {
 489 					mlen = (gint) (tc - text);
 490 				}
 491 			}
 492 		}
 493 
 494 		g_string_insert (tmp_string, mlen, preedit_string);
 495 	}
 496 
 497 	pango_layout_set_text (layout, tmp_string->str, tmp_string->len);
 498 
 499 	attrs = (PangoAttrList *) build_attr_list (text_view, row, text_length);
 500 
 501 	if (preedit_length)
 502 		pango_attr_list_splice (attrs, preedit_attrs, mlen, preedit_length);
 503 	pango_layout_set_attributes (layout, attrs);
 504 	g_string_free (tmp_string, TRUE);
 505 	if (preedit_string)
 506 		g_free (preedit_string);
 507 	if (preedit_attrs)
 508 		pango_attr_list_unref (preedit_attrs);
 509 	pango_attr_list_unref (attrs);
 510 
 511 	update_im_cursor_location (text_view);
 512 
 513 	return layout;
 514 }
 515 
 516 static PangoLayout *
 517 build_layout (ECellTextView *text_view,
 518               gint row,
 519               const gchar *text,
 520               gint width)
 521 {
 522 	ECellView *ecell_view = (ECellView *) text_view;
 523 	ECellText *ect = E_CELL_TEXT (ecell_view->ecell);
 524 	PangoAttrList *attrs;
 525 	PangoLayout *layout;
 526 
 527 	layout = gtk_widget_create_pango_layout (GTK_WIDGET (((GnomeCanvasItem *) ecell_view->e_table_item_view)->canvas), text);
 528 
 529 	attrs = (PangoAttrList *) build_attr_list (text_view, row, text ? strlen (text) : 0);
 530 
 531 	pango_layout_set_attributes (layout, attrs);
 532 	pango_attr_list_unref (attrs);
 533 
 534 	if (text_view->edit || width <= 0)
 535 		return layout;
 536 
 537 	if (ect->font_name)
 538 	{
 539 		PangoFontDescription *desc = NULL, *fixed_desc = NULL;
 540 		gchar *fixed_family = NULL;
 541 		gint fixed_size = 0;
 542 		gboolean fixed_points = TRUE;
 543 
 544 		fixed_desc = pango_font_description_from_string (ect->font_name);
 545 		if (fixed_desc) {
 546 			fixed_family = (gchar *) pango_font_description_get_family (fixed_desc);
 547 			fixed_size = pango_font_description_get_size (fixed_desc);
 548 			fixed_points = !pango_font_description_get_size_is_absolute (fixed_desc);
 549 		}
 550 
 551 		desc = pango_font_description_copy (gtk_widget_get_style (GTK_WIDGET (((GnomeCanvasItem *) ecell_view->e_table_item_view)->canvas))->font_desc);
 552 		pango_font_description_set_family (desc, fixed_family);
 553 		if (fixed_points)
 554 			pango_font_description_set_size (desc, fixed_size);
 555 		else
 556 			pango_font_description_set_absolute_size (desc, fixed_size);
 557 /*		pango_font_description_set_style (desc, PANGO_STYLE_OBLIQUE); */
 558 		pango_layout_set_font_description (layout, desc);
 559 		pango_font_description_free (desc);
 560 		pango_font_description_free (fixed_desc);
 561 	}
 562 
 563 	pango_layout_set_width (layout, width * PANGO_SCALE);
 564 	pango_layout_set_wrap (layout, PANGO_WRAP_WORD_CHAR);
 565 
 566 	pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_END);
 567 	pango_layout_set_height (layout, 0);
 568 
 569 	switch (ect->justify) {
 570 	case GTK_JUSTIFY_RIGHT:
 571 		pango_layout_set_alignment (layout, PANGO_ALIGN_RIGHT);
 572 		break;
 573 	case GTK_JUSTIFY_CENTER:
 574 		pango_layout_set_alignment (layout, PANGO_ALIGN_CENTER);
 575 		break;
 576 	case GTK_JUSTIFY_LEFT:
 577 	default:
 578 		break;
 579 	}
 580 
 581 	return layout;
 582 }
 583 
 584 static PangoLayout *
 585 generate_layout (ECellTextView *text_view,
 586                  gint model_col,
 587                  gint view_col,
 588                  gint row,
 589                  gint width)
 590 {
 591 	ECellView *ecell_view = (ECellView *) text_view;
 592 	ECellText *ect = E_CELL_TEXT (ecell_view->ecell);
 593 	PangoLayout *layout;
 594 	CellEdit *edit = text_view->edit;
 595 
 596 	if (edit && edit->layout && edit->model_col == model_col && edit->row == row) {
 597 		g_object_ref (edit->layout);
 598 		return edit->layout;
 599 	}
 600 
 601 	if (row >= 0) {
 602 		gchar *temp = e_cell_text_get_text (ect, ecell_view->e_table_model, model_col, row);
 603 		layout = build_layout (text_view, row, temp ? temp : "?", width);
 604 		e_cell_text_free_text (ect, temp);
 605 	} else
 606 		layout = build_layout (text_view, row, "Mumbo Jumbo", width);
 607 
 608 	return layout;
 609 }
 610 
 611 static void
 612 draw_cursor (cairo_t *cr,
 613              gint x1,
 614              gint y1,
 615              PangoRectangle rect)
 616 {
 617 	gdouble scaled_x;
 618 	gdouble scaled_y;
 619 	gdouble scaled_height;
 620 
 621 	/* Pango stores each cursor position as a zero-width rectangle. */
 622 	scaled_x = x1 + ((gdouble) rect.x) / PANGO_SCALE;
 623 	scaled_y = y1 + ((gdouble) rect.y) / PANGO_SCALE;
 624 	scaled_height = ((gdouble) rect.height) / PANGO_SCALE;
 625 
 626 	/* Adding 0.5 to scaled_x gives a sharp, one-pixel line. */
 627 	cairo_move_to (cr, scaled_x + 0.5, scaled_y);
 628 	cairo_line_to (cr, scaled_x + 0.5, scaled_y + scaled_height);
 629 	cairo_set_line_width (cr, 1);
 630 	cairo_stroke (cr);
 631 }
 632 
 633 static gboolean
 634 show_pango_rectangle (CellEdit *edit,
 635                       PangoRectangle rect)
 636 {
 637 	gint x1 = rect.x / PANGO_SCALE;
 638 	gint x2 = (rect.x + rect.width) / PANGO_SCALE;
 639 #if 0
 640 	gint y1 = rect.y / PANGO_SCALE;
 641 	gint y2 = (rect.y + rect.height) / PANGO_SCALE;
 642 #endif
 643 
 644 	gint new_xofs_edit = edit->xofs_edit;
 645 	gint new_yofs_edit = edit->yofs_edit;
 646 
 647 	if (x1 < new_xofs_edit)
 648 		new_xofs_edit = x1;
 649 	if (2 + x2 - edit->cell_width > new_xofs_edit)
 650 		new_xofs_edit = 2 + x2 - edit->cell_width;
 651 	if (new_xofs_edit < 0)
 652 		new_xofs_edit = 0;
 653 
 654 #if 0
 655 	if (y1 < new_yofs_edit)
 656 		new_yofs_edit = y1;
 657 	if (2 + y2 - edit->cell_height > new_yofs_edit)
 658 		new_yofs_edit = 2 + y2 - edit->cell_height;
 659 	if (new_yofs_edit < 0)
 660 		new_yofs_edit = 0;
 661 #endif
 662 
 663 	if (new_xofs_edit != edit->xofs_edit ||
 664 	    new_yofs_edit != edit->yofs_edit) {
 665 		edit->xofs_edit = new_xofs_edit;
 666 		edit->yofs_edit = new_yofs_edit;
 667 		return TRUE;
 668 	}
 669 
 670 	return FALSE;
 671 }
 672 
 673 static gint
 674 get_vertical_spacing (GtkWidget *canvas)
 675 {
 676 	GtkStyle *style;
 677 	GtkWidget *widget;
 678 	gint vspacing = 0;
 679 
 680 	g_return_val_if_fail (E_IS_CANVAS (canvas), 3);
 681 
 682 	/* The parent should be either an ETable or ETree. */
 683 	widget = gtk_widget_get_parent (canvas);
 684 	style = gtk_widget_get_style (widget);
 685 
 686 	gtk_style_get (
 687 		style, G_OBJECT_TYPE (widget),
 688 		"vertical-spacing", &vspacing, NULL);
 689 
 690 	return vspacing;
 691 }
 692 
 693 /*
 694  * ECell::draw method
 695  */
 696 static void
 697 ect_draw (ECellView *ecell_view,
 698           cairo_t *cr,
 699           gint model_col,
 700           gint view_col,
 701           gint row,
 702           ECellFlags flags,
 703           gint x1,
 704           gint y1,
 705           gint x2,
 706           gint y2)
 707 {
 708 	PangoLayout *layout;
 709 	ECellTextView *text_view = (ECellTextView *) ecell_view;
 710 	ECellText *ect = E_CELL_TEXT (ecell_view->ecell);
 711 	CellEdit *edit = text_view->edit;
 712 	gboolean selected;
 713 	GtkWidget *canvas = GTK_WIDGET (text_view->canvas);
 714 	GtkStyle *style;
 715 	gint x_origin, y_origin, vspacing;
 716 
 717 	cairo_save (cr);
 718 	style = gtk_widget_get_style (canvas);
 719 
 720 	selected = flags & E_CELL_SELECTED;
 721 
 722 	if (selected) {
 723 		if (gtk_widget_has_focus (canvas))
 724 			gdk_cairo_set_source_color (cr, &style->fg[GTK_STATE_SELECTED]);
 725 		else
 726 			gdk_cairo_set_source_color (cr, &style->fg[GTK_STATE_ACTIVE]);
 727 	} else {
 728 		gdk_cairo_set_source_color (cr, &style->text[GTK_STATE_NORMAL]);
 729 
 730 		if (ect->color_column != -1) {
 731 			gchar *color_spec;
 732 			GdkColor color;
 733 
 734 			color_spec = e_table_model_value_at (
 735 				ecell_view->e_table_model,
 736 				ect->color_column, row);
 737 			if (color_spec && gdk_color_parse (color_spec, &color))
 738 				gdk_cairo_set_source_color (cr, &color);
 739 		}
 740 	}
 741 
 742 	vspacing = get_vertical_spacing (canvas);
 743 
 744 	x1 += 4;
 745 	y1 += vspacing;
 746 	x2 -= 4;
 747 	y2 -= vspacing;
 748 
 749 	x_origin = x1 + ect->x + text_view->xofs - (edit ? edit->xofs_edit : 0);
 750 	y_origin = y1 + ect->y + text_view->yofs - (edit ? edit->yofs_edit : 0);
 751 
 752 	cairo_rectangle (cr, x1, y1, x2 - x1, y2 - y1);
 753 	cairo_clip (cr);
 754 
 755 	layout = generate_layout (text_view, model_col, view_col, row, x2 - x1);
 756 
 757 	if (edit && edit->view_col == view_col && edit->row == row) {
 758 		layout = layout_with_preedit  (text_view, row, edit->text ? edit->text : "?",  x2 - x1);
 759 	}
 760 
 761 	cairo_move_to (cr, x_origin, y_origin);
 762 	pango_cairo_show_layout (cr, layout);
 763 
 764 	if (edit && edit->view_col == view_col && edit->row == row) {
 765 		if (edit->selection_start != edit->selection_end) {
 766 			cairo_region_t *clip_region;
 767 			gint indices[2];
 768 			GtkStateType state;
 769 
 770 			state = edit->has_selection ? GTK_STATE_SELECTED : GTK_STATE_ACTIVE;
 771 
 772 			indices[0] = MIN (edit->selection_start, edit->selection_end);
 773 			indices[1] = MAX (edit->selection_start, edit->selection_end);
 774 
 775 			clip_region = gdk_pango_layout_get_clip_region (
 776 				layout, x_origin, y_origin, indices, 1);
 777 			gdk_cairo_region (cr, clip_region);
 778 			cairo_clip (cr);
 779 			cairo_region_destroy (clip_region);
 780 
 781 			gdk_cairo_set_source_color (cr, &style->base[state]);
 782 			cairo_paint (cr);
 783 
 784 			gdk_cairo_set_source_color (cr, &style->text[state]);
 785 			cairo_move_to (cr, x_origin, y_origin);
 786 			pango_cairo_show_layout (cr, layout);
 787 		} else {
 788 			if (edit->show_cursor) {
 789 				PangoRectangle strong_pos, weak_pos;
 790 				pango_layout_get_cursor_pos (layout, edit->selection_start + edit->preedit_length, &strong_pos, &weak_pos);
 791 
 792 				draw_cursor (cr, x_origin, y_origin, strong_pos);
 793 				if (strong_pos.x != weak_pos.x ||
 794 				    strong_pos.y != weak_pos.y ||
 795 				    strong_pos.width != weak_pos.width ||
 796 				    strong_pos.height != weak_pos.height)
 797 					draw_cursor (cr, x_origin, y_origin, weak_pos);
 798 			}
 799 		}
 800 	}
 801 
 802 	g_object_unref (layout);
 803 	cairo_restore (cr);
 804 }
 805 
 806 /*
 807  * Get the background color
 808  */
 809 static gchar *
 810 ect_get_bg_color (ECellView *ecell_view,
 811                   gint row)
 812 {
 813 	ECellText *ect = E_CELL_TEXT (ecell_view->ecell);
 814 	gchar *color_spec;
 815 
 816 	if (ect->bg_color_column == -1)
 817 		return NULL;
 818 
 819 	color_spec = e_table_model_value_at (
 820 		ecell_view->e_table_model,
 821 		ect->bg_color_column, row);
 822 
 823 	return color_spec;
 824 }
 825 
 826 /*
 827  * Selects the entire string
 828  */
 829 
 830 static void
 831 ect_edit_select_all (ECellTextView *text_view)
 832 {
 833 	g_return_if_fail (text_view->edit);
 834 
 835 	text_view->edit->selection_start = 0;
 836 	text_view->edit->selection_end = strlen (text_view->edit->text);
 837 }
 838 
 839 static gboolean
 840 key_begins_editing (GdkEventKey *event)
 841 {
 842 	if (event->length == 0)
 843 		return FALSE;
 844 
 845 	return TRUE;
 846 }
 847 
 848 /*
 849  * ECell::event method
 850  */
 851 static gint
 852 ect_event (ECellView *ecell_view,
 853            GdkEvent *event,
 854            gint model_col,
 855            gint view_col,
 856            gint row,
 857            ECellFlags flags,
 858            ECellActions *actions)
 859 {
 860 	ECellTextView *text_view = (ECellTextView *) ecell_view;
 861 	ETextEventProcessorEvent e_tep_event;
 862 	gboolean edit_display = FALSE;
 863 	gint preedit_len;
 864 	CellEdit *edit = text_view->edit;
 865 	GtkWidget *canvas = GTK_WIDGET (text_view->canvas);
 866 	gint return_val = 0;
 867 	d (gboolean press = FALSE);
 868 
 869 	if (!(flags & E_CELL_EDITING))
 870 		return 0;
 871 
 872 	if (edit && !edit->preedit_length && flags & E_CELL_PREEDIT)
 873 		return 1;
 874 
 875 	if (edit && edit->view_col == view_col && edit->row == row) {
 876 		edit_display = TRUE;
 877 	}
 878 
 879 	e_tep_event.type = event->type;
 880 	switch (event->type) {
 881 	case GDK_FOCUS_CHANGE:
 882 		break;
 883 	case GDK_KEY_PRESS: /* Fall Through */
 884 		if (edit_display) {
 885 			edit->show_cursor = FALSE;
 886 		} else {
 887 			ect_stop_editing (text_view, TRUE);
 888 		}
 889 		return_val = TRUE;
 890 		/* Fallthrough */
 891 	case GDK_KEY_RELEASE:
 892 		preedit_len = edit->preedit_length;
Access to field 'preedit_length' results in a dereference of a null pointer (loaded from variable 'edit')
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

Access to field 'preedit_length' results in a dereference of a null pointer (loaded from variable 'edit')
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

893 if (edit_display && edit->im_context && 894 gtk_im_context_filter_keypress (\ 895 edit->im_context, 896 (GdkEventKey *) event)) { 897 898 edit->need_im_reset = TRUE; 899 if (preedit_len && flags & E_CELL_PREEDIT) 900 return 0; 901 else 902 return 1; 903 } 904 905 if (event->key.keyval == GDK_KEY_Escape) { 906 /* if not changed, then pass this even to parent */ 907 return_val = text_view->edit != NULL && text_view->edit->text && text_view->edit->old_text && 0 != strcmp (text_view->edit->text, text_view->edit->old_text); 908 ect_cancel_edit (text_view); 909 break; 910 } 911 912 if ((!edit_display) && 913 e_table_model_is_cell_editable (ecell_view->e_table_model, model_col, row) && 914 key_begins_editing (&event->key)) { 915 e_table_item_enter_edit (text_view->cell_view.e_table_item_view, view_col, row); 916 ect_edit_select_all (text_view); 917 edit = text_view->edit; 918 edit_display = TRUE; 919 } 920 if (edit_display) { 921 GdkEventKey key = event->key; 922 if (key.type == GDK_KEY_PRESS && 923 (key.keyval == GDK_KEY_KP_Enter || key.keyval == GDK_KEY_Return)) { 924 /* stop editing when it's only GDK_KEY_PRESS event */ 925 e_table_item_leave_edit_ (text_view->cell_view.e_table_item_view); 926 } else { 927 e_tep_event.key.time = key.time; 928 e_tep_event.key.state = key.state; 929 e_tep_event.key.keyval = key.keyval; 930 931 /* This is probably ugly hack, but we have to handle UTF-8 input somehow */ 932 #if 0 933 e_tep_event.key.length = key.length; 934 e_tep_event.key.string = key.string; 935 #else 936 e_tep_event.key.string = e_utf8_from_gtk_event_key (canvas, key.keyval, key.string); 937 if (e_tep_event.key.string != NULL) { 938 e_tep_event.key.length = strlen (e_tep_event.key.string); 939 } else { 940 e_tep_event.key.length = 0; 941 } 942 #endif 943 _get_tep (edit); 944 return_val = e_text_event_processor_handle_event (edit->tep, &e_tep_event); 945 if (e_tep_event.key.string) 946 g_free ((gpointer) e_tep_event.key.string); 947 break; 948 } 949 } 950 951 break; 952 case GDK_BUTTON_PRESS: /* Fall Through */ 953 d (press = TRUE); 954 case GDK_BUTTON_RELEASE: 955 d (g_print ("%s: %s\n", __FUNCTION__, press ? "GDK_BUTTON_PRESS" : "GDK_BUTTON_RELEASE")); 956 event->button.x -= 4; 957 event->button.y -= 1; 958 if ((!edit_display) 959 && e_table_model_is_cell_editable (ecell_view->e_table_model, model_col, row) 960 && event->type == GDK_BUTTON_RELEASE 961 && event->button.button == 1) { 962 GdkEventButton button = event->button; 963 964 e_table_item_enter_edit (text_view->cell_view.e_table_item_view, view_col, row); 965 edit = text_view->edit; 966 edit_display = TRUE; 967 968 e_tep_event.button.type = GDK_BUTTON_PRESS; 969 e_tep_event.button.time = button.time; 970 e_tep_event.button.state = button.state; 971 e_tep_event.button.button = button.button; 972 e_tep_event.button.position = get_position_from_xy (edit, event->button.x, event->button.y); 973 _get_tep (edit); 974 edit->actions = 0; 975 return_val = e_text_event_processor_handle_event ( 976 edit->tep, &e_tep_event); 977 *actions = edit->actions; 978 if (event->button.button == 1) { 979 if (event->type == GDK_BUTTON_PRESS) 980 edit->button_down = TRUE; 981 else 982 edit->button_down = FALSE; 983 } 984 edit->lastx = button.x; 985 edit->lasty = button.y; 986 edit->last_state = button.state; 987 988 e_tep_event.button.type = GDK_BUTTON_RELEASE; 989 } 990 if (edit_display) { 991 GdkEventButton button = event->button; 992 e_tep_event.button.time = button.time; 993 e_tep_event.button.state = button.state; 994 e_tep_event.button.button = button.button; 995 e_tep_event.button.position = get_position_from_xy (edit, event->button.x, event->button.y); 996 _get_tep (edit); 997 edit->actions = 0; 998 return_val = e_text_event_processor_handle_event ( 999 edit->tep, &e_tep_event); 1000 *actions = edit->actions; 1001 if (event->button.button == 1) { 1002 if (event->type == GDK_BUTTON_PRESS) 1003 edit->button_down = TRUE; 1004 else 1005 edit->button_down = FALSE; 1006 } 1007 edit->lastx = button.x; 1008 edit->lasty = button.y; 1009 edit->last_state = button.state; 1010 } 1011 break; 1012 case GDK_MOTION_NOTIFY: 1013 event->motion.x -= 4; 1014 event->motion.y -= 1; 1015 if (edit_display) { 1016 GdkEventMotion motion = event->motion; 1017 e_tep_event.motion.time = motion.time; 1018 e_tep_event.motion.state = motion.state; 1019 e_tep_event.motion.position = get_position_from_xy (edit, event->motion.x, event->motion.y); 1020 _get_tep (edit); 1021 edit->actions = 0; 1022 return_val = e_text_event_processor_handle_event ( 1023 edit->tep, &e_tep_event); 1024 *actions = edit->actions; 1025 edit->lastx = motion.x; 1026 edit->lasty = motion.y; 1027 edit->last_state = motion.state; 1028 } 1029 break; 1030 case GDK_ENTER_NOTIFY: 1031 #if 0 1032 edit->pointer_in = TRUE; 1033 #endif 1034 if (edit_display) { 1035 if (edit->default_cursor_shown) { 1036 GdkWindow *window; 1037 1038 window = gtk_widget_get_window (canvas); 1039 gdk_window_set_cursor (window, text_view->i_cursor); 1040 edit->default_cursor_shown = FALSE; 1041 } 1042 } 1043 break; 1044 case GDK_LEAVE_NOTIFY: 1045 #if 0 1046 text_view->pointer_in = FALSE; 1047 #endif 1048 if (edit_display) { 1049 if (!edit->default_cursor_shown) { 1050 GdkWindow *window; 1051 1052 window = gtk_widget_get_window (canvas); 1053 gdk_window_set_cursor (window, NULL); 1054 edit->default_cursor_shown = TRUE; 1055 } 1056 } 1057 break; 1058 default: 1059 break; 1060 } 1061 1062 return return_val; 1063 } 1064 1065 /* 1066 * ECell::height method 1067 */ 1068 static gint 1069 ect_height (ECellView *ecell_view, 1070 gint model_col, 1071 gint view_col, 1072 gint row) 1073 { 1074 ECellTextView *text_view = (ECellTextView *) ecell_view; 1075 gint height; 1076 PangoLayout *layout; 1077 1078 layout = generate_layout (text_view, model_col, view_col, row, 0); 1079 pango_layout_get_pixel_size (layout, NULL, &height); 1080 g_object_unref (layout); 1081 return height + (get_vertical_spacing (GTK_WIDGET (text_view->canvas)) * 2); 1082 } 1083 1084 /* 1085 * ECellView::enter_edit method 1086 */ 1087 static gpointer 1088 ect_enter_edit (ECellView *ecell_view, 1089 gint model_col, 1090 gint view_col, 1091 gint row) 1092 { 1093 ECellTextView *text_view = (ECellTextView *) ecell_view; 1094 CellEdit *edit; 1095 ECellText *ect = E_CELL_TEXT (ecell_view->ecell); 1096 gchar *temp; 1097 1098 edit = g_new0 (CellEdit, 1); 1099 text_view->edit = edit; 1100 1101 edit->im_context = E_CANVAS (text_view->canvas)->im_context; 1102 edit->need_im_reset = FALSE; 1103 edit->im_context_signals_registered = FALSE; 1104 edit->view_col = -1; 1105 edit->model_col = -1; 1106 edit->row = -1; 1107 1108 edit->text_view = text_view; 1109 edit->model_col = model_col; 1110 edit->view_col = view_col; 1111 edit->row = row; 1112 edit->cell_width = e_table_header_get_column ( 1113 ((ETableItem *) ecell_view->e_table_item_view)->header, 1114 view_col)->width - 8; 1115 1116 edit->layout = generate_layout (text_view, model_col, view_col, row, edit->cell_width); 1117 1118 edit->xofs_edit = 0.0; 1119 edit->yofs_edit = 0.0; 1120 1121 edit->selection_start = 0; 1122 edit->selection_end = 0; 1123 edit->select_by_word = FALSE; 1124 1125 edit->timeout_id = g_timeout_add (10, _blink_scroll_timeout, text_view); 1126 edit->timer = g_timer_new (); 1127 g_timer_elapsed (edit->timer, &(edit->scroll_start)); 1128 g_timer_start (edit->timer); 1129 1130 edit->lastx = 0; 1131 edit->lasty = 0; 1132 edit->last_state = 0; 1133 1134 edit->scroll_start = 0; 1135 edit->show_cursor = TRUE; 1136 edit->button_down = FALSE; 1137 1138 edit->tep = NULL; 1139 1140 edit->has_selection = FALSE; 1141 1142 edit->pointer_in = FALSE; 1143 edit->default_cursor_shown = TRUE; 1144 1145 temp = e_cell_text_get_text (ect, ecell_view->e_table_model, model_col, row); 1146 edit->old_text = g_strdup (temp); 1147 e_cell_text_free_text (ect, temp); 1148 edit->text = g_strdup (edit->old_text); 1149 1150 if (edit->im_context) { 1151 gtk_im_context_reset (edit->im_context); 1152 if (!edit->im_context_signals_registered) { 1153 g_signal_connect ( 1154 edit->im_context, "preedit_changed", 1155 G_CALLBACK (e_cell_text_preedit_changed_cb), 1156 text_view); 1157 g_signal_connect ( 1158 edit->im_context, "commit", 1159 G_CALLBACK (e_cell_text_commit_cb), 1160 text_view); 1161 g_signal_connect ( 1162 edit->im_context, "retrieve_surrounding", 1163 G_CALLBACK (e_cell_text_retrieve_surrounding_cb), 1164 text_view); 1165 g_signal_connect ( 1166 edit->im_context, "delete_surrounding", 1167 G_CALLBACK (e_cell_text_delete_surrounding_cb), 1168 text_view); 1169 1170 edit->im_context_signals_registered = TRUE; 1171 } 1172 gtk_im_context_focus_in (edit->im_context); 1173 } 1174 1175 #if 0 1176 if (edit->pointer_in) { 1177 if (edit->default_cursor_shown) { 1178 gdk_window_set_cursor (GTK_WIDGET (item->canvas)->window, text_view->i_cursor); 1179 edit->default_cursor_shown = FALSE; 1180 } 1181 } 1182 #endif 1183 ect_queue_redraw (text_view, view_col, row); 1184 1185 return NULL; 1186 } 1187 1188 /* 1189 * ECellView::leave_edit method 1190 */ 1191 static void 1192 ect_leave_edit (ECellView *ecell_view, 1193 gint model_col, 1194 gint view_col, 1195 gint row, 1196 gpointer edit_context) 1197 { 1198 ECellTextView *text_view = (ECellTextView *) ecell_view; 1199 CellEdit *edit = text_view->edit; 1200 1201 if (edit) { 1202 if (edit->im_context) { 1203 gtk_im_context_focus_out (edit->im_context); 1204 1205 if (edit->im_context_signals_registered) { 1206 g_signal_handlers_disconnect_matched (edit->im_context, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, edit); 1207 edit->im_context_signals_registered = FALSE; 1208 } 1209 } 1210 ect_stop_editing (text_view, TRUE); 1211 } else { 1212 /* 1213 * We did invoke this leave edit internally 1214 */ 1215 } 1216 } 1217 1218 /* 1219 * ECellView::save_state method 1220 */ 1221 static gpointer 1222 ect_save_state (ECellView *ecell_view, 1223 gint model_col, 1224 gint view_col, 1225 gint row, 1226 gpointer edit_context) 1227 { 1228 ECellTextView *text_view = (ECellTextView *) ecell_view; 1229 CellEdit *edit = text_view->edit; 1230 1231 gint *save_state = g_new (int, 2); 1232 1233 save_state[0] = edit->selection_start; 1234 save_state[1] = edit->selection_end; 1235 return save_state; 1236 } 1237 1238 /* 1239 * ECellView::load_state method 1240 */ 1241 static void 1242 ect_load_state (ECellView *ecell_view, 1243 gint model_col, 1244 gint view_col, 1245 gint row, 1246 gpointer edit_context, 1247 gpointer save_state) 1248 { 1249 ECellTextView *text_view = (ECellTextView *) ecell_view; 1250 CellEdit *edit = text_view->edit; 1251 gint length; 1252 gint *selection = save_state; 1253 1254 length = strlen (edit->text); 1255 1256 edit->selection_start = MIN (selection[0], length); 1257 edit->selection_end = MIN (selection[1], length); 1258 1259 ect_queue_redraw (text_view, view_col, row); 1260 } 1261 1262 /* 1263 * ECellView::free_state method 1264 */ 1265 static void 1266 ect_free_state (ECellView *ecell_view, 1267 gint model_col, 1268 gint view_col, 1269 gint row, 1270 gpointer save_state) 1271 { 1272 g_free (save_state); 1273 } 1274 1275 static void 1276 get_font_size (PangoLayout *layout, 1277 PangoFontDescription *font, 1278 const gchar *text, 1279 gdouble *width, 1280 gdouble *height) 1281 { 1282 gint w; 1283 gint h; 1284 1285 g_return_if_fail (layout != NULL); 1286 pango_layout_set_font_description (layout, font); 1287 pango_layout_set_text (layout, text, -1); 1288 pango_layout_set_width (layout, -1); 1289 pango_layout_set_indent (layout, 0); 1290 1291 pango_layout_get_size (layout, &w, &h); 1292 1293 *width = (gdouble)w/(gdouble)PANGO_SCALE; 1294 *height = (gdouble)h/(gdouble)PANGO_SCALE; 1295 } 1296 1297 static void 1298 ect_print (ECellView *ecell_view, 1299 GtkPrintContext *context, 1300 gint model_col, 1301 gint view_col, 1302 gint row, 1303 gdouble width, 1304 gdouble height) 1305 { 1306 PangoFontDescription *font_des; 1307 PangoLayout *layout; 1308 PangoContext *pango_context; 1309 PangoFontMetrics *font_metrics; 1310 ECellText *ect = E_CELL_TEXT (ecell_view->ecell); 1311 ECellTextView *ectView = (ECellTextView *) ecell_view; 1312 GtkWidget *canvas = GTK_WIDGET (ectView->canvas); 1313 GtkStyle *style; 1314 PangoDirection dir; 1315 gboolean strikeout, underline; 1316 cairo_t *cr; 1317 gchar *string; 1318 gdouble ty, ly, text_width = 0.0, text_height = 0.0; 1319 1320 cr = gtk_print_context_get_cairo_context (context); 1321 string = e_cell_text_get_text (ect, ecell_view->e_table_model, model_col, row); 1322 1323 cairo_save (cr); 1324 layout = gtk_print_context_create_pango_layout (context); 1325 font_des = pango_font_description_from_string ("sans 10"); /* fix me font hardcoded */ 1326 pango_layout_set_font_description (layout, font_des); 1327 1328 pango_layout_set_text (layout, string, -1); 1329 get_font_size (layout, font_des, string, &text_width, &text_height); 1330 1331 cairo_move_to (cr, 2, 2); 1332 cairo_rectangle (cr, 2, 2, width + 2, height + 2); 1333 cairo_clip (cr); 1334 1335 style = gtk_widget_get_style (canvas); 1336 pango_context = gtk_widget_get_pango_context (canvas); 1337 font_metrics = pango_context_get_metrics ( 1338 pango_context, style->font_desc, 1339 pango_context_get_language (pango_context)); 1340 ty = (gdouble)(text_height - 1341 pango_font_metrics_get_ascent (font_metrics) - 1342 pango_font_metrics_get_descent (font_metrics)) / 2.0 /(gdouble) PANGO_SCALE; 1343 1344 strikeout = ect->strikeout_column >= 0 && row >= 0 && 1345 e_table_model_value_at (ecell_view->e_table_model, ect->strikeout_column, row); 1346 underline = ect->underline_column >= 0 && row >= 0 && 1347 e_table_model_value_at (ecell_view->e_table_model, ect->underline_column, row); 1348 1349 dir = pango_find_base_dir (string, strlen (string)); 1350 1351 if (underline) { 1352 ly = ty + (gdouble) pango_font_metrics_get_underline_position (font_metrics) / (gdouble) PANGO_SCALE; 1353 cairo_new_path (cr); 1354 if (dir == PANGO_DIRECTION_RTL) { 1355 cairo_move_to (cr, width - 2, ly + text_height + 6); 1356 cairo_line_to (cr, MAX (width - 2 - text_width, 2), ly + text_height + 6); 1357 } 1358 else { 1359 cairo_move_to (cr, 2, ly + text_height + 6); 1360 cairo_line_to (cr, MIN (2 + text_width, width - 2), ly + text_height + 6); 1361 } 1362 cairo_set_line_width (cr, (gdouble) pango_font_metrics_get_underline_thickness (font_metrics) / (gdouble) PANGO_SCALE); 1363 cairo_stroke (cr); 1364 } 1365 1366 if (strikeout) { 1367 ly = ty + (gdouble) pango_font_metrics_get_strikethrough_position (font_metrics) / (gdouble) PANGO_SCALE; 1368 cairo_new_path (cr); 1369 if (dir == PANGO_DIRECTION_RTL) { 1370 cairo_move_to (cr, width - 2, ly + text_height + 6); 1371 cairo_line_to (cr, MAX (width - 2 - text_width, 2), ly + text_height + 6); 1372 } 1373 else { 1374 cairo_move_to (cr, 2, ly + text_height + 6); 1375 cairo_line_to (cr, MIN (2 + text_width, width - 2), ly + text_height + 6); 1376 } 1377 cairo_set_line_width (cr,(gdouble) pango_font_metrics_get_strikethrough_thickness (font_metrics) / (gdouble) PANGO_SCALE); 1378 1379 cairo_stroke (cr); 1380 } 1381 1382 cairo_move_to (cr, 2, text_height- 5); 1383 pango_layout_set_width (layout, (width - 4) * PANGO_SCALE); 1384 pango_layout_set_wrap (layout, PANGO_WRAP_CHAR); 1385 pango_cairo_show_layout (cr, layout); 1386 cairo_restore (cr); 1387 1388 pango_font_description_free (font_des); 1389 g_object_unref (layout); 1390 e_cell_text_free_text (ect, string); 1391 } 1392 1393 static gdouble 1394 ect_print_height (ECellView *ecell_view, 1395 GtkPrintContext *context, 1396 gint model_col, 1397 gint view_col, 1398 gint row, 1399 gdouble width) 1400 { 1401 /* 1402 * Font size is 16 by default. To leave some margin for cell 1403 * text area, 2 for footer, 2 for header, actual print height 1404 * should be 16 + 4. 1405 * Height of some special font is much higher than others, 1406 * such as Arabic. So leave some more margin for cell. 1407 */ 1408 PangoFontDescription *font_des; 1409 PangoLayout *layout; 1410 ECellText *ect = E_CELL_TEXT (ecell_view->ecell); 1411 gchar *string; 1412 gdouble text_width = 0.0, text_height = 0.0; 1413 gint lines = 1; 1414 1415 string = e_cell_text_get_text (ect, ecell_view->e_table_model, model_col, row); 1416 1417 layout = gtk_print_context_create_pango_layout (context); 1418 font_des = pango_font_description_from_string ("sans 10"); /* fix me font hardcoded */ 1419 pango_layout_set_font_description (layout, font_des); 1420 1421 pango_layout_set_text (layout, string, -1); 1422 get_font_size (layout, font_des, string, &text_width, &text_height); 1423 /* Checking if the text width goes beyond the column width to increase the 1424 * number of lines. 1425 */ 1426 if (text_width > width - 4) 1427 lines = (text_width / (width - 4)) + 1; 1428 return 16 *lines + 8; 1429 } 1430 1431 static gint 1432 ect_max_width (ECellView *ecell_view, 1433 gint model_col, 1434 gint view_col) 1435 { 1436 /* New ECellText */ 1437 ECellTextView *text_view = (ECellTextView *) ecell_view; 1438 gint row; 1439 gint number_of_rows; 1440 gint max_width = 0; 1441 1442 number_of_rows = e_table_model_row_count (ecell_view->e_table_model); 1443 1444 for (row = 0; row < number_of_rows; row++) { 1445 PangoLayout *layout = generate_layout (text_view, model_col, view_col, row, 0); 1446 gint width; 1447 1448 pango_layout_get_pixel_size (layout, &width, NULL); 1449 1450 max_width = MAX (max_width, width); 1451 g_object_unref (layout); 1452 } 1453 1454 return max_width + 8; 1455 } 1456 1457 static gint 1458 ect_max_width_by_row (ECellView *ecell_view, 1459 gint model_col, 1460 gint view_col, 1461 gint row) 1462 { 1463 /* New ECellText */ 1464 ECellTextView *text_view = (ECellTextView *) ecell_view; 1465 gint width; 1466 PangoLayout *layout; 1467 1468 if (row >= e_table_model_row_count (ecell_view->e_table_model)) 1469 return 0; 1470 1471 layout = generate_layout (text_view, model_col, view_col, row, 0); 1472 pango_layout_get_pixel_size (layout, &width, NULL); 1473 g_object_unref (layout); 1474 1475 return width + 8; 1476 } 1477 1478 static void 1479 ect_finalize (GObject *object) 1480 { 1481 ECellText *ect = E_CELL_TEXT (object); 1482 1483 g_free (ect->font_name); 1484 1485 G_OBJECT_CLASS (e_cell_text_parent_class)->finalize (object); 1486 } 1487 1488 /* Set_arg handler for the text item */ 1489 static void 1490 ect_set_property (GObject *object, 1491 guint property_id, 1492 const GValue *value, 1493 GParamSpec *pspec) 1494 { 1495 ECellText *text; 1496 1497 text = E_CELL_TEXT (object); 1498 1499 switch (property_id) { 1500 case PROP_STRIKEOUT_COLUMN: 1501 text->strikeout_column = g_value_get_int (value); 1502 break; 1503 1504 case PROP_UNDERLINE_COLUMN: 1505 text->underline_column = g_value_get_int (value); 1506 break; 1507 1508 case PROP_BOLD_COLUMN: 1509 text->bold_column = g_value_get_int (value); 1510 break; 1511 1512 case PROP_COLOR_COLUMN: 1513 text->color_column = g_value_get_int (value); 1514 break; 1515 1516 case PROP_EDITABLE: 1517 text->editable = g_value_get_boolean (value); 1518 break; 1519 1520 case PROP_BG_COLOR_COLUMN: 1521 text->bg_color_column = g_value_get_int (value); 1522 break; 1523 1524 default: 1525 return; 1526 } 1527 } 1528 1529 /* Get_arg handler for the text item */ 1530 static void 1531 ect_get_property (GObject *object, 1532 guint property_id, 1533 GValue *value, 1534 GParamSpec *pspec) 1535 { 1536 ECellText *text; 1537 1538 text = E_CELL_TEXT (object); 1539 1540 switch (property_id) { 1541 case PROP_STRIKEOUT_COLUMN: 1542 g_value_set_int (value, text->strikeout_column); 1543 break; 1544 1545 case PROP_UNDERLINE_COLUMN: 1546 g_value_set_int (value, text->underline_column); 1547 break; 1548 1549 case PROP_BOLD_COLUMN: 1550 g_value_set_int (value, text->bold_column); 1551 break; 1552 1553 case PROP_COLOR_COLUMN: 1554 g_value_set_int (value, text->color_column); 1555 break; 1556 1557 case PROP_EDITABLE: 1558 g_value_set_boolean (value, text->editable); 1559 break; 1560 1561 case PROP_BG_COLOR_COLUMN: 1562 g_value_set_int (value, text->bg_color_column); 1563 break; 1564 1565 default: 1566 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); 1567 break; 1568 } 1569 } 1570 1571 static gchar *ellipsis_default = NULL; 1572 static gboolean use_ellipsis_default = TRUE; 1573 1574 static void 1575 e_cell_text_class_init (ECellTextClass *class) 1576 { 1577 ECellClass *ecc = E_CELL_CLASS (class); 1578 GObjectClass *object_class = G_OBJECT_CLASS (class); 1579 const gchar *ellipsis_env; 1580 1581 object_class->finalize = ect_finalize; 1582 1583 ecc->new_view = ect_new_view; 1584 ecc->kill_view = ect_kill_view; 1585 ecc->realize = ect_realize; 1586 ecc->unrealize = ect_unrealize; 1587 ecc->draw = ect_draw; 1588 ecc->event = ect_event; 1589 ecc->height = ect_height; 1590 ecc->enter_edit = ect_enter_edit; 1591 ecc->leave_edit = ect_leave_edit; 1592 ecc->save_state = ect_save_state; 1593 ecc->load_state = ect_load_state; 1594 ecc->free_state = ect_free_state; 1595 ecc->print = ect_print; 1596 ecc->print_height = ect_print_height; 1597 ecc->max_width = ect_max_width; 1598 ecc->max_width_by_row = ect_max_width_by_row; 1599 ecc->get_bg_color = ect_get_bg_color; 1600 1601 class->get_text = ect_real_get_text; 1602 class->free_text = ect_real_free_text; 1603 class->set_value = ect_real_set_value; 1604 1605 object_class->get_property = ect_get_property; 1606 object_class->set_property = ect_set_property; 1607 1608 signals[TEXT_INSERTED] = g_signal_new ( 1609 "text_inserted", 1610 G_TYPE_FROM_CLASS (object_class), 1611 G_SIGNAL_RUN_FIRST, 1612 G_STRUCT_OFFSET (ECellTextClass, text_inserted), 1613 NULL, NULL, 1614 e_marshal_VOID__POINTER_INT_INT_INT_INT, 1615 G_TYPE_NONE, 5, 1616 G_TYPE_POINTER, 1617 G_TYPE_INT, 1618 G_TYPE_INT, 1619 G_TYPE_INT, 1620 G_TYPE_INT); 1621 1622 signals[TEXT_DELETED] = g_signal_new ( 1623 "text_deleted", 1624 G_TYPE_FROM_CLASS (object_class), 1625 G_SIGNAL_RUN_FIRST, 1626 G_STRUCT_OFFSET (ECellTextClass, text_deleted), 1627 NULL, NULL, 1628 e_marshal_VOID__POINTER_INT_INT_INT_INT, 1629 G_TYPE_NONE, 5, 1630 G_TYPE_POINTER, 1631 G_TYPE_INT, 1632 G_TYPE_INT, 1633 G_TYPE_INT, 1634 G_TYPE_INT); 1635 1636 g_object_class_install_property ( 1637 object_class, 1638 PROP_STRIKEOUT_COLUMN, 1639 g_param_spec_int ( 1640 "strikeout_column", 1641 "Strikeout Column", 1642 NULL, 1643 -1, G_MAXINT, -1, 1644 G_PARAM_READWRITE)); 1645 1646 g_object_class_install_property ( 1647 object_class, 1648 PROP_UNDERLINE_COLUMN, 1649 g_param_spec_int ( 1650 "underline_column", 1651 "Underline Column", 1652 NULL, 1653 -1, G_MAXINT, -1, 1654 G_PARAM_READWRITE)); 1655 1656 g_object_class_install_property ( 1657 object_class, 1658 PROP_BOLD_COLUMN, 1659 g_param_spec_int ( 1660 "bold_column", 1661 "Bold Column", 1662 NULL, 1663 -1, G_MAXINT, -1, 1664 G_PARAM_READWRITE)); 1665 1666 g_object_class_install_property ( 1667 object_class, 1668 PROP_COLOR_COLUMN, 1669 g_param_spec_int ( 1670 "color_column", 1671 "Color Column", 1672 NULL, 1673 -1, G_MAXINT, -1, 1674 G_PARAM_READWRITE)); 1675 1676 g_object_class_install_property ( 1677 object_class, 1678 PROP_EDITABLE, 1679 g_param_spec_boolean ( 1680 "editable", 1681 "Editable", 1682 NULL, 1683 FALSE, 1684 G_PARAM_READWRITE)); 1685 1686 g_object_class_install_property ( 1687 object_class, 1688 PROP_BG_COLOR_COLUMN, 1689 g_param_spec_int ( 1690 "bg_color_column", 1691 "BG Color Column", 1692 NULL, 1693 -1, G_MAXINT, -1, 1694 G_PARAM_READWRITE)); 1695 1696 if (!clipboard_atom) 1697 clipboard_atom = gdk_atom_intern ("CLIPBOARD", FALSE); 1698 1699 ellipsis_env = g_getenv ("GAL_ELLIPSIS"); 1700 if (ellipsis_env) { 1701 if (*ellipsis_env) { 1702 ellipsis_default = g_strdup (ellipsis_env); 1703 } else { 1704 use_ellipsis_default = FALSE; 1705 } 1706 } 1707 } 1708 1709 /* IM Context Callbacks */ 1710 1711 static void 1712 e_cell_text_get_cursor_locations (ECellTextView *tv, 1713 GdkRectangle *strong_pos, 1714 GdkRectangle *weak_pos) 1715 { 1716 GdkRectangle area; 1717 CellEdit *edit = tv->edit; 1718 ECellView *cell_view = (ECellView *) tv; 1719 ETableItem *item = E_TABLE_ITEM ((cell_view)->e_table_item_view); 1720 GnomeCanvasItem *parent_item = GNOME_CANVAS_ITEM (item)->parent; 1721 PangoRectangle pango_strong_pos; 1722 PangoRectangle pango_weak_pos; 1723 gint x, y, col, row; 1724 gdouble x1,y1; 1725 gint cx, cy; 1726 gint index; 1727 1728 row = edit->row; 1729 col = edit->view_col; 1730 1731 e_table_item_get_cell_geometry ( 1732 item, &row, &col, &x, &y, NULL, &area.height); 1733 1734 gnome_canvas_item_get_bounds (GNOME_CANVAS_ITEM (parent_item), &x1, &y1, NULL, NULL); 1735 1736 gnome_canvas_get_scroll_offsets (GNOME_CANVAS (GNOME_CANVAS_ITEM (parent_item)->canvas), &cx, &cy); 1737 1738 index = edit->selection_end + edit->preedit_pos; 1739 1740 pango_layout_get_cursor_pos ( 1741 edit->layout, 1742 index, 1743 strong_pos ? &pango_strong_pos : NULL, 1744 weak_pos ? &pango_weak_pos : NULL); 1745 1746 if (strong_pos) { 1747 strong_pos->x = x + x1 - cx - edit->xofs_edit + pango_strong_pos.x / PANGO_SCALE; 1748 strong_pos->y = y + y1 - cy - edit->yofs_edit + pango_strong_pos.y / PANGO_SCALE; 1749 strong_pos->width = 0; 1750 strong_pos->height = pango_strong_pos.height / PANGO_SCALE; 1751 } 1752 1753 if (weak_pos) { 1754 weak_pos->x = x + x1 - cx - edit->xofs_edit + pango_weak_pos.x / PANGO_SCALE; 1755 weak_pos->y = y + y1 - cy - edit->yofs_edit + pango_weak_pos.y / PANGO_SCALE; 1756 weak_pos->width = 0; 1757 weak_pos->height = pango_weak_pos.height / PANGO_SCALE; 1758 } 1759 } 1760 1761 static void 1762 update_im_cursor_location (ECellTextView *tv) 1763 { 1764 CellEdit *edit = tv->edit; 1765 GdkRectangle area; 1766 1767 e_cell_text_get_cursor_locations (tv, &area, NULL); 1768 1769 gtk_im_context_set_cursor_location (edit->im_context, &area); 1770 } 1771 1772 static void 1773 e_cell_text_preedit_changed_cb (GtkIMContext *context, 1774 ECellTextView *tv) 1775 { 1776 gchar *preedit_string; 1777 gint cursor_pos; 1778 CellEdit *edit = tv->edit; 1779 gtk_im_context_get_preedit_string ( 1780 edit->im_context, &preedit_string, 1781 NULL, &cursor_pos); 1782 1783 edit->preedit_length = strlen (preedit_string); 1784 cursor_pos = CLAMP (cursor_pos, 0, g_utf8_strlen (preedit_string, -1)); 1785 edit->preedit_pos = g_utf8_offset_to_pointer (preedit_string, cursor_pos) - preedit_string; 1786 g_free (preedit_string); 1787 1788 ect_queue_redraw (tv, edit->view_col, edit->row); 1789 } 1790 1791 static void 1792 e_cell_text_commit_cb (GtkIMContext *context, 1793 const gchar *str, 1794 ECellTextView *tv) 1795 { 1796 CellEdit *edit = tv->edit; 1797 ETextEventProcessorCommand command; 1798 1799 if (g_utf8_validate (str, strlen (str), NULL)) { 1800 command.action = E_TEP_INSERT; 1801 command.position = E_TEP_SELECTION; 1802 command.string = (gchar *) str; 1803 command.value = strlen (str); 1804 e_cell_text_view_command (edit->tep, &command, edit); 1805 } 1806 1807 } 1808 1809 static gboolean 1810 e_cell_text_retrieve_surrounding_cb (GtkIMContext *context, 1811 ECellTextView *tv) 1812 { 1813 CellEdit *edit = tv->edit; 1814 1815 gtk_im_context_set_surrounding ( 1816 context, 1817 edit->text, 1818 strlen (edit->text), 1819 MIN (edit->selection_start, edit->selection_end)); 1820 1821 return TRUE; 1822 } 1823 1824 static gboolean 1825 e_cell_text_delete_surrounding_cb (GtkIMContext *context, 1826 gint offset, 1827 gint n_chars, 1828 ECellTextView *tv) 1829 { 1830 gint begin_pos, end_pos; 1831 glong text_len; 1832 CellEdit *edit = tv->edit; 1833 1834 text_len = g_utf8_strlen (edit->text, -1); 1835 begin_pos = g_utf8_pointer_to_offset ( 1836 edit->text, 1837 edit->text + MIN (edit->selection_start, edit->selection_end)); 1838 begin_pos += offset; 1839 end_pos = begin_pos + n_chars; 1840 if (begin_pos < 0 || text_len < begin_pos) 1841 return FALSE; 1842 if (end_pos > text_len) 1843 end_pos = text_len; 1844 edit->selection_start = g_utf8_offset_to_pointer (edit->text, begin_pos) 1845 - edit->text; 1846 edit->selection_end = g_utf8_offset_to_pointer (edit->text, end_pos) 1847 - edit->text; 1848 1849 _delete_selection (tv); 1850 1851 return TRUE; 1852 } 1853 1854 static void 1855 e_cell_text_init (ECellText *ect) 1856 { 1857 ect->ellipsis = g_strdup (ellipsis_default); 1858 ect->use_ellipsis = use_ellipsis_default; 1859 ect->strikeout_column = -1; 1860 ect->underline_column = -1; 1861 ect->bold_column = -1; 1862 ect->color_column = -1; 1863 ect->bg_color_column = -1; 1864 ect->editable = TRUE; 1865 } 1866 1867 /** 1868 * e_cell_text_new: 1869 * @fontname: this param is no longer used, but left here for api stability 1870 * @justify: Justification of the string in the cell. 1871 * 1872 * Creates a new ECell renderer that can be used to render strings that 1873 * that come from the model. The value returned from the model is 1874 * interpreted as being a gchar *. 1875 * 1876 * The ECellText object support a large set of properties that can be 1877 * configured through the Gtk argument system and allows the user to have 1878 * a finer control of the way the string is displayed. The arguments supported 1879 * allow the control of strikeout, underline, bold, and color. 1880 * 1881 * The arguments "strikeout_column", "underline_column", "bold_column" 1882 * and "color_column" set and return an integer that points to a 1883 * column in the model that controls these settings. So controlling 1884 * the way things are rendered is achieved by having special columns 1885 * in the model that will be used to flag whether the text should be 1886 * rendered with strikeout, or bolded. In the case of the 1887 * "color_column" argument, the column in the model is expected to 1888 * have a string that can be parsed by gdk_color_parse(). 1889 * 1890 * Returns: an ECell object that can be used to render strings. 1891 */ 1892 ECell * 1893 e_cell_text_new (const gchar *fontname, 1894 GtkJustification justify) 1895 { 1896 ECellText *ect = g_object_new (E_TYPE_CELL_TEXT, NULL); 1897 1898 e_cell_text_construct (ect, fontname, justify); 1899 1900 return (ECell *) ect; 1901 } 1902 1903 /** 1904 * e_cell_text_construct: 1905 * @cell: The cell to construct 1906 * @fontname: this param is no longer used, but left here for api stability 1907 * @justify: Justification of the string in the cell 1908 * 1909 * constructs the ECellText. To be used by subclasses and language 1910 * bindings. 1911 * 1912 * Returns: The ECellText. 1913 */ 1914 ECell * 1915 e_cell_text_construct (ECellText *cell, 1916 const gchar *fontname, 1917 GtkJustification justify) 1918 { 1919 if (!cell) 1920 return E_CELL (NULL); 1921 if (fontname) 1922 cell->font_name = g_strdup (fontname); 1923 cell->justify = justify; 1924 return E_CELL (cell); 1925 } 1926 1927 gchar * 1928 e_cell_text_get_text (ECellText *cell, 1929 ETableModel *model, 1930 gint col, 1931 gint row) 1932 { 1933 ECellTextClass *class; 1934 1935 g_return_val_if_fail (E_IS_CELL_TEXT (cell), NULL); 1936 1937 class = E_CELL_TEXT_GET_CLASS (cell); 1938 if (class->get_text == NULL) 1939 return NULL; 1940 1941 return class->get_text (cell, model, col, row); 1942 } 1943 1944 void 1945 e_cell_text_free_text (ECellText *cell, 1946 gchar *text) 1947 { 1948 ECellTextClass *class; 1949 1950 g_return_if_fail (E_IS_CELL_TEXT (cell)); 1951 1952 class = E_CELL_TEXT_GET_CLASS (cell); 1953 if (class->free_text == NULL) 1954 return; 1955 1956 class->free_text (cell, text); 1957 } 1958 1959 void 1960 e_cell_text_set_value (ECellText *cell, 1961 ETableModel *model, 1962 gint col, 1963 gint row, 1964 const gchar *text) 1965 { 1966 ECellTextClass *class; 1967 1968 g_return_if_fail (E_IS_CELL_TEXT (cell)); 1969 1970 class = E_CELL_TEXT_GET_CLASS (cell); 1971 if (class->set_value == NULL) 1972 return; 1973 1974 class->set_value (cell, model, col, row, text); 1975 } 1976 1977 /* fixme: Handle Font attributes */ 1978 /* position is in BYTES */ 1979 1980 static gint 1981 get_position_from_xy (CellEdit *edit, 1982 gint x, 1983 gint y) 1984 { 1985 gint index; 1986 gint trailing; 1987 const gchar *text; 1988 1989 PangoLayout *layout = generate_layout (edit->text_view, edit->model_col, edit->view_col, edit->row, edit->cell_width);
Access to field 'text_view' results in a dereference of a null pointer (loaded from variable 'edit')
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

Access to field 'text_view' results in a dereference of a null pointer (loaded from variable 'edit')
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

1990 ECellTextView *text_view = edit->text_view; 1991 ECellText *ect = (ECellText *) ((ECellView *) text_view)->ecell; 1992 1993 x -= (ect->x + text_view->xofs - edit->xofs_edit); 1994 y -= (ect->y + text_view->yofs - edit->yofs_edit); 1995 1996 pango_layout_xy_to_index (layout, x * PANGO_SCALE, y * PANGO_SCALE, &index, &trailing); 1997 1998 text = pango_layout_get_text (layout); 1999 2000 return g_utf8_offset_to_pointer (text + index, trailing) - text; 2001 } 2002 2003 #define SCROLL_WAIT_TIME 30000 2004 2005 static gboolean 2006 _blink_scroll_timeout (gpointer data) 2007 { 2008 ECellTextView *text_view = (ECellTextView *) data; 2009 ECellText *ect = E_CELL_TEXT (((ECellView *) text_view)->ecell); 2010 CellEdit *edit = text_view->edit; 2011 2012 gulong current_time; 2013 gboolean scroll = FALSE; 2014 gboolean redraw = FALSE; 2015 gint width, height; 2016 2017 g_timer_elapsed (edit->timer, &current_time); 2018 2019 if (edit->scroll_start + SCROLL_WAIT_TIME > 1000000) { 2020 if (current_time > edit->scroll_start - (1000000 - SCROLL_WAIT_TIME) && 2021 current_time < edit->scroll_start) 2022 scroll = TRUE; 2023 } else { 2024 if (current_time > edit->scroll_start + SCROLL_WAIT_TIME || 2025 current_time < edit->scroll_start) 2026 scroll = TRUE; 2027 } 2028 2029 pango_layout_get_pixel_size (edit->layout, &width, &height); 2030 2031 if (scroll && edit->button_down) { 2032 /* FIXME: Copy this for y. */ 2033 if (edit->lastx - ect->x > edit->cell_width) { 2034 if (edit->xofs_edit < width - edit->cell_width) { 2035 edit->xofs_edit += 4; 2036 if (edit->xofs_edit > width - edit->cell_width + 1) 2037 edit->xofs_edit = width - edit->cell_width + 1; 2038 redraw = TRUE; 2039 } 2040 } 2041 if (edit->lastx - ect->x < 0 && 2042 edit->xofs_edit > 0) { 2043 edit->xofs_edit -= 4; 2044 if (edit->xofs_edit < 0) 2045 edit->xofs_edit = 0; 2046 redraw = TRUE; 2047 } 2048 if (redraw) { 2049 ETextEventProcessorEvent e_tep_event; 2050 e_tep_event.type = GDK_MOTION_NOTIFY; 2051 e_tep_event.motion.state = edit->last_state; 2052 e_tep_event.motion.time = 0; 2053 e_tep_event.motion.position = get_position_from_xy (edit, edit->lastx, edit->lasty); 2054 _get_tep (edit); 2055 e_text_event_processor_handle_event ( 2056 edit->tep, 2057 &e_tep_event); 2058 edit->scroll_start = current_time; 2059 } 2060 } 2061 2062 if (!((current_time / 500000) % 2)) { 2063 if (!edit->show_cursor) 2064 redraw = TRUE; 2065 edit->show_cursor = TRUE; 2066 } else { 2067 if (edit->show_cursor) 2068 redraw = TRUE; 2069 edit->show_cursor = FALSE; 2070 } 2071 if (redraw) { 2072 ect_queue_redraw (text_view, edit->view_col, edit->row); 2073 } 2074 return TRUE; 2075 } 2076 2077 static gint 2078 next_word (CellEdit *edit, 2079 gint start) 2080 { 2081 gchar *p; 2082 gint length; 2083 2084 length = strlen (edit->text); 2085 if (start >= length) 2086 return length; 2087 2088 p = g_utf8_next_char (edit->text + start); 2089 2090 while (*p && g_unichar_validate (g_utf8_get_char (p))) { 2091 gunichar unival = g_utf8_get_char (p); 2092 if (g_unichar_isspace (unival)) 2093 return p - edit->text; 2094 p = g_utf8_next_char (p); 2095 } 2096 2097 return p - edit->text; 2098 } 2099 2100 static gint 2101 _get_position (ECellTextView *text_view, 2102 ETextEventProcessorCommand *command) 2103 { 2104 gint length; 2105 CellEdit *edit = text_view->edit; 2106 gchar *p; 2107 gint unival; 2108 gint index; 2109 gint trailing; 2110 2111 switch (command->position) { 2112 2113 case E_TEP_VALUE: 2114 return command->value; 2115 2116 case E_TEP_SELECTION: 2117 return edit->selection_end; 2118 2119 case E_TEP_START_OF_BUFFER: 2120 return 0; 2121 2122 /* fixme: this probably confuses TEP */ 2123 2124 case E_TEP_END_OF_BUFFER: 2125 return strlen (edit->text); 2126 2127 case E_TEP_START_OF_LINE: 2128 2129 if (edit->selection_end < 1) return 0; 2130 2131 p = g_utf8_find_prev_char (edit->text, edit->text + edit->selection_end); 2132 2133 if (p == edit->text) return 0; 2134 2135 p = g_utf8_find_prev_char (edit->text, p); 2136 2137 while (p && p > edit->text) { 2138 if (*p == '\n') return p - edit->text + 1; 2139 p = g_utf8_find_prev_char (edit->text, p); 2140 } 2141 2142 return 0; 2143 2144 case E_TEP_END_OF_LINE: 2145 2146 length = strlen (edit->text); 2147 if (edit->selection_end >= length) return length; 2148 2149 p = g_utf8_next_char (edit->text + edit->selection_end); 2150 2151 while (*p && g_unichar_validate (g_utf8_get_char (p))) { 2152 if (*p == '\n') return p - edit->text; 2153 p = g_utf8_next_char (p); 2154 } 2155 2156 return p - edit->text; 2157 2158 case E_TEP_FORWARD_CHARACTER: 2159 2160 length = strlen (edit->text); 2161 if (edit->selection_end >= length) return length; 2162 2163 p = g_utf8_next_char (edit->text + edit->selection_end); 2164 2165 return p - edit->text; 2166 2167 case E_TEP_BACKWARD_CHARACTER: 2168 2169 if (edit->selection_end < 1) return 0; 2170 2171 p = g_utf8_find_prev_char (edit->text, edit->text + edit->selection_end); 2172 2173 if (p == NULL) return 0; 2174 2175 return p - edit->text; 2176 2177 case E_TEP_FORWARD_WORD: 2178 return next_word (edit, edit->selection_end); 2179 2180 case E_TEP_BACKWARD_WORD: 2181 2182 if (edit->selection_end < 1) return 0; 2183 2184 p = g_utf8_find_prev_char (edit->text, edit->text + edit->selection_end); 2185 2186 if (p == edit->text) return 0; 2187 2188 p = g_utf8_find_prev_char (edit->text, p); 2189 2190 while (p && p > edit->text && g_unichar_validate (g_utf8_get_char (p))) { 2191 unival = g_utf8_get_char (p); 2192 if (g_unichar_isspace (unival)) { 2193 return (g_utf8_next_char (p) - edit->text); 2194 } 2195 p = g_utf8_find_prev_char (edit->text, p); 2196 } 2197 2198 return 0; 2199 2200 case E_TEP_FORWARD_LINE: 2201 pango_layout_move_cursor_visually ( 2202 edit->layout, 2203 TRUE, 2204 edit->selection_end, 2205 0, 2206 TRUE, 2207 &index, 2208 &trailing); 2209 index = g_utf8_offset_to_pointer (edit->text + index, trailing) - edit->text; 2210 if (index < 0) 2211 return 0; 2212 length = strlen (edit->text); 2213 if (index >= length) 2214 return length; 2215 return index; 2216 case E_TEP_BACKWARD_LINE: 2217 pango_layout_move_cursor_visually ( 2218 edit->layout, 2219 TRUE, 2220 edit->selection_end, 2221 0, 2222 TRUE, 2223 &index, 2224 &trailing); 2225 2226 index = g_utf8_offset_to_pointer (edit->text + index, trailing) - edit->text; 2227 if (index < 0) 2228 return 0; 2229 length = strlen (edit->text); 2230 if (index >= length) 2231 return length; 2232 return index; 2233 case E_TEP_FORWARD_PARAGRAPH: 2234 case E_TEP_BACKWARD_PARAGRAPH: 2235 2236 case E_TEP_FORWARD_PAGE: 2237 case E_TEP_BACKWARD_PAGE: 2238 return edit->selection_end; 2239 default: 2240 return edit->selection_end; 2241 } 2242 2243 g_return_val_if_reached (0); 2244 2245 return 0; /* Kill warning */ 2246 } 2247 2248 static void 2249 _delete_selection (ECellTextView *text_view) 2250 { 2251 CellEdit *edit = text_view->edit; 2252 gint length; 2253 gchar *sp, *ep; 2254 2255 if (edit->selection_end == edit->selection_start) return; 2256 2257 if (edit->selection_end < edit->selection_start) { 2258 edit->selection_end ^= edit->selection_start; 2259 edit->selection_start ^= edit->selection_end; 2260 edit->selection_end ^= edit->selection_start; 2261 } 2262 2263 sp = edit->text + edit->selection_start; 2264 ep = edit->text + edit->selection_end; 2265 length = strlen (ep) + 1; 2266 2267 memmove (sp, ep, length); 2268 2269 edit->selection_end = edit->selection_start; 2270 2271 g_signal_emit (VIEW_TO_CELL (text_view), signals[TEXT_DELETED], 0, text_view, edit->selection_start, ep - sp, edit->row, edit->model_col); 2272 } 2273 2274 /* fixme: */ 2275 /* NB! We expect value to be length IN BYTES */ 2276 2277 static void 2278 _insert (ECellTextView *text_view, 2279 const gchar *string, 2280 gint value) 2281 { 2282 CellEdit *edit = text_view->edit; 2283 gchar *temp; 2284 2285 if (value <= 0) return; 2286 2287 edit->selection_start = MIN (strlen (edit->text), edit->selection_start); 2288 2289 temp = g_new (gchar, strlen (edit->text) + value + 1); 2290 2291 strncpy (temp, edit->text, edit->selection_start); 2292 strncpy (temp + edit->selection_start, string, value); 2293 strcpy (temp + edit->selection_start + value, edit->text + edit->selection_end); 2294 2295 g_free (edit->text); 2296 2297 edit->text = temp; 2298 2299 edit->selection_start += value; 2300 edit->selection_end = edit->selection_start; 2301 2302 g_signal_emit (VIEW_TO_CELL (text_view), signals[TEXT_INSERTED], 0, text_view, edit->selection_end - value, value, edit->row, edit->model_col); 2303 } 2304 2305 static void 2306 capitalize (CellEdit *edit, 2307 gint start, 2308 gint end, 2309 ETextEventProcessorCaps type) 2310 { 2311 ECellTextView *text_view = edit->text_view; 2312 2313 gboolean first = TRUE; 2314 gint character_length = g_utf8_strlen (edit->text + start, start - end); 2315 const gchar *p = edit->text + start; 2316 const gchar *text_end = edit->text + end; 2317 gchar *new_text = g_new0 (char, character_length * 6 + 1); 2318 gchar *output = new_text; 2319 2320 while (p && *p && p < text_end && g_unichar_validate (g_utf8_get_char (p))) { 2321 gunichar unival = g_utf8_get_char (p); 2322 gunichar newval = unival; 2323 2324 switch (type) { 2325 case E_TEP_CAPS_UPPER: 2326 newval = g_unichar_toupper (unival); 2327 break; 2328 case E_TEP_CAPS_LOWER: 2329 newval = g_unichar_tolower (unival); 2330 break; 2331 case E_TEP_CAPS_TITLE: 2332 if (g_unichar_isalpha (unival)) { 2333 if (first) 2334 newval = g_unichar_totitle (unival); 2335 else 2336 newval = g_unichar_tolower (unival); 2337 first = FALSE; 2338 } else { 2339 first = TRUE; 2340 } 2341 break; 2342 } 2343 g_unichar_to_utf8 (newval, output); 2344 output = g_utf8_next_char (output); 2345 2346 p = g_utf8_next_char (p); 2347 } 2348 *output = 0; 2349 2350 edit->selection_end = end; 2351 edit->selection_start = start; 2352 _delete_selection (text_view); 2353 2354 _insert (text_view, new_text, output - new_text); 2355 2356 g_free (new_text); 2357 } 2358 2359 static void 2360 e_cell_text_view_command (ETextEventProcessor *tep, 2361 ETextEventProcessorCommand *command, 2362 gpointer data) 2363 { 2364 CellEdit *edit = (CellEdit *) data; 2365 ECellTextView *text_view = edit->text_view; 2366 ECellText *ect = E_CELL_TEXT (text_view->cell_view.ecell); 2367 2368 gboolean change = FALSE; 2369 gboolean redraw = FALSE; 2370 2371 gint sel_start, sel_end; 2372 2373 /* If the EText isn't editable, then ignore any commands that would 2374 * modify the text. */ 2375 if (!ect->editable && (command->action == E_TEP_DELETE 2376 || command->action == E_TEP_INSERT 2377 || command->action == E_TEP_PASTE 2378 || command->action == E_TEP_GET_SELECTION)) 2379 return; 2380 2381 switch (command->action) { 2382 case E_TEP_MOVE: 2383 edit->selection_start = _get_position (text_view, command); 2384 edit->selection_end = edit->selection_start; 2385 if (edit->timer) { 2386 g_timer_reset (edit->timer); 2387 } 2388 redraw = TRUE; 2389 break; 2390 case E_TEP_SELECT: 2391 edit->selection_end = _get_position (text_view, command); 2392 sel_start = MIN (edit->selection_start, edit->selection_end); 2393 sel_end = MAX (edit->selection_start, edit->selection_end); 2394 if (sel_start != sel_end) { 2395 e_cell_text_view_supply_selection ( 2396 edit, command->time, GDK_SELECTION_PRIMARY, 2397 edit->text + sel_start, 2398 sel_end - sel_start); 2399 } else if (edit->timer) { 2400 g_timer_reset (edit->timer); 2401 } 2402 redraw = TRUE; 2403 break; 2404 case E_TEP_DELETE: 2405 if (edit->selection_end == edit->selection_start) { 2406 edit->selection_end = _get_position (text_view, command); 2407 } 2408 _delete_selection (text_view); 2409 if (edit->timer) { 2410 g_timer_reset (edit->timer); 2411 } 2412 redraw = TRUE; 2413 change = TRUE; 2414 break; 2415 2416 case E_TEP_INSERT: 2417 if (!edit->preedit_length && edit->selection_end != edit->selection_start) { 2418 _delete_selection (text_view); 2419 } 2420 _insert (text_view, command->string, command->value); 2421 if (edit->timer) { 2422 g_timer_reset (edit->timer); 2423 } 2424 redraw = TRUE; 2425 change = TRUE; 2426 break; 2427 case E_TEP_COPY: 2428 sel_start = MIN (edit->selection_start, edit->selection_end); 2429 sel_end = MAX (edit->selection_start, edit->selection_end); 2430 if (sel_start != sel_end) { 2431 e_cell_text_view_supply_selection ( 2432 edit, command->time, clipboard_atom, 2433 edit->text + sel_start, 2434 sel_end - sel_start); 2435 } 2436 if (edit->timer) { 2437 g_timer_reset (edit->timer); 2438 } 2439 break; 2440 case E_TEP_PASTE: 2441 e_cell_text_view_get_selection (edit, clipboard_atom, command->time); 2442 if (edit->timer) { 2443 g_timer_reset (edit->timer); 2444 } 2445 redraw = TRUE; 2446 change = TRUE; 2447 break; 2448 case E_TEP_GET_SELECTION: 2449 e_cell_text_view_get_selection (edit, GDK_SELECTION_PRIMARY, command->time); 2450 break; 2451 case E_TEP_ACTIVATE: 2452 e_table_item_leave_edit_ (text_view->cell_view.e_table_item_view); 2453 break; 2454 case E_TEP_SET_SELECT_BY_WORD: 2455 edit->select_by_word = command->value; 2456 break; 2457 case E_TEP_GRAB: 2458 edit->actions = E_CELL_GRAB; 2459 break; 2460 case E_TEP_UNGRAB: 2461 edit->actions = E_CELL_UNGRAB; 2462 break; 2463 case E_TEP_CAPS: 2464 if (edit->selection_start == edit->selection_end) { 2465 capitalize (edit, edit->selection_start, next_word (edit, edit->selection_start), command->value); 2466 } else { 2467 gint selection_start = MIN (edit->selection_start, edit->selection_end); 2468 gint selection_end = edit->selection_start + edit->selection_end - selection_start; /* Slightly faster than MAX */ 2469 capitalize (edit, selection_start, selection_end, command->value); 2470 } 2471 if (edit->timer) { 2472 g_timer_reset (edit->timer); 2473 } 2474 redraw = TRUE; 2475 change = TRUE; 2476 break; 2477 case E_TEP_NOP: 2478 break; 2479 } 2480 2481 if (change) { 2482 if (edit->layout) 2483 g_object_unref (edit->layout); 2484 edit->layout = build_layout (text_view, edit->row, edit->text, edit->cell_width); 2485 } 2486 2487 if (!edit->button_down) { 2488 PangoRectangle strong_pos, weak_pos; 2489 pango_layout_get_cursor_pos (edit->layout, edit->selection_end, &strong_pos, &weak_pos); 2490 if (strong_pos.x != weak_pos.x || 2491 strong_pos.y != weak_pos.y || 2492 strong_pos.width != weak_pos.width || 2493 strong_pos.height != weak_pos.height) { 2494 if (show_pango_rectangle (edit, weak_pos)) 2495 redraw = TRUE; 2496 } 2497 if (show_pango_rectangle (edit, strong_pos)) { 2498 redraw = TRUE; 2499 } 2500 } 2501 2502 if (redraw) { 2503 ect_queue_redraw (text_view, edit->view_col, edit->row); 2504 } 2505 } 2506 2507 static void 2508 e_cell_text_view_supply_selection (CellEdit *edit, 2509 guint time, 2510 GdkAtom selection, 2511 gchar *data, 2512 gint length) 2513 { 2514 #if DO_SELECTION 2515 GtkClipboard *clipboard; 2516 2517 clipboard = gtk_widget_get_clipboard (GTK_WIDGET (edit->text_view->canvas), selection); 2518 2519 if (selection == GDK_SELECTION_PRIMARY) { 2520 edit->has_selection = TRUE; 2521 } 2522 2523 gtk_clipboard_set_text (clipboard, data, length); 2524 #endif 2525 } 2526 2527 #ifdef DO_SELECTION 2528 static void 2529 paste_received (GtkClipboard *clipboard, 2530 const gchar *text, 2531 gpointer data) 2532 { 2533 CellEdit *edit; 2534 2535 g_return_if_fail (data); 2536 2537 edit = (CellEdit *) data; 2538 2539 if (text && g_utf8_validate (text, strlen (text), NULL)) { 2540 ETextEventProcessorCommand command; 2541 command.action = E_TEP_INSERT; 2542 command.position = E_TEP_SELECTION; 2543 command.string = (gchar *) text; 2544 command.value = strlen (text); 2545 command.time = GDK_CURRENT_TIME; 2546 e_cell_text_view_command (edit->tep, &command, edit); 2547 } 2548 } 2549 #endif 2550 2551 static void 2552 e_cell_text_view_get_selection (CellEdit *edit, 2553 GdkAtom selection, 2554 guint32 time) 2555 { 2556 #if DO_SELECTION 2557 gtk_clipboard_request_text ( 2558 gtk_widget_get_clipboard (GTK_WIDGET (edit->text_view->canvas), 2559 selection), 2560 paste_received, edit); 2561 #endif 2562 } 2563 2564 static void 2565 _get_tep (CellEdit *edit) 2566 { 2567 if (!edit->tep) {
Access to field 'tep' results in a dereference of a null pointer (loaded from variable 'edit')
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

Access to field 'tep' results in a dereference of a null pointer (loaded from variable 'edit')
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

2568 edit->tep = e_text_event_processor_emacs_like_new (); 2569 g_signal_connect ( 2570 edit->tep, "command", 2571 G_CALLBACK (e_cell_text_view_command), edit); 2572 } 2573 } 2574 2575 /** 2576 * e_cell_text_set_selection: 2577 * @cell_view: the given cell view 2578 * @col: column of the given cell in the view 2579 * @row: row of the given cell in the view 2580 * @start: start offset of the selection 2581 * @end: end offset of the selection 2582 * 2583 * Sets the selection of given text cell. 2584 * If the current editing cell is not the given cell, this function 2585 * will return FALSE; 2586 * 2587 * If success, the [start, end) part of the text will be selected. 2588 * 2589 * This API is most likely to be used by a11y implementations. 2590 * 2591 * Returns: whether the action is successful. 2592 */ 2593 gboolean 2594 e_cell_text_set_selection (ECellView *cell_view, 2595 gint col, 2596 gint row, 2597 gint start, 2598 gint end) 2599 { 2600 ECellTextView *ectv; 2601 CellEdit *edit; 2602 ETextEventProcessorCommand command1, command2; 2603 2604 g_return_val_if_fail (cell_view != NULL, FALSE); 2605 2606 ectv = (ECellTextView *) cell_view; 2607 edit = ectv->edit; 2608 if (!edit) 2609 return FALSE; 2610 2611 if (edit->view_col != col || edit->row != row) 2612 return FALSE; 2613 2614 command1.action = E_TEP_MOVE; 2615 command1.position = E_TEP_VALUE; 2616 command1.value = start; 2617 e_cell_text_view_command (edit->tep, &command1, edit); 2618 2619 command2.action = E_TEP_SELECT; 2620 command2.position = E_TEP_VALUE; 2621 command2.value = end; 2622 e_cell_text_view_command (edit->tep, &command2, edit); 2623 2624 return TRUE; 2625 } 2626 2627 /** 2628 * e_cell_text_get_selection: 2629 * @cell_view: the given cell view 2630 * @col: column of the given cell in the view 2631 * @row: row of the given cell in the view 2632 * @start: a pointer to an gint value indicates the start offset of the selection 2633 * @end: a pointer to an gint value indicates the end offset of the selection 2634 * 2635 * Gets the selection of given text cell. 2636 * If the current editing cell is not the given cell, this function 2637 * will return FALSE; 2638 * 2639 * This API is most likely to be used by a11y implementations. 2640 * 2641 * Returns: whether the action is successful. 2642 */ 2643 gboolean 2644 e_cell_text_get_selection (ECellView *cell_view, 2645 gint col, 2646 gint row, 2647 gint *start, 2648 gint *end) 2649 { 2650 ECellTextView *ectv; 2651 CellEdit *edit; 2652 2653 g_return_val_if_fail (cell_view != NULL, FALSE); 2654 2655 ectv = (ECellTextView *) cell_view; 2656 edit = ectv->edit; 2657 if (!edit) 2658 return FALSE; 2659 2660 if (edit->view_col != col || edit->row != row) 2661 return FALSE; 2662 2663 if (start) 2664 *start = edit->selection_start; 2665 if (end) 2666 *end = edit->selection_end; 2667 return TRUE; 2668 } 2669 2670 /** 2671 * e_cell_text_copy_clipboard: 2672 * @cell_view: the given cell view 2673 * @col: column of the given cell in the view 2674 * @row: row of the given cell in the view 2675 * 2676 * Copys the selected text to clipboard. 2677 * 2678 * This API is most likely to be used by a11y implementations. 2679 */ 2680 void 2681 e_cell_text_copy_clipboard (ECellView *cell_view, 2682 gint col, 2683 gint row) 2684 { 2685 ECellTextView *ectv; 2686 CellEdit *edit; 2687 ETextEventProcessorCommand command; 2688 2689 g_return_if_fail (cell_view != NULL); 2690 2691 ectv = (ECellTextView *) cell_view; 2692 edit = ectv->edit; 2693 if (!edit) 2694 return; 2695 2696 if (edit->view_col != col || edit->row != row) 2697 return; 2698 2699 command.action = E_TEP_COPY; 2700 command.time = GDK_CURRENT_TIME; 2701 e_cell_text_view_command (edit->tep, &command, edit); 2702 } 2703 2704 /** 2705 * e_cell_text_paste_clipboard: 2706 * @cell_view: the given cell view 2707 * @col: column of the given cell in the view 2708 * @row: row of the given cell in the view 2709 * 2710 * Pastes the text from the clipboardt. 2711 * 2712 * This API is most likely to be used by a11y implementations. 2713 */ 2714 void 2715 e_cell_text_paste_clipboard (ECellView *cell_view, 2716 gint col, 2717 gint row) 2718 { 2719 ECellTextView *ectv; 2720 CellEdit *edit; 2721 ETextEventProcessorCommand command; 2722 2723 g_return_if_fail (cell_view != NULL); 2724 2725 ectv = (ECellTextView *) cell_view; 2726 edit = ectv->edit; 2727 if (!edit) 2728 return; 2729 2730 if (edit->view_col != col || edit->row != row) 2731 return; 2732 2733 command.action = E_TEP_PASTE; 2734 command.time = GDK_CURRENT_TIME; 2735 e_cell_text_view_command (edit->tep, &command, edit); 2736 } 2737 2738 /** 2739 * e_cell_text_delete_selection: 2740 * @cell_view: the given cell view 2741 * @col: column of the given cell in the view 2742 * @row: row of the given cell in the view 2743 * 2744 * Deletes the selected text of the cell. 2745 * 2746 * This API is most likely to be used by a11y implementations. 2747 */ 2748 void 2749 e_cell_text_delete_selection (ECellView *cell_view, 2750 gint col, 2751 gint row) 2752 { 2753 ECellTextView *ectv; 2754 CellEdit *edit; 2755 ETextEventProcessorCommand command; 2756 2757 g_return_if_fail (cell_view != NULL); 2758 2759 ectv = (ECellTextView *) cell_view; 2760 edit = ectv->edit; 2761 if (!edit) 2762 return; 2763 2764 if (edit->view_col != col || edit->row != row) 2765 return; 2766 2767 command.action = E_TEP_DELETE; 2768 command.position = E_TEP_SELECTION; 2769 e_cell_text_view_command (edit->tep, &command, edit); 2770 } 2771 2772 /** 2773 * e_cell_text_get_text_by_view: 2774 * @cell_view: the given cell view 2775 * @col: column of the given cell in the model 2776 * @row: row of the given cell in the model 2777 * 2778 * Get the cell's text directly from CellEdit, 2779 * during editting this cell, the cell's text value maybe inconsistant 2780 * with the text got from table_model. 2781 * The caller should free the text after using it. 2782 * 2783 * This API is most likely to be used by a11y implementations. 2784 */ 2785 gchar * 2786 e_cell_text_get_text_by_view (ECellView *cell_view, 2787 gint col, 2788 gint row) 2789 { 2790 ECellTextView *ectv; 2791 CellEdit *edit; 2792 gchar *ret, *model_text; 2793 2794 g_return_val_if_fail (cell_view != NULL, NULL); 2795 2796 ectv = (ECellTextView *) cell_view; 2797 edit = ectv->edit; 2798 2799 if (edit && ectv->edit->row == row && ectv->edit->model_col == col) { /* being editted now */ 2800 ret = g_strdup (edit->text); 2801 } else{ 2802 model_text = e_cell_text_get_text ( 2803 E_CELL_TEXT (cell_view->ecell), 2804 cell_view->e_table_model, col, row); 2805 ret = g_strdup (model_text); 2806 e_cell_text_free_text (E_CELL_TEXT (cell_view->ecell), model_text); 2807 } 2808 2809 return ret; 2810 2811 }