evolution-3.6.4/mail/em-subscription-editor.c

Location Tool Test ID Function Issue
em-subscription-editor.c:769:3 clang-analyzer Value stored to 'found' is never read
em-subscription-editor.c:769:3 clang-analyzer Value stored to 'found' is never read
   1 /*
   2  * em-subscription-editor.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 
  19 #ifdef HAVE_CONFIG_H
  20 #include <config.h>
  21 #endif
  22 
  23 #include "em-subscription-editor.h"
  24 
  25 #include <string.h>
  26 #include <glib/gi18n-lib.h>
  27 
  28 #include <libemail-utils/mail-mt.h>
  29 #include <libemail-engine/mail-tools.h>
  30 #include <libemail-engine/mail-ops.h>
  31 
  32 #include <e-util/e-dialog-utils.h>
  33 #include <e-util/e-util.h>
  34 #include <e-util/e-util-private.h>
  35 
  36 #include "em-folder-utils.h"
  37 
  38 #define EM_SUBSCRIPTION_EDITOR_GET_PRIVATE(obj) \
  39 	(G_TYPE_INSTANCE_GET_PRIVATE \
  40 	((obj), EM_TYPE_SUBSCRIPTION_EDITOR, EMSubscriptionEditorPrivate))
  41 
  42 #define FOLDER_CAN_SELECT(folder_info) \
  43 	((folder_info) != NULL && \
  44 	((folder_info)->flags & CAMEL_FOLDER_NOSELECT) == 0)
  45 #define FOLDER_SUBSCRIBED(folder_info) \
  46 	((folder_info) != NULL && \
  47 	((folder_info)->flags & CAMEL_FOLDER_SUBSCRIBED) != 0)
  48 
  49 #define EM_SUBSCRIPTION_EDITOR_GET_PRIVATE(obj) \
  50 	(G_TYPE_INSTANCE_GET_PRIVATE \
  51 	((obj), EM_TYPE_SUBSCRIPTION_EDITOR, EMSubscriptionEditorPrivate))
  52 
  53 typedef struct _AsyncContext AsyncContext;
  54 typedef struct _TreeRowData TreeRowData;
  55 typedef struct _StoreData StoreData;
  56 
  57 struct _EMSubscriptionEditorPrivate {
  58 	EMailSession *session;
  59 	CamelStore *initial_store;
  60 
  61 	GtkWidget *combo_box;		/* not referenced */
  62 	GtkWidget *entry;		/* not referenced */
  63 	GtkWidget *notebook;		/* not referenced */
  64 	GtkWidget *subscribe_button;	/* not referenced */
  65 	GtkWidget *subscribe_arrow;	/* not referenced */
  66 	GtkWidget *unsubscribe_button;	/* not referenced */
  67 	GtkWidget *unsubscribe_arrow;	/* not referenced */
  68 	GtkWidget *collapse_all_button;	/* not referenced */
  69 	GtkWidget *expand_all_button;	/* not referenced */
  70 	GtkWidget *refresh_button;	/* not referenced */
  71 	GtkWidget *stop_button;		/* not referenced */
  72 
  73 	/* Indicies coincide with the combo box. */
  74 	GPtrArray *stores;
  75 
  76 	/* Points at an item in the stores array. */
  77 	StoreData *active;
  78 
  79 	/* Casefolded search string. */
  80 	gchar *search_string;
  81 
  82 	guint timeout_id;
  83 };
  84 
  85 struct _TreeRowData {
  86 	CamelFolderInfo *folder_info;
  87 	GtkTreeRowReference *reference;
  88 };
  89 
  90 struct _AsyncContext {
  91 	EMSubscriptionEditor *editor;
  92 	GQueue *tree_rows;
  93 };
  94 
  95 struct _StoreData {
  96 	CamelStore *store;
  97 	GtkTreeView *tree_view;
  98 	GtkTreeModel *list_store;
  99 	GtkTreeModel *tree_store;
 100 	GCancellable *cancellable;
 101 	CamelFolderInfo *folder_info;
 102 	gboolean filtered_view;
 103 	gboolean needs_refresh;
 104 };
 105 
 106 enum {
 107 	PROP_0,
 108 	PROP_SESSION,
 109 	PROP_STORE
 110 };
 111 
 112 enum {
 113 	COL_CASEFOLDED,		/* G_TYPE_STRING  */
 114 	COL_FOLDER_NAME,	/* G_TYPE_STRING  */
 115 	COL_FOLDER_ICON,	/* G_TYPE_STRING  */
 116 	COL_FOLDER_INFO,	/* G_TYPE_POINTER */
 117 	N_COLUMNS
 118 };
 119 
 120 G_DEFINE_TYPE (EMSubscriptionEditor, em_subscription_editor, GTK_TYPE_DIALOG)
 121 
 122 static void
 123 tree_row_data_free (TreeRowData *tree_row_data)
 124 {
 125 	g_return_if_fail (tree_row_data != NULL);
 126 
 127 	gtk_tree_row_reference_free (tree_row_data->reference);
 128 	g_slice_free (TreeRowData, tree_row_data);
 129 }
 130 
 131 static AsyncContext *
 132 async_context_new (EMSubscriptionEditor *editor,
 133                    GQueue *tree_rows)
 134 {
 135 	AsyncContext *context;
 136 
 137 	context = g_slice_new0 (AsyncContext);
 138 	context->editor = g_object_ref (editor);
 139 
 140 	/* Transfer GQueue contents. */
 141 	context->tree_rows = g_queue_copy (tree_rows);
 142 	g_queue_clear (tree_rows);
 143 
 144 	return context;
 145 }
 146 
 147 static void
 148 async_context_free (AsyncContext *context)
 149 {
 150 	while (!g_queue_is_empty (context->tree_rows))
 151 		tree_row_data_free (g_queue_pop_head (context->tree_rows));
 152 
 153 	g_object_unref (context->editor);
 154 	g_queue_free (context->tree_rows);
 155 
 156 	g_slice_free (AsyncContext, context);
 157 }
 158 
 159 static void
 160 store_data_free (StoreData *data)
 161 {
 162 	if (data->store != NULL)
 163 		g_object_unref (data->store);
 164 
 165 	if (data->tree_view != NULL)
 166 		g_object_unref (data->tree_view);
 167 
 168 	if (data->list_store != NULL)
 169 		g_object_unref (data->list_store);
 170 
 171 	if (data->tree_store != NULL)
 172 		g_object_unref (data->tree_store);
 173 
 174 	if (data->cancellable != NULL) {
 175 		g_cancellable_cancel (data->cancellable);
 176 		g_object_unref (data->cancellable);
 177 	}
 178 
 179 	camel_folder_info_free (data->folder_info);
 180 
 181 	g_slice_free (StoreData, data);
 182 }
 183 
 184 static void
 185 subscription_editor_populate (EMSubscriptionEditor *editor,
 186                               CamelFolderInfo *folder_info,
 187                               GtkTreeIter *parent,
 188                               GList **expand_paths)
 189 {
 190 	GtkListStore *list_store;
 191 	GtkTreeStore *tree_store;
 192 
 193 	list_store = GTK_LIST_STORE (editor->priv->active->list_store);
 194 	tree_store = GTK_TREE_STORE (editor->priv->active->tree_store);
 195 
 196 	while (folder_info != NULL) {
 197 		GtkTreeIter iter;
 198 		const gchar *icon_name;
 199 		gchar *casefolded;
 200 
 201 		icon_name =
 202 			em_folder_utils_get_icon_name (folder_info->flags);
 203 
 204 		casefolded = g_utf8_casefold (folder_info->full_name, -1);
 205 
 206 		gtk_list_store_append (list_store, &iter);
 207 
 208 		gtk_list_store_set (
 209 			list_store, &iter,
 210 			COL_CASEFOLDED, casefolded,
 211 			COL_FOLDER_ICON, icon_name,
 212 			COL_FOLDER_NAME, folder_info->full_name,
 213 			COL_FOLDER_INFO, folder_info, -1);
 214 
 215 		gtk_tree_store_append (tree_store, &iter, parent);
 216 
 217 		gtk_tree_store_set (
 218 			tree_store, &iter,
 219 			COL_CASEFOLDED, NULL,  /* not needed */
 220 			COL_FOLDER_ICON, icon_name,
 221 			COL_FOLDER_NAME, folder_info->display_name,
 222 			COL_FOLDER_INFO, folder_info, -1);
 223 
 224 		if (FOLDER_SUBSCRIBED (folder_info)) {
 225 			GtkTreePath *path;
 226 
 227 			path = gtk_tree_model_get_path (
 228 				GTK_TREE_MODEL (tree_store), &iter);
 229 			*expand_paths = g_list_prepend (*expand_paths, path);
 230 		}
 231 
 232 		g_free (casefolded);
 233 
 234 		if (folder_info->child != NULL)
 235 			subscription_editor_populate (
 236 				editor, folder_info->child,
 237 				&iter, expand_paths);
 238 
 239 		folder_info = folder_info->next;
 240 	}
 241 }
 242 
 243 static void
 244 expand_paths_cb (gpointer path,
 245                  gpointer tree_view)
 246 {
 247 	gtk_tree_view_expand_to_path (tree_view, path);
 248 }
 249 
 250 static void
 251 subscription_editor_get_folder_info_done (CamelStore *store,
 252                                           GAsyncResult *result,
 253                                           EMSubscriptionEditor *editor)
 254 {
 255 	GtkTreePath *path;
 256 	GtkTreeView *tree_view;
 257 	GtkTreeModel *list_store;
 258 	GtkTreeModel *tree_store;
 259 	GtkTreeModel *model;
 260 	GtkTreeSelection *selection;
 261 	CamelFolderInfo *folder_info;
 262 	GdkWindow *window;
 263 	GList *expand_paths = NULL;
 264 	GError *error = NULL;
 265 
 266 	folder_info = camel_store_get_folder_info_finish (
 267 		store, result, &error);
 268 
 269 	/* Just return quietly if we were cancelled. */
 270 	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
 271 		g_warn_if_fail (folder_info == NULL);
 272 		g_error_free (error);
 273 		goto exit;
 274 	}
 275 
 276 	gtk_widget_set_sensitive (editor->priv->notebook, TRUE);
 277 	gtk_widget_set_sensitive (editor->priv->refresh_button, TRUE);
 278 	gtk_widget_set_sensitive (editor->priv->stop_button, FALSE);
 279 
 280 	window = gtk_widget_get_window (GTK_WIDGET (editor));
 281 	gdk_window_set_cursor (window, NULL);
 282 
 283 	/* XXX Do something smarter with errors. */
 284 	if (error != NULL) {
 285 		g_warn_if_fail (folder_info == NULL);
 286 		e_notice (GTK_WINDOW (editor), GTK_MESSAGE_ERROR, "%s", error->message);
 287 		g_error_free (error);
 288 		goto exit;
 289 	}
 290 
 291 	g_return_if_fail (folder_info != NULL);
 292 
 293 	camel_folder_info_free (editor->priv->active->folder_info);
 294 	editor->priv->active->folder_info = folder_info;
 295 
 296 	tree_view = editor->priv->active->tree_view;
 297 	list_store = editor->priv->active->list_store;
 298 	tree_store = editor->priv->active->tree_store;
 299 
 300 	gtk_list_store_clear (GTK_LIST_STORE (list_store));
 301 	gtk_tree_store_clear (GTK_TREE_STORE (tree_store));
 302 
 303 	model = gtk_tree_view_get_model (tree_view);
 304 	gtk_tree_view_set_model (tree_view, NULL);
 305 	subscription_editor_populate (editor, folder_info, NULL, &expand_paths);
 306 	gtk_tree_view_set_model (tree_view, model);
 307 
 308 	g_list_foreach (expand_paths, expand_paths_cb, tree_view);
 309 	g_list_foreach (expand_paths, (GFunc) gtk_tree_path_free, NULL);
 310 	g_list_free (expand_paths);
 311 
 312 	path = gtk_tree_path_new_first ();
 313 	selection = gtk_tree_view_get_selection (tree_view);
 314 	gtk_tree_selection_select_path (selection, path);
 315 	gtk_tree_path_free (path);
 316 
 317 	gtk_widget_grab_focus (GTK_WIDGET (tree_view));
 318 
 319 exit:
 320 	g_object_unref (editor);
 321 }
 322 
 323 static void
 324 subscription_editor_subscribe_folder_done (CamelSubscribable *subscribable,
 325                                            GAsyncResult *result,
 326                                            AsyncContext *context)
 327 {
 328 	GtkTreeView *tree_view;
 329 	GtkTreeModel *tree_model;
 330 	GtkTreeSelection *selection;
 331 	GtkTreePath *path;
 332 	GtkTreeIter iter;
 333 	GdkWindow *window;
 334 	GError *error = NULL;
 335 	TreeRowData *tree_row_data;
 336 
 337 	camel_subscribable_subscribe_folder_finish (
 338 		subscribable, result, &error);
 339 
 340 	/* Just return quietly if we were cancelled. */
 341 	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
 342 		g_error_free (error);
 343 		goto exit;
 344 	}
 345 
 346 	tree_row_data = g_queue_pop_head (context->tree_rows);
 347 
 348 	/* XXX Do something smarter with errors. */
 349 	if (error == NULL)
 350 		tree_row_data->folder_info->flags |= CAMEL_FOLDER_SUBSCRIBED;
 351 	else {
 352 		e_notice (
 353 			GTK_WINDOW (context->editor),
 354 			GTK_MESSAGE_ERROR, "%s", error->message);
 355 		g_error_free (error);
 356 		tree_row_data_free (tree_row_data);
 357 		goto exit;
 358 	}
 359 
 360 	/* Update the toggle renderer in the selected row. */
 361 	tree_model = gtk_tree_row_reference_get_model (tree_row_data->reference);
 362 	path = gtk_tree_row_reference_get_path (tree_row_data->reference);
 363 	gtk_tree_model_get_iter (tree_model, &iter, path);
 364 	gtk_tree_model_row_changed (tree_model, path, &iter);
 365 	gtk_tree_path_free (path);
 366 
 367 	tree_row_data_free (tree_row_data);
 368 
 369 	if (!g_queue_is_empty (context->tree_rows)) {
 370 		GCancellable *cancellable;
 371 
 372 		/* continue with the next to subscribe */
 373 		tree_row_data = g_queue_peek_head (context->tree_rows);
 374 		g_return_if_fail (tree_row_data != NULL);
 375 
 376 		cancellable = context->editor->priv->active->cancellable;
 377 
 378 		camel_subscribable_subscribe_folder (
 379 			subscribable, tree_row_data->folder_info->full_name,
 380 			G_PRIORITY_DEFAULT, cancellable, (GAsyncReadyCallback)
 381 			subscription_editor_subscribe_folder_done, context);
 382 		return;
 383 	}
 384 
 385 exit:
 386 	gtk_widget_set_sensitive (context->editor->priv->notebook, TRUE);
 387 	gtk_widget_set_sensitive (context->editor->priv->refresh_button, TRUE);
 388 	gtk_widget_set_sensitive (context->editor->priv->stop_button, FALSE);
 389 
 390 	window = gtk_widget_get_window (GTK_WIDGET (context->editor));
 391 	gdk_window_set_cursor (window, NULL);
 392 
 393 	/* Update the Subscription/Unsubscription buttons. */
 394 	tree_view = context->editor->priv->active->tree_view;
 395 	selection = gtk_tree_view_get_selection (tree_view);
 396 	g_signal_emit_by_name (selection, "changed");
 397 
 398 	async_context_free (context);
 399 
 400 	gtk_widget_grab_focus (GTK_WIDGET (tree_view));
 401 }
 402 
 403 static void
 404 subscription_editor_subscribe_many (EMSubscriptionEditor *editor,
 405                                     GQueue *tree_rows)
 406 {
 407 	TreeRowData *tree_row_data;
 408 	GCancellable *cancellable;
 409 	CamelStore *active_store;
 410 	AsyncContext *context;
 411 	GdkCursor *cursor;
 412 	GdkWindow *window;
 413 
 414 	g_return_if_fail (editor != NULL);
 415 
 416 	if (g_queue_is_empty (tree_rows))
 417 		return;
 418 
 419 	tree_row_data = g_queue_peek_head (tree_rows);
 420 	g_return_if_fail (tree_row_data != NULL);
 421 
 422 	/* Cancel any operation on this store still in progress. */
 423 	gtk_button_clicked (GTK_BUTTON (editor->priv->stop_button));
 424 
 425 	/* Start a new 'subscription' operation. */
 426 	editor->priv->active->cancellable = g_cancellable_new ();
 427 
 428 	gtk_widget_set_sensitive (editor->priv->notebook, FALSE);
 429 	gtk_widget_set_sensitive (editor->priv->subscribe_button, FALSE);
 430 	gtk_widget_set_sensitive (editor->priv->subscribe_arrow, FALSE);
 431 	gtk_widget_set_sensitive (editor->priv->unsubscribe_button, FALSE);
 432 	gtk_widget_set_sensitive (editor->priv->unsubscribe_arrow, FALSE);
 433 	gtk_widget_set_sensitive (editor->priv->refresh_button, FALSE);
 434 	gtk_widget_set_sensitive (editor->priv->stop_button, TRUE);
 435 
 436 	cursor = gdk_cursor_new (GDK_WATCH);
 437 	window = gtk_widget_get_window (GTK_WIDGET (editor));
 438 	gdk_window_set_cursor (window, cursor);
 439 	g_object_unref (cursor);
 440 
 441 	context = async_context_new (editor, tree_rows);
 442 
 443 	active_store = editor->priv->active->store;
 444 	cancellable = editor->priv->active->cancellable;
 445 
 446 	camel_subscribable_subscribe_folder (
 447 		CAMEL_SUBSCRIBABLE (active_store),
 448 		tree_row_data->folder_info->full_name,
 449 		G_PRIORITY_DEFAULT, cancellable, (GAsyncReadyCallback)
 450 		subscription_editor_subscribe_folder_done, context);
 451 }
 452 
 453 static void
 454 subscription_editor_unsubscribe_folder_done (CamelSubscribable *subscribable,
 455                                              GAsyncResult *result,
 456                                              AsyncContext *context)
 457 {
 458 	GtkTreeView *tree_view;
 459 	GtkTreeModel *tree_model;
 460 	GtkTreeSelection *selection;
 461 	GtkTreePath *path;
 462 	GtkTreeIter iter;
 463 	GdkWindow *window;
 464 	GError *error = NULL;
 465 	TreeRowData *tree_row_data;
 466 
 467 	camel_subscribable_unsubscribe_folder_finish (
 468 		subscribable, result, &error);
 469 
 470 	/* Just return quietly if we were cancelled. */
 471 	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
 472 		g_error_free (error);
 473 		goto exit;
 474 	}
 475 
 476 	tree_row_data = g_queue_pop_head (context->tree_rows);
 477 
 478 	/* XXX Do something smarter with errors. */
 479 	if (error == NULL)
 480 		tree_row_data->folder_info->flags &= ~CAMEL_FOLDER_SUBSCRIBED;
 481 	else {
 482 		e_notice (
 483 			GTK_WINDOW (context->editor),
 484 			GTK_MESSAGE_ERROR, "%s", error->message);
 485 		g_error_free (error);
 486 		tree_row_data_free (tree_row_data);
 487 		goto exit;
 488 	}
 489 
 490 	/* Update the toggle renderer in the selected row. */
 491 	tree_model = gtk_tree_row_reference_get_model (tree_row_data->reference);
 492 	path = gtk_tree_row_reference_get_path (tree_row_data->reference);
 493 	gtk_tree_model_get_iter (tree_model, &iter, path);
 494 	gtk_tree_model_row_changed (tree_model, path, &iter);
 495 	gtk_tree_path_free (path);
 496 
 497 	tree_row_data_free (tree_row_data);
 498 
 499 	if (!g_queue_is_empty (context->tree_rows)) {
 500 		GCancellable *cancellable;
 501 
 502 		/* continue with the next to unsubscribe */
 503 		tree_row_data = g_queue_peek_head (context->tree_rows);
 504 		g_return_if_fail (tree_row_data != NULL);
 505 
 506 		cancellable = context->editor->priv->active->cancellable;
 507 
 508 		camel_subscribable_unsubscribe_folder (
 509 			subscribable, tree_row_data->folder_info->full_name,
 510 			G_PRIORITY_DEFAULT, cancellable, (GAsyncReadyCallback)
 511 			subscription_editor_unsubscribe_folder_done, context);
 512 		return;
 513 	}
 514 
 515 exit:
 516 	gtk_widget_set_sensitive (context->editor->priv->notebook, TRUE);
 517 	gtk_widget_set_sensitive (context->editor->priv->refresh_button, TRUE);
 518 	gtk_widget_set_sensitive (context->editor->priv->stop_button, FALSE);
 519 
 520 	window = gtk_widget_get_window (GTK_WIDGET (context->editor));
 521 	gdk_window_set_cursor (window, NULL);
 522 
 523 	/* Update the Subscription/Unsubscription buttons. */
 524 	tree_view = context->editor->priv->active->tree_view;
 525 	selection = gtk_tree_view_get_selection (tree_view);
 526 	g_signal_emit_by_name (selection, "changed");
 527 
 528 	async_context_free (context);
 529 
 530 	gtk_widget_grab_focus (GTK_WIDGET (tree_view));
 531 }
 532 
 533 static void
 534 subscription_editor_unsubscribe_many (EMSubscriptionEditor *editor,
 535                                       GQueue *tree_rows)
 536 {
 537 	TreeRowData *tree_row_data;
 538 	AsyncContext *context;
 539 	CamelStore *active_store;
 540 	GdkCursor *cursor;
 541 	GdkWindow *window;
 542 
 543 	g_return_if_fail (editor != NULL);
 544 
 545 	if (g_queue_is_empty (tree_rows))
 546 		return;
 547 
 548 	tree_row_data = g_queue_peek_head (tree_rows);
 549 	g_return_if_fail (tree_row_data != NULL);
 550 
 551 	/* Cancel any operation on this store still in progress. */
 552 	gtk_button_clicked (GTK_BUTTON (editor->priv->stop_button));
 553 
 554 	/* Start a new 'subscription' operation. */
 555 	editor->priv->active->cancellable = g_cancellable_new ();
 556 
 557 	gtk_widget_set_sensitive (editor->priv->notebook, FALSE);
 558 	gtk_widget_set_sensitive (editor->priv->subscribe_button, FALSE);
 559 	gtk_widget_set_sensitive (editor->priv->subscribe_arrow, FALSE);
 560 	gtk_widget_set_sensitive (editor->priv->unsubscribe_button, FALSE);
 561 	gtk_widget_set_sensitive (editor->priv->unsubscribe_arrow, FALSE);
 562 	gtk_widget_set_sensitive (editor->priv->refresh_button, FALSE);
 563 	gtk_widget_set_sensitive (editor->priv->stop_button, TRUE);
 564 
 565 	cursor = gdk_cursor_new (GDK_WATCH);
 566 	window = gtk_widget_get_window (GTK_WIDGET (editor));
 567 	gdk_window_set_cursor (window, cursor);
 568 	g_object_unref (cursor);
 569 
 570 	context = async_context_new (editor, tree_rows);
 571 
 572 	active_store = editor->priv->active->store;
 573 
 574 	camel_subscribable_unsubscribe_folder (
 575 		CAMEL_SUBSCRIBABLE (active_store),
 576 		tree_row_data->folder_info->full_name, G_PRIORITY_DEFAULT,
 577 		editor->priv->active->cancellable, (GAsyncReadyCallback)
 578 		subscription_editor_unsubscribe_folder_done, context);
 579 }
 580 
 581 static GtkWidget *
 582 subscription_editor_create_menu_item (const gchar *label,
 583                                       gboolean sensitive,
 584                                       GCallback activate_cb,
 585                                       EMSubscriptionEditor *editor)
 586 {
 587 	GtkWidget *item;
 588 
 589 	item = gtk_menu_item_new_with_mnemonic (label);
 590 	gtk_widget_set_sensitive (item, sensitive);
 591 
 592 	gtk_widget_show (item);
 593 
 594 	g_signal_connect_swapped (
 595 		item, "activate", activate_cb, editor);
 596 
 597 	return item;
 598 }
 599 
 600 static void
 601 position_below_widget_cb (GtkMenu *menu,
 602                           gint *x,
 603                           gint *y,
 604                           gboolean *push_in,
 605                           gpointer under_widget)
 606 {
 607 	GtkRequisition menu_requisition;
 608 	GtkTextDirection direction;
 609 	GtkAllocation allocation;
 610 	GdkRectangle monitor;
 611 	GdkScreen *screen;
 612 	GdkWindow *window;
 613 	GtkWidget *widget;
 614 	gint monitor_num;
 615 
 616 	widget = under_widget;
 617 	gtk_widget_get_preferred_size (
 618 		GTK_WIDGET (menu), &menu_requisition, NULL);
 619 
 620 	window = gtk_widget_get_parent_window (widget);
 621 	screen = gtk_widget_get_screen (GTK_WIDGET (menu));
 622 	monitor_num = gdk_screen_get_monitor_at_window (screen, window);
 623 	if (monitor_num < 0)
 624 		monitor_num = 0;
 625 	gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
 626 
 627 	gtk_widget_get_allocation (widget, &allocation);
 628 
 629 	gdk_window_get_origin (window, x, y);
 630 	*x += allocation.x;
 631 	*y += allocation.y + 2 + gtk_widget_get_allocated_height (under_widget);
 632 
 633 	direction = gtk_widget_get_direction (widget);
 634 	if (direction == GTK_TEXT_DIR_LTR)
 635 		*x += MAX (allocation.width - menu_requisition.width, 0);
 636 	else if (menu_requisition.width > allocation.width)
 637 		*x -= menu_requisition.width - allocation.width;
 638 
 639 	*push_in = FALSE;
 640 }
 641 
 642 static TreeRowData *
 643 subscription_editor_tree_row_data_from_iter (GtkTreeView *tree_view,
 644                                              GtkTreeModel *model,
 645                                              GtkTreeIter *iter,
 646                                              gboolean *is_expanded)
 647 {
 648 	TreeRowData *tree_row_data;
 649 	CamelFolderInfo *folder_info = NULL;
 650 	GtkTreeRowReference *reference;
 651 	GtkTreePath *path;
 652 
 653 	gtk_tree_model_get (
 654 		model, iter, COL_FOLDER_INFO, &folder_info, -1);
 655 
 656 	if (!FOLDER_CAN_SELECT (folder_info))
 657 		return NULL;
 658 
 659 	path = gtk_tree_model_get_path (model, iter);
 660 	reference = gtk_tree_row_reference_new (model, path);
 661 	if (is_expanded)
 662 		*is_expanded = gtk_tree_view_row_expanded (tree_view, path);
 663 	gtk_tree_path_free (path);
 664 
 665 	tree_row_data = g_slice_new0 (TreeRowData);
 666 	tree_row_data->folder_info = folder_info;
 667 	tree_row_data->reference = reference;
 668 
 669 	return tree_row_data;
 670 }
 671 
 672 typedef enum {
 673 	PICK_ALL,
 674 	PICK_SUBSCRIBED,
 675 	PICK_UNSUBSCRIBED
 676 } EPickMode;
 677 
 678 static gboolean
 679 can_pick_folder_info (CamelFolderInfo *fi,
 680                       EPickMode mode)
 681 {
 682 	if (!FOLDER_CAN_SELECT (fi))
 683 		return FALSE;
 684 
 685 	if (mode == PICK_ALL)
 686 		return TRUE;
 687 
 688 	return (FOLDER_SUBSCRIBED (fi) ? 1 : 0) == (mode == PICK_SUBSCRIBED ? 1 : 0);
 689 }
 690 
 691 struct PickAllData {
 692 	GtkTreeView *tree_view;
 693 	EPickMode mode;
 694 	GHashTable *skip_folder_infos;
 695 	GQueue *out_tree_rows;
 696 };
 697 
 698 static gboolean
 699 pick_all_cb (GtkTreeModel *model,
 700              GtkTreePath *path,
 701              GtkTreeIter *iter,
 702              gpointer user_data)
 703 {
 704 	struct PickAllData *data = user_data;
 705 	TreeRowData *tree_row_data;
 706 
 707 	tree_row_data = subscription_editor_tree_row_data_from_iter (
 708 		data->tree_view, model, iter, NULL);
 709 	if (tree_row_data == NULL)
 710 		return FALSE;
 711 
 712 	if (can_pick_folder_info (tree_row_data->folder_info, data->mode) &&
 713 	    (data->skip_folder_infos == NULL ||
 714 	    !g_hash_table_lookup_extended (
 715 		data->skip_folder_infos,
 716 		tree_row_data->folder_info, NULL, NULL))) {
 717 		g_queue_push_tail (data->out_tree_rows, tree_row_data);
 718 	} else
 719 		tree_row_data_free (tree_row_data);
 720 
 721 	return FALSE;
 722 }
 723 
 724 /* skip_folder_infos contains CamelFolderInfo-s to skip;
 725  * these should come from the tree view; can be NULL
 726  * to include everything.
 727 */
 728 static void
 729 subscription_editor_pick_all (EMSubscriptionEditor *editor,
 730                               EPickMode mode,
 731                               GHashTable *skip_folder_infos,
 732                               GQueue *out_tree_rows)
 733 {
 734 	GtkTreeView *tree_view;
 735 	GtkTreeModel *tree_model;
 736 	struct PickAllData data;
 737 
 738 	tree_view = editor->priv->active->tree_view;
 739 	tree_model = gtk_tree_view_get_model (tree_view);
 740 
 741 	data.tree_view = tree_view;
 742 	data.mode = mode;
 743 	data.skip_folder_infos = skip_folder_infos;
 744 	data.out_tree_rows = out_tree_rows;
 745 
 746 	gtk_tree_model_foreach (tree_model, pick_all_cb, &data);
 747 }
 748 
 749 static void
 750 subscription_editor_pick_shown (EMSubscriptionEditor *editor,
 751                                 EPickMode mode,
 752                                 GQueue *out_tree_rows)
 753 {
 754 	GtkTreeView *tree_view;
 755 	GtkTreeModel *tree_model;
 756 	GtkTreeIter iter, iter2;
 757 	gboolean found = TRUE;
 758 
 759 	tree_view = editor->priv->active->tree_view;
 760 	tree_model = gtk_tree_view_get_model (tree_view);
 761 
 762 	if (!gtk_tree_model_get_iter_first (tree_model, &iter))
 763 		return;
 764 
 765 	while (found) {
 766 		TreeRowData *tree_row_data;
 767 		gboolean is_expanded = FALSE;
 768 
 769 		found = FALSE;
Value stored to 'found' is never read
(emitted by clang-analyzer)

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

Value stored to 'found' is never read
(emitted by clang-analyzer)

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

770 tree_row_data = subscription_editor_tree_row_data_from_iter ( 771 tree_view, tree_model, &iter, &is_expanded); 772 773 if (tree_row_data != NULL) { 774 if (can_pick_folder_info (tree_row_data->folder_info, mode)) 775 g_queue_push_tail (out_tree_rows, tree_row_data); 776 else 777 tree_row_data_free (tree_row_data); 778 } 779 780 if (is_expanded && gtk_tree_model_iter_children ( 781 tree_model, &iter2, &iter)) { 782 iter = iter2; 783 found = TRUE; 784 } else { 785 iter2 = iter; 786 if (gtk_tree_model_iter_next (tree_model, &iter2)) { 787 iter = iter2; 788 found = TRUE; 789 } else { 790 while (found = gtk_tree_model_iter_parent ( 791 tree_model, &iter2, &iter), found) { 792 iter = iter2; 793 if (gtk_tree_model_iter_next ( 794 tree_model, &iter2)) { 795 iter = iter2; 796 break; 797 } 798 } 799 } 800 } 801 } 802 } 803 804 static void 805 subscription_editor_subscribe (EMSubscriptionEditor *editor) 806 { 807 GtkTreeSelection *selection; 808 GtkTreeModel *tree_model; 809 GtkTreeView *tree_view; 810 GtkTreeIter iter; 811 gboolean have_selection; 812 GQueue tree_rows = G_QUEUE_INIT; 813 TreeRowData *tree_row_data; 814 815 tree_view = editor->priv->active->tree_view; 816 selection = gtk_tree_view_get_selection (tree_view); 817 818 have_selection = gtk_tree_selection_get_selected ( 819 selection, &tree_model, &iter); 820 g_return_if_fail (have_selection); 821 822 tree_row_data = subscription_editor_tree_row_data_from_iter ( 823 tree_view, tree_model, &iter, NULL); 824 825 g_queue_push_tail (&tree_rows, tree_row_data); 826 subscription_editor_subscribe_many (editor, &tree_rows); 827 g_warn_if_fail (g_queue_is_empty (&tree_rows)); 828 } 829 830 static void 831 subscription_editor_subscribe_shown (EMSubscriptionEditor *editor) 832 { 833 GQueue tree_rows = G_QUEUE_INIT; 834 835 subscription_editor_pick_shown ( 836 editor, PICK_UNSUBSCRIBED, &tree_rows); 837 subscription_editor_subscribe_many (editor, &tree_rows); 838 } 839 840 static void 841 subscription_editor_subscribe_all (EMSubscriptionEditor *editor) 842 { 843 GQueue tree_rows = G_QUEUE_INIT; 844 845 subscription_editor_pick_all ( 846 editor, PICK_UNSUBSCRIBED, NULL, &tree_rows); 847 subscription_editor_subscribe_many (editor, &tree_rows); 848 } 849 850 static void 851 subscription_editor_subscribe_popup_cb (EMSubscriptionEditor *editor) 852 { 853 GtkWidget *menu; 854 GtkTreeIter iter; 855 gboolean tree_filled; 856 857 tree_filled = editor->priv->active && 858 gtk_tree_model_get_iter_first ( 859 editor->priv->active->filtered_view 860 ? editor->priv->active->list_store 861 : editor->priv->active->tree_store, 862 &iter); 863 864 menu = gtk_menu_new (); 865 866 gtk_menu_shell_append ( 867 GTK_MENU_SHELL (menu), 868 subscription_editor_create_menu_item ( 869 _("_Subscribe"), 870 gtk_widget_get_sensitive ( 871 editor->priv->subscribe_button), 872 G_CALLBACK (subscription_editor_subscribe), 873 editor)); 874 875 gtk_menu_shell_append ( 876 GTK_MENU_SHELL (menu), 877 subscription_editor_create_menu_item ( 878 _("Su_bscribe To Shown"), 879 tree_filled, 880 G_CALLBACK (subscription_editor_subscribe_shown), 881 editor)); 882 883 gtk_menu_shell_append ( 884 GTK_MENU_SHELL (menu), 885 subscription_editor_create_menu_item ( 886 _("Subscribe To _All"), 887 tree_filled, 888 G_CALLBACK (subscription_editor_subscribe_all), 889 editor)); 890 891 gtk_menu_popup ( 892 GTK_MENU (menu), NULL, NULL, 893 position_below_widget_cb, 894 editor->priv->subscribe_button, 895 0, gtk_get_current_event_time ()); 896 } 897 898 static void 899 subscription_editor_unsubscribe_hidden (EMSubscriptionEditor *editor) 900 { 901 GQueue tree_rows = G_QUEUE_INIT; 902 GHashTable *skip_shown; 903 904 subscription_editor_pick_shown (editor, PICK_ALL, &tree_rows); 905 g_return_if_fail (!g_queue_is_empty (&tree_rows)); 906 907 skip_shown = g_hash_table_new (g_direct_hash, g_direct_equal); 908 909 while (!g_queue_is_empty (&tree_rows)) { 910 TreeRowData *tree_row_data; 911 912 tree_row_data = g_queue_pop_head (&tree_rows); 913 914 if (tree_row_data == NULL) 915 continue; 916 917 g_hash_table_insert ( 918 skip_shown, 919 tree_row_data->folder_info, 920 GINT_TO_POINTER (1)); 921 922 tree_row_data_free (tree_row_data); 923 } 924 925 subscription_editor_pick_all ( 926 editor, PICK_SUBSCRIBED, skip_shown, &tree_rows); 927 subscription_editor_unsubscribe_many (editor, &tree_rows); 928 929 g_hash_table_destroy (skip_shown); 930 } 931 932 static void 933 subscription_editor_unsubscribe_all (EMSubscriptionEditor *editor) 934 { 935 GQueue tree_rows = G_QUEUE_INIT; 936 937 subscription_editor_pick_all ( 938 editor, PICK_SUBSCRIBED, NULL, &tree_rows); 939 subscription_editor_unsubscribe_many (editor, &tree_rows); 940 } 941 942 static void 943 subscription_editor_unsubscribe (EMSubscriptionEditor *editor) 944 { 945 GtkTreeSelection *selection; 946 GtkTreeModel *tree_model; 947 GtkTreeView *tree_view; 948 GtkTreeIter iter; 949 gboolean have_selection; 950 GQueue tree_rows = G_QUEUE_INIT; 951 TreeRowData *tree_row_data; 952 953 tree_view = editor->priv->active->tree_view; 954 selection = gtk_tree_view_get_selection (tree_view); 955 956 have_selection = gtk_tree_selection_get_selected ( 957 selection, &tree_model, &iter); 958 g_return_if_fail (have_selection); 959 960 tree_row_data = subscription_editor_tree_row_data_from_iter ( 961 tree_view, tree_model, &iter, NULL); 962 963 g_queue_push_tail (&tree_rows, tree_row_data); 964 subscription_editor_unsubscribe_many (editor, &tree_rows); 965 } 966 967 static void 968 subscription_editor_unsubscribe_popup_cb (EMSubscriptionEditor *editor) 969 { 970 GtkWidget *menu; 971 GtkTreeIter iter; 972 gboolean tree_filled; 973 974 tree_filled = editor->priv->active && 975 gtk_tree_model_get_iter_first ( 976 editor->priv->active->filtered_view 977 ? editor->priv->active->list_store 978 : editor->priv->active->tree_store, 979 &iter); 980 981 menu = gtk_menu_new (); 982 983 gtk_menu_shell_append ( 984 GTK_MENU_SHELL (menu), 985 subscription_editor_create_menu_item ( 986 _("_Unsubscribe"), 987 gtk_widget_get_sensitive ( 988 editor->priv->unsubscribe_button), 989 G_CALLBACK (subscription_editor_unsubscribe), 990 editor)); 991 992 gtk_menu_shell_append ( 993 GTK_MENU_SHELL (menu), 994 subscription_editor_create_menu_item ( 995 _("Unsu_bscribe From Hidden"), 996 tree_filled, 997 G_CALLBACK (subscription_editor_unsubscribe_hidden), 998 editor)); 999 1000 gtk_menu_shell_append ( 1001 GTK_MENU_SHELL (menu), 1002 subscription_editor_create_menu_item ( 1003 _("Unsubscribe From _All"), 1004 tree_filled, 1005 G_CALLBACK (subscription_editor_unsubscribe_all), 1006 editor)); 1007 1008 gtk_menu_popup ( 1009 GTK_MENU (menu), NULL, NULL, 1010 position_below_widget_cb, 1011 editor->priv->unsubscribe_button, 1012 0, gtk_get_current_event_time ()); 1013 } 1014 1015 static void 1016 subscription_editor_collapse_all (EMSubscriptionEditor *editor) 1017 { 1018 gtk_tree_view_collapse_all (editor->priv->active->tree_view); 1019 } 1020 1021 static void 1022 subscription_editor_expand_all (EMSubscriptionEditor *editor) 1023 { 1024 gtk_tree_view_expand_all (editor->priv->active->tree_view); 1025 } 1026 1027 static void 1028 subscription_editor_refresh (EMSubscriptionEditor *editor) 1029 { 1030 GdkCursor *cursor; 1031 GdkWindow *window; 1032 1033 /* Cancel any operation on this store still in progress. */ 1034 gtk_button_clicked (GTK_BUTTON (editor->priv->stop_button)); 1035 1036 /* Start a new 'refresh' operation. */ 1037 editor->priv->active->cancellable = g_cancellable_new (); 1038 1039 gtk_widget_set_sensitive (editor->priv->notebook, FALSE); 1040 gtk_widget_set_sensitive (editor->priv->subscribe_button, FALSE); 1041 gtk_widget_set_sensitive (editor->priv->subscribe_arrow, FALSE); 1042 gtk_widget_set_sensitive (editor->priv->unsubscribe_button, FALSE); 1043 gtk_widget_set_sensitive (editor->priv->unsubscribe_arrow, FALSE); 1044 gtk_widget_set_sensitive (editor->priv->refresh_button, FALSE); 1045 gtk_widget_set_sensitive (editor->priv->stop_button, TRUE); 1046 1047 cursor = gdk_cursor_new (GDK_WATCH); 1048 window = gtk_widget_get_window (GTK_WIDGET (editor)); 1049 gdk_window_set_cursor (window, cursor); 1050 g_object_unref (cursor); 1051 1052 camel_store_get_folder_info ( 1053 editor->priv->active->store, NULL, 1054 CAMEL_STORE_FOLDER_INFO_RECURSIVE | 1055 CAMEL_STORE_FOLDER_INFO_NO_VIRTUAL | 1056 CAMEL_STORE_FOLDER_INFO_SUBSCRIPTION_LIST, 1057 G_PRIORITY_DEFAULT, editor->priv->active->cancellable, 1058 (GAsyncReadyCallback) subscription_editor_get_folder_info_done, 1059 g_object_ref (editor)); 1060 } 1061 1062 static void 1063 subscription_editor_stop (EMSubscriptionEditor *editor) 1064 { 1065 GdkWindow *window; 1066 1067 if (editor->priv->active->cancellable != NULL) { 1068 g_cancellable_cancel (editor->priv->active->cancellable); 1069 g_object_unref (editor->priv->active->cancellable); 1070 editor->priv->active->cancellable = NULL; 1071 } 1072 1073 gtk_widget_set_sensitive (editor->priv->notebook, TRUE); 1074 gtk_widget_set_sensitive (editor->priv->subscribe_button, TRUE); 1075 gtk_widget_set_sensitive (editor->priv->subscribe_arrow, TRUE); 1076 gtk_widget_set_sensitive (editor->priv->unsubscribe_button, TRUE); 1077 gtk_widget_set_sensitive (editor->priv->unsubscribe_arrow, TRUE); 1078 gtk_widget_set_sensitive (editor->priv->refresh_button, TRUE); 1079 gtk_widget_set_sensitive (editor->priv->stop_button, FALSE); 1080 gtk_widget_grab_focus (GTK_WIDGET (editor->priv->active->tree_view)); 1081 1082 window = gtk_widget_get_window (GTK_WIDGET (editor)); 1083 gdk_window_set_cursor (window, NULL); 1084 } 1085 1086 static gboolean 1087 subscription_editor_filter_cb (GtkTreeModel *tree_model, 1088 GtkTreeIter *iter, 1089 EMSubscriptionEditor *editor) 1090 { 1091 CamelFolderInfo *folder_info; 1092 gchar *casefolded; 1093 gboolean match; 1094 1095 /* If there's no search string let everything through. */ 1096 if (editor->priv->search_string == NULL) 1097 return TRUE; 1098 1099 gtk_tree_model_get ( 1100 tree_model, iter, 1101 COL_CASEFOLDED, &casefolded, 1102 COL_FOLDER_INFO, &folder_info, -1); 1103 1104 match = FOLDER_CAN_SELECT (folder_info) && 1105 (casefolded != NULL) && (*casefolded != '\0') && 1106 (strstr (casefolded, editor->priv->search_string) != NULL); 1107 1108 g_free (casefolded); 1109 1110 return match; 1111 } 1112 1113 static void 1114 subscription_editor_update_view (EMSubscriptionEditor *editor) 1115 { 1116 GtkEntry *entry; 1117 GtkTreeView *tree_view; 1118 GtkTreeModel *tree_model; 1119 const gchar *text; 1120 1121 entry = GTK_ENTRY (editor->priv->entry); 1122 tree_view = editor->priv->active->tree_view; 1123 1124 editor->priv->timeout_id = 0; 1125 1126 text = gtk_entry_get_text (entry); 1127 1128 if (text != NULL && *text != '\0') { 1129 g_free (editor->priv->search_string); 1130 editor->priv->search_string = g_utf8_casefold (text, -1); 1131 1132 /* Install the list store in the tree view if needed. */ 1133 if (!editor->priv->active->filtered_view) { 1134 GtkTreeSelection *selection; 1135 GtkTreePath *path; 1136 1137 tree_model = gtk_tree_model_filter_new ( 1138 editor->priv->active->list_store, NULL); 1139 gtk_tree_model_filter_set_visible_func ( 1140 GTK_TREE_MODEL_FILTER (tree_model), 1141 (GtkTreeModelFilterVisibleFunc) 1142 subscription_editor_filter_cb, editor, 1143 (GDestroyNotify) NULL); 1144 gtk_tree_view_set_model (tree_view, tree_model); 1145 g_object_unref (tree_model); 1146 1147 path = gtk_tree_path_new_first (); 1148 selection = gtk_tree_view_get_selection (tree_view); 1149 gtk_tree_selection_select_path (selection, path); 1150 gtk_tree_path_free (path); 1151 1152 editor->priv->active->filtered_view = TRUE; 1153 } 1154 1155 tree_model = gtk_tree_view_get_model (tree_view); 1156 gtk_tree_model_filter_refilter ( 1157 GTK_TREE_MODEL_FILTER (tree_model)); 1158 1159 gtk_entry_set_icon_sensitive ( 1160 entry, GTK_ENTRY_ICON_SECONDARY, TRUE); 1161 1162 gtk_widget_set_sensitive ( 1163 editor->priv->collapse_all_button, FALSE); 1164 gtk_widget_set_sensitive ( 1165 editor->priv->expand_all_button, FALSE); 1166 1167 } else { 1168 /* Install the tree store in the tree view if needed. */ 1169 if (editor->priv->active->filtered_view) { 1170 GtkTreeSelection *selection; 1171 GtkTreePath *path; 1172 1173 tree_model = editor->priv->active->tree_store; 1174 gtk_tree_view_set_model (tree_view, tree_model); 1175 1176 path = gtk_tree_path_new_first (); 1177 selection = gtk_tree_view_get_selection (tree_view); 1178 gtk_tree_selection_select_path (selection, path); 1179 gtk_tree_path_free (path); 1180 1181 editor->priv->active->filtered_view = FALSE; 1182 } 1183 1184 gtk_entry_set_icon_sensitive ( 1185 entry, GTK_ENTRY_ICON_SECONDARY, FALSE); 1186 1187 gtk_widget_set_sensitive ( 1188 editor->priv->collapse_all_button, TRUE); 1189 gtk_widget_set_sensitive ( 1190 editor->priv->expand_all_button, TRUE); 1191 } 1192 } 1193 1194 static gboolean 1195 subscription_editor_timeout_cb (EMSubscriptionEditor *editor) 1196 { 1197 subscription_editor_update_view (editor); 1198 editor->priv->timeout_id = 0; 1199 1200 return FALSE; 1201 } 1202 1203 static void 1204 subscription_editor_combo_box_changed_cb (GtkComboBox *combo_box, 1205 EMSubscriptionEditor *editor) 1206 { 1207 StoreData *data; 1208 gint index; 1209 1210 index = gtk_combo_box_get_active (combo_box); 1211 g_return_if_fail (index < editor->priv->stores->len); 1212 1213 data = g_ptr_array_index (editor->priv->stores, index); 1214 g_return_if_fail (data != NULL); 1215 1216 editor->priv->active = data; 1217 1218 subscription_editor_stop (editor); 1219 subscription_editor_update_view (editor); 1220 1221 g_object_notify (G_OBJECT (editor), "store"); 1222 1223 if (data->needs_refresh) { 1224 subscription_editor_refresh (editor); 1225 data->needs_refresh = FALSE; 1226 } 1227 } 1228 1229 static void 1230 subscription_editor_entry_changed_cb (GtkEntry *entry, 1231 EMSubscriptionEditor *editor) 1232 { 1233 const gchar *text; 1234 1235 if (editor->priv->timeout_id > 0) { 1236 g_source_remove (editor->priv->timeout_id); 1237 editor->priv->timeout_id = 0; 1238 } 1239 1240 text = gtk_entry_get_text (entry); 1241 1242 if (text != NULL && *text != '\0') 1243 editor->priv->timeout_id = g_timeout_add_seconds ( 1244 1, (GSourceFunc) subscription_editor_timeout_cb, editor); 1245 else 1246 subscription_editor_update_view (editor); 1247 } 1248 1249 static void 1250 subscription_editor_icon_release_cb (GtkEntry *entry, 1251 GtkEntryIconPosition icon_pos, 1252 GdkEvent *event, 1253 EMSubscriptionEditor *editor) 1254 { 1255 if (icon_pos == GTK_ENTRY_ICON_SECONDARY) 1256 gtk_entry_set_text (entry, ""); 1257 } 1258 1259 static void 1260 subscription_editor_renderer_toggled_cb (GtkCellRendererToggle *renderer, 1261 const gchar *path_string, 1262 EMSubscriptionEditor *editor) 1263 { 1264 GtkTreeSelection *selection; 1265 GtkTreeView *tree_view; 1266 GtkTreePath *path; 1267 1268 tree_view = editor->priv->active->tree_view; 1269 selection = gtk_tree_view_get_selection (tree_view); 1270 1271 path = gtk_tree_path_new_from_string (path_string); 1272 gtk_tree_selection_select_path (selection, path); 1273 gtk_tree_path_free (path); 1274 1275 if (gtk_cell_renderer_toggle_get_active (renderer)) 1276 subscription_editor_unsubscribe (editor); 1277 else 1278 subscription_editor_subscribe (editor); 1279 } 1280 1281 static void 1282 subscription_editor_render_toggle_cb (GtkCellLayout *cell_layout, 1283 GtkCellRenderer *renderer, 1284 GtkTreeModel *tree_model, 1285 GtkTreeIter *iter) 1286 { 1287 CamelFolderInfo *folder_info; 1288 1289 gtk_tree_model_get ( 1290 tree_model, iter, COL_FOLDER_INFO, &folder_info, -1); 1291 1292 g_object_set ( 1293 renderer, "active", FOLDER_SUBSCRIBED (folder_info), 1294 "visible", FOLDER_CAN_SELECT (folder_info), NULL); 1295 } 1296 1297 static void 1298 subscription_editor_selection_changed_cb (GtkTreeSelection *selection, 1299 EMSubscriptionEditor *editor) 1300 { 1301 GtkTreeModel *tree_model; 1302 GtkTreeIter iter; 1303 1304 if (gtk_tree_selection_get_selected (selection, &tree_model, &iter)) { 1305 CamelFolderInfo *folder_info; 1306 1307 gtk_tree_model_get ( 1308 tree_model, &iter, 1309 COL_FOLDER_INFO, &folder_info, -1); 1310 gtk_widget_set_sensitive ( 1311 editor->priv->subscribe_button, 1312 FOLDER_CAN_SELECT (folder_info) && 1313 !FOLDER_SUBSCRIBED (folder_info)); 1314 gtk_widget_set_sensitive ( 1315 editor->priv->unsubscribe_button, 1316 FOLDER_CAN_SELECT (folder_info) && 1317 FOLDER_SUBSCRIBED (folder_info)); 1318 } else { 1319 gtk_widget_set_sensitive ( 1320 editor->priv->subscribe_button, FALSE); 1321 gtk_widget_set_sensitive ( 1322 editor->priv->unsubscribe_button, FALSE); 1323 } 1324 1325 gtk_widget_set_sensitive (editor->priv->subscribe_arrow, TRUE); 1326 gtk_widget_set_sensitive (editor->priv->unsubscribe_arrow, TRUE); 1327 } 1328 1329 static void 1330 subscription_editor_add_store (EMSubscriptionEditor *editor, 1331 CamelStore *store) 1332 { 1333 StoreData *data; 1334 CamelService *service; 1335 GtkListStore *list_store; 1336 GtkTreeStore *tree_store; 1337 GtkTreeViewColumn *column; 1338 GtkTreeSelection *selection; 1339 GtkCellRenderer *renderer; 1340 GtkComboBoxText *combo_box; 1341 GtkWidget *container; 1342 GtkWidget *widget; 1343 const gchar *display_name; 1344 1345 service = CAMEL_SERVICE (store); 1346 display_name = camel_service_get_display_name (service); 1347 1348 combo_box = GTK_COMBO_BOX_TEXT (editor->priv->combo_box); 1349 gtk_combo_box_text_append_text (combo_box, display_name); 1350 1351 tree_store = gtk_tree_store_new ( 1352 N_COLUMNS, 1353 /* COL_CASEFOLDED */ G_TYPE_STRING, 1354 /* COL_FOLDER_ICON */ G_TYPE_STRING, 1355 /* COL_FOLDER_NAME */ G_TYPE_STRING, 1356 /* COL_FOLDER_INFO */ G_TYPE_POINTER); 1357 1358 list_store = gtk_list_store_new ( 1359 N_COLUMNS, 1360 /* COL_CASEFOLDED */ G_TYPE_STRING, 1361 /* COL_FOLDER_ICON */ G_TYPE_STRING, 1362 /* COL_FOLDER_NAME */ G_TYPE_STRING, 1363 /* COL_FOLDER_INFO */ G_TYPE_POINTER); 1364 1365 container = editor->priv->notebook; 1366 1367 widget = gtk_scrolled_window_new (NULL, NULL); 1368 gtk_scrolled_window_set_policy ( 1369 GTK_SCROLLED_WINDOW (widget), 1370 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); 1371 gtk_scrolled_window_set_shadow_type ( 1372 GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN); 1373 gtk_notebook_append_page (GTK_NOTEBOOK (container), widget, NULL); 1374 gtk_container_child_set ( 1375 GTK_CONTAINER (container), widget, 1376 "tab-fill", FALSE, "tab-expand", FALSE, NULL); 1377 gtk_widget_show (widget); 1378 1379 container = widget; 1380 1381 widget = gtk_tree_view_new_with_model (GTK_TREE_MODEL (tree_store)); 1382 gtk_tree_view_set_enable_search (GTK_TREE_VIEW (widget), TRUE); 1383 gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (widget), FALSE); 1384 gtk_tree_view_set_rules_hint (GTK_TREE_VIEW (widget), TRUE); 1385 gtk_tree_view_set_search_column ( 1386 GTK_TREE_VIEW (widget), COL_FOLDER_NAME); 1387 gtk_container_add (GTK_CONTAINER (container), widget); 1388 gtk_widget_show (widget); 1389 1390 column = gtk_tree_view_column_new (); 1391 gtk_tree_view_append_column (GTK_TREE_VIEW (widget), column); 1392 1393 renderer = gtk_cell_renderer_toggle_new (); 1394 g_object_set (renderer, "activatable", TRUE, NULL); 1395 gtk_tree_view_column_pack_start (column, renderer, FALSE); 1396 1397 gtk_cell_layout_set_cell_data_func ( 1398 GTK_CELL_LAYOUT (column), renderer, 1399 (GtkCellLayoutDataFunc) subscription_editor_render_toggle_cb, 1400 NULL, (GDestroyNotify) NULL); 1401 1402 g_signal_connect ( 1403 renderer, "toggled", 1404 G_CALLBACK (subscription_editor_renderer_toggled_cb), editor); 1405 1406 column = gtk_tree_view_column_new (); 1407 gtk_tree_view_append_column (GTK_TREE_VIEW (widget), column); 1408 gtk_tree_view_set_expander_column (GTK_TREE_VIEW (widget), column); 1409 1410 renderer = gtk_cell_renderer_pixbuf_new (); 1411 gtk_tree_view_column_pack_start (column, renderer, FALSE); 1412 gtk_tree_view_column_add_attribute ( 1413 column, renderer, "icon-name", COL_FOLDER_ICON); 1414 1415 renderer = gtk_cell_renderer_text_new (); 1416 gtk_tree_view_column_pack_start (column, renderer, TRUE); 1417 gtk_tree_view_column_add_attribute ( 1418 column, renderer, "text", COL_FOLDER_NAME); 1419 1420 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)); 1421 1422 g_signal_connect ( 1423 selection, "changed", 1424 G_CALLBACK (subscription_editor_selection_changed_cb), editor); 1425 1426 data = g_slice_new0 (StoreData); 1427 data->store = g_object_ref (store); 1428 data->tree_view = g_object_ref (widget); 1429 data->list_store = GTK_TREE_MODEL (list_store); 1430 data->tree_store = GTK_TREE_MODEL (tree_store); 1431 data->needs_refresh = TRUE; 1432 1433 g_ptr_array_add (editor->priv->stores, data); 1434 } 1435 1436 static void 1437 subscription_editor_set_store (EMSubscriptionEditor *editor, 1438 CamelStore *store) 1439 { 1440 g_return_if_fail (editor->priv->initial_store == NULL); 1441 1442 if (CAMEL_IS_SUBSCRIBABLE (store)) 1443 editor->priv->initial_store = g_object_ref (store); 1444 } 1445 1446 static void 1447 subscription_editor_set_session (EMSubscriptionEditor *editor, 1448 EMailSession *session) 1449 { 1450 g_return_if_fail (E_IS_MAIL_SESSION (session)); 1451 g_return_if_fail (editor->priv->session == NULL); 1452 1453 editor->priv->session = g_object_ref (session); 1454 } 1455 1456 static void 1457 subscription_editor_set_property (GObject *object, 1458 guint property_id, 1459 const GValue *value, 1460 GParamSpec *pspec) 1461 { 1462 switch (property_id) { 1463 case PROP_SESSION: 1464 subscription_editor_set_session ( 1465 EM_SUBSCRIPTION_EDITOR (object), 1466 g_value_get_object (value)); 1467 return; 1468 1469 case PROP_STORE: 1470 subscription_editor_set_store ( 1471 EM_SUBSCRIPTION_EDITOR (object), 1472 g_value_get_object (value)); 1473 return; 1474 } 1475 1476 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); 1477 } 1478 1479 static void 1480 subscription_editor_get_property (GObject *object, 1481 guint property_id, 1482 GValue *value, 1483 GParamSpec *pspec) 1484 { 1485 switch (property_id) { 1486 case PROP_SESSION: 1487 g_value_set_object ( 1488 value, 1489 em_subscription_editor_get_session ( 1490 EM_SUBSCRIPTION_EDITOR (object))); 1491 return; 1492 1493 case PROP_STORE: 1494 g_value_set_object ( 1495 value, 1496 em_subscription_editor_get_store ( 1497 EM_SUBSCRIPTION_EDITOR (object))); 1498 return; 1499 } 1500 1501 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); 1502 } 1503 1504 static void 1505 subscription_editor_dispose (GObject *object) 1506 { 1507 EMSubscriptionEditorPrivate *priv; 1508 1509 priv = EM_SUBSCRIPTION_EDITOR_GET_PRIVATE (object); 1510 1511 if (priv->session != NULL) { 1512 g_object_unref (priv->session); 1513 priv->session = NULL; 1514 } 1515 1516 if (priv->initial_store != NULL) { 1517 g_object_unref (priv->initial_store); 1518 priv->initial_store = NULL; 1519 } 1520 1521 if (priv->timeout_id > 0) { 1522 g_source_remove (priv->timeout_id); 1523 priv->timeout_id = 0; 1524 } 1525 1526 g_ptr_array_set_size (priv->stores, 0); 1527 1528 /* Chain up to parent's dispose() method. */ 1529 G_OBJECT_CLASS (em_subscription_editor_parent_class)->dispose (object); 1530 } 1531 1532 static void 1533 subscription_editor_finalize (GObject *object) 1534 { 1535 EMSubscriptionEditorPrivate *priv; 1536 1537 priv = EM_SUBSCRIPTION_EDITOR_GET_PRIVATE (object); 1538 1539 g_ptr_array_free (priv->stores, TRUE); 1540 1541 g_free (priv->search_string); 1542 1543 /* Chain up to parent's finalize() method. */ 1544 G_OBJECT_CLASS (em_subscription_editor_parent_class)->finalize (object); 1545 } 1546 1547 static void 1548 subscription_editor_constructed (GObject *object) 1549 { 1550 EMSubscriptionEditor *editor; 1551 1552 editor = EM_SUBSCRIPTION_EDITOR (object); 1553 1554 /* Pick an initial store based on the default mail account, if 1555 * one wasn't already given in em_subscription_editor_new(). */ 1556 if (editor->priv->initial_store == NULL) { 1557 ESource *source; 1558 ESourceRegistry *registry; 1559 CamelService *service; 1560 EMailSession *session; 1561 1562 session = em_subscription_editor_get_session (editor); 1563 registry = e_mail_session_get_registry (session); 1564 1565 source = e_source_registry_ref_default_mail_account (registry); 1566 1567 service = camel_session_ref_service ( 1568 CAMEL_SESSION (session), 1569 e_source_get_uid (source)); 1570 1571 if (CAMEL_IS_SUBSCRIBABLE (service)) 1572 editor->priv->initial_store = g_object_ref (service); 1573 1574 if (service != NULL) 1575 g_object_unref (service); 1576 1577 g_object_unref (source); 1578 } 1579 1580 /* Chain up to parent's constructed() method. */ 1581 G_OBJECT_CLASS (em_subscription_editor_parent_class)->constructed (object); 1582 } 1583 1584 static void 1585 subscription_editor_realize (GtkWidget *widget) 1586 { 1587 EMSubscriptionEditor *editor; 1588 EMFolderTreeModel *model; 1589 GtkComboBox *combo_box; 1590 GList *list, *link; 1591 gint initial_index = 0; 1592 1593 editor = EM_SUBSCRIPTION_EDITOR (widget); 1594 1595 /* Chain up to parent's realize() method. */ 1596 GTK_WIDGET_CLASS (em_subscription_editor_parent_class)->realize (widget); 1597 1598 /* Find stores to display, and watch for the initial store. */ 1599 1600 model = em_folder_tree_model_get_default (); 1601 list = em_folder_tree_model_list_stores (model); 1602 1603 for (link = list; link != NULL; link = g_list_next (link)) { 1604 CamelStore *store = CAMEL_STORE (link->data); 1605 1606 if (!CAMEL_IS_SUBSCRIBABLE (store)) 1607 continue; 1608 1609 if (store == editor->priv->initial_store) 1610 initial_index = editor->priv->stores->len; 1611 1612 subscription_editor_add_store (editor, store); 1613 } 1614 1615 g_list_free (list); 1616 1617 /* The subscription editor should only be accessible if 1618 * at least one enabled store supports subscriptions. */ 1619 g_return_if_fail (editor->priv->stores->len > 0); 1620 1621 combo_box = GTK_COMBO_BOX (editor->priv->combo_box); 1622 gtk_combo_box_set_active (combo_box, initial_index); 1623 } 1624 1625 static void 1626 em_subscription_editor_class_init (EMSubscriptionEditorClass *class) 1627 { 1628 GObjectClass *object_class; 1629 GtkWidgetClass *widget_class; 1630 1631 g_type_class_add_private (class, sizeof (EMSubscriptionEditorPrivate)); 1632 1633 object_class = G_OBJECT_CLASS (class); 1634 object_class->set_property = subscription_editor_set_property; 1635 object_class->get_property = subscription_editor_get_property; 1636 object_class->dispose = subscription_editor_dispose; 1637 object_class->finalize = subscription_editor_finalize; 1638 object_class->constructed = subscription_editor_constructed; 1639 1640 widget_class = GTK_WIDGET_CLASS (class); 1641 widget_class->realize = subscription_editor_realize; 1642 1643 g_object_class_install_property ( 1644 object_class, 1645 PROP_SESSION, 1646 g_param_spec_object ( 1647 "session", 1648 NULL, 1649 NULL, 1650 E_TYPE_MAIL_SESSION, 1651 G_PARAM_READWRITE | 1652 G_PARAM_CONSTRUCT_ONLY | 1653 G_PARAM_STATIC_STRINGS)); 1654 1655 g_object_class_install_property ( 1656 object_class, 1657 PROP_STORE, 1658 g_param_spec_object ( 1659 "store", 1660 NULL, 1661 NULL, 1662 CAMEL_TYPE_STORE, 1663 G_PARAM_READWRITE | 1664 G_PARAM_CONSTRUCT_ONLY | 1665 G_PARAM_STATIC_STRINGS)); 1666 } 1667 1668 static void 1669 em_subscription_editor_init (EMSubscriptionEditor *editor) 1670 { 1671 GtkWidget *container; 1672 GtkWidget *widget; 1673 GtkWidget *box; 1674 const gchar *tooltip; 1675 1676 editor->priv = EM_SUBSCRIPTION_EDITOR_GET_PRIVATE (editor); 1677 1678 editor->priv->stores = g_ptr_array_new_with_free_func ( 1679 (GDestroyNotify) store_data_free); 1680 1681 gtk_container_set_border_width (GTK_CONTAINER (editor), 5); 1682 gtk_window_set_title (GTK_WINDOW (editor), _("Folder Subscriptions")); 1683 gtk_window_set_default_size (GTK_WINDOW (editor), 600, 400); 1684 1685 e_restore_window ( 1686 GTK_WINDOW (editor), 1687 "/org/gnome/evolution/mail/subscription-window/", 1688 E_RESTORE_WINDOW_SIZE); 1689 1690 gtk_dialog_add_button ( 1691 GTK_DIALOG (editor), 1692 GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE); 1693 1694 container = gtk_dialog_get_content_area (GTK_DIALOG (editor)); 1695 1696 widget = gtk_vbox_new (FALSE, 12); 1697 gtk_container_set_border_width (GTK_CONTAINER (widget), 5); 1698 gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); 1699 gtk_widget_show (widget); 1700 1701 container = box = widget; 1702 1703 widget = gtk_table_new (2, 3, FALSE); 1704 gtk_table_set_col_spacings (GTK_TABLE (widget), 6); 1705 gtk_table_set_row_spacings (GTK_TABLE (widget), 6); 1706 gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); 1707 gtk_widget_show (widget); 1708 1709 container = widget; 1710 1711 widget = gtk_combo_box_text_new (); 1712 gtk_table_attach ( 1713 GTK_TABLE (container), widget, 1714 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); 1715 editor->priv->combo_box = widget; 1716 gtk_widget_show (widget); 1717 1718 g_signal_connect ( 1719 widget, "changed", 1720 G_CALLBACK (subscription_editor_combo_box_changed_cb), editor); 1721 1722 widget = gtk_label_new_with_mnemonic (_("_Account:")); 1723 gtk_label_set_mnemonic_widget ( 1724 GTK_LABEL (widget), editor->priv->combo_box); 1725 gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5); 1726 gtk_table_attach ( 1727 GTK_TABLE (container), widget, 1728 0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0); 1729 gtk_widget_show (widget); 1730 1731 widget = gtk_entry_new (); 1732 gtk_entry_set_icon_from_stock ( 1733 GTK_ENTRY (widget), 1734 GTK_ENTRY_ICON_SECONDARY, GTK_STOCK_CLEAR); 1735 gtk_entry_set_icon_tooltip_text ( 1736 GTK_ENTRY (widget), 1737 GTK_ENTRY_ICON_SECONDARY, _("Clear Search")); 1738 gtk_entry_set_icon_sensitive ( 1739 GTK_ENTRY (widget), 1740 GTK_ENTRY_ICON_SECONDARY, FALSE); 1741 gtk_table_attach ( 1742 GTK_TABLE (container), widget, 1743 1, 2, 1, 2, GTK_EXPAND | GTK_FILL, GTK_FILL, 0, 0); 1744 editor->priv->entry = widget; 1745 gtk_widget_show (widget); 1746 1747 g_signal_connect ( 1748 widget, "changed", 1749 G_CALLBACK (subscription_editor_entry_changed_cb), editor); 1750 1751 g_signal_connect ( 1752 widget, "icon-release", 1753 G_CALLBACK (subscription_editor_icon_release_cb), editor); 1754 1755 widget = gtk_label_new_with_mnemonic (_("Sho_w items that contain:")); 1756 gtk_label_set_mnemonic_widget ( 1757 GTK_LABEL (widget), editor->priv->entry); 1758 gtk_misc_set_alignment (GTK_MISC (widget), 1.0, 0.5); 1759 gtk_table_attach ( 1760 GTK_TABLE (container), widget, 1761 0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0); 1762 gtk_widget_show (widget); 1763 1764 container = box; 1765 1766 widget = gtk_hbox_new (FALSE, 6); 1767 gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); 1768 gtk_widget_show (widget); 1769 1770 container = widget; 1771 1772 widget = gtk_notebook_new (); 1773 gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE); 1774 gtk_notebook_set_show_border (GTK_NOTEBOOK (widget), FALSE); 1775 gtk_container_add (GTK_CONTAINER (container), widget); 1776 editor->priv->notebook = widget; 1777 gtk_widget_show (widget); 1778 1779 g_object_bind_property ( 1780 editor->priv->combo_box, "active", 1781 editor->priv->notebook, "page", 1782 G_BINDING_BIDIRECTIONAL | 1783 G_BINDING_SYNC_CREATE); 1784 1785 widget = gtk_button_box_new (GTK_ORIENTATION_VERTICAL); 1786 gtk_box_set_spacing (GTK_BOX (widget), 6); 1787 gtk_button_box_set_layout ( 1788 GTK_BUTTON_BOX (widget), GTK_BUTTONBOX_START); 1789 gtk_box_pack_start (GTK_BOX (container), widget, FALSE, TRUE, 0); 1790 gtk_widget_show (widget); 1791 1792 container = box = widget; 1793 1794 widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2); 1795 gtk_box_pack_start (GTK_BOX (container), widget, FALSE, TRUE, 0); 1796 gtk_widget_show (widget); 1797 1798 container = widget; 1799 1800 tooltip = _("Subscribe to the selected folder"); 1801 widget = gtk_button_new_with_mnemonic (_("Su_bscribe")); 1802 gtk_widget_set_sensitive (widget, FALSE); 1803 gtk_widget_set_tooltip_text (widget, tooltip); 1804 editor->priv->subscribe_button = widget; 1805 gtk_widget_show (widget); 1806 1807 g_signal_connect_swapped ( 1808 widget, "clicked", 1809 G_CALLBACK (subscription_editor_subscribe), editor); 1810 1811 widget = gtk_button_new (); 1812 gtk_button_set_image ( 1813 GTK_BUTTON (widget), 1814 gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE)); 1815 editor->priv->subscribe_arrow = widget; 1816 gtk_widget_show (widget); 1817 1818 g_signal_connect_swapped ( 1819 widget, "clicked", 1820 G_CALLBACK (subscription_editor_subscribe_popup_cb), editor); 1821 1822 if (gtk_widget_get_direction (container) == GTK_TEXT_DIR_LTR) { 1823 gtk_box_pack_start ( 1824 GTK_BOX (container), 1825 editor->priv->subscribe_button, TRUE, TRUE, 0); 1826 gtk_box_pack_start ( 1827 GTK_BOX (container), 1828 editor->priv->subscribe_arrow, FALSE, FALSE, 0); 1829 } else { 1830 gtk_box_pack_start ( 1831 GTK_BOX (container), 1832 editor->priv->subscribe_arrow, FALSE, FALSE, 0); 1833 gtk_box_pack_start ( 1834 GTK_BOX (container), 1835 editor->priv->subscribe_button, TRUE, TRUE, 0); 1836 } 1837 1838 container = box; 1839 1840 widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2); 1841 gtk_box_pack_start (GTK_BOX (container), widget, FALSE, TRUE, 0); 1842 gtk_widget_show (widget); 1843 1844 container = widget; 1845 1846 tooltip = _("Unsubscribe from the selected folder"); 1847 widget = gtk_button_new_with_mnemonic (_("_Unsubscribe")); 1848 gtk_widget_set_sensitive (widget, FALSE); 1849 gtk_widget_set_tooltip_text (widget, tooltip); 1850 editor->priv->unsubscribe_button = widget; 1851 gtk_widget_show (widget); 1852 1853 g_signal_connect_swapped ( 1854 widget, "clicked", 1855 G_CALLBACK (subscription_editor_unsubscribe), editor); 1856 1857 widget = gtk_button_new (); 1858 gtk_button_set_image ( 1859 GTK_BUTTON (widget), 1860 gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_NONE)); 1861 editor->priv->unsubscribe_arrow = widget; 1862 gtk_widget_show (widget); 1863 1864 g_signal_connect_swapped ( 1865 widget, "clicked", 1866 G_CALLBACK (subscription_editor_unsubscribe_popup_cb), editor); 1867 1868 if (gtk_widget_get_direction (container) == GTK_TEXT_DIR_LTR) { 1869 gtk_box_pack_start ( 1870 GTK_BOX (container), 1871 editor->priv->unsubscribe_button, TRUE, TRUE, 0); 1872 gtk_box_pack_start ( 1873 GTK_BOX (container), 1874 editor->priv->unsubscribe_arrow, FALSE, FALSE, 0); 1875 } else { 1876 gtk_box_pack_start ( 1877 GTK_BOX (container), 1878 editor->priv->unsubscribe_arrow, FALSE, FALSE, 0); 1879 gtk_box_pack_start ( 1880 GTK_BOX (container), 1881 editor->priv->unsubscribe_button, TRUE, TRUE, 0); 1882 } 1883 1884 container = box; 1885 1886 tooltip = _("Collapse all folders"); 1887 widget = gtk_button_new_with_mnemonic (_("C_ollapse All")); 1888 gtk_widget_set_tooltip_text (widget, tooltip); 1889 gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); 1890 editor->priv->collapse_all_button = widget; 1891 gtk_widget_show (widget); 1892 1893 g_signal_connect_swapped ( 1894 widget, "clicked", 1895 G_CALLBACK (subscription_editor_collapse_all), editor); 1896 1897 tooltip = _("Expand all folders"); 1898 widget = gtk_button_new_with_mnemonic (_("E_xpand All")); 1899 gtk_widget_set_tooltip_text (widget, tooltip); 1900 gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); 1901 editor->priv->expand_all_button = widget; 1902 gtk_widget_show (widget); 1903 1904 g_signal_connect_swapped ( 1905 widget, "clicked", 1906 G_CALLBACK (subscription_editor_expand_all), editor); 1907 1908 tooltip = _("Refresh the folder list"); 1909 widget = gtk_button_new_from_stock (GTK_STOCK_REFRESH); 1910 gtk_widget_set_tooltip_text (widget, tooltip); 1911 gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); 1912 gtk_widget_set_sensitive (widget, FALSE); 1913 editor->priv->refresh_button = widget; 1914 gtk_widget_show (widget); 1915 1916 g_signal_connect_swapped ( 1917 widget, "clicked", 1918 G_CALLBACK (subscription_editor_refresh), editor); 1919 1920 tooltip = _("Stop the current operation"); 1921 widget = gtk_button_new_from_stock (GTK_STOCK_STOP); 1922 gtk_widget_set_tooltip_text (widget, tooltip); 1923 gtk_box_pack_start (GTK_BOX (container), widget, FALSE, FALSE, 0); 1924 gtk_widget_set_sensitive (widget, FALSE); 1925 editor->priv->stop_button = widget; 1926 gtk_widget_show (widget); 1927 1928 g_signal_connect_swapped ( 1929 widget, "clicked", 1930 G_CALLBACK (subscription_editor_stop), editor); 1931 } 1932 1933 GtkWidget * 1934 em_subscription_editor_new (GtkWindow *parent, 1935 EMailSession *session, 1936 CamelStore *initial_store) 1937 { 1938 g_return_val_if_fail (GTK_IS_WINDOW (parent), NULL); 1939 g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL); 1940 1941 return g_object_new ( 1942 EM_TYPE_SUBSCRIPTION_EDITOR, 1943 "session", session, 1944 "store", initial_store, 1945 "transient-for", parent, 1946 NULL); 1947 } 1948 1949 EMailSession * 1950 em_subscription_editor_get_session (EMSubscriptionEditor *editor) 1951 { 1952 g_return_val_if_fail (EM_IS_SUBSCRIPTION_EDITOR (editor), NULL); 1953 1954 return editor->priv->session; 1955 } 1956 1957 CamelStore * 1958 em_subscription_editor_get_store (EMSubscriptionEditor *editor) 1959 { 1960 g_return_val_if_fail (EM_IS_SUBSCRIPTION_EDITOR (editor), NULL); 1961 1962 if (editor->priv->active == NULL) 1963 return NULL; 1964 1965 return editor->priv->active->store; 1966 }