1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
2 * em-subscribe-editor.c *
4 * Authors: Michael Zucchi <notzed@ximian.com>
6 * Copyright 2003 Ximian, Inc. (www.ximian.com)
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of version 2 of the GNU General Public
10 * License as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public
18 * License along with this program; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
32 #include "mail-tools.h"
35 /*#include "mail-folder-cache.h"*/
36 #include "camel/camel-exception.h"
37 #include "camel/camel-store.h"
38 #include "camel/camel-session.h"
39 #include "e-util/e-account-list.h"
41 #include "em-subscribe-editor.h"
43 #include "mail-config.h"
45 #include <glade/glade.h>
46 #include <libgnome/gnome-i18n.h>
48 #include <gtk/gtkdialog.h>
49 #include <gtk/gtkscrolledwindow.h>
50 #include <gtk/gtkbox.h>
51 #include <gtk/gtklabel.h>
52 #include <gtk/gtktreeview.h>
53 #include <gtk/gtktreestore.h>
54 #include <gtk/gtktreeselection.h>
55 #include <gtk/gtkcellrenderertoggle.h>
56 #include <gtk/gtkcellrenderertext.h>
57 #include <gtk/gtkoptionmenu.h>
58 #include <gtk/gtkprogressbar.h>
59 #include <gtk/gtkmenuitem.h>
63 typedef struct _EMSubscribeEditor EMSubscribeEditor
;
64 struct _EMSubscribeEditor
{
70 struct _EMSubscribe
*current
; /* the current one, if any */
73 GtkWidget
*vbox
; /* where new stores are added */
74 GtkWidget
*optionmenu
;
75 GtkWidget
*none_selected
; /* 'please select a xxx' message */
76 GtkWidget
*none_selected_item
;
77 GtkWidget
*subscribe_button
;
78 GtkWidget
*unsubscribe_button
;
82 typedef struct _EMSubscribe EMSubscribe
;
84 struct _EMSubscribe
*next
;
85 struct _EMSubscribe
*prev
;
89 int seq
; /* upped every time we refresh */
91 struct _EMSubscribeEditor
*editor
; /* parent object*/
94 int store_id
; /* looking up a store */
99 GtkWidget
*widget
; /* widget to show for this store */
100 GtkTreeView
*tree
; /* tree, if we have it */
102 /* list of all returns from get_folder_info, accessed by other structures */
105 /* pending LISTs, EMSubscribeNode's */
109 /* queue of pending UN/SUBSCRIBEs, EMsg's */
113 /* working variables at runtime */
115 int selected_subscribed_count
;
116 gboolean subscribed_state
:1; /* for setting the selection*/
119 typedef struct _EMSubscribeNode EMSubscribeNode
;
120 struct _EMSubscribeNode
{
121 struct _EMSubscribeNode
*next
;
122 struct _EMSubscribeNode
*prev
;
124 CamelFolderInfo
*info
;
128 static void sub_editor_busy(EMSubscribeEditor
*se
, int dir
);
129 static int sub_queue_fill_level(EMSubscribe
*sub
, EMSubscribeNode
*node
);
130 static void sub_selection_changed(GtkTreeSelection
*selection
, EMSubscribe
*sub
);
133 sub_node_free(char *key
, EMSubscribeNode
*node
, EMSubscribe
*sub
)
135 d(printf("sub node free '%s'\n", node
->info
?node
->info
->full_name
:"<unknown>"));
137 gtk_tree_path_free(node
->path
);
142 sub_ref(EMSubscribe
*sub
)
148 sub_unref(EMSubscribe
*sub
)
153 if (sub
->ref_count
== 0) {
154 d(printf("subscribe object finalised\n"));
155 /* we dont have to delete the "subscribe" task list, as it must be empty,
156 otherwise we wouldn't be unreffed (intentional circular reference) */
158 g_hash_table_foreach(sub
->folders
, (GHFunc
)sub_node_free
, sub
);
159 g_hash_table_destroy(sub
->folders
);
165 camel_store_free_folder_info(sub
->store
, (CamelFolderInfo
*)l
->data
);
170 camel_object_unref(sub
->store
);
171 g_free(sub
->store_uri
);
176 /* ** Subscribe folder operation **************************************** */
178 struct _zsubscribe_msg
{
179 struct _mail_msg msg
;
182 EMSubscribeNode
*node
;
188 sub_folder_subscribe (struct _mail_msg
*mm
)
190 struct _zsubscribe_msg
*m
= (struct _zsubscribe_msg
*) mm
;
193 camel_store_subscribe_folder (m
->sub
->store
, m
->node
->info
->full_name
, &mm
->ex
);
195 camel_store_unsubscribe_folder (m
->sub
->store
, m
->node
->info
->full_name
, &mm
->ex
);
199 sub_folder_subscribed (struct _mail_msg
*mm
)
201 struct _zsubscribe_msg
*m
= (struct _zsubscribe_msg
*)mm
, *next
;
204 EMSubscribeNode
*node
;
205 gboolean subscribed
, issub
;
207 m
->sub
->subscribe_id
= -1;
211 if (!camel_exception_is_set(&mm
->ex
)) {
213 m
->node
->info
->flags
|= CAMEL_FOLDER_SUBSCRIBED
;
215 m
->node
->info
->flags
&= ~CAMEL_FOLDER_SUBSCRIBED
;
218 /* make sure the tree view matches the correct state */
219 model
= gtk_tree_view_get_model(m
->sub
->tree
);
220 if (gtk_tree_model_get_iter_from_string(model
, &iter
, m
->path
)) {
221 issub
= (m
->node
->info
->flags
& CAMEL_FOLDER_SUBSCRIBED
) != 0;
222 gtk_tree_model_get(model
, &iter
, 0, &subscribed
, 2, &node
, -1);
224 gtk_tree_store_set((GtkTreeStore
*)model
, &iter
, 0, issub
, -1);
226 d(printf("node mismatch, or subscribe state changed failed\n"));
229 /* queue any further ones, or if out, update the ui */
230 next
= (struct _zsubscribe_msg
*)e_dlist_remhead(&m
->sub
->subscribe
);
232 next
->sub
->subscribe_id
= next
->msg
.seq
;
233 e_thread_put(mail_thread_new
, (EMsg
*)next
);
235 /* should it go off the model instead? */
236 sub_selection_changed(gtk_tree_view_get_selection(m
->sub
->tree
), m
->sub
);
241 sub_folder_free (struct _mail_msg
*mm
)
243 struct _zsubscribe_msg
*m
= (struct _zsubscribe_msg
*) mm
;
249 static struct _mail_msg_op sub_subscribe_folder_op
= {
250 NULL
, /*subscribe_folder_desc,*/
251 sub_folder_subscribe
,
252 sub_folder_subscribed
,
256 /* spath is tree path in string form */
258 sub_subscribe_folder (EMSubscribe
*sub
, EMSubscribeNode
*node
, int state
, const char *spath
)
260 struct _zsubscribe_msg
*m
;
263 m
= mail_msg_new (&sub_subscribe_folder_op
, NULL
, sizeof(*m
));
267 m
->subscribe
= state
;
268 m
->path
= g_strdup(spath
);
271 if (sub
->subscribe_id
== -1) {
272 sub
->subscribe_id
= id
;
273 d(printf("running subscribe folder '%s'\n", spath
));
274 e_thread_put (mail_thread_new
, (EMsg
*)m
);
276 d(printf("queueing subscribe folder '%s'\n", spath
));
277 e_dlist_addtail(&sub
->subscribe
, (EDListNode
*)m
);
283 /* ********************************************************************** */
285 sub_fill_level(EMSubscribe
*sub
, CamelFolderInfo
*info
, GtkTreeIter
*parent
, int pending
)
288 GtkTreeStore
*treestore
;
290 EMSubscribeNode
*node
;
292 treestore
= (GtkTreeStore
*)gtk_tree_view_get_model(sub
->tree
);
294 /* first, fill a level up */
297 if ((node
= g_hash_table_lookup(sub
->folders
, fi
->full_name
)) == NULL
) {
300 gtk_tree_store_append(treestore
, &iter
, parent
);
301 node
= g_malloc0(sizeof(*node
));
303 state
= (fi
->flags
& CAMEL_FOLDER_SUBSCRIBED
) != 0;
304 gtk_tree_store_set(treestore
, &iter
, 0, state
, 1, fi
->name
, 2, node
, -1);
305 if ((fi
->flags
& CAMEL_FOLDER_NOINFERIORS
) == 0)
306 node
->path
= gtk_tree_model_get_path((GtkTreeModel
*)treestore
, &iter
);
307 g_hash_table_insert(sub
->folders
, fi
->full_name
, node
);
308 } else if (node
->path
) {
309 gtk_tree_model_get_iter(gtk_tree_view_get_model(sub
->tree
), &iter
, node
->path
);
312 if ((fi
->flags
& CAMEL_FOLDER_NOINFERIORS
) == 0
314 /* save time, if we have any children alread, dont re-scan */
316 d(printf("scanning child '%s'\n", fi
->child
->full_name
));
317 sub_fill_level(sub
, fi
->child
, &iter
, FALSE
);
320 e_dlist_addtail(&sub
->pending
, (EDListNode
*)node
);
327 /* async query of folderinfo */
329 struct _emse_folderinfo_msg
{
330 struct _mail_msg msg
;
335 EMSubscribeNode
*node
;
336 CamelFolderInfo
*info
;
340 sub_folderinfo_get (struct _mail_msg
*mm
)
342 struct _emse_folderinfo_msg
*m
= (struct _emse_folderinfo_msg
*) mm
;
344 if (m
->seq
== m
->sub
->seq
) {
345 camel_operation_register(mm
->cancel
);
346 m
->info
= camel_store_get_folder_info(m
->sub
->store
, m
->node
?m
->node
->info
->full_name
:"", CAMEL_STORE_FOLDER_INFO_FAST
| CAMEL_STORE_FOLDER_INFO_NO_VIRTUAL
, &mm
->ex
);
347 camel_operation_unregister(mm
->cancel
);
352 sub_folderinfo_got(struct _mail_msg
*mm
)
354 struct _emse_folderinfo_msg
*m
= (struct _emse_folderinfo_msg
*) mm
;
355 EMSubscribeNode
*node
;
357 m
->sub
->pending_id
= -1;
358 if (m
->sub
->cancel
|| m
->seq
!= m
->sub
->seq
)
361 if (camel_exception_is_set (&mm
->ex
)) {
362 g_warning ("Error getting folder info from store: %s",
363 camel_exception_get_description (&mm
->ex
));
370 gtk_tree_model_get_iter(gtk_tree_view_get_model(m
->sub
->tree
), &iter
, m
->node
->path
);
371 sub_fill_level(m
->sub
, m
->info
, &iter
, FALSE
);
373 sub_fill_level(m
->sub
, m
->info
, NULL
, TRUE
);
377 /* check for more to do */
378 node
= (EMSubscribeNode
*)e_dlist_remhead(&m
->sub
->pending
);
380 sub_queue_fill_level(m
->sub
, node
);
384 sub_folderinfo_free(struct _mail_msg
*mm
)
386 struct _emse_folderinfo_msg
*m
= (struct _emse_folderinfo_msg
*) mm
;
389 m
->sub
->info_list
= g_slist_prepend(m
->sub
->info_list
, m
->info
);
392 sub_editor_busy(m
->sub
->editor
, -1);
397 static struct _mail_msg_op sub_folderinfo_op
= {
398 NULL
, /*sub_folderinfo_desc, we do our own progress reporting/cancellation */
405 sub_queue_fill_level(EMSubscribe
*sub
, EMSubscribeNode
*node
)
407 struct _emse_folderinfo_msg
*m
;
410 d(printf("Starting get folderinfo of '%s'\n", node
?node
->info
->full_name
:"<root>"));
412 m
= mail_msg_new (&sub_folderinfo_op
, NULL
, sizeof(*m
));
418 sub
->pending_id
= m
->msg
.seq
;
420 sub_editor_busy(sub
->editor
, 1);
424 e_thread_put (mail_thread_new
, (EMsg
*)m
);
428 /* ********************************************************************** */
430 /* (un) subscribes the current selection */
431 static void sub_do_subscribe(GtkTreeModel
*model
, GtkTreePath
*path
, GtkTreeIter
*iter
, void *data
)
433 EMSubscribe
*sub
= data
;
434 EMSubscribeNode
*node
;
437 gtk_tree_model_get(model
, iter
, 0, &subscribed
, 2, &node
, -1);
438 if (sub
->subscribed_state
^ subscribed
) {
441 spath
= gtk_tree_path_to_string(path
);
442 gtk_tree_store_set((GtkTreeStore
*)model
, iter
, 0, subscribed
, -1);
443 sub_subscribe_folder(sub
, node
, sub
->subscribed_state
, spath
);
449 sub_subscribe(EMSubscribe
*sub
, gboolean subscribed
)
451 GtkTreeSelection
*selection
;
453 if (sub
->tree
== NULL
)
456 sub
->subscribed_state
= subscribed
;
457 selection
= gtk_tree_view_get_selection (sub
->tree
);
458 gtk_tree_selection_selected_foreach(selection
, sub_do_subscribe
, sub
);
462 sub_subscribe_toggled(GtkCellRendererToggle
*render
, const char *spath
, EMSubscribe
*sub
)
465 GtkTreeModel
*model
= gtk_tree_view_get_model(sub
->tree
);
466 EMSubscribeNode
*node
;
469 d(printf("subscribe toggled?\n"));
471 if (gtk_tree_model_get_iter_from_string(model
, &iter
, spath
)) {
472 gtk_tree_model_get(model
, &iter
, 0, &subscribed
, 2, &node
, -1);
473 subscribed
= !subscribed
;
474 d(printf("new state is %s\n", subscribed
?"subscribed":"not subscribed"));
475 gtk_tree_store_set((GtkTreeStore
*)model
, &iter
, 0, subscribed
, -1);
476 sub_subscribe_folder(sub
, node
, subscribed
, spath
);
480 static void sub_do_changed(GtkTreeModel
*model
, GtkTreePath
*path
, GtkTreeIter
*iter
, void *data
)
482 EMSubscribe
*sub
= data
;
483 EMSubscribeNode
*node
;
486 gtk_tree_model_get(model
, iter
, 0, &subscribed
, 2, &node
, -1);
489 sub
->selected_subscribed_count
++;
490 sub
->selected_count
++;
494 sub_selection_changed(GtkTreeSelection
*selection
, EMSubscribe
*sub
)
496 int dosub
= TRUE
, dounsub
= TRUE
;
498 sub
->selected_count
= 0;
499 sub
->selected_subscribed_count
= 0;
500 gtk_tree_selection_selected_foreach(selection
, sub_do_changed
, sub
);
502 if (sub
->selected_count
== 0) {
505 } else if (sub
->selected_subscribed_count
== sub
->selected_count
)
507 else if (sub
->selected_subscribed_count
== 0)
510 gtk_widget_set_sensitive(sub
->editor
->subscribe_button
, dosub
);
511 gtk_widget_set_sensitive(sub
->editor
->unsubscribe_button
, dounsub
);
514 /* double-clicking causes a node item to be evaluated directly */
515 static void sub_row_activated(GtkTreeView
*tree
, GtkTreePath
*path
, GtkTreeViewColumn
*col
, EMSubscribe
*sub
) {
516 EMSubscribeNode
*node
;
518 GtkTreeModel
*model
= gtk_tree_view_get_model(tree
);
520 if (gtk_tree_model_get_iter(model
, &iter
, path
) != TRUE
) return;
522 gtk_tree_model_get(model
, &iter
, 2, &node
, -1);
524 /* check whether the item is already processed */
525 if (node
->path
== NULL
)
528 /* remove it from wherever in the list it is, and place it in front instead */
529 e_dlist_remove((EDListNode
*)node
);
530 e_dlist_addhead(&sub
->pending
, (EDListNode
*)node
);
532 if (sub
->pending_id
== -1
533 && (node
= (EMSubscribeNode
*)e_dlist_remtail(&sub
->pending
)))
534 sub_queue_fill_level(sub
, node
);
538 sub_row_expanded(GtkTreeView
*tree
, GtkTreeIter
*iter
, GtkTreePath
*path
, EMSubscribe
*sub
)
540 EMSubscribeNode
*node
;
542 GtkTreeModel
*model
= (GtkTreeModel
*)gtk_tree_view_get_model(tree
);
545 gtk_tree_model_get(model
, iter
, 2, &node
, -1);
546 if (node
->path
== NULL
) {
547 d(printf("path '%s' already processed\n", node
->info
->full_name
));
550 gtk_tree_path_free(node
->path
);
555 /* add all children nodes to pending, and fire off a pending */
556 /* we add them to the head of the pending list, to make it more interactive */
557 gtk_tree_model_iter_children(model
, &child
, iter
);
559 gtk_tree_model_get(model
, &child
, 2, &node
, -1);
561 e_dlist_addtail(&list
, (EDListNode
*)node
);
562 } while (gtk_tree_model_iter_next(model
, &child
));
564 while ( (node
= (EMSubscribeNode
*)e_dlist_remtail(&list
)) )
565 e_dlist_addhead(&sub
->pending
, (EDListNode
*)node
);
567 if (sub
->pending_id
== -1
568 && (node
= (EMSubscribeNode
*)e_dlist_remtail(&sub
->pending
)))
569 sub_queue_fill_level(sub
, node
);
573 sub_destroy(GtkWidget
*w
, EMSubscribe
*sub
)
575 struct _zsubscribe_msg
*m
;
577 d(printf("subscribe closed\n"));
580 if (sub
->pending_id
!= -1)
581 mail_msg_cancel(sub
->pending_id
);
583 if (sub
->subscribe_id
!= -1)
584 mail_msg_cancel(sub
->subscribe_id
);
586 while ( (m
= (struct _zsubscribe_msg
*)e_dlist_remhead(&sub
->subscribe
)) )
593 subscribe_new(EMSubscribeEditor
*se
, const char *uri
)
597 sub
= g_malloc0(sizeof(*sub
));
598 sub
->store_uri
= g_strdup(uri
);
601 sub
->pending_id
= -1;
602 e_dlist_init(&sub
->pending
);
603 sub
->subscribe_id
= -1;
604 e_dlist_init(&sub
->subscribe
);
611 subscribe_set_store(EMSubscribe
*sub
, CamelStore
*store
)
613 if (store
== NULL
|| !camel_store_supports_subscriptions(store
)) {
614 GtkWidget
*w
= gtk_label_new(_("This store does not support subscriptions, or they are not enabled."));
616 gtk_label_set_line_wrap((GtkLabel
*)w
, TRUE
);
617 sub
->widget
= gtk_viewport_new(NULL
, NULL
);
618 gtk_viewport_set_shadow_type((GtkViewport
*)sub
->widget
, GTK_SHADOW_IN
);
619 gtk_container_add((GtkContainer
*)sub
->widget
, w
);
621 gtk_widget_show(sub
->widget
);
623 GtkTreeSelection
*selection
;
624 GtkCellRenderer
*renderer
;
628 camel_object_ref(store
);
629 sub
->folders
= g_hash_table_new(g_str_hash
, g_str_equal
);
631 model
= gtk_tree_store_new (3, G_TYPE_BOOLEAN
, G_TYPE_STRING
, G_TYPE_POINTER
);
632 sub
->tree
= (GtkTreeView
*) gtk_tree_view_new_with_model ((GtkTreeModel
*) model
);
633 gtk_widget_show ((GtkWidget
*)sub
->tree
);
635 sub
->widget
= gtk_scrolled_window_new (NULL
, NULL
);
636 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sub
->widget
), GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
);
637 gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (sub
->widget
), GTK_SHADOW_IN
);
638 gtk_container_add((GtkContainer
*)sub
->widget
, (GtkWidget
*)sub
->tree
);
639 gtk_widget_show(sub
->widget
);
641 renderer
= gtk_cell_renderer_toggle_new ();
642 g_object_set(renderer
, "activatable", TRUE
, NULL
);
643 gtk_tree_view_insert_column_with_attributes (sub
->tree
, -1, _("Subscribed"), renderer
, "active", 0, NULL
);
644 g_signal_connect(renderer
, "toggled", G_CALLBACK(sub_subscribe_toggled
), sub
);
646 renderer
= gtk_cell_renderer_text_new ();
647 gtk_tree_view_insert_column_with_attributes (sub
->tree
, -1, _("Folder"), renderer
, "text", 1, NULL
);
648 gtk_tree_view_set_expander_column(sub
->tree
, gtk_tree_view_get_column(sub
->tree
, 1));
650 selection
= gtk_tree_view_get_selection (sub
->tree
);
651 gtk_tree_selection_set_mode (selection
, GTK_SELECTION_MULTIPLE
);
652 gtk_tree_view_set_headers_visible (sub
->tree
, FALSE
);
654 g_signal_connect(sub
->tree
, "row-expanded", G_CALLBACK(sub_row_expanded
), sub
);
655 g_signal_connect(sub
->tree
, "row-activated", G_CALLBACK(sub_row_activated
), sub
);
656 g_signal_connect(sub
->tree
, "destroy", G_CALLBACK(sub_destroy
), sub
);
658 sub_selection_changed(selection
, sub
);
659 g_signal_connect(selection
, "changed", G_CALLBACK(sub_selection_changed
), sub
);
661 sub_queue_fill_level(sub
, NULL
);
664 gtk_box_pack_start((GtkBox
*)sub
->editor
->vbox
, sub
->widget
, TRUE
, TRUE
, 0);
668 sub_editor_destroy(GtkWidget
*w
, EMSubscribeEditor
*se
)
670 /* need to clean out pending store opens */
671 d(printf("editor destroyed, freeing editor\n"));
673 g_source_remove(se
->busy_id
);
679 sub_editor_close(GtkWidget
*w
, EMSubscribeEditor
*se
)
681 gtk_widget_destroy((GtkWidget
*)se
->dialog
);
685 sub_editor_refresh(GtkWidget
*w
, EMSubscribeEditor
*se
)
687 EMSubscribe
*sub
= se
->current
;
690 d(printf("sub editor refresh?\n"));
691 if (sub
== NULL
|| sub
->store
== NULL
)
696 /* drop any currently pending */
697 if (sub
->pending_id
!= -1)
698 mail_msg_cancel(sub
->pending_id
);
700 gtk_tree_store_clear((GtkTreeStore
*)gtk_tree_view_get_model(sub
->tree
));
702 e_dlist_init(&sub
->pending
);
704 g_hash_table_foreach(sub
->folders
, (GHFunc
)sub_node_free
, sub
);
705 g_hash_table_destroy(sub
->folders
);
707 sub
->folders
= g_hash_table_new(g_str_hash
, g_str_equal
);
710 sub
->info_list
= NULL
;
714 camel_store_free_folder_info(sub
->store
, (CamelFolderInfo
*)l
->data
);
719 sub_queue_fill_level(sub
, NULL
);
723 sub_editor_subscribe(GtkWidget
*w
, EMSubscribeEditor
*se
)
725 d(printf("subscribe clicked, current = %p\n", se
->current
));
728 sub_subscribe(se
->current
, TRUE
);
732 sub_editor_unsubscribe(GtkWidget
*w
, EMSubscribeEditor
*se
)
734 d(printf("unsubscribe clicked\n"));
737 sub_subscribe(se
->current
, FALSE
);
741 sub_editor_got_store(char *uri
, CamelStore
*store
, void *data
)
743 struct _EMSubscribe
*sub
= data
;
746 subscribe_set_store(sub
, store
);
751 sub_editor_menu_changed(GtkWidget
*w
, EMSubscribeEditor
*se
)
754 struct _EMSubscribe
*sub
;
756 d(printf("menu changed\n"));
759 n
= gtk_option_menu_get_history((GtkOptionMenu
*)se
->optionmenu
);
761 gtk_widget_show(se
->none_selected
);
763 gtk_widget_hide(se
->none_selected
);
764 gtk_widget_hide(se
->none_selected_item
);
768 sub
= (struct _EMSubscribe
*)se
->stores
.head
;
773 gtk_widget_show(sub
->widget
);
774 } else if (sub
->store_id
== -1) {
776 sub
->store_id
= mail_get_store(sub
->store_uri
, NULL
, sub_editor_got_store
, sub
);
780 gtk_widget_hide(sub
->widget
);
787 static gboolean
sub_editor_timeout(EMSubscribeEditor
*se
)
789 gtk_progress_bar_pulse((GtkProgressBar
*)se
->progress
);
794 static void sub_editor_busy(EMSubscribeEditor
*se
, int dir
)
800 if (was
&& !se
->busy
) {
801 g_source_remove(se
->busy_id
);
803 gtk_widget_hide(se
->progress
);
804 } else if (!was
&& se
->busy
) {
805 se
->busy_id
= g_timeout_add(1000/5, (GSourceFunc
)sub_editor_timeout
, se
);
806 gtk_widget_show(se
->progress
);
811 #define DEFAULT_WIDTH 600
812 #define DEFAULT_HEIGHT 400
814 static GtkAllocation window_size
= { 0, 0, 0, 0 };
817 window_size_allocate (GtkWidget
*widget
, GtkAllocation
*allocation
)
821 /* save to in-memory variable for current session access */
822 window_size
= *allocation
;
824 /* save the setting across sessions */
825 gconf
= gconf_client_get_default ();
826 gconf_client_set_int (gconf
, "/apps/evolution/mail/subscribe_window/width", window_size
.width
, NULL
);
827 gconf_client_set_int (gconf
, "/apps/evolution/mail/subscribe_window/height", window_size
.height
, NULL
);
828 g_object_unref (gconf
);
831 GtkDialog
*em_subscribe_editor_new(void)
833 EMSubscribeEditor
*se
;
834 EAccountList
*accounts
;
839 se
= g_malloc0(sizeof(*se
));
840 e_dlist_init(&se
->stores
);
842 xml
= glade_xml_new (EVOLUTION_GLADEDIR
"/mail-dialogs.glade", "subscribe_dialog", NULL
);
847 se
->dialog
= (GtkDialog
*)glade_xml_get_widget (xml
, "subscribe_dialog");
848 g_signal_connect(se
->dialog
, "destroy", G_CALLBACK(sub_editor_destroy
), se
);
850 gtk_widget_ensure_style ((GtkWidget
*)se
->dialog
);
851 gtk_container_set_border_width ((GtkContainer
*) ((GtkDialog
*)se
->dialog
)->action_area
, 12);
852 gtk_container_set_border_width ((GtkContainer
*) ((GtkDialog
*)se
->dialog
)->vbox
, 0);
854 se
->vbox
= glade_xml_get_widget(xml
, "tree_box");
856 se
->subscribe_button
= glade_xml_get_widget (xml
, "subscribe_button");
857 g_signal_connect(se
->subscribe_button
, "clicked", G_CALLBACK(sub_editor_subscribe
), se
);
858 se
->unsubscribe_button
= glade_xml_get_widget (xml
, "unsubscribe_button");
859 g_signal_connect(se
->unsubscribe_button
, "clicked", G_CALLBACK(sub_editor_unsubscribe
), se
);
861 /* FIXME: This is just to get the shadow, is there a better way? */
862 w
= gtk_label_new(_("Please select a server."));
863 se
->none_selected
= gtk_viewport_new(NULL
, NULL
);
864 gtk_viewport_set_shadow_type((GtkViewport
*)se
->none_selected
, GTK_SHADOW_IN
);
865 gtk_container_add((GtkContainer
*)se
->none_selected
, w
);
868 gtk_box_pack_start((GtkBox
*)se
->vbox
, se
->none_selected
, TRUE
, TRUE
, 0);
869 gtk_widget_show(se
->none_selected
);
871 se
->progress
= glade_xml_get_widget(xml
, "progress_bar");
872 gtk_widget_hide(se
->progress
);
874 w
= glade_xml_get_widget(xml
, "close_button");
875 g_signal_connect(w
, "clicked", G_CALLBACK(sub_editor_close
), se
);
877 w
= glade_xml_get_widget(xml
, "refresh_button");
878 g_signal_connect(w
, "clicked", G_CALLBACK(sub_editor_refresh
), se
);
880 /* setup stores menu */
881 se
->optionmenu
= glade_xml_get_widget(xml
, "store_menu");
882 menu
= gtk_menu_new();
883 se
->none_selected_item
= w
= gtk_menu_item_new_with_label(_("No server has been selected"));
885 gtk_menu_shell_append ((GtkMenuShell
*)menu
, w
);
887 accounts
= mail_config_get_accounts ();
888 for (iter
= e_list_get_iterator ((EList
*) accounts
);
889 e_iterator_is_valid (iter
);
890 e_iterator_next (iter
)) {
891 EAccount
*account
= (EAccount
*) e_iterator_get (iter
);
893 /* setup url table, and store table? */
894 if (account
->enabled
&& account
->source
->url
) {
895 d(printf("adding account '%s'\n", account
->name
));
896 w
= gtk_menu_item_new_with_label(account
->name
);
897 gtk_menu_shell_append ((GtkMenuShell
*)menu
, w
);
899 e_dlist_addtail(&se
->stores
, (EDListNode
*)subscribe_new(se
, account
->source
->url
));
901 d(printf("not adding account '%s'\n", account
->name
));
904 g_object_unref(iter
);
906 gtk_option_menu_set_menu((GtkOptionMenu
*)se
->optionmenu
, menu
);
907 g_signal_connect(se
->optionmenu
, "changed", G_CALLBACK(sub_editor_menu_changed
), se
);
909 if (window_size
.width
== 0) {
910 /* initialize @window_size with the previous session's size */
914 gconf
= gconf_client_get_default ();
916 window_size
.width
= gconf_client_get_int (gconf
, "/apps/evolution/mail/subscribe_window/width", &err
);
918 window_size
.width
= DEFAULT_WIDTH
;
919 g_clear_error (&err
);
922 window_size
.height
= gconf_client_get_int (gconf
, "/apps/evolution/mail/subscribe_window/height", &err
);
924 window_size
.height
= DEFAULT_HEIGHT
;
925 g_clear_error (&err
);
928 g_object_unref (gconf
);
931 gtk_window_set_default_size ((GtkWindow
*) se
->dialog
, window_size
.width
, window_size
.height
);
932 g_signal_connect (se
->dialog
, "size-allocate", G_CALLBACK (window_size_allocate
), NULL
);