diff options
-rw-r--r-- | mail/ChangeLog | 22 | ||||
-rw-r--r-- | mail/em-folder-view.c | 30 | ||||
-rw-r--r-- | mail/em-folder-view.h | 4 | ||||
-rw-r--r-- | mail/message-list.c | 211 | ||||
-rw-r--r-- | mail/message-list.h | 10 |
5 files changed, 178 insertions, 99 deletions
diff --git a/mail/ChangeLog b/mail/ChangeLog index ba743cb80c..42eba10a99 100644 --- a/mail/ChangeLog +++ b/mail/ChangeLog @@ -1,3 +1,25 @@ +2004-07-27 Not Zed <NotZed@Ximian.com> + + ** See #57972. + + * message-list.c (search_func): removed. + (ml_search_path): new function to just search, not actually change + the cursor like e_tree_find does. + (message_list_can_select): new function, returns true if the + selection specified is possible without changing the selection. + (message_list_select): rewritten. + (select_path): helper to select a path in a way that 'works + reliably'. + (message_list_select_next_thread): rewritten to use the + table-adapter, so it properly handles arbitrary sorting. + + * em-folder-view.c (em_folder_view_get_popup_target): setup + next/prev flags as appropriate. + (emfv_enable_map[]): setup next/prev flags. + + * em-folder-view.h: added last and first message status bits to + folder view select mask. + 2004-07-23 Radek Doulik <rodo@ximian.com> * added len parameter to em_utils_part_to_html and diff --git a/mail/em-folder-view.c b/mail/em-folder-view.c index 51d5eee890..85c6cd9f92 100644 --- a/mail/em-folder-view.c +++ b/mail/em-folder-view.c @@ -724,7 +724,7 @@ emfv_popup_mark_junk (GtkWidget *w, EMFolderView *emfv) CAMEL_MESSAGE_SEEN|CAMEL_MESSAGE_JUNK|CAMEL_MESSAGE_JUNK_LEARN, CAMEL_MESSAGE_SEEN|CAMEL_MESSAGE_JUNK|CAMEL_MESSAGE_JUNK_LEARN); if (uids->len == 1) - message_list_select(emfv->list, MESSAGE_LIST_SELECT_NEXT, 0, 0, FALSE); + message_list_select(emfv->list, MESSAGE_LIST_SELECT_NEXT, 0, 0); message_list_free_uids(emfv->list, uids); } @@ -739,7 +739,7 @@ emfv_popup_mark_nojunk (GtkWidget *w, EMFolderView *emfv) CAMEL_MESSAGE_JUNK|CAMEL_MESSAGE_JUNK_LEARN, CAMEL_MESSAGE_JUNK_LEARN); if (uids->len == 1) - message_list_select(emfv->list, MESSAGE_LIST_SELECT_NEXT, 0, 0, FALSE); + message_list_select(emfv->list, MESSAGE_LIST_SELECT_NEXT, 0, 0); message_list_free_uids(emfv->list, uids); } @@ -753,8 +753,8 @@ emfv_popup_delete(GtkWidget *w, EMFolderView *emfv) em_folder_view_mark_selected(emfv, CAMEL_MESSAGE_SEEN|CAMEL_MESSAGE_DELETED, CAMEL_MESSAGE_SEEN|CAMEL_MESSAGE_DELETED); if (uids->len == 1) { - if (!message_list_select (emfv->list, MESSAGE_LIST_SELECT_NEXT, 0, 0, FALSE) && emfv->hide_deleted) - message_list_select (emfv->list, MESSAGE_LIST_SELECT_PREVIOUS, 0, 0, FALSE); + if (!message_list_select (emfv->list, MESSAGE_LIST_SELECT_NEXT, 0, 0) && emfv->hide_deleted) + message_list_select (emfv->list, MESSAGE_LIST_SELECT_PREVIOUS, 0, 0); } em_utils_uids_free(uids); } @@ -1110,7 +1110,7 @@ emfv_mail_next(BonoboUIComponent *uid, void *data, const char *path) { EMFolderView *emfv = data; - message_list_select(emfv->list, MESSAGE_LIST_SELECT_NEXT, 0, 0, FALSE); + message_list_select(emfv->list, MESSAGE_LIST_SELECT_NEXT, 0, 0); } static void @@ -1118,7 +1118,7 @@ emfv_mail_next_flagged(BonoboUIComponent *uid, void *data, const char *path) { EMFolderView *emfv = data; - message_list_select(emfv->list, MESSAGE_LIST_SELECT_NEXT, CAMEL_MESSAGE_FLAGGED, CAMEL_MESSAGE_FLAGGED, TRUE); + message_list_select(emfv->list, MESSAGE_LIST_SELECT_NEXT|MESSAGE_LIST_SELECT_WRAP, CAMEL_MESSAGE_FLAGGED, CAMEL_MESSAGE_FLAGGED); } static void @@ -1126,7 +1126,7 @@ emfv_mail_next_unread(BonoboUIComponent *uid, void *data, const char *path) { EMFolderView *emfv = data; - message_list_select(emfv->list, MESSAGE_LIST_SELECT_NEXT, 0, CAMEL_MESSAGE_SEEN, TRUE); + message_list_select(emfv->list, MESSAGE_LIST_SELECT_NEXT|MESSAGE_LIST_SELECT_WRAP, 0, CAMEL_MESSAGE_SEEN); } static void @@ -1142,7 +1142,7 @@ emfv_mail_previous(BonoboUIComponent *uid, void *data, const char *path) { EMFolderView *emfv = data; - message_list_select(emfv->list, MESSAGE_LIST_SELECT_PREVIOUS, 0, 0, FALSE); + message_list_select(emfv->list, MESSAGE_LIST_SELECT_PREVIOUS, 0, 0); } static void @@ -1150,7 +1150,7 @@ emfv_mail_previous_flagged(BonoboUIComponent *uid, void *data, const char *path) { EMFolderView *emfv = data; - message_list_select(emfv->list, MESSAGE_LIST_SELECT_PREVIOUS, CAMEL_MESSAGE_FLAGGED, CAMEL_MESSAGE_FLAGGED, TRUE); + message_list_select(emfv->list, MESSAGE_LIST_SELECT_PREVIOUS|MESSAGE_LIST_SELECT_WRAP, CAMEL_MESSAGE_FLAGGED, CAMEL_MESSAGE_FLAGGED); } static void @@ -1158,7 +1158,7 @@ emfv_mail_previous_unread(BonoboUIComponent *uid, void *data, const char *path) { EMFolderView *emfv = data; - message_list_select(emfv->list, MESSAGE_LIST_SELECT_PREVIOUS, 0, CAMEL_MESSAGE_SEEN, TRUE); + message_list_select(emfv->list, MESSAGE_LIST_SELECT_PREVIOUS|MESSAGE_LIST_SELECT_WRAP, 0, CAMEL_MESSAGE_SEEN); } static void @@ -1549,11 +1549,11 @@ static const EMFolderViewEnable emfv_enable_map[] = { { "EditPaste", EM_POPUP_SELECT_FOLDER }, /* FIXME: should these be single-selection? */ - { "MailNext", EM_POPUP_SELECT_MANY }, + { "MailNext", EM_POPUP_SELECT_MANY|EM_FOLDER_VIEW_SELECT_NEXT_MSG }, { "MailNextFlagged", EM_POPUP_SELECT_MANY }, { "MailNextUnread", EM_POPUP_SELECT_MANY }, { "MailNextThread", EM_POPUP_SELECT_MANY }, - { "MailPrevious", EM_POPUP_SELECT_MANY }, + { "MailPrevious", EM_POPUP_SELECT_MANY|EM_FOLDER_VIEW_SELECT_PREV_MSG }, { "MailPreviousFlagged", EM_POPUP_SELECT_MANY }, { "MailPreviousUnread", EM_POPUP_SELECT_MANY }, @@ -1870,6 +1870,12 @@ em_folder_view_get_popup_target(EMFolderView *emfv) if (message_list_hidden(emfv->list) != 0) t->mask &= ~EM_FOLDER_VIEW_SELECT_HIDDEN; + if (message_list_can_select(emfv->list, MESSAGE_LIST_SELECT_NEXT, 0, 0)) + t->mask &= ~EM_FOLDER_VIEW_SELECT_NEXT_MSG; + + if (message_list_can_select(emfv->list, MESSAGE_LIST_SELECT_PREVIOUS, 0, 0)) + t->mask &= ~EM_FOLDER_VIEW_SELECT_PREV_MSG; + /* See bug #54770 */ if (!emfv->hide_deleted) t->mask &= ~EM_POPUP_SELECT_DELETE; diff --git a/mail/em-folder-view.h b/mail/em-folder-view.h index 279e9ab0ea..3cf9586bb4 100644 --- a/mail/em-folder-view.h +++ b/mail/em-folder-view.h @@ -47,7 +47,9 @@ typedef struct _EMFolderViewEnable EMFolderViewEnable; enum { EM_FOLDER_VIEW_SELECT_THREADED = EM_POPUP_SELECT_LAST, EM_FOLDER_VIEW_SELECT_HIDDEN = EM_POPUP_SELECT_LAST<<1, - EM_FOLDER_VIEW_SELECT_LAST = EM_POPUP_SELECT_LAST<<2, + EM_FOLDER_VIEW_SELECT_NEXT_MSG = EM_POPUP_SELECT_LAST<<2, + EM_FOLDER_VIEW_SELECT_PREV_MSG = EM_POPUP_SELECT_LAST<<3, + EM_FOLDER_VIEW_SELECT_LAST = EM_POPUP_SELECT_LAST<<4, }; struct _EMFolderViewEnable { diff --git a/mail/message-list.c b/mail/message-list.c index 57047a857e..ab48b5e816 100644 --- a/mail/message-list.c +++ b/mail/message-list.c @@ -461,32 +461,6 @@ get_normalised_string (MessageList *message_list, CamelMessageInfo *info, int co return e_poolv_get (poolv, index); } -struct search_func_data { - MessageList *message_list; - guint32 flags; - guint32 mask; - ETreePath path; -}; - -static gboolean -search_func (ETreeModel *model, ETreePath path, struct search_func_data *data) -{ - CamelMessageInfo *info; - - if (e_tree_model_node_is_root (data->message_list->model, path)) - return FALSE; - - info = get_message_info (data->message_list, path); - - if (info && (info->flags & data->mask) == data->flags) { - g_free(data->message_list->cursor_uid); - data->message_list->cursor_uid = NULL; - data->path = path; - return TRUE; - } - return FALSE; -} - static void clear_selection(MessageList *ml, struct _MLSelection *selection) { @@ -502,6 +476,88 @@ clear_selection(MessageList *ml, struct _MLSelection *selection) selection->folder_uri = NULL; } +static ETreePath +ml_search_forward(MessageList *ml, int start, int end, guint32 flags, guint32 mask) +{ + ETreePath path; + int row; + CamelMessageInfo *info; + ETreeTableAdapter *etta = e_tree_get_table_adapter(ml->tree); + + for (row = start; row <= end; row ++) { + path = e_tree_table_adapter_node_at_row(etta, row); + if (path + && (info = get_message_info(ml, path)) + && (info->flags & mask) == flags) + return path; + } + + return NULL; +} + +static ETreePath +ml_search_backward(MessageList *ml, int start, int end, guint32 flags, guint32 mask) +{ + ETreePath path; + int row; + CamelMessageInfo *info; + ETreeTableAdapter *etta = e_tree_get_table_adapter(ml->tree); + + for (row = start; row >= end; row --) { + path = e_tree_table_adapter_node_at_row(etta, row); + if (path + && (info = get_message_info(ml, path)) + && (info->flags & mask) == flags) + return path; + } + + return NULL; +} + +static ETreePath +ml_search_path(MessageList *ml, MessageListSelectDirection direction, guint32 flags, guint32 mask) +{ + ETreePath node; + int row, count; + ETreeTableAdapter *etta = e_tree_get_table_adapter(ml->tree); + + if (ml->cursor_uid == NULL + || (node = g_hash_table_lookup(ml->uid_nodemap, ml->cursor_uid)) == NULL) + return NULL; + + row = e_tree_table_adapter_row_of_node(etta, node); + if (row == -1) + return NULL; + count = e_table_model_row_count((ETableModel *)etta); + + if ((direction & MESSAGE_LIST_SELECT_DIRECTION) == MESSAGE_LIST_SELECT_NEXT) + node = ml_search_forward(ml, row + 1, count - 1, flags, mask); + else + node = ml_search_backward(ml, row-1, 0, flags, mask); + + if (node == NULL && (direction & MESSAGE_LIST_SELECT_WRAP)) { + if ((direction & MESSAGE_LIST_SELECT_DIRECTION) == MESSAGE_LIST_SELECT_NEXT) + node = ml_search_forward(ml, 0, row, flags, mask); + else + node = ml_search_backward(ml, count-1, row, flags, mask); + } + + return node; +} + +static void +select_path(MessageList *ml, ETreePath path) +{ + ETreeSelectionModel *etsm = (ETreeSelectionModel *)e_tree_get_selection_model(ml->tree); + + g_free(ml->cursor_uid); + ml->cursor_uid = NULL; + + e_tree_table_adapter_show_node(e_tree_get_table_adapter(ml->tree), path); + e_tree_set_cursor(ml->tree, path); + e_tree_selection_model_select_single_path(etsm, path); +} + /** * message_list_select: * @message_list: a MessageList @@ -509,8 +565,6 @@ clear_selection(MessageList *ml, struct _MLSelection *selection) * @direction: the direction to search in * @flags: a set of flag values * @mask: a mask for comparing against @flags - * @wraparound: if %TRUE, go back to the beginning for - * the next match if necessary. * * This moves the message list selection to a suitable row. @base_row * lists the first (model) row to try, but as a special case, model @@ -518,43 +572,43 @@ clear_selection(MessageList *ml, struct _MLSelection *selection) * what constitutes a suitable row. @direction is * %MESSAGE_LIST_SELECT_NEXT if it should find the next matching * message, or %MESSAGE_LIST_SELECT_PREVIOUS if it should find the - * previous. If no suitable row is found, the selection will be + * previous. %MESSAGE_LIST_SELECT_WRAP is an option bit which specifies the + * search should wrap. + * + * If no suitable row is found, the selection will be * unchanged. * * Returns %TRUE if a new message has been selected or %FALSE otherwise. **/ gboolean -message_list_select (MessageList *message_list, - MessageListSelectDirection direction, - guint32 flags, - guint32 mask, - gboolean wraparound) -{ - struct search_func_data data; - ETreeFindNextParams params = 0; - - data.message_list = message_list; - data.flags = flags; - data.mask = mask; - data.path = NULL; - - if (direction == MESSAGE_LIST_SELECT_NEXT) - params |= E_TREE_FIND_NEXT_FORWARD; - else - params |= E_TREE_FIND_NEXT_BACKWARD; - - if (wraparound) - params |= E_TREE_FIND_NEXT_WRAP; - - if (e_tree_find_next (message_list->tree, params, (ETreePathFunc) search_func, &data)) { - ETreeSelectionModel *etsm = (ETreeSelectionModel *)e_tree_get_selection_model (message_list->tree); +message_list_select(MessageList *ml, MessageListSelectDirection direction, guint32 flags, guint32 mask) +{ + ETreePath path; - e_tree_selection_model_select_single_path(etsm, data.path); + path = ml_search_path(ml, direction, flags, mask); + if (path) { + select_path(ml, path); return TRUE; } else return FALSE; } +/** + * message_list_can_select: + * @ml: + * @direction: + * @flags: + * @mask: + * + * Returns true if the selection specified is possible with the current view. + * + * Return value: + **/ +gboolean +message_list_can_select(MessageList *ml, MessageListSelectDirection direction, guint32 flags, guint32 mask) +{ + return ml_search_path(ml, direction, flags, mask) != NULL; +} /** * message_list_select_uid: @@ -591,40 +645,33 @@ message_list_select_uid (MessageList *message_list, const char *uid) } } - void -message_list_select_next_thread (MessageList *message_list) +message_list_select_next_thread (MessageList *ml) { - ETreePath node, last; - - if (!message_list->cursor_uid) + ETreePath node; + ETreeTableAdapter *etta = e_tree_get_table_adapter(ml->tree); + int i, count, row; + + if (!ml->cursor_uid + || (node = g_hash_table_lookup(ml->uid_nodemap, ml->cursor_uid)) == NULL) return; - - /* get the thread parent node */ - last = node = g_hash_table_lookup (message_list->uid_nodemap, message_list->cursor_uid); - while (!e_tree_model_node_is_root (message_list->model, node)) { - last = node; - node = e_tree_model_node_get_parent (message_list->model, node); - } - - /* get the next toplevel node */ - node = e_tree_model_node_get_next (message_list->model, last); - - if (node) { - CamelMessageInfo *info; - - info = get_message_info (message_list, node); - e_tree_set_cursor (message_list->tree, node); - - g_free (message_list->cursor_uid); - message_list->cursor_uid = g_strdup (camel_message_info_uid (info)); - - g_signal_emit (GTK_OBJECT (message_list), message_list_signals[MESSAGE_SELECTED], 0, - camel_message_info_uid (info)); + + row = e_tree_table_adapter_row_of_node(etta, node); + if (row == -1) + return; + count = e_table_model_row_count((ETableModel *)etta); + + /* find the next node which has a root parent (i.e. toplevel node) */ + for (i=row+1;i<count-1;i++) { + node = e_tree_table_adapter_node_at_row(etta, i); + if (node + && e_tree_model_node_is_root(ml->model, e_tree_model_node_get_parent(ml->model, node))) { + select_path(ml, node); + return; + } } } - /** * message_list_select_all: * @message_list: Message List widget diff --git a/mail/message-list.h b/mail/message-list.h index c8ec571ec5..1c09c2ce9f 100644 --- a/mail/message-list.h +++ b/mail/message-list.h @@ -165,8 +165,10 @@ typedef void (*MessageListForeachFunc) (MessageList *message_list, gpointer user_data); typedef enum { - MESSAGE_LIST_SELECT_NEXT = 1, - MESSAGE_LIST_SELECT_PREVIOUS = -1 + MESSAGE_LIST_SELECT_NEXT = 0, + MESSAGE_LIST_SELECT_PREVIOUS = 1, + MESSAGE_LIST_SELECT_DIRECTION = 1, /* direction mask */ + MESSAGE_LIST_SELECT_WRAP = 1<<1, /* option bit */ } MessageListSelectDirection; GtkType message_list_get_type (void); @@ -188,8 +190,8 @@ void message_list_free_uids(MessageList *ml, GPtrArray *uids); gboolean message_list_select (MessageList *message_list, MessageListSelectDirection direction, guint32 flags, - guint32 mask, - gboolean wraparound); + guint32 mask); +gboolean message_list_can_select(MessageList *ml, MessageListSelectDirection direction, guint32 flags, guint32 mask); void message_list_select_uid (MessageList *message_list, const char *uid); |