static void on_notify_style (GObject *obj, GParamSpec *spec, gpointer userdata);
static void update_style (ModestHeaderView *self);
+static void modest_header_view_refilter_by_chunks (ModestHeaderView *self);
typedef enum {
HEADER_VIEW_NON_EMPTY,
ModestHeaderViewFilter filter;
#ifdef MODEST_TOOLKIT_HILDON2
GtkWidget *live_search;
+ guint live_search_timeout;
#endif
gint sort_colid[2][TNY_FOLDER_TYPE_NUM];
gboolean filter_date_range;
time_t date_range_start;
time_t date_range_end;
+
+ guint refilter_handler_id;
+ GtkTreeModel *filtered_model;
+ GtkTreeIter refilter_iter;
};
typedef struct _HeadersCountChangedHelper HeadersCountChangedHelper;
#define MODEST_HEADER_VIEW_PTR "modest-header-view"
+#define _HEADER_VIEW_SUBJECT_FOLD "_subject_modest_header_view"
+#define _HEADER_VIEW_FROM_FOLD "_from_modest_header_view"
+#define _HEADER_VIEW_TO_FOLD "_to_modest_header_view"
+#define _HEADER_VIEW_CC_FOLD "_cc_modest_header_view"
+#define _HEADER_VIEW_BCC_FOLD "_bcc_modest_header_view"
+
enum {
HEADER_SELECTED_SIGNAL,
HEADER_ACTIVATED_SIGNAL,
gboolean
modest_header_view_set_columns (ModestHeaderView *self, const GList *columns, TnyFolderType type)
{
- GtkTreeModel *sortable;
+ GtkTreeModel *sortable, *filter_model;
GtkTreeViewColumn *column=NULL;
GtkTreeSelection *selection = NULL;
GtkCellRenderer *renderer_header,
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(self));
gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
- sortable = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
+ sortable = NULL;
+ filter_model = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
+ if (GTK_IS_TREE_MODEL_FILTER (filter_model)) {
+ sortable = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (filter_model));
+ }
/* Add new columns */
for (cursor = columns; cursor; cursor = g_list_next(cursor)) {
priv->selection_changed_handler = 0;
priv->acc_removed_handler = 0;
+ priv->filtered_model = NULL;
+ priv->refilter_handler_id = 0;
+
/* Sort parameters */
for (j=0; j < 2; j++) {
for (i=0; i < TNY_FOLDER_TYPE_NUM; i++) {
self = MODEST_HEADER_VIEW(obj);
priv = MODEST_HEADER_VIEW_GET_PRIVATE(self);
+ if (priv->refilter_handler_id > 0) {
+ g_source_remove (priv->refilter_handler_id);
+ priv->refilter_handler_id = 0;
+ priv->filtered_model = NULL;
+ }
+
+#ifdef MODEST_TOOLKIT_HILDON2
+ if (priv->live_search_timeout > 0) {
+ g_source_remove (priv->live_search_timeout);
+ priv->live_search_timeout = 0;
+ }
+#endif
+
if (priv->datetime_formatter) {
g_object_unref (priv->datetime_formatter);
priv->datetime_formatter = NULL;
priv = MODEST_HEADER_VIEW_GET_PRIVATE(self);
headers = TNY_LIST (tny_gtk_header_list_model_new ());
+ tny_gtk_header_list_model_set_update_in_batches (TNY_GTK_HEADER_LIST_MODEL (headers), 300);
/* Start the monitor in the callback of the
tny_gtk_header_list_model_set_folder call. It's crucial to
set_folder_intern_get_headers_async_cb,
NULL, self);
- /* Create a tree model filter to hide and show rows for cut operations */
- filter_model = gtk_tree_model_filter_new (GTK_TREE_MODEL (headers), NULL);
- gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter_model),
- filter_row, self, NULL);
- g_object_unref (headers);
-
/* Init filter_row function to examine empty status */
priv->status = HEADER_VIEW_INIT;
/* Create sortable model */
- sortable = gtk_tree_model_sort_new_with_model (filter_model);
- g_object_unref (filter_model);
+ sortable = gtk_tree_model_sort_new_with_model (GTK_TREE_MODEL (headers));
+ g_object_unref (headers);
+
+ /* Create a tree model filter to hide and show rows for cut operations */
+ filter_model = gtk_tree_model_filter_new (GTK_TREE_MODEL (sortable), NULL);
+ gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (filter_model),
+ filter_row, self, NULL);
+ g_object_unref (sortable);
/* install our special sorting functions */
cursor = cols = gtk_tree_view_get_columns (GTK_TREE_VIEW(self));
}
/* Set new model */
- gtk_tree_view_set_model (GTK_TREE_VIEW (self), sortable);
+ gtk_tree_view_set_model (GTK_TREE_VIEW (self), filter_model);
modest_header_view_notify_observers (self, sortable, tny_folder_get_id (folder));
- g_object_unref (sortable);
+ g_object_unref (filter_model);
/* Free */
g_list_free (cols);
GtkSortType sort_type)
{
ModestHeaderViewPrivate *priv = NULL;
- GtkTreeModel *sortable = NULL;
+ GtkTreeModel *sortable = NULL, *filter_model = NULL;
TnyFolderType type;
g_return_if_fail (self && MODEST_IS_HEADER_VIEW(self));
/* Get model and private data */
priv = MODEST_HEADER_VIEW_GET_PRIVATE (self);
- sortable = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
+ filter_model = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
+ if (GTK_IS_TREE_MODEL_FILTER (filter_model)) {
+ sortable = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (filter_model));
+ }
/* Sort tree model */
type = modest_tny_folder_guess_folder_type (priv->folder);
static gboolean
header_match_string (TnyHeader *header, gchar **words)
{
- gchar *subject;
- gchar *cc;
- gchar *bcc;
- gchar *to;
- gchar *from;
gchar *subject_fold;
gchar *cc_fold;
gchar *bcc_fold;
gchar **current_word;
gboolean found;
- subject = tny_header_dup_subject (header);
- cc = tny_header_dup_cc (header);
- bcc = tny_header_dup_bcc (header);
- to = tny_header_dup_to (header);
- from = tny_header_dup_from (header);
-
- subject_fold = g_utf8_casefold (subject, -1);
- g_free (subject);
- bcc_fold = g_utf8_casefold (bcc, -1);
- g_free (bcc);
- cc_fold = g_utf8_casefold (cc, -1);
- g_free (cc);
- to_fold = g_utf8_casefold (to, -1);
- g_free (to);
- from_fold = g_utf8_casefold (from, -1);
- g_free (from);
+ subject_fold = g_object_get_data (G_OBJECT (header), _HEADER_VIEW_SUBJECT_FOLD);
+ if (subject_fold == NULL) {
+ gchar *subject;
+ subject = tny_header_dup_subject (header);
+ if (subject != NULL) {
+ subject_fold = subject?g_utf8_casefold (subject, -1):NULL;
+ g_object_set_data_full (G_OBJECT (header), _HEADER_VIEW_SUBJECT_FOLD,
+ subject_fold, (GDestroyNotify) g_free);
+ }
+ g_free (subject);
+ }
+
+ from_fold = g_object_get_data (G_OBJECT (header), _HEADER_VIEW_FROM_FOLD);
+ if (from_fold == NULL) {
+ gchar *from;
+ from = tny_header_dup_from (header);
+ if (from != NULL) {
+ from_fold = from?g_utf8_casefold (from, -1):NULL;
+ g_object_set_data_full (G_OBJECT (header), _HEADER_VIEW_FROM_FOLD,
+ from_fold, (GDestroyNotify) g_free);
+ }
+ g_free (from);
+ }
+
+ to_fold = g_object_get_data (G_OBJECT (header), _HEADER_VIEW_TO_FOLD);
+ if (to_fold == NULL) {
+ gchar *to;
+ to = tny_header_dup_to (header);
+ if (to != NULL) {
+ to_fold = to?g_utf8_casefold (to, -1):NULL;
+ g_object_set_data_full (G_OBJECT (header), _HEADER_VIEW_TO_FOLD,
+ to_fold, (GDestroyNotify) g_free);
+ }
+ g_free (to);
+ }
+
+ cc_fold = g_object_get_data (G_OBJECT (header), _HEADER_VIEW_CC_FOLD);
+ if (cc_fold == NULL) {
+ gchar *cc;
+ cc = tny_header_dup_cc (header);
+ if (cc != NULL) {
+ cc_fold = cc?g_utf8_casefold (cc, -1):NULL;
+ g_object_set_data_full (G_OBJECT (header), _HEADER_VIEW_CC_FOLD,
+ cc_fold, (GDestroyNotify) g_free);
+ }
+ g_free (cc);
+ }
+
+ bcc_fold = g_object_get_data (G_OBJECT (header), _HEADER_VIEW_BCC_FOLD);
+ if (bcc_fold == NULL) {
+ gchar *bcc;
+ bcc = tny_header_dup_bcc (header);
+ if (bcc != NULL) {
+ bcc_fold = bcc?g_utf8_casefold (bcc, -1):NULL;
+ g_object_set_data_full (G_OBJECT (header), _HEADER_VIEW_BCC_FOLD,
+ bcc_fold, (GDestroyNotify) g_free);
+ }
+ g_free (bcc);
+ }
found = TRUE;
for (current_word = words; *current_word != NULL; current_word++) {
- if ((subject && g_strstr_len (subject_fold, -1, *current_word))
- || (cc && g_strstr_len (cc_fold, -1, *current_word))
- || (bcc && g_strstr_len (bcc_fold, -1, *current_word))
- || (to && g_strstr_len (to_fold, -1, *current_word))
- || (from && g_strstr_len (from_fold, -1, *current_word))) {
+ if ((subject_fold && g_strstr_len (subject_fold, -1, *current_word))
+ || (cc_fold && g_strstr_len (cc_fold, -1, *current_word))
+ || (bcc_fold && g_strstr_len (bcc_fold, -1, *current_word))
+ || (to_fold && g_strstr_len (to_fold, -1, *current_word))
+ || (from_fold && g_strstr_len (from_fold, -1, *current_word))) {
found = TRUE;
} else {
found = FALSE;
}
}
- g_free (subject_fold);
- g_free (cc_fold);
- g_free (bcc_fold);
- g_free (to_fold);
- g_free (from_fold);
-
return found;
}
priv = MODEST_HEADER_VIEW_GET_PRIVATE (user_data);
/* Get header from model */
- gtk_tree_model_get_value (model, iter, TNY_GTK_HEADER_LIST_MODEL_FLAGS_COLUMN, &value);
- flags = (TnyHeaderFlags) g_value_get_int (&value);
- g_value_unset (&value);
gtk_tree_model_get_value (model, iter, TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN, &value);
header = (TnyHeader *) g_value_get_object (&value);
g_value_unset (&value);
+ flags = tny_header_get_flags (header);
/* Get message id from header (ensure is a valid id) */
if (!header) {
void
modest_header_view_refilter (ModestHeaderView *header_view)
{
- GtkTreeModel *model, *sortable = NULL;
+ GtkTreeModel *filter_model = NULL;
ModestHeaderViewPrivate *priv = NULL;
g_return_if_fail (header_view && MODEST_IS_HEADER_VIEW (header_view));
priv = MODEST_HEADER_VIEW_GET_PRIVATE(header_view);
/* Hide cut headers */
- sortable = gtk_tree_view_get_model (GTK_TREE_VIEW (header_view));
- if (GTK_IS_TREE_MODEL_SORT (sortable)) {
- model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (sortable));
- if (GTK_IS_TREE_MODEL_FILTER (model)) {
- priv->status = HEADER_VIEW_INIT;
- gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (model));
- }
+ filter_model = gtk_tree_view_get_model (GTK_TREE_VIEW (header_view));
+ if (GTK_IS_TREE_MODEL_FILTER (filter_model)) {
+ priv->status = HEADER_VIEW_INIT;
+ modest_header_view_refilter_by_chunks (header_view);
}
}
#ifdef MODEST_TOOLKIT_HILDON2
static gboolean
-on_live_search_refilter (HildonLiveSearch *livesearch,
- ModestHeaderView *self)
+on_live_search_timeout (ModestHeaderView *self)
{
const gchar *needle;
+ ModestHeaderViewPrivate *priv;
- needle = hildon_live_search_get_text (livesearch);
+ priv = MODEST_HEADER_VIEW_GET_PRIVATE (self);
+
+ needle = hildon_live_search_get_text ((HildonLiveSearch *) priv->live_search);
if (needle && needle[0] != '\0') {
modest_header_view_set_filter_string (MODEST_HEADER_VIEW (self), needle);
} else {
modest_header_view_set_filter_string (MODEST_HEADER_VIEW (self), NULL);
}
-
+
+ priv->live_search_timeout = 0;
+
+ return FALSE;
+}
+
+static gboolean
+on_live_search_refilter (HildonLiveSearch *livesearch,
+ ModestHeaderView *self)
+{
+ ModestHeaderViewPrivate *priv;
+ GtkTreeModel *model, *sortable, *filter;
+
+ priv = MODEST_HEADER_VIEW_GET_PRIVATE (self);
+
+ if (priv->live_search_timeout > 0) {
+ g_source_remove (priv->live_search_timeout);
+ priv->live_search_timeout = 0;
+ }
+
+ model = NULL;
+ filter = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
+ if (GTK_IS_TREE_MODEL_FILTER (filter)) {
+ sortable = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (filter));
+ if (GTK_IS_TREE_MODEL_SORT (sortable)) {
+ model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (sortable));
+ }
+ }
+
+ if (model && tny_list_get_length (TNY_LIST (model)) > 250) {
+ priv->live_search_timeout = g_timeout_add (1000, (GSourceFunc) on_live_search_timeout, self);
+ } else {
+ on_live_search_timeout (self);
+ }
+
return TRUE;
}
return priv->live_search;
}
#endif
+
+static gboolean
+refilter_idle_handler (gpointer userdata)
+{
+ ModestHeaderView *self = MODEST_HEADER_VIEW (userdata);
+ ModestHeaderViewPrivate *priv;
+ GtkTreeModel *filter_model;
+ GtkTreeModel *filtered_model;
+ gint i;
+ gboolean has_more;
+
+ priv = MODEST_HEADER_VIEW_GET_PRIVATE (self);
+ filter_model = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
+ filtered_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (filter_model));
+
+ if (filtered_model != priv->filtered_model) {
+ priv->refilter_handler_id = 0;
+ priv->filtered_model = NULL;
+ return FALSE;
+ }
+
+ if (!gtk_tree_model_sort_iter_is_valid (GTK_TREE_MODEL_SORT (filtered_model), &(priv->refilter_iter))) {
+ priv->refilter_handler_id = 0;
+ priv->filtered_model = NULL;
+ modest_header_view_refilter_by_chunks (self);
+ return FALSE;
+ }
+
+ i = 0;
+ do {
+ GtkTreePath *path;
+ path = gtk_tree_model_get_path (priv->filtered_model, &(priv->refilter_iter));
+ gtk_tree_model_row_changed (priv->filtered_model, path, &(priv->refilter_iter));
+ gtk_tree_path_free (path);
+ i++;
+
+ has_more = gtk_tree_model_iter_next (priv->filtered_model, &(priv->refilter_iter));
+ } while (i < 100 && has_more);
+
+ if (has_more) {
+ return TRUE;
+ } else {
+ priv->filtered_model = NULL;
+ priv->refilter_handler_id = 0;
+ return FALSE;
+ }
+}
+
+static void
+modest_header_view_refilter_by_chunks (ModestHeaderView *self)
+{
+ ModestHeaderViewPrivate *priv;
+ GtkTreeModel *filter_model;
+
+ g_return_if_fail (MODEST_IS_HEADER_VIEW (self));
+ priv = MODEST_HEADER_VIEW_GET_PRIVATE (self);
+
+ if (priv->refilter_handler_id > 0) {
+ g_source_remove (priv->refilter_handler_id);
+ priv->refilter_handler_id = 0;
+ }
+
+ filter_model = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
+ priv->filtered_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (filter_model));
+
+ if (gtk_tree_model_get_iter_first (priv->filtered_model, &(priv->refilter_iter))) {
+ priv->refilter_handler_id = g_idle_add (refilter_idle_handler, self);
+ }
+}