aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mail/ChangeLog28
-rw-r--r--mail/em-folder-tree-model.c6
-rw-r--r--mail/em-folder-tree.c339
3 files changed, 218 insertions, 155 deletions
diff --git a/mail/ChangeLog b/mail/ChangeLog
index ef6a9c8b17..29ebcc8609 100644
--- a/mail/ChangeLog
+++ b/mail/ChangeLog
@@ -1,3 +1,31 @@
+2004-08-23 Not Zed <NotZed@Ximian.com>
+
+ * em-folder-tree.c (em_folder_tree_set_selected): store the
+ select-uri on the view not in the thread message.
+ (emft_get_folder_info__free):
+ (emft_get_folder_info__got): select_uri removed.
+ (em_folder_tree_set_selected_list): don't set each selected
+ separately, do it as a list.
+ (emft_maybe_expand_row): if this is a selected row, select it too.
+ (emft_get_folder_info__got): do no pending set selection stuff
+ here.
+ (em_folder_tree_set_selected): just call set_selected_list with
+ one item.
+ (emft_expand_node): if this is a selected row, select it too.
+ (emft_get_folder_info__got): no longer need to track lost folders.
+ (emft_tree_row_activated): clear the pending select list.
+ (emft_tree_selection_changed): and here too.
+ (em_folder_tree_get_selected_uris): get the lost folders from the
+ un-applied selected ones now. also fixes a list appending error.
+ (emft_tree_user_event): find out when the user hits a key or mouse
+ button to override any pending single-user select and don't
+ override the cursor setting either.
+ (emft_tree_row_expanded): set the 'load subdirs' false before we
+ load it, so we don't try to load it again if its still being
+ loaded.
+ (emft_get_folder_info__got): don't check the loaded flag here, it
+ should be set by the callee, also check the exception return.
+
2004-08-13 Jeffrey Stedfast <fejj@novell.com>
Fix for bug #62812
diff --git a/mail/em-folder-tree-model.c b/mail/em-folder-tree-model.c
index ffbbe60b72..6947dc5ef4 100644
--- a/mail/em-folder-tree-model.c
+++ b/mail/em-folder-tree-model.c
@@ -924,7 +924,11 @@ em_folder_tree_model_get_expanded (EMFolderTreeModel *model, const char *key)
xmlNodePtr node;
const char *name;
char *buf, *p;
-
+
+ /* This code needs to be rewritten.
+ First it doesn't belong on the model
+ Second, it shouldn't use an xml tree to store a bit table in memory! */
+
node = model->state ? model->state->children : NULL;
if (!node || strcmp (node->name, "tree-state") != 0)
return FALSE;
diff --git a/mail/em-folder-tree.c b/mail/em-folder-tree.c
index e99da52814..361675a43e 100644
--- a/mail/em-folder-tree.c
+++ b/mail/em-folder-tree.c
@@ -72,20 +72,30 @@
#define d(x)
+struct _selected_uri {
+ char *key; /* store:path or account/path */
+ char *uri;
+ CamelStore *store;
+ char *path;
+};
+
struct _EMFolderTreePrivate {
GtkTreeView *treeview;
EMFolderTreeModel *model;
- char *select_uri; /* uri to load when the proper store/etc have been populated */
+ GSList *select_uris; /* selected_uri structures of each path pending selection. */
+ GHashTable *select_uris_table; /*Removed as they're encountered, so use this to find uri's not presnet but selected */
char *selected_uri;
char *selected_path;
guint32 excluded;
- gboolean do_multiselect;
- /* when doing a multiselect, folders that we didn't find */
- GList *lost_folders;
+ int do_multiselect:1; /* multiple select mode */
+ int cursor_set:1; /* set to TRUE means we or something
+ * else has set the cursor, otherwise
+ * we need to set it when we set the
+ * selection */
guint save_state_id;
@@ -154,6 +164,7 @@ static gboolean emft_tree_test_collapse_row (GtkTreeView *treeview, GtkTreeIter
static void emft_tree_row_expanded (GtkTreeView *treeview, GtkTreeIter *root, GtkTreePath *path, EMFolderTree *emft);
static gboolean emft_tree_button_press (GtkTreeView *treeview, GdkEventButton *event, EMFolderTree *emft);
static void emft_tree_selection_changed (GtkTreeSelection *selection, EMFolderTree *emft);
+static gboolean emft_tree_user_event (GtkTreeView *treeview, GdkEvent *e, EMFolderTree *emft);
struct _emft_selection_data {
GtkTreeModel *model;
@@ -348,18 +359,31 @@ emft_select_func(GtkTreeSelection *selection, GtkTreeModel *model, GtkTreePath *
}
static void
+emft_free_select_uri(void *v, void *data)
+{
+ struct _selected_uri *u = v;
+
+ g_free(u->uri);
+ if (u->store)
+ camel_object_unref(u->store);
+ g_free(u->key);
+ g_free(u->path);
+ g_free(u);
+}
+
+static void
em_folder_tree_init (EMFolderTree *emft)
{
struct _EMFolderTreePrivate *priv;
priv = g_new0 (struct _EMFolderTreePrivate, 1);
- priv->lost_folders = NULL;
+ priv->select_uris_table = g_hash_table_new(g_str_hash, g_str_equal);
priv->selected_uri = NULL;
priv->selected_path = NULL;
priv->treeview = NULL;
priv->model = NULL;
priv->drag_row = NULL;
-
+
emft->priv = priv;
}
@@ -368,14 +392,13 @@ em_folder_tree_finalize (GObject *obj)
{
EMFolderTree *emft = (EMFolderTree *) obj;
- /* clear list of lost uris */
- if (emft->priv->lost_folders) {
- g_list_foreach (emft->priv->lost_folders, (GFunc) g_free, NULL);
- g_list_free (emft->priv->lost_folders);
- emft->priv->lost_folders = NULL;
+ if (emft->priv->select_uris) {
+ g_slist_foreach(emft->priv->select_uris, emft_free_select_uri, emft);
+ g_slist_free(emft->priv->select_uris);
+ g_hash_table_destroy(emft->priv->select_uris_table);
+ emft->priv->select_uris = NULL;
}
-
- g_free (emft->priv->select_uri);
+
g_free (emft->priv->selected_uri);
g_free (emft->priv->selected_path);
g_free (emft->priv);
@@ -475,6 +498,7 @@ em_folder_tree_construct (EMFolderTree *emft, EMFolderTreeModel *model)
g_signal_connect (priv->treeview, "test-collapse-row", G_CALLBACK (emft_tree_test_collapse_row), emft);
g_signal_connect (priv->treeview, "row-activated", G_CALLBACK (emft_tree_row_activated), emft);
g_signal_connect (priv->treeview, "button-press-event", G_CALLBACK (emft_tree_button_press), emft);
+ g_signal_connect (priv->treeview, "key-press-event", G_CALLBACK (emft_tree_user_event), emft);
selection = gtk_tree_view_get_selection ((GtkTreeView *) priv->treeview);
g_signal_connect (selection, "changed", G_CALLBACK (emft_tree_selection_changed), emft);
@@ -498,6 +522,25 @@ em_folder_tree_new (void)
return (GtkWidget *) emft;
}
+/* NOTE: Removes and frees the selected uri structure */
+static void
+emft_select_uri(EMFolderTree *emft, GtkTreePath *path, struct _selected_uri *u)
+{
+ struct _EMFolderTreePrivate *priv = emft->priv;
+ GtkTreeSelection *selection;
+
+ selection = gtk_tree_view_get_selection(priv->treeview);
+ gtk_tree_selection_select_path(selection, path);
+ if (!priv->cursor_set) {
+ gtk_tree_view_set_cursor (priv->treeview, path, NULL, FALSE);
+ priv->cursor_set = TRUE;
+ }
+ gtk_tree_view_scroll_to_cell (priv->treeview, path, NULL, TRUE, 0.8f, 0.0f);
+ g_hash_table_remove(priv->select_uris_table, u->key);
+ priv->select_uris = g_slist_remove(priv->select_uris, u);
+ emft_free_select_uri((void *)u, NULL);
+}
+
static void
emft_expand_node (EMFolderTreeModel *model, const char *key, EMFolderTree *emft)
{
@@ -511,7 +554,8 @@ emft_expand_node (EMFolderTreeModel *model, const char *key, EMFolderTree *emft)
const char *p;
char *uid;
size_t n;
-
+ struct _selected_uri *u;
+
if (!(p = strchr (key, '/')))
n = strlen (key);
else
@@ -559,19 +603,26 @@ emft_expand_node (EMFolderTreeModel *model, const char *key, EMFolderTree *emft)
path = gtk_tree_row_reference_get_path (row);
gtk_tree_view_expand_row (priv->treeview, path, FALSE);
+
+ u = g_hash_table_lookup(emft->priv->select_uris_table, key);
+ if (u)
+ emft_select_uri(emft, path, u);
+
gtk_tree_path_free (path);
}
static void
emft_maybe_expand_row (EMFolderTreeModel *model, GtkTreePath *tree_path, GtkTreeIter *iter, EMFolderTree *emft)
{
+ struct _EMFolderTreePrivate *priv = emft->priv;
struct _EMFolderTreeModelStoreInfo *si;
gboolean is_store;
CamelStore *store;
EAccount *account;
char *full_name;
char *key;
-
+ struct _selected_uri *u;
+
gtk_tree_model_get ((GtkTreeModel *) model, iter,
COL_STRING_FULL_NAME, &full_name,
COL_POINTER_CAMEL_STORE, &store,
@@ -588,12 +639,16 @@ emft_maybe_expand_row (EMFolderTreeModel *model, GtkTreePath *tree_path, GtkTree
/* local store */
key = g_strdup_printf ("local/%s", full_name ? full_name : "");
}
-
- if (em_folder_tree_model_get_expanded (model, key)) {
- gtk_tree_view_expand_to_path (emft->priv->treeview, tree_path);
- gtk_tree_view_expand_row (emft->priv->treeview, tree_path, FALSE);
+
+ u = g_hash_table_lookup(priv->select_uris_table, key);
+ if (em_folder_tree_model_get_expanded (model, key) || u) {
+ gtk_tree_view_expand_to_path (priv->treeview, tree_path);
+ gtk_tree_view_expand_row (priv->treeview, tree_path, FALSE);
+
+ if (u)
+ emft_select_uri(emft, tree_path, u);
}
-
+
g_free (full_name);
g_free (key);
}
@@ -1490,11 +1545,12 @@ em_folder_tree_get_selected_uris (EMFolderTree *emft)
{
GtkTreeSelection *selection = gtk_tree_view_get_selection (emft->priv->treeview);
GList *list = NULL, *rows, *l;
+ GSList *sl;
GtkTreeModel *model;
/* at first, add lost uris */
- for (l = emft->priv->lost_folders; l; l = g_list_next(l))
- list = g_list_append (l, g_strdup (l->data));
+ for (sl = emft->priv->select_uris; sl; sl = g_slist_next(sl))
+ list = g_list_append (list, g_strdup (((struct _selected_uri *)sl->data)->uri));
rows = gtk_tree_selection_get_selected_rows(selection, &model);
for (l=rows; l; l=g_list_next(l)) {
@@ -1535,21 +1591,80 @@ em_folder_tree_get_selected_paths (EMFolderTree *emft)
return list;
}
+static void
+emft_clear_selected_list(EMFolderTree *emft)
+{
+ struct _EMFolderTreePrivate *priv = emft->priv;
+
+ g_slist_foreach(priv->select_uris, emft_free_select_uri, emft);
+ g_slist_free(priv->select_uris);
+ g_hash_table_destroy(priv->select_uris_table);
+ priv->select_uris = NULL;
+ priv->select_uris_table = g_hash_table_new(g_str_hash, g_str_equal);
+ priv->cursor_set = FALSE;
+}
+
void
em_folder_tree_set_selected_list (EMFolderTree *emft, GList *list)
{
struct _EMFolderTreePrivate *priv = emft->priv;
+ int id = 0;
+
+ /* FIXME: need to remove any currently selected stuff? */
+ emft_clear_selected_list(emft);
+
+ for (;list;list = list->next) {
+ struct _selected_uri *u = g_malloc0(sizeof(*u));
+ CamelURL *url;
+ CamelException ex = { 0 };
+
+ u->uri = g_strdup(list->data);
+ u->store = (CamelStore *)camel_session_get_service (session, u->uri, CAMEL_PROVIDER_STORE, &ex);
+ camel_exception_clear(&ex);
+
+ url = camel_url_new(u->uri, NULL);
+ if (u->store == NULL || url == NULL) {
+ u->key = g_strdup_printf("dummy-%d:%s", id++, u->uri);
+ g_hash_table_insert(priv->select_uris_table, u->key, u);
+ priv->select_uris = g_slist_append(priv->select_uris, u);
+ } else {
+ const char *path;
+ char *expand_key, *end;
+ EAccount *account;
- /* clear list of lost uris */
- if (priv->lost_folders) {
- g_list_foreach (priv->lost_folders, (GFunc)g_free, NULL);
- g_list_free (priv->lost_folders);
- priv->lost_folders = NULL;
- }
-
- while (list) {
- em_folder_tree_set_selected (emft, list->data);
- list = g_list_next (list);
+ if (((CamelService *)u->store)->provider->url_flags & CAMEL_URL_FRAGMENT_IS_PATH)
+ path = url->fragment;
+ else
+ path = url->path && url->path[0]=='/' ? url->path+1:url->path;
+ if (path == NULL)
+ path = "";
+
+ /* This makes sure all our parents up to the root are expanded */
+ /* FIXME: Why does the expanded state store this made up path rather than the euri? */
+ if ( (account = mail_config_get_account_by_source_url(u->uri)) )
+ expand_key = g_strdup_printf ("%s/%s", account->uid, path);
+ else if (CAMEL_IS_VEE_STORE (u->store))
+ expand_key = g_strdup_printf ("vfolder/%s", path);
+ else
+ expand_key = g_strdup_printf ("local/%s", path);
+
+ u->key = g_strdup(expand_key);
+
+ g_hash_table_insert(priv->select_uris_table, u->key, u);
+ priv->select_uris = g_slist_append(priv->select_uris, u);
+
+ end = strrchr(expand_key, '/');
+ do {
+ emft_expand_node(priv->model, expand_key, emft);
+ em_folder_tree_model_set_expanded(priv->model, expand_key, TRUE);
+ *end = 0;
+ end = strrchr(expand_key, '/');
+ } while (end);
+ g_free(expand_key);
+ }
+
+ if (url)
+ camel_url_free(url);
}
}
@@ -1586,9 +1701,6 @@ struct _EMFolderTreeGetFolderInfo {
/* output data */
CamelFolderInfo *fi;
-
- /* uri to select if any after the op is done */
- char *select_uri;
};
static void
@@ -1614,7 +1726,6 @@ emft_get_folder_info__got (struct _mail_msg *mm)
GtkTreeStore *model;
GtkTreePath *path;
gboolean is_store;
- gboolean load;
/* check that we haven't been destroyed */
if (priv->treeview == NULL)
@@ -1628,24 +1739,27 @@ emft_get_folder_info__got (struct _mail_msg *mm)
/* store has been removed in the interim - do nothing */
return;
}
-
+
model = (GtkTreeStore *) gtk_tree_view_get_model (priv->treeview);
-
+
path = gtk_tree_row_reference_get_path (m->root);
gtk_tree_model_get_iter ((GtkTreeModel *) model, &root, path);
+
+ /* if we had an error, then we need to re-set the load subdirs state and collapse the node */
+ if (camel_exception_is_set(&mm->ex)) {
+ gtk_tree_store_set(model, &root, COL_BOOL_LOAD_SUBDIRS, TRUE, -1);
+ gtk_tree_view_collapse_row (priv->treeview, path);
+ gtk_tree_path_free (path);
+ return;
+ }
+
gtk_tree_path_free (path);
/* make sure we still need to load the tree subfolders... */
gtk_tree_model_get ((GtkTreeModel *) model, &root,
- COL_BOOL_LOAD_SUBDIRS, &load,
COL_BOOL_IS_STORE, &is_store,
-1);
- if (!load) {
- if (priv->do_multiselect && m->select_uri)
- priv->lost_folders = g_list_append (priv->lost_folders, g_strdup (m->select_uri));
- return;
- }
-
+
/* get the first child (which will be a dummy node) */
gtk_tree_model_iter_children ((GtkTreeModel *) model, &iter, &root);
@@ -1683,17 +1797,6 @@ emft_get_folder_info__got (struct _mail_msg *mm)
}
gtk_tree_store_set (model, &root, COL_BOOL_LOAD_SUBDIRS, FALSE, -1);
-
- if (m->select_uri) {
- em_folder_tree_set_selected (m->emft, m->select_uri);
- } else if (priv->select_uri) {
- char *uri = priv->select_uri;
-
- priv->select_uri = NULL;
- em_folder_tree_set_selected (m->emft, uri);
- g_free (uri);
- }
-
emft_queue_save_state (m->emft);
}
@@ -1707,7 +1810,6 @@ emft_get_folder_info__free (struct _mail_msg *mm)
gtk_tree_row_reference_free (m->root);
g_object_unref(m->emft);
camel_object_unref (m->store);
- g_free (m->select_uri);
g_free (m->top);
}
@@ -1775,6 +1877,8 @@ emft_tree_row_expanded (GtkTreeView *treeview, GtkTreeIter *root, GtkTreePath *t
g_free (full_name);
return;
}
+
+ gtk_tree_store_set((GtkTreeStore *)model, root, COL_BOOL_LOAD_SUBDIRS, FALSE, -1);
m = mail_msg_new (&get_folder_info_op, NULL, sizeof (struct _EMFolderTreeGetFolderInfo));
m->root = gtk_tree_row_reference_new (model, tree_path);
@@ -1784,7 +1888,6 @@ emft_tree_row_expanded (GtkTreeView *treeview, GtkTreeIter *root, GtkTreePath *t
g_object_ref(emft);
m->top = full_name;
m->flags = CAMEL_STORE_FOLDER_INFO_RECURSIVE;
- m->select_uri = NULL;
e_thread_put (mail_thread_new, (EMsg *) m);
}
@@ -1826,9 +1929,8 @@ emft_tree_row_activated (GtkTreeView *treeview, GtkTreePath *tree_path, GtkTreeV
gtk_tree_model_get (model, &iter, COL_STRING_FULL_NAME, &full_name,
COL_STRING_URI, &uri, COL_UINT_FLAGS, &flags, -1);
-
- g_free (priv->select_uri);
- priv->select_uri = NULL;
+
+ emft_clear_selected_list(emft);
g_free (priv->selected_uri);
priv->selected_uri = uri;
@@ -2636,6 +2738,9 @@ emft_tree_button_press (GtkTreeView *treeview, GdkEventButton *event, EMFolderTr
GtkMenu *menu;
EMPopup *emp;
int i;
+
+ /* this centralises working out when the user's done something */
+ emft_tree_user_event(treeview, (GdkEvent *)event, emft);
if (event->button != 3 && !(event->button == 1 && event->type == GDK_2BUTTON_PRESS))
return FALSE;
@@ -2717,6 +2822,19 @@ emft_tree_button_press (GtkTreeView *treeview, GdkEventButton *event, EMFolderTr
return TRUE;
}
+/* This is called for keyboard and mouse events, it seems the only way
+ * we know the user has done something to the selection as opposed to
+ * code or initialisation processes */
+static gboolean
+emft_tree_user_event (GtkTreeView *treeview, GdkEvent *e, EMFolderTree *emft)
+{
+ if (!emft->priv->do_multiselect)
+ emft_clear_selected_list(emft);
+
+ emft->priv->cursor_set = TRUE;
+
+ return FALSE;
+}
static void
emft_tree_selection_changed (GtkTreeSelection *selection, EMFolderTree *emft)
@@ -2732,10 +2850,7 @@ emft_tree_selection_changed (GtkTreeSelection *selection, EMFolderTree *emft)
gtk_tree_model_get (model, &iter, COL_STRING_FULL_NAME, &full_name,
COL_STRING_URI, &uri, COL_UINT_FLAGS, &flags, -1);
-
- g_free (priv->select_uri);
- priv->select_uri = NULL;
-
+
g_free (priv->selected_uri);
priv->selected_uri = uri;
@@ -2749,96 +2864,12 @@ emft_tree_selection_changed (GtkTreeSelection *selection, EMFolderTree *emft)
void
em_folder_tree_set_selected (EMFolderTree *emft, const char *uri)
{
- struct _EMFolderTreeModelStoreInfo *si;
- struct _EMFolderTreeGetFolderInfo *m;
- struct _EMFolderTreePrivate *priv;
- GtkTreeRowReference *row = NULL;
- GtkTreeSelection *selection;
- GtkTreePath *tree_path;
- CamelStore *store;
- CamelException ex;
- char *path, *p;
- CamelURL *url;
-
- g_return_if_fail (EM_IS_FOLDER_TREE (emft));
-
- priv = emft->priv;
- g_free (priv->select_uri);
- priv->select_uri = NULL;
-
- camel_exception_init (&ex);
- if (!(store = (CamelStore *) camel_session_get_service (session, uri, CAMEL_PROVIDER_STORE, &ex))) {
- camel_exception_clear (&ex);
- return;
- }
-
- if (!(si = g_hash_table_lookup (priv->model->store_hash, store))) {
- priv->select_uri = g_strdup (uri);
- camel_object_unref (store);
- return;
- }
-
- if (!(url = camel_url_new (uri, NULL))) {
- camel_object_unref (store);
- return;
- }
-
- if (((CamelService *) store)->provider->url_flags & CAMEL_URL_FRAGMENT_IS_PATH)
- path = url->fragment;
- else
- path = url->path && url->path[0]=='/' ? url->path+1:url->path;
- path = g_strdup(path?path:"");
- camel_url_free (url);
-
- if (path[0] == 0)
- row = si->row;
-
- if (row || (row = g_hash_table_lookup (si->full_hash, path))) {
- /* the folder-info node has already been loaded */
- tree_path = gtk_tree_row_reference_get_path (row);
- gtk_tree_view_expand_to_path (priv->treeview, tree_path);
- selection = gtk_tree_view_get_selection (priv->treeview);
- gtk_tree_selection_select_path (selection, tree_path);
- gtk_tree_view_set_cursor (priv->treeview, tree_path, NULL, FALSE);
- gtk_tree_view_scroll_to_cell (priv->treeview, tree_path, NULL, TRUE, 0.8f, 0.0f);
- gtk_tree_path_free (tree_path);
- camel_object_unref (store);
- g_free (path);
- return;
- }
-
- /* look for the first of our parent folders that has already been loaded */
- p = path + strlen (path);
- while (p > path) {
- if (*p == '/') {
- *p = '\0';
-
- if ((row = g_hash_table_lookup (si->full_hash, path)))
- break;
- }
-
- p--;
- }
-
- /* FIXME: this gets all the subfolders of our first loaded
- * parent folder - ideally we'd only get what we needed, but
- * it's probably not worth the effort */
- m = mail_msg_new (&get_folder_info_op, NULL, sizeof (struct _EMFolderTreeGetFolderInfo));
- m->store = store;
- m->emft = emft;
- g_object_ref(emft);
- if (row) {
- m->top = path;
- m->root = gtk_tree_row_reference_copy(row);
- } else {
- g_free(path);
- m->root = gtk_tree_row_reference_copy(si->row);
- }
+ GList *l;
- m->flags = CAMEL_STORE_FOLDER_INFO_FAST | CAMEL_STORE_FOLDER_INFO_RECURSIVE;
- m->select_uri = g_strdup (uri);
-
- e_thread_put (mail_thread_new, (EMsg *) m);
+ l = g_list_append(NULL, (void *)uri);
+
+ em_folder_tree_set_selected_list(emft, l);
+ g_list_free(l);
}
const char *