evolution-3.6.4/widgets/misc/e-attachment-view.c

Location Tool Test ID Function Issue
e-attachment-view.c:1200:23 clang-analyzer Access to field 'data' results in a dereference of a null pointer (loaded from variable 'list')
e-attachment-view.c:1200:23 clang-analyzer Access to field 'data' results in a dereference of a null pointer (loaded from variable 'list')
   1 /*
   2  * e-attachment-view.c
   3  *
   4  * This program is free software; you can redistribute it and/or
   5  * modify it under the terms of the GNU Lesser General Public
   6  * License as published by the Free Software Foundation; either
   7  * version 2 of the License, or (at your option) version 3.
   8  *
   9  * This program is distributed in the hope that it will be useful,
  10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12  * Lesser General Public License for more details.
  13  *
  14  * You should have received a copy of the GNU Lesser General Public
  15  * License along with the program; if not, see <http://www.gnu.org/licenses/>
  16  *
  17  *
  18  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
  19  *
  20  */
  21 
  22 #ifdef HAVE_CONFIG_H
  23 #include <config.h>
  24 #endif
  25 
  26 #include "e-attachment-view.h"
  27 
  28 #include <glib/gi18n.h>
  29 #include <gdk/gdkkeysyms.h>
  30 
  31 #include "e-util/e-selection.h"
  32 #include "e-util/e-ui-manager.h"
  33 #include "e-util/e-util.h"
  34 
  35 #include "e-attachment-dialog.h"
  36 #include "e-attachment-handler-image.h"
  37 #include "e-attachment-handler-sendto.h"
  38 
  39 enum {
  40 	UPDATE_ACTIONS,
  41 	LAST_SIGNAL
  42 };
  43 
  44 /* Note: Do not use the info field. */
  45 static GtkTargetEntry target_table[] = {
  46 	{ (gchar *) "_NETSCAPE_URL", 0, 0 }
  47 };
  48 
  49 static const gchar *ui =
  50 "<ui>"
  51 "  <popup name='context'>"
  52 "    <menuitem action='cancel'/>"
  53 "    <menuitem action='save-as'/>"
  54 "    <menuitem action='remove'/>"
  55 "    <menuitem action='properties'/>"
  56 "    <separator/>"
  57 "    <placeholder name='inline-actions'>"
  58 "      <menuitem action='show'/>"
  59 "      <menuitem action='show-all'/>"
  60 "      <separator/>"
  61 "      <menuitem action='hide'/>"
  62 "      <menuitem action='hide-all'/>"
  63 "    </placeholder>"
  64 "    <separator/>"
  65 "    <placeholder name='custom-actions'/>"
  66 "    <separator/>"
  67 "    <menuitem action='add'/>"
  68 "    <separator/>"
  69 "    <placeholder name='open-actions'/>"
  70 "    <menuitem action='open-with'/>"
  71 "  </popup>"
  72 "</ui>";
  73 
  74 static gulong signals[LAST_SIGNAL];
  75 
  76 G_DEFINE_INTERFACE (
  77 	EAttachmentView,
  78 	e_attachment_view,
  79 	GTK_TYPE_WIDGET)
  80 
  81 static void
  82 action_add_cb (GtkAction *action,
  83                EAttachmentView *view)
  84 {
  85 	EAttachmentStore *store;
  86 	gpointer parent;
  87 
  88 	parent = gtk_widget_get_toplevel (GTK_WIDGET (view));
  89 	parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
  90 
  91 	store = e_attachment_view_get_store (view);
  92 	e_attachment_store_run_load_dialog (store, parent);
  93 }
  94 
  95 static void
  96 action_cancel_cb (GtkAction *action,
  97                   EAttachmentView *view)
  98 {
  99 	EAttachment *attachment;
 100 	GList *list;
 101 
 102 	list = e_attachment_view_get_selected_attachments (view);
 103 	g_return_if_fail (g_list_length (list) == 1);
 104 	attachment = list->data;
 105 
 106 	e_attachment_cancel (attachment);
 107 
 108 	g_list_foreach (list, (GFunc) g_object_unref, NULL);
 109 	g_list_free (list);
 110 }
 111 
 112 static void
 113 action_hide_cb (GtkAction *action,
 114                 EAttachmentView *view)
 115 {
 116 	EAttachment *attachment;
 117 	GList *list;
 118 
 119 	list = e_attachment_view_get_selected_attachments (view);
 120 	g_return_if_fail (g_list_length (list) == 1);
 121 	attachment = list->data;
 122 
 123 	e_attachment_set_shown (attachment, FALSE);
 124 
 125 	g_list_foreach (list, (GFunc) g_object_unref, NULL);
 126 	g_list_free (list);
 127 }
 128 
 129 static void
 130 action_hide_all_cb (GtkAction *action,
 131                     EAttachmentView *view)
 132 {
 133 	EAttachmentStore *store;
 134 	GList *list, *iter;
 135 
 136 	store = e_attachment_view_get_store (view);
 137 	list = e_attachment_store_get_attachments (store);
 138 
 139 	for (iter = list; iter != NULL; iter = iter->next) {
 140 		EAttachment *attachment;
 141 
 142 		attachment = E_ATTACHMENT (iter->data);
 143 		e_attachment_set_shown (attachment, FALSE);
 144 	}
 145 
 146 	g_list_foreach (list, (GFunc) g_object_unref, NULL);
 147 	g_list_free (list);
 148 }
 149 
 150 static void
 151 action_open_with_cb (GtkAction *action,
 152                      EAttachmentView *view)
 153 {
 154 	EAttachment *attachment;
 155 	EAttachmentStore *store;
 156 	GtkWidget *dialog;
 157 	GtkTreePath *path;
 158 	GtkTreeIter iter;
 159 	GAppInfo *app_info = NULL;
 160 	GFileInfo *file_info;
 161 	GList *list;
 162 	gpointer parent;
 163 	const gchar *content_type;
 164 
 165 	parent = gtk_widget_get_toplevel (GTK_WIDGET (view));
 166 	parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
 167 
 168 	list = e_attachment_view_get_selected_paths (view);
 169 	g_return_if_fail (g_list_length (list) == 1);
 170 	path = list->data;
 171 
 172 	store = e_attachment_view_get_store (view);
 173 	gtk_tree_model_get_iter (GTK_TREE_MODEL (store), &iter, path);
 174 	gtk_tree_model_get (
 175 		GTK_TREE_MODEL (store), &iter,
 176 		E_ATTACHMENT_STORE_COLUMN_ATTACHMENT, &attachment, -1);
 177 	g_return_if_fail (E_IS_ATTACHMENT (attachment));
 178 
 179 	file_info = e_attachment_get_file_info (attachment);
 180 	g_return_if_fail (file_info != NULL);
 181 
 182 	content_type = g_file_info_get_content_type (file_info);
 183 
 184 	dialog = gtk_app_chooser_dialog_new_for_content_type (
 185 		parent, 0, content_type);
 186 	if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) {
 187 		GtkAppChooser *app_chooser = GTK_APP_CHOOSER (dialog);
 188 		app_info = gtk_app_chooser_get_app_info (app_chooser);
 189 	}
 190 	gtk_widget_destroy (dialog);
 191 
 192 	if (app_info != NULL) {
 193 		e_attachment_view_open_path (view, path, app_info);
 194 		g_object_unref (app_info);
 195 	}
 196 
 197 	g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
 198 	g_list_free (list);
 199 }
 200 
 201 static void
 202 action_open_with_app_info_cb (GtkAction *action,
 203                               EAttachmentView *view)
 204 {
 205 	GAppInfo *app_info;
 206 	GtkTreePath *path;
 207 	GList *list;
 208 
 209 	list = e_attachment_view_get_selected_paths (view);
 210 	g_return_if_fail (g_list_length (list) == 1);
 211 	path = list->data;
 212 
 213 	app_info = g_object_get_data (G_OBJECT (action), "app-info");
 214 	g_return_if_fail (G_IS_APP_INFO (app_info));
 215 
 216 	e_attachment_view_open_path (view, path, app_info);
 217 
 218 	g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
 219 	g_list_free (list);
 220 }
 221 
 222 static void
 223 action_properties_cb (GtkAction *action,
 224                       EAttachmentView *view)
 225 {
 226 	EAttachment *attachment;
 227 	GtkWidget *dialog;
 228 	GList *list;
 229 	gpointer parent;
 230 
 231 	list = e_attachment_view_get_selected_attachments (view);
 232 	g_return_if_fail (g_list_length (list) == 1);
 233 	attachment = list->data;
 234 
 235 	parent = gtk_widget_get_toplevel (GTK_WIDGET (view));
 236 	parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
 237 
 238 	dialog = e_attachment_dialog_new (parent, attachment);
 239 	gtk_dialog_run (GTK_DIALOG (dialog));
 240 	gtk_widget_destroy (dialog);
 241 
 242 	g_list_foreach (list, (GFunc) g_object_unref, NULL);
 243 	g_list_free (list);
 244 }
 245 
 246 static void
 247 action_remove_cb (GtkAction *action,
 248                   EAttachmentView *view)
 249 {
 250 	e_attachment_view_remove_selected (view, FALSE);
 251 }
 252 
 253 static void
 254 action_save_all_cb (GtkAction *action,
 255                     EAttachmentView *view)
 256 {
 257 	EAttachmentStore *store;
 258 	GList *list, *iter;
 259 	GFile *destination;
 260 	gpointer parent;
 261 
 262 	store = e_attachment_view_get_store (view);
 263 
 264 	parent = gtk_widget_get_toplevel (GTK_WIDGET (view));
 265 	parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
 266 
 267 	/* XXX We lose the previous selection. */
 268 	e_attachment_view_select_all (view);
 269 	list = e_attachment_view_get_selected_attachments (view);
 270 	e_attachment_view_unselect_all (view);
 271 
 272 	destination = e_attachment_store_run_save_dialog (
 273 		store, list, parent);
 274 
 275 	if (destination == NULL)
 276 		goto exit;
 277 
 278 	for (iter = list; iter != NULL; iter = iter->next) {
 279 		EAttachment *attachment = iter->data;
 280 
 281 		e_attachment_save_async (
 282 			attachment, destination, (GAsyncReadyCallback)
 283 			e_attachment_save_handle_error, parent);
 284 	}
 285 
 286 	g_object_unref (destination);
 287 
 288 exit:
 289 	g_list_foreach (list, (GFunc) g_object_unref, NULL);
 290 	g_list_free (list);
 291 }
 292 
 293 static void
 294 action_save_as_cb (GtkAction *action,
 295                    EAttachmentView *view)
 296 {
 297 	EAttachmentStore *store;
 298 	GList *list, *iter;
 299 	GFile *destination;
 300 	gpointer parent;
 301 
 302 	store = e_attachment_view_get_store (view);
 303 
 304 	parent = gtk_widget_get_toplevel (GTK_WIDGET (view));
 305 	parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
 306 
 307 	list = e_attachment_view_get_selected_attachments (view);
 308 
 309 	destination = e_attachment_store_run_save_dialog (
 310 		store, list, parent);
 311 
 312 	if (destination == NULL)
 313 		goto exit;
 314 
 315 	for (iter = list; iter != NULL; iter = iter->next) {
 316 		EAttachment *attachment = iter->data;
 317 
 318 		e_attachment_save_async (
 319 			attachment, destination, (GAsyncReadyCallback)
 320 			e_attachment_save_handle_error, parent);
 321 	}
 322 
 323 	g_object_unref (destination);
 324 
 325 exit:
 326 	g_list_foreach (list, (GFunc) g_object_unref, NULL);
 327 	g_list_free (list);
 328 }
 329 
 330 static void
 331 action_show_cb (GtkAction *action,
 332                 EAttachmentView *view)
 333 {
 334 	EAttachment *attachment;
 335 	GList *list;
 336 
 337 	list = e_attachment_view_get_selected_attachments (view);
 338 	g_return_if_fail (g_list_length (list) == 1);
 339 	attachment = list->data;
 340 
 341 	e_attachment_set_shown (attachment, TRUE);
 342 
 343 	g_list_foreach (list, (GFunc) g_object_unref, NULL);
 344 	g_list_free (list);
 345 }
 346 
 347 static void
 348 action_show_all_cb (GtkAction *action,
 349                     EAttachmentView *view)
 350 {
 351 	EAttachmentStore *store;
 352 	GList *list, *iter;
 353 
 354 	store = e_attachment_view_get_store (view);
 355 	list = e_attachment_store_get_attachments (store);
 356 
 357 	for (iter = list; iter != NULL; iter = iter->next) {
 358 		EAttachment *attachment;
 359 
 360 		attachment = E_ATTACHMENT (iter->data);
 361 		e_attachment_set_shown (attachment, TRUE);
 362 	}
 363 
 364 	g_list_foreach (list, (GFunc) g_object_unref, NULL);
 365 	g_list_free (list);
 366 }
 367 
 368 static GtkActionEntry standard_entries[] = {
 369 
 370 	{ "cancel",
 371 	  GTK_STOCK_CANCEL,
 372 	  NULL,
 373 	  NULL,
 374 	  NULL,  /* XXX Add a tooltip! */
 375 	  G_CALLBACK (action_cancel_cb) },
 376 
 377 	{ "open-with",
 378 	  NULL,
 379 	  N_("Open With Other Application..."),
 380 	  NULL,
 381 	  NULL,  /* XXX Add a tooltip! */
 382 	  G_CALLBACK (action_open_with_cb) },
 383 
 384 	{ "save-all",
 385 	  GTK_STOCK_SAVE_AS,
 386 	  N_("S_ave All"),
 387 	  NULL,
 388 	  NULL,  /* XXX Add a tooltip! */
 389 	  G_CALLBACK (action_save_all_cb) },
 390 
 391 	{ "save-as",
 392 	  GTK_STOCK_SAVE_AS,
 393 	  NULL,
 394 	  NULL,
 395 	  NULL,  /* XXX Add a tooltip! */
 396 	  G_CALLBACK (action_save_as_cb) },
 397 
 398 	/* Alternate "save-all" label, for when
 399 	 * the attachment store has one row. */
 400 	{ "save-one",
 401 	  GTK_STOCK_SAVE_AS,
 402 	  NULL,
 403 	  NULL,
 404 	  NULL,  /* XXX Add a tooltip! */
 405 	  G_CALLBACK (action_save_all_cb) },
 406 };
 407 
 408 static GtkActionEntry editable_entries[] = {
 409 
 410 	{ "add",
 411 	  GTK_STOCK_ADD,
 412 	  N_("A_dd Attachment..."),
 413 	  NULL,
 414 	  N_("Attach a file"),
 415 	  G_CALLBACK (action_add_cb) },
 416 
 417 	{ "properties",
 418 	  GTK_STOCK_PROPERTIES,
 419 	  NULL,
 420 	  NULL,
 421 	  NULL,  /* XXX Add a tooltip! */
 422 	  G_CALLBACK (action_properties_cb) },
 423 
 424 	{ "remove",
 425 	  GTK_STOCK_REMOVE,
 426 	  NULL,
 427 	  NULL,
 428 	  NULL,  /* XXX Add a tooltip! */
 429 	  G_CALLBACK (action_remove_cb) }
 430 };
 431 
 432 static GtkActionEntry inline_entries[] = {
 433 
 434 	{ "hide",
 435 	  NULL,
 436 	  N_("_Hide"),
 437 	  NULL,
 438 	  NULL,  /* XXX Add a tooltip! */
 439 	  G_CALLBACK (action_hide_cb) },
 440 
 441 	{ "hide-all",
 442 	  NULL,
 443 	  N_("Hid_e All"),
 444 	  NULL,
 445 	  NULL,  /* XXX Add a tooltip! */
 446 	  G_CALLBACK (action_hide_all_cb) },
 447 
 448 	{ "show",
 449 	  NULL,
 450 	  N_("_View Inline"),
 451 	  NULL,
 452 	  NULL,  /* XXX Add a tooltip! */
 453 	  G_CALLBACK (action_show_cb) },
 454 
 455 	{ "show-all",
 456 	  NULL,
 457 	  N_("Vie_w All Inline"),
 458 	  NULL,
 459 	  NULL,  /* XXX Add a tooltip! */
 460 	  G_CALLBACK (action_show_all_cb) }
 461 };
 462 
 463 static void
 464 attachment_view_netscape_url (EAttachmentView *view,
 465                               GdkDragContext *drag_context,
 466                               gint x,
 467                               gint y,
 468                               GtkSelectionData *selection_data,
 469                               guint info,
 470                               guint time)
 471 {
 472 	static GdkAtom atom = GDK_NONE;
 473 	EAttachmentStore *store;
 474 	EAttachment *attachment;
 475 	const gchar *data;
 476 	gpointer parent;
 477 	gchar *copied_data;
 478 	gchar **strv;
 479 	gint length;
 480 
 481 	if (G_UNLIKELY (atom == GDK_NONE))
 482 		atom = gdk_atom_intern_static_string ("_NETSCAPE_URL");
 483 
 484 	if (gtk_selection_data_get_target (selection_data) != atom)
 485 		return;
 486 
 487 	g_signal_stop_emission_by_name (view, "drag-data-received");
 488 
 489 	/* _NETSCAPE_URL is represented as "URI\nTITLE" */
 490 
 491 	data = (const gchar *) gtk_selection_data_get_data (selection_data);
 492 	length = gtk_selection_data_get_length (selection_data);
 493 
 494 	copied_data = g_strndup (data, length);
 495 	strv = g_strsplit (copied_data, "\n", 2);
 496 	g_free (copied_data);
 497 
 498 	store = e_attachment_view_get_store (view);
 499 
 500 	parent = gtk_widget_get_toplevel (GTK_WIDGET (view));
 501 	parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
 502 
 503 	attachment = e_attachment_new_for_uri (strv[0]);
 504 	e_attachment_store_add_attachment (store, attachment);
 505 	e_attachment_load_async (
 506 		attachment, (GAsyncReadyCallback)
 507 		e_attachment_load_handle_error, parent);
 508 	g_object_unref (attachment);
 509 
 510 	g_strfreev (strv);
 511 
 512 	gtk_drag_finish (drag_context, TRUE, FALSE, time);
 513 }
 514 
 515 static void
 516 attachment_view_text_calendar (EAttachmentView *view,
 517                                GdkDragContext *drag_context,
 518                                gint x,
 519                                gint y,
 520                                GtkSelectionData *selection_data,
 521                                guint info,
 522                                guint time)
 523 {
 524 	EAttachmentStore *store;
 525 	EAttachment *attachment;
 526 	CamelMimePart *mime_part;
 527 	GdkAtom data_type;
 528 	GdkAtom target;
 529 	const gchar *data;
 530 	gpointer parent;
 531 	gchar *content_type;
 532 	gint length;
 533 
 534 	target = gtk_selection_data_get_target (selection_data);
 535 	if (!e_targets_include_calendar (&target, 1))
 536 		return;
 537 
 538 	g_signal_stop_emission_by_name (view, "drag-data-received");
 539 
 540 	data = (const gchar *) gtk_selection_data_get_data (selection_data);
 541 	length = gtk_selection_data_get_length (selection_data);
 542 	data_type = gtk_selection_data_get_data_type (selection_data);
 543 
 544 	mime_part = camel_mime_part_new ();
 545 
 546 	content_type = gdk_atom_name (data_type);
 547 	camel_mime_part_set_content (mime_part, data, length, content_type);
 548 	camel_mime_part_set_disposition (mime_part, "inline");
 549 	g_free (content_type);
 550 
 551 	store = e_attachment_view_get_store (view);
 552 
 553 	parent = gtk_widget_get_toplevel (GTK_WIDGET (view));
 554 	parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
 555 
 556 	attachment = e_attachment_new ();
 557 	e_attachment_set_mime_part (attachment, mime_part);
 558 	e_attachment_store_add_attachment (store, attachment);
 559 	e_attachment_load_async (
 560 		attachment, (GAsyncReadyCallback)
 561 		e_attachment_load_handle_error, parent);
 562 	g_object_unref (attachment);
 563 
 564 	g_object_unref (mime_part);
 565 
 566 	gtk_drag_finish (drag_context, TRUE, FALSE, time);
 567 }
 568 
 569 static void
 570 attachment_view_text_x_vcard (EAttachmentView *view,
 571                               GdkDragContext *drag_context,
 572                               gint x,
 573                               gint y,
 574                               GtkSelectionData *selection_data,
 575                               guint info,
 576                               guint time)
 577 {
 578 	EAttachmentStore *store;
 579 	EAttachment *attachment;
 580 	CamelMimePart *mime_part;
 581 	GdkAtom data_type;
 582 	GdkAtom target;
 583 	const gchar *data;
 584 	gpointer parent;
 585 	gchar *content_type;
 586 	gint length;
 587 
 588 	target = gtk_selection_data_get_target (selection_data);
 589 	if (!e_targets_include_directory (&target, 1))
 590 		return;
 591 
 592 	g_signal_stop_emission_by_name (view, "drag-data-received");
 593 
 594 	data = (const gchar *) gtk_selection_data_get_data (selection_data);
 595 	length = gtk_selection_data_get_length (selection_data);
 596 	data_type = gtk_selection_data_get_data_type (selection_data);
 597 
 598 	mime_part = camel_mime_part_new ();
 599 
 600 	content_type = gdk_atom_name (data_type);
 601 	camel_mime_part_set_content (mime_part, data, length, content_type);
 602 	camel_mime_part_set_disposition (mime_part, "inline");
 603 	g_free (content_type);
 604 
 605 	store = e_attachment_view_get_store (view);
 606 
 607 	parent = gtk_widget_get_toplevel (GTK_WIDGET (view));
 608 	parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
 609 
 610 	attachment = e_attachment_new ();
 611 	e_attachment_set_mime_part (attachment, mime_part);
 612 	e_attachment_store_add_attachment (store, attachment);
 613 	e_attachment_load_async (
 614 		attachment, (GAsyncReadyCallback)
 615 		e_attachment_load_handle_error, parent);
 616 	g_object_unref (attachment);
 617 
 618 	g_object_unref (mime_part);
 619 
 620 	gtk_drag_finish (drag_context, TRUE, FALSE, time);
 621 }
 622 
 623 static void
 624 attachment_view_uris (EAttachmentView *view,
 625                       GdkDragContext *drag_context,
 626                       gint x,
 627                       gint y,
 628                       GtkSelectionData *selection_data,
 629                       guint info,
 630                       guint time)
 631 {
 632 	EAttachmentStore *store;
 633 	gpointer parent;
 634 	gchar **uris;
 635 	gint ii;
 636 
 637 	uris = gtk_selection_data_get_uris (selection_data);
 638 
 639 	if (uris == NULL)
 640 		return;
 641 
 642 	g_signal_stop_emission_by_name (view, "drag-data-received");
 643 
 644 	store = e_attachment_view_get_store (view);
 645 
 646 	parent = gtk_widget_get_toplevel (GTK_WIDGET (view));
 647 	parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
 648 
 649 	for (ii = 0; uris[ii] != NULL; ii++) {
 650 		EAttachment *attachment;
 651 
 652 		attachment = e_attachment_new_for_uri (uris[ii]);
 653 		e_attachment_store_add_attachment (store, attachment);
 654 		e_attachment_load_async (
 655 			attachment, (GAsyncReadyCallback)
 656 			e_attachment_load_handle_error, parent);
 657 		g_object_unref (attachment);
 658 	}
 659 
 660 	g_strfreev (uris);
 661 
 662 	gtk_drag_finish (drag_context, TRUE, FALSE, time);
 663 }
 664 
 665 static void
 666 attachment_view_update_actions (EAttachmentView *view)
 667 {
 668 	EAttachmentViewPrivate *priv;
 669 	EAttachment *attachment;
 670 	EAttachmentStore *store;
 671 	GtkActionGroup *action_group;
 672 	GtkAction *action;
 673 	GList *list, *iter;
 674 	guint n_shown = 0;
 675 	guint n_hidden = 0;
 676 	guint n_selected;
 677 	gboolean busy = FALSE;
 678 	gboolean can_show = FALSE;
 679 	gboolean shown = FALSE;
 680 	gboolean visible;
 681 
 682 	g_return_if_fail (E_IS_ATTACHMENT_VIEW (view));
 683 
 684 	priv = e_attachment_view_get_private (view);
 685 
 686 	store = e_attachment_view_get_store (view);
 687 	list = e_attachment_store_get_attachments (store);
 688 
 689 	for (iter = list; iter != NULL; iter = iter->next) {
 690 		attachment = iter->data;
 691 
 692 		if (!e_attachment_get_can_show (attachment))
 693 			continue;
 694 
 695 		if (e_attachment_get_shown (attachment))
 696 			n_shown++;
 697 		else
 698 			n_hidden++;
 699 	}
 700 
 701 	g_list_foreach (list, (GFunc) g_object_unref, NULL);
 702 	g_list_free (list);
 703 
 704 	list = e_attachment_view_get_selected_attachments (view);
 705 	n_selected = g_list_length (list);
 706 
 707 	if (n_selected == 1) {
 708 		attachment = g_object_ref (list->data);
 709 		busy |= e_attachment_get_loading (attachment);
 710 		busy |= e_attachment_get_saving (attachment);
 711 		can_show = e_attachment_get_can_show (attachment);
 712 		shown = e_attachment_get_shown (attachment);
 713 	} else
 714 		attachment = NULL;
 715 
 716 	g_list_foreach (list, (GFunc) g_object_unref, NULL);
 717 	g_list_free (list);
 718 
 719 	action = e_attachment_view_get_action (view, "cancel");
 720 	gtk_action_set_visible (action, busy);
 721 
 722 	action = e_attachment_view_get_action (view, "hide");
 723 	gtk_action_set_visible (action, can_show && shown);
 724 
 725 	/* Show this action if there are multiple viewable
 726 	 * attachments, and at least one of them is shown. */
 727 	visible = (n_shown + n_hidden > 1) && (n_shown > 0);
 728 	action = e_attachment_view_get_action (view, "hide-all");
 729 	gtk_action_set_visible (action, visible);
 730 
 731 	action = e_attachment_view_get_action (view, "open-with");
 732 	gtk_action_set_visible (action, !busy && n_selected == 1);
 733 
 734 	action = e_attachment_view_get_action (view, "properties");
 735 	gtk_action_set_visible (action, !busy && n_selected == 1);
 736 
 737 	action = e_attachment_view_get_action (view, "remove");
 738 	gtk_action_set_visible (action, !busy && n_selected > 0);
 739 
 740 	action = e_attachment_view_get_action (view, "save-as");
 741 	gtk_action_set_visible (action, !busy && n_selected > 0);
 742 
 743 	action = e_attachment_view_get_action (view, "show");
 744 	gtk_action_set_visible (action, can_show && !shown);
 745 
 746 	/* Show this action if there are multiple viewable
 747 	 * attachments, and at least one of them is hidden. */
 748 	visible = (n_shown + n_hidden > 1) && (n_hidden > 0);
 749 	action = e_attachment_view_get_action (view, "show-all");
 750 	gtk_action_set_visible (action, visible);
 751 
 752 	/* Clear out the "openwith" action group. */
 753 	gtk_ui_manager_remove_ui (priv->ui_manager, priv->merge_id);
 754 	action_group = e_attachment_view_get_action_group (view, "openwith");
 755 	e_action_group_remove_all_actions (action_group);
 756 	gtk_ui_manager_ensure_update (priv->ui_manager);
 757 
 758 	if (attachment == NULL || busy)
 759 		return;
 760 
 761 	list = e_attachment_list_apps (attachment);
 762 
 763 	for (iter = list; iter != NULL; iter = iter->next) {
 764 		GAppInfo *app_info = iter->data;
 765 		GtkAction *action;
 766 		GIcon *app_icon;
 767 		const gchar *app_executable;
 768 		const gchar *app_name;
 769 		gchar *action_tooltip;
 770 		gchar *action_label;
 771 		gchar *action_name;
 772 
 773 		app_executable = g_app_info_get_executable (app_info);
 774 		app_icon = g_app_info_get_icon (app_info);
 775 		app_name = g_app_info_get_name (app_info);
 776 
 777 		action_name = g_strdup_printf ("open-with-%s", app_executable);
 778 		action_label = g_strdup_printf (_("Open With \"%s\""), app_name);
 779 
 780 		action_tooltip = g_strdup_printf (
 781 			_("Open this attachment in %s"), app_name);
 782 
 783 		action = gtk_action_new (
 784 			action_name, action_label, action_tooltip, NULL);
 785 
 786 		gtk_action_set_gicon (action, app_icon);
 787 
 788 		g_object_set_data_full (
 789 			G_OBJECT (action),
 790 			"app-info", g_object_ref (app_info),
 791 			(GDestroyNotify) g_object_unref);
 792 
 793 		g_object_set_data_full (
 794 			G_OBJECT (action),
 795 			"attachment", g_object_ref (attachment),
 796 			(GDestroyNotify) g_object_unref);
 797 
 798 		g_signal_connect (
 799 			action, "activate",
 800 			G_CALLBACK (action_open_with_app_info_cb), view);
 801 
 802 		gtk_action_group_add_action (action_group, action);
 803 
 804 		gtk_ui_manager_add_ui (
 805 			priv->ui_manager, priv->merge_id,
 806 			"/context/open-actions", action_name,
 807 			action_name, GTK_UI_MANAGER_AUTO, FALSE);
 808 
 809 		g_free (action_name);
 810 		g_free (action_label);
 811 		g_free (action_tooltip);
 812 	}
 813 
 814 	g_object_unref (attachment);
 815 	g_list_foreach (list, (GFunc) g_object_unref, NULL);
 816 	g_list_free (list);
 817 }
 818 
 819 static void
 820 attachment_view_init_drag_dest (EAttachmentView *view)
 821 {
 822 	EAttachmentViewPrivate *priv;
 823 	GtkTargetList *target_list;
 824 
 825 	priv = e_attachment_view_get_private (view);
 826 
 827 	target_list = gtk_target_list_new (
 828 		target_table, G_N_ELEMENTS (target_table));
 829 
 830 	gtk_target_list_add_uri_targets (target_list, 0);
 831 	e_target_list_add_calendar_targets (target_list, 0);
 832 	e_target_list_add_directory_targets (target_list, 0);
 833 
 834 	priv->target_list = target_list;
 835 	priv->drag_actions = GDK_ACTION_COPY;
 836 }
 837 
 838 static void
 839 e_attachment_view_default_init (EAttachmentViewInterface *interface)
 840 {
 841 	interface->update_actions = attachment_view_update_actions;
 842 
 843 	g_object_interface_install_property (
 844 		interface,
 845 		g_param_spec_boolean (
 846 			"dragging",
 847 			"Dragging",
 848 			NULL,
 849 			FALSE,
 850 			G_PARAM_READWRITE));
 851 
 852 	g_object_interface_install_property (
 853 		interface,
 854 		g_param_spec_boolean (
 855 			"editable",
 856 			"Editable",
 857 			NULL,
 858 			TRUE,
 859 			G_PARAM_READWRITE |
 860 			G_PARAM_CONSTRUCT));
 861 
 862 	signals[UPDATE_ACTIONS] = g_signal_new (
 863 		"update-actions",
 864 		G_TYPE_FROM_INTERFACE (interface),
 865 		G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
 866 		G_STRUCT_OFFSET (EAttachmentViewInterface, update_actions),
 867 		NULL, NULL,
 868 		g_cclosure_marshal_VOID__VOID,
 869 		G_TYPE_NONE, 0);
 870 
 871 	/* Register known handler types. */
 872 	e_attachment_handler_image_get_type ();
 873 	e_attachment_handler_sendto_get_type ();
 874 }
 875 
 876 void
 877 e_attachment_view_init (EAttachmentView *view)
 878 {
 879 	EAttachmentViewPrivate *priv;
 880 	GtkUIManager *ui_manager;
 881 	GtkActionGroup *action_group;
 882 	GError *error = NULL;
 883 
 884 	priv = e_attachment_view_get_private (view);
 885 
 886 	ui_manager = e_ui_manager_new ();
 887 	priv->merge_id = gtk_ui_manager_new_merge_id (ui_manager);
 888 	priv->ui_manager = ui_manager;
 889 
 890 	action_group = e_attachment_view_add_action_group (view, "standard");
 891 
 892 	gtk_action_group_add_actions (
 893 		action_group, standard_entries,
 894 		G_N_ELEMENTS (standard_entries), view);
 895 
 896 	action_group = e_attachment_view_add_action_group (view, "editable");
 897 
 898 	g_object_bind_property (
 899 		view, "editable",
 900 		action_group, "visible",
 901 		G_BINDING_BIDIRECTIONAL |
 902 		G_BINDING_SYNC_CREATE);
 903 	gtk_action_group_add_actions (
 904 		action_group, editable_entries,
 905 		G_N_ELEMENTS (editable_entries), view);
 906 
 907 	action_group = e_attachment_view_add_action_group (view, "inline");
 908 
 909 	gtk_action_group_add_actions (
 910 		action_group, inline_entries,
 911 		G_N_ELEMENTS (inline_entries), view);
 912 	gtk_action_group_set_visible (action_group, FALSE);
 913 
 914 	e_attachment_view_add_action_group (view, "openwith");
 915 
 916 	/* Because we are loading from a hard-coded string, there is
 917 	 * no chance of I/O errors.  Failure here implies a malformed
 918 	 * UI definition.  Full stop. */
 919 	gtk_ui_manager_add_ui_from_string (ui_manager, ui, -1, &error);
 920 	if (error != NULL)
 921 		g_error ("%s", error->message);
 922 
 923 	attachment_view_init_drag_dest (view);
 924 
 925 	e_attachment_view_drag_source_set (view);
 926 
 927 	/* Connect built-in drag and drop handlers. */
 928 
 929 	g_signal_connect (
 930 		view, "drag-data-received",
 931 		G_CALLBACK (attachment_view_netscape_url), NULL);
 932 
 933 	g_signal_connect (
 934 		view, "drag-data-received",
 935 		G_CALLBACK (attachment_view_text_calendar), NULL);
 936 
 937 	g_signal_connect (
 938 		view, "drag-data-received",
 939 		G_CALLBACK (attachment_view_text_x_vcard), NULL);
 940 
 941 	g_signal_connect (
 942 		view, "drag-data-received",
 943 		G_CALLBACK (attachment_view_uris), NULL);
 944 }
 945 
 946 void
 947 e_attachment_view_dispose (EAttachmentView *view)
 948 {
 949 	EAttachmentViewPrivate *priv;
 950 
 951 	priv = e_attachment_view_get_private (view);
 952 
 953 	if (priv->target_list != NULL) {
 954 		gtk_target_list_unref (priv->target_list);
 955 		priv->target_list = NULL;
 956 	}
 957 
 958 	if (priv->ui_manager != NULL) {
 959 		g_object_unref (priv->ui_manager);
 960 		priv->ui_manager = NULL;
 961 	}
 962 }
 963 
 964 void
 965 e_attachment_view_finalize (EAttachmentView *view)
 966 {
 967 	EAttachmentViewPrivate *priv;
 968 
 969 	priv = e_attachment_view_get_private (view);
 970 
 971 	g_list_foreach (priv->event_list, (GFunc) gdk_event_free, NULL);
 972 	g_list_free (priv->event_list);
 973 
 974 	g_list_foreach (priv->selected, (GFunc) g_object_unref, NULL);
 975 	g_list_free (priv->selected);
 976 }
 977 
 978 EAttachmentViewPrivate *
 979 e_attachment_view_get_private (EAttachmentView *view)
 980 {
 981 	EAttachmentViewInterface *interface;
 982 
 983 	g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), NULL);
 984 
 985 	interface = E_ATTACHMENT_VIEW_GET_INTERFACE (view);
 986 	g_return_val_if_fail (interface->get_private != NULL, NULL);
 987 
 988 	return interface->get_private (view);
 989 }
 990 
 991 EAttachmentStore *
 992 e_attachment_view_get_store (EAttachmentView *view)
 993 {
 994 	EAttachmentViewInterface *interface;
 995 
 996 	g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), NULL);
 997 
 998 	interface = E_ATTACHMENT_VIEW_GET_INTERFACE (view);
 999 	g_return_val_if_fail (interface->get_store != NULL, NULL);
1000 
1001 	return interface->get_store (view);
1002 }
1003 
1004 gboolean
1005 e_attachment_view_get_editable (EAttachmentView *view)
1006 {
1007 	EAttachmentViewPrivate *priv;
1008 
1009 	g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), FALSE);
1010 
1011 	priv = e_attachment_view_get_private (view);
1012 
1013 	return priv->editable;
1014 }
1015 
1016 void
1017 e_attachment_view_set_editable (EAttachmentView *view,
1018                                 gboolean editable)
1019 {
1020 	EAttachmentViewPrivate *priv;
1021 
1022 	g_return_if_fail (E_IS_ATTACHMENT_VIEW (view));
1023 
1024 	priv = e_attachment_view_get_private (view);
1025 
1026 	priv->editable = editable;
1027 
1028 	if (editable)
1029 		e_attachment_view_drag_dest_set (view);
1030 	else
1031 		e_attachment_view_drag_dest_unset (view);
1032 
1033 	g_object_notify (G_OBJECT (view), "editable");
1034 }
1035 
1036 gboolean
1037 e_attachment_view_get_dragging (EAttachmentView *view)
1038 {
1039 	EAttachmentViewPrivate *priv;
1040 
1041 	g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), FALSE);
1042 
1043 	priv = e_attachment_view_get_private (view);
1044 
1045 	return priv->dragging;
1046 }
1047 
1048 void
1049 e_attachment_view_set_dragging (EAttachmentView *view,
1050                                 gboolean dragging)
1051 {
1052 	EAttachmentViewPrivate *priv;
1053 
1054 	g_return_if_fail (E_IS_ATTACHMENT_VIEW (view));
1055 
1056 	priv = e_attachment_view_get_private (view);
1057 
1058 	priv->dragging = dragging;
1059 
1060 	g_object_notify (G_OBJECT (view), "dragging");
1061 }
1062 
1063 GtkTargetList *
1064 e_attachment_view_get_target_list (EAttachmentView *view)
1065 {
1066 	EAttachmentViewPrivate *priv;
1067 
1068 	g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), NULL);
1069 
1070 	priv = e_attachment_view_get_private (view);
1071 
1072 	return priv->target_list;
1073 }
1074 
1075 GdkDragAction
1076 e_attachment_view_get_drag_actions (EAttachmentView *view)
1077 {
1078 	EAttachmentViewPrivate *priv;
1079 
1080 	g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), 0);
1081 
1082 	priv = e_attachment_view_get_private (view);
1083 
1084 	return priv->drag_actions;
1085 }
1086 
1087 void
1088 e_attachment_view_add_drag_actions (EAttachmentView *view,
1089                                     GdkDragAction drag_actions)
1090 {
1091 	EAttachmentViewPrivate *priv;
1092 
1093 	g_return_if_fail (E_IS_ATTACHMENT_VIEW (view));
1094 
1095 	priv = e_attachment_view_get_private (view);
1096 
1097 	priv->drag_actions |= drag_actions;
1098 }
1099 
1100 GList *
1101 e_attachment_view_get_selected_attachments (EAttachmentView *view)
1102 {
1103 	EAttachmentStore *store;
1104 	GtkTreeModel *model;
1105 	GList *list, *item;
1106 	gint column_id;
1107 
1108 	g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), NULL);
1109 
1110 	column_id = E_ATTACHMENT_STORE_COLUMN_ATTACHMENT;
1111 	list = e_attachment_view_get_selected_paths (view);
1112 	store = e_attachment_view_get_store (view);
1113 	model = GTK_TREE_MODEL (store);
1114 
1115 	/* Convert the GtkTreePaths to EAttachments. */
1116 	for (item = list; item != NULL; item = item->next) {
1117 		EAttachment *attachment;
1118 		GtkTreePath *path;
1119 		GtkTreeIter iter;
1120 
1121 		path = item->data;
1122 
1123 		gtk_tree_model_get_iter (model, &iter, path);
1124 		gtk_tree_model_get (model, &iter, column_id, &attachment, -1);
1125 		gtk_tree_path_free (path);
1126 
1127 		item->data = attachment;
1128 	}
1129 
1130 	return list;
1131 }
1132 
1133 void
1134 e_attachment_view_open_path (EAttachmentView *view,
1135                              GtkTreePath *path,
1136                              GAppInfo *app_info)
1137 {
1138 	EAttachmentStore *store;
1139 	EAttachment *attachment;
1140 	GtkTreeModel *model;
1141 	GtkTreeIter iter;
1142 	gpointer parent;
1143 	gint column_id;
1144 
1145 	g_return_if_fail (E_IS_ATTACHMENT_VIEW (view));
1146 	g_return_if_fail (path != NULL);
1147 
1148 	column_id = E_ATTACHMENT_STORE_COLUMN_ATTACHMENT;
1149 	store = e_attachment_view_get_store (view);
1150 	model = GTK_TREE_MODEL (store);
1151 
1152 	gtk_tree_model_get_iter (model, &iter, path);
1153 	gtk_tree_model_get (model, &iter, column_id, &attachment, -1);
1154 
1155 	parent = gtk_widget_get_toplevel (GTK_WIDGET (view));
1156 	parent = gtk_widget_is_toplevel (parent) ? parent : NULL;
1157 
1158 	e_attachment_open_async (
1159 		attachment, app_info, (GAsyncReadyCallback)
1160 		e_attachment_open_handle_error, parent);
1161 
1162 	g_object_unref (attachment);
1163 }
1164 
1165 void
1166 e_attachment_view_remove_selected (EAttachmentView *view,
1167                                    gboolean select_next)
1168 {
1169 	EAttachmentStore *store;
1170 	GtkTreeModel *model;
1171 	GList *list, *item;
1172 	gint column_id;
1173 
1174 	g_return_if_fail (E_IS_ATTACHMENT_VIEW (view));
1175 
1176 	column_id = E_ATTACHMENT_STORE_COLUMN_ATTACHMENT;
1177 	list = e_attachment_view_get_selected_paths (view);
1178 	store = e_attachment_view_get_store (view);
1179 	model = GTK_TREE_MODEL (store);
1180 
1181 	/* Remove attachments in reverse order to avoid invalidating
1182 	 * tree paths as we iterate over the list.  Note, the list is
1183 	 * probably already sorted but we sort again just to be safe. */
1184 	list = g_list_reverse (g_list_sort (
1185 		list, (GCompareFunc) gtk_tree_path_compare));
1186 
1187 	for (item = list; item != NULL; item = item->next) {
1188 		EAttachment *attachment;
1189 		GtkTreePath *path = item->data;
1190 		GtkTreeIter iter;
1191 
1192 		gtk_tree_model_get_iter (model, &iter, path);
1193 		gtk_tree_model_get (model, &iter, column_id, &attachment, -1);
1194 		e_attachment_store_remove_attachment (store, attachment);
1195 		g_object_unref (attachment);
1196 	}
1197 
1198 	/* If we only removed one attachment, try to select another. */
1199 	if (select_next && g_list_length (list) == 1) {
1200 		GtkTreePath *path = list->data;
Access to field 'data' results in a dereference of a null pointer (loaded from variable 'list')
(emitted by clang-analyzer)

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

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

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

1201 1202 e_attachment_view_select_path (view, path); 1203 if (!e_attachment_view_path_is_selected (view, path)) 1204 if (gtk_tree_path_prev (path)) 1205 e_attachment_view_select_path (view, path); 1206 } 1207 1208 g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL); 1209 g_list_free (list); 1210 } 1211 1212 gboolean 1213 e_attachment_view_button_press_event (EAttachmentView *view, 1214 GdkEventButton *event) 1215 { 1216 EAttachmentViewPrivate *priv; 1217 GtkTreePath *path; 1218 gboolean editable; 1219 gboolean handled = FALSE; 1220 gboolean path_is_selected = FALSE; 1221 1222 g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), FALSE); 1223 g_return_val_if_fail (event != NULL, FALSE); 1224 1225 priv = e_attachment_view_get_private (view); 1226 1227 if (g_list_find (priv->event_list, event) != NULL) 1228 return FALSE; 1229 1230 if (priv->event_list != NULL) { 1231 /* Save the event to be propagated in order. */ 1232 priv->event_list = g_list_append ( 1233 priv->event_list, 1234 gdk_event_copy ((GdkEvent *) event)); 1235 return TRUE; 1236 } 1237 1238 editable = e_attachment_view_get_editable (view); 1239 path = e_attachment_view_get_path_at_pos (view, event->x, event->y); 1240 path_is_selected = e_attachment_view_path_is_selected (view, path); 1241 1242 if (event->button == 1 && event->type == GDK_BUTTON_PRESS) { 1243 GList *list, *iter; 1244 gboolean busy = FALSE; 1245 1246 list = e_attachment_view_get_selected_attachments (view); 1247 1248 for (iter = list; iter != NULL; iter = iter->next) { 1249 EAttachment *attachment = iter->data; 1250 busy |= e_attachment_get_loading (attachment); 1251 busy |= e_attachment_get_saving (attachment); 1252 } 1253 1254 /* Prepare for dragging if the clicked item is selected 1255 * and none of the selected items are loading or saving. */ 1256 if (path_is_selected && !busy) { 1257 priv->start_x = event->x; 1258 priv->start_y = event->y; 1259 priv->event_list = g_list_append ( 1260 priv->event_list, 1261 gdk_event_copy ((GdkEvent *) event)); 1262 handled = TRUE; 1263 } 1264 1265 g_list_foreach (list, (GFunc) g_object_unref, NULL); 1266 g_list_free (list); 1267 } 1268 1269 if (event->button == 3 && event->type == GDK_BUTTON_PRESS) { 1270 /* If the user clicked on a selected item, retain the 1271 * current selection. If the user clicked on an unselected 1272 * item, select the clicked item only. If the user did not 1273 * click on an item, clear the current selection. */ 1274 if (path == NULL) 1275 e_attachment_view_unselect_all (view); 1276 else if (!path_is_selected) { 1277 e_attachment_view_unselect_all (view); 1278 e_attachment_view_select_path (view, path); 1279 } 1280 1281 /* Non-editable attachment views should only show a 1282 * popup menu when right-clicking on an attachment, 1283 * but editable views can show the menu any time. */ 1284 if (path != NULL || editable) { 1285 e_attachment_view_show_popup_menu ( 1286 view, event, NULL, NULL); 1287 handled = TRUE; 1288 } 1289 } 1290 1291 if (path != NULL) 1292 gtk_tree_path_free (path); 1293 1294 return handled; 1295 } 1296 1297 gboolean 1298 e_attachment_view_button_release_event (EAttachmentView *view, 1299 GdkEventButton *event) 1300 { 1301 EAttachmentViewPrivate *priv; 1302 GtkWidget *widget = GTK_WIDGET (view); 1303 GList *iter; 1304 1305 g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), FALSE); 1306 g_return_val_if_fail (event != NULL, FALSE); 1307 1308 priv = e_attachment_view_get_private (view); 1309 1310 for (iter = priv->event_list; iter != NULL; iter = iter->next) { 1311 GdkEvent *event = iter->data; 1312 1313 gtk_propagate_event (widget, event); 1314 gdk_event_free (event); 1315 } 1316 1317 g_list_free (priv->event_list); 1318 priv->event_list = NULL; 1319 1320 return FALSE; 1321 } 1322 1323 gboolean 1324 e_attachment_view_motion_notify_event (EAttachmentView *view, 1325 GdkEventMotion *event) 1326 { 1327 EAttachmentViewPrivate *priv; 1328 GtkWidget *widget = GTK_WIDGET (view); 1329 GtkTargetList *targets; 1330 1331 g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), FALSE); 1332 g_return_val_if_fail (event != NULL, FALSE); 1333 1334 priv = e_attachment_view_get_private (view); 1335 1336 if (priv->event_list == NULL) 1337 return FALSE; 1338 1339 if (!gtk_drag_check_threshold ( 1340 widget, priv->start_x, priv->start_y, event->x, event->y)) 1341 return TRUE; 1342 1343 g_list_foreach (priv->event_list, (GFunc) gdk_event_free, NULL); 1344 g_list_free (priv->event_list); 1345 priv->event_list = NULL; 1346 1347 targets = gtk_drag_source_get_target_list (widget); 1348 1349 gtk_drag_begin ( 1350 widget, targets, GDK_ACTION_COPY, 1, (GdkEvent *) event); 1351 1352 return TRUE; 1353 } 1354 1355 gboolean 1356 e_attachment_view_key_press_event (EAttachmentView *view, 1357 GdkEventKey *event) 1358 { 1359 gboolean editable; 1360 1361 g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), FALSE); 1362 g_return_val_if_fail (event != NULL, FALSE); 1363 1364 editable = e_attachment_view_get_editable (view); 1365 1366 if (event->keyval == GDK_KEY_Delete && editable) { 1367 e_attachment_view_remove_selected (view, TRUE); 1368 return TRUE; 1369 } 1370 1371 return FALSE; 1372 } 1373 1374 GtkTreePath * 1375 e_attachment_view_get_path_at_pos (EAttachmentView *view, 1376 gint x, 1377 gint y) 1378 { 1379 EAttachmentViewInterface *interface; 1380 1381 g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), NULL); 1382 1383 interface = E_ATTACHMENT_VIEW_GET_INTERFACE (view); 1384 g_return_val_if_fail (interface->get_path_at_pos != NULL, NULL); 1385 1386 return interface->get_path_at_pos (view, x, y); 1387 } 1388 1389 GList * 1390 e_attachment_view_get_selected_paths (EAttachmentView *view) 1391 { 1392 EAttachmentViewInterface *interface; 1393 1394 g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), NULL); 1395 1396 interface = E_ATTACHMENT_VIEW_GET_INTERFACE (view); 1397 g_return_val_if_fail (interface->get_selected_paths != NULL, NULL); 1398 1399 return interface->get_selected_paths (view); 1400 } 1401 1402 gboolean 1403 e_attachment_view_path_is_selected (EAttachmentView *view, 1404 GtkTreePath *path) 1405 { 1406 EAttachmentViewInterface *interface; 1407 1408 g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), FALSE); 1409 1410 /* Handle NULL paths gracefully. */ 1411 if (path == NULL) 1412 return FALSE; 1413 1414 interface = E_ATTACHMENT_VIEW_GET_INTERFACE (view); 1415 g_return_val_if_fail (interface->path_is_selected != NULL, FALSE); 1416 1417 return interface->path_is_selected (view, path); 1418 } 1419 1420 void 1421 e_attachment_view_select_path (EAttachmentView *view, 1422 GtkTreePath *path) 1423 { 1424 EAttachmentViewInterface *interface; 1425 1426 g_return_if_fail (E_IS_ATTACHMENT_VIEW (view)); 1427 g_return_if_fail (path != NULL); 1428 1429 interface = E_ATTACHMENT_VIEW_GET_INTERFACE (view); 1430 g_return_if_fail (interface->select_path != NULL); 1431 1432 interface->select_path (view, path); 1433 } 1434 1435 void 1436 e_attachment_view_unselect_path (EAttachmentView *view, 1437 GtkTreePath *path) 1438 { 1439 EAttachmentViewInterface *interface; 1440 1441 g_return_if_fail (E_IS_ATTACHMENT_VIEW (view)); 1442 g_return_if_fail (path != NULL); 1443 1444 interface = E_ATTACHMENT_VIEW_GET_INTERFACE (view); 1445 g_return_if_fail (interface->unselect_path != NULL); 1446 1447 interface->unselect_path (view, path); 1448 } 1449 1450 void 1451 e_attachment_view_select_all (EAttachmentView *view) 1452 { 1453 EAttachmentViewInterface *interface; 1454 1455 g_return_if_fail (E_IS_ATTACHMENT_VIEW (view)); 1456 1457 interface = E_ATTACHMENT_VIEW_GET_INTERFACE (view); 1458 g_return_if_fail (interface->select_all != NULL); 1459 1460 interface->select_all (view); 1461 } 1462 1463 void 1464 e_attachment_view_unselect_all (EAttachmentView *view) 1465 { 1466 EAttachmentViewInterface *interface; 1467 1468 g_return_if_fail (E_IS_ATTACHMENT_VIEW (view)); 1469 1470 interface = E_ATTACHMENT_VIEW_GET_INTERFACE (view); 1471 g_return_if_fail (interface->unselect_all != NULL); 1472 1473 interface->unselect_all (view); 1474 } 1475 1476 void 1477 e_attachment_view_sync_selection (EAttachmentView *view, 1478 EAttachmentView *target) 1479 { 1480 GList *list, *iter; 1481 1482 g_return_if_fail (E_IS_ATTACHMENT_VIEW (view)); 1483 g_return_if_fail (E_IS_ATTACHMENT_VIEW (target)); 1484 1485 list = e_attachment_view_get_selected_paths (view); 1486 e_attachment_view_unselect_all (target); 1487 1488 for (iter = list; iter != NULL; iter = iter->next) 1489 e_attachment_view_select_path (target, iter->data); 1490 1491 g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL); 1492 g_list_free (list); 1493 } 1494 1495 void 1496 e_attachment_view_drag_source_set (EAttachmentView *view) 1497 { 1498 EAttachmentViewInterface *interface; 1499 GtkTargetEntry *targets; 1500 GtkTargetList *list; 1501 gint n_targets; 1502 1503 g_return_if_fail (E_IS_ATTACHMENT_VIEW (view)); 1504 1505 interface = E_ATTACHMENT_VIEW_GET_INTERFACE (view); 1506 if (interface->drag_source_set == NULL) 1507 return; 1508 1509 list = gtk_target_list_new (NULL, 0); 1510 gtk_target_list_add_uri_targets (list, 0); 1511 targets = gtk_target_table_new_from_list (list, &n_targets); 1512 1513 interface->drag_source_set ( 1514 view, GDK_BUTTON1_MASK, 1515 targets, n_targets, GDK_ACTION_COPY); 1516 1517 gtk_target_table_free (targets, n_targets); 1518 gtk_target_list_unref (list); 1519 } 1520 1521 void 1522 e_attachment_view_drag_source_unset (EAttachmentView *view) 1523 { 1524 EAttachmentViewInterface *interface; 1525 1526 g_return_if_fail (E_IS_ATTACHMENT_VIEW (view)); 1527 1528 interface = E_ATTACHMENT_VIEW_GET_INTERFACE (view); 1529 if (interface->drag_source_unset == NULL) 1530 return; 1531 1532 interface->drag_source_unset (view); 1533 } 1534 1535 void 1536 e_attachment_view_drag_begin (EAttachmentView *view, 1537 GdkDragContext *context) 1538 { 1539 EAttachmentViewPrivate *priv; 1540 guint n_selected; 1541 1542 g_return_if_fail (E_IS_ATTACHMENT_VIEW (view)); 1543 g_return_if_fail (GDK_IS_DRAG_CONTEXT (context)); 1544 1545 priv = e_attachment_view_get_private (view); 1546 1547 e_attachment_view_set_dragging (view, TRUE); 1548 1549 g_warn_if_fail (priv->selected == NULL); 1550 priv->selected = e_attachment_view_get_selected_attachments (view); 1551 n_selected = g_list_length (priv->selected); 1552 1553 if (n_selected > 1) 1554 gtk_drag_set_icon_stock ( 1555 context, GTK_STOCK_DND_MULTIPLE, 0, 0); 1556 1557 else if (n_selected == 1) { 1558 EAttachment *attachment; 1559 GtkIconTheme *icon_theme; 1560 GtkIconInfo *icon_info; 1561 GIcon *icon; 1562 gint width, height; 1563 1564 attachment = E_ATTACHMENT (priv->selected->data); 1565 icon = e_attachment_get_icon (attachment); 1566 g_return_if_fail (icon != NULL); 1567 1568 icon_theme = gtk_icon_theme_get_default (); 1569 gtk_icon_size_lookup (GTK_ICON_SIZE_DND, &width, &height); 1570 1571 icon_info = gtk_icon_theme_lookup_by_gicon ( 1572 icon_theme, icon, MIN (width, height), 1573 GTK_ICON_LOOKUP_USE_BUILTIN); 1574 1575 if (icon_info != NULL) { 1576 GdkPixbuf *pixbuf; 1577 GError *error = NULL; 1578 1579 pixbuf = gtk_icon_info_load_icon (icon_info, &error); 1580 1581 if (pixbuf != NULL) { 1582 gtk_drag_set_icon_pixbuf ( 1583 context, pixbuf, 0, 0); 1584 g_object_unref (pixbuf); 1585 } else if (error != NULL) { 1586 g_warning ("%s", error->message); 1587 g_error_free (error); 1588 } 1589 1590 gtk_icon_info_free (icon_info); 1591 } 1592 } 1593 } 1594 1595 void 1596 e_attachment_view_drag_end (EAttachmentView *view, 1597 GdkDragContext *context) 1598 { 1599 EAttachmentViewPrivate *priv; 1600 1601 g_return_if_fail (E_IS_ATTACHMENT_VIEW (view)); 1602 g_return_if_fail (GDK_IS_DRAG_CONTEXT (context)); 1603 1604 priv = e_attachment_view_get_private (view); 1605 1606 e_attachment_view_set_dragging (view, FALSE); 1607 1608 g_list_foreach (priv->selected, (GFunc) g_object_unref, NULL); 1609 g_list_free (priv->selected); 1610 priv->selected = NULL; 1611 } 1612 1613 static void 1614 attachment_view_got_uris_cb (EAttachmentStore *store, 1615 GAsyncResult *result, 1616 gpointer user_data) 1617 { 1618 struct { 1619 gchar **uris; 1620 gboolean done; 1621 } *status = user_data; 1622 1623 /* XXX Since this is a best-effort function, 1624 * should we care about errors? */ 1625 status->uris = e_attachment_store_get_uris_finish ( 1626 store, result, NULL); 1627 1628 status->done = TRUE; 1629 } 1630 1631 void 1632 e_attachment_view_drag_data_get (EAttachmentView *view, 1633 GdkDragContext *context, 1634 GtkSelectionData *selection, 1635 guint info, 1636 guint time) 1637 { 1638 EAttachmentViewPrivate *priv; 1639 EAttachmentStore *store; 1640 1641 struct { 1642 gchar **uris; 1643 gboolean done; 1644 } status; 1645 1646 g_return_if_fail (E_IS_ATTACHMENT_VIEW (view)); 1647 g_return_if_fail (GDK_IS_DRAG_CONTEXT (context)); 1648 g_return_if_fail (selection != NULL); 1649 1650 status.uris = NULL; 1651 status.done = FALSE; 1652 1653 priv = e_attachment_view_get_private (view); 1654 store = e_attachment_view_get_store (view); 1655 1656 if (priv->selected == NULL) 1657 return; 1658 1659 e_attachment_store_get_uris_async ( 1660 store, priv->selected, (GAsyncReadyCallback) 1661 attachment_view_got_uris_cb, &status); 1662 1663 /* We can't return until we have results, so crank 1664 * the main loop until the callback gets triggered. */ 1665 while (!status.done) 1666 if (gtk_main_iteration ()) 1667 break; 1668 1669 if (status.uris != NULL) 1670 gtk_selection_data_set_uris (selection, status.uris); 1671 1672 g_strfreev (status.uris); 1673 } 1674 1675 void 1676 e_attachment_view_drag_dest_set (EAttachmentView *view) 1677 { 1678 EAttachmentViewPrivate *priv; 1679 EAttachmentViewInterface *interface; 1680 GtkTargetEntry *targets; 1681 gint n_targets; 1682 1683 g_return_if_fail (E_IS_ATTACHMENT_VIEW (view)); 1684 1685 interface = E_ATTACHMENT_VIEW_GET_INTERFACE (view); 1686 if (interface->drag_dest_set == NULL) 1687 return; 1688 1689 priv = e_attachment_view_get_private (view); 1690 1691 targets = gtk_target_table_new_from_list ( 1692 priv->target_list, &n_targets); 1693 1694 interface->drag_dest_set ( 1695 view, targets, n_targets, priv->drag_actions); 1696 1697 gtk_target_table_free (targets, n_targets); 1698 } 1699 1700 void 1701 e_attachment_view_drag_dest_unset (EAttachmentView *view) 1702 { 1703 EAttachmentViewInterface *interface; 1704 1705 g_return_if_fail (E_IS_ATTACHMENT_VIEW (view)); 1706 1707 interface = E_ATTACHMENT_VIEW_GET_INTERFACE (view); 1708 if (interface->drag_dest_unset == NULL) 1709 return; 1710 1711 interface->drag_dest_unset (view); 1712 } 1713 1714 gboolean 1715 e_attachment_view_drag_motion (EAttachmentView *view, 1716 GdkDragContext *context, 1717 gint x, 1718 gint y, 1719 guint time) 1720 { 1721 EAttachmentViewPrivate *priv; 1722 GdkDragAction actions; 1723 GdkDragAction chosen_action; 1724 1725 g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), FALSE); 1726 g_return_val_if_fail (GDK_IS_DRAG_CONTEXT (context), FALSE); 1727 1728 priv = e_attachment_view_get_private (view); 1729 1730 /* Disallow drops if we're not editable. */ 1731 if (!e_attachment_view_get_editable (view)) 1732 return FALSE; 1733 1734 /* Disallow drops if we initiated the drag. 1735 * This helps prevent duplicate attachments. */ 1736 if (e_attachment_view_get_dragging (view)) 1737 return FALSE; 1738 1739 actions = gdk_drag_context_get_actions (context); 1740 actions &= priv->drag_actions; 1741 chosen_action = gdk_drag_context_get_suggested_action (context); 1742 1743 if (chosen_action == GDK_ACTION_ASK) { 1744 GdkDragAction mask; 1745 1746 mask = GDK_ACTION_COPY | GDK_ACTION_MOVE; 1747 if ((actions & mask) != mask) 1748 chosen_action = GDK_ACTION_COPY; 1749 } 1750 1751 gdk_drag_status (context, chosen_action, time); 1752 1753 return (chosen_action != 0); 1754 } 1755 1756 gboolean 1757 e_attachment_view_drag_drop (EAttachmentView *view, 1758 GdkDragContext *context, 1759 gint x, 1760 gint y, 1761 guint time) 1762 { 1763 g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), FALSE); 1764 g_return_val_if_fail (GDK_IS_DRAG_CONTEXT (context), FALSE); 1765 1766 /* Disallow drops if we initiated the drag. 1767 * This helps prevent duplicate attachments. */ 1768 return !e_attachment_view_get_dragging (view); 1769 } 1770 1771 void 1772 e_attachment_view_drag_data_received (EAttachmentView *view, 1773 GdkDragContext *drag_context, 1774 gint x, 1775 gint y, 1776 GtkSelectionData *selection_data, 1777 guint info, 1778 guint time) 1779 { 1780 GdkAtom atom; 1781 gchar *name; 1782 1783 g_return_if_fail (E_IS_ATTACHMENT_VIEW (view)); 1784 g_return_if_fail (GDK_IS_DRAG_CONTEXT (drag_context)); 1785 1786 /* Drop handlers are supposed to stop further emission of the 1787 * "drag-data-received" signal if they can handle the data. If 1788 * we get this far it means none of the handlers were successful, 1789 * so report the drop as failed. */ 1790 1791 atom = gtk_selection_data_get_target (selection_data); 1792 1793 name = gdk_atom_name (atom); 1794 g_warning ("Unknown selection target: %s", name); 1795 g_free (name); 1796 1797 gtk_drag_finish (drag_context, FALSE, FALSE, time); 1798 } 1799 1800 GtkAction * 1801 e_attachment_view_get_action (EAttachmentView *view, 1802 const gchar *action_name) 1803 { 1804 GtkUIManager *ui_manager; 1805 1806 g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), NULL); 1807 g_return_val_if_fail (action_name != NULL, NULL); 1808 1809 ui_manager = e_attachment_view_get_ui_manager (view); 1810 1811 return e_lookup_action (ui_manager, action_name); 1812 } 1813 1814 GtkActionGroup * 1815 e_attachment_view_add_action_group (EAttachmentView *view, 1816 const gchar *group_name) 1817 { 1818 GtkActionGroup *action_group; 1819 GtkUIManager *ui_manager; 1820 const gchar *domain; 1821 1822 g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), NULL); 1823 g_return_val_if_fail (group_name != NULL, NULL); 1824 1825 ui_manager = e_attachment_view_get_ui_manager (view); 1826 domain = GETTEXT_PACKAGE; 1827 1828 action_group = gtk_action_group_new (group_name); 1829 gtk_action_group_set_translation_domain (action_group, domain); 1830 gtk_ui_manager_insert_action_group (ui_manager, action_group, 0); 1831 g_object_unref (action_group); 1832 1833 return action_group; 1834 } 1835 1836 GtkActionGroup * 1837 e_attachment_view_get_action_group (EAttachmentView *view, 1838 const gchar *group_name) 1839 { 1840 GtkUIManager *ui_manager; 1841 1842 g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), NULL); 1843 g_return_val_if_fail (group_name != NULL, NULL); 1844 1845 ui_manager = e_attachment_view_get_ui_manager (view); 1846 1847 return e_lookup_action_group (ui_manager, group_name); 1848 } 1849 1850 GtkWidget * 1851 e_attachment_view_get_popup_menu (EAttachmentView *view) 1852 { 1853 GtkUIManager *ui_manager; 1854 GtkWidget *menu; 1855 1856 g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), NULL); 1857 1858 ui_manager = e_attachment_view_get_ui_manager (view); 1859 menu = gtk_ui_manager_get_widget (ui_manager, "/context"); 1860 g_return_val_if_fail (GTK_IS_MENU (menu), NULL); 1861 1862 return menu; 1863 } 1864 1865 GtkUIManager * 1866 e_attachment_view_get_ui_manager (EAttachmentView *view) 1867 { 1868 EAttachmentViewPrivate *priv; 1869 1870 g_return_val_if_fail (E_IS_ATTACHMENT_VIEW (view), NULL); 1871 1872 priv = e_attachment_view_get_private (view); 1873 1874 return priv->ui_manager; 1875 } 1876 1877 void 1878 e_attachment_view_show_popup_menu (EAttachmentView *view, 1879 GdkEventButton *event, 1880 GtkMenuPositionFunc func, 1881 gpointer user_data) 1882 { 1883 GtkWidget *menu; 1884 1885 g_return_if_fail (E_IS_ATTACHMENT_VIEW (view)); 1886 1887 e_attachment_view_update_actions (view); 1888 1889 menu = e_attachment_view_get_popup_menu (view); 1890 1891 if (event != NULL) 1892 gtk_menu_popup ( 1893 GTK_MENU (menu), NULL, NULL, func, 1894 user_data, event->button, event->time); 1895 else 1896 gtk_menu_popup ( 1897 GTK_MENU (menu), NULL, NULL, func, 1898 user_data, 0, gtk_get_current_event_time ()); 1899 } 1900 1901 void 1902 e_attachment_view_update_actions (EAttachmentView *view) 1903 { 1904 g_return_if_fail (E_IS_ATTACHMENT_VIEW (view)); 1905 1906 g_signal_emit (view, signals[UPDATE_ACTIONS], 0); 1907 }