X-Git-Url: http://git.maemo.org/git/?a=blobdiff_plain;f=src%2Fwidgets%2Fmodest-folder-view.c;h=64f9379d22790e55194752d20bbd419a30829bbb;hb=f43c0f52d3cd3dd76c80da510b2dda837ba05884;hp=a882bf89daed3325fe88902538a348d10544037d;hpb=e374da56f67092cecb1572dd4bee2ca34e0bc04c;p=modest diff --git a/src/widgets/modest-folder-view.c b/src/widgets/modest-folder-view.c index a882bf8..64f9379 100644 --- a/src/widgets/modest-folder-view.c +++ b/src/widgets/modest-folder-view.c @@ -62,7 +62,7 @@ #include #include #include "modest-dnd.h" -#include +#include "modest-ui-constants.h" #include "widgets/modest-window.h" /* Folder view drag types */ @@ -193,6 +193,11 @@ static void update_style (ModestFolderView *self); static void on_notify_style (GObject *obj, GParamSpec *spec, gpointer userdata); static gint get_cmp_pos (TnyFolderType t, TnyFolder *folder_store); +static gboolean get_inner_models (ModestFolderView *self, + GtkTreeModel **filter_model, + GtkTreeModel **sort_model, + GtkTreeModel **tny_model); + enum { FOLDER_SELECTION_CHANGED_SIGNAL, FOLDER_DISPLAY_NAME_CHANGED_SIGNAL, @@ -220,6 +225,7 @@ struct _ModestFolderViewPrivate { /* Filter tree model */ gchar **hidding_ids; guint n_selected; + ModestFolderViewFilter filter; TnyFolderStoreQuery *query; guint timer_expander; @@ -234,6 +240,8 @@ struct _ModestFolderViewPrivate { gboolean reexpand; /* next time we expose, we'll expand all root folders */ GtkCellRenderer *messages_renderer; + + gulong outbox_deleted_handler; }; #define MODEST_FOLDER_VIEW_GET_PRIVATE(o) \ (G_TYPE_INSTANCE_GET_PRIVATE((o), \ @@ -340,6 +348,41 @@ modest_folder_view_class_init (ModestFolderViewClass *klass) } +/* Retrieves the filter, sort and tny models of the folder view. If + any of these does not exist then it returns FALSE */ +static gboolean +get_inner_models (ModestFolderView *self, + GtkTreeModel **filter_model, + GtkTreeModel **sort_model, + GtkTreeModel **tny_model) +{ + GtkTreeModel *s_model, *f_model, *t_model; + + f_model = gtk_tree_view_get_model (GTK_TREE_VIEW (self)); + if (!GTK_IS_TREE_MODEL_FILTER(f_model)) { + g_warning ("BUG: %s: not a valid filter model", __FUNCTION__); + return FALSE; + } + + s_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (f_model)); + if (!GTK_IS_TREE_MODEL_SORT(s_model)) { + g_warning ("BUG: %s: not a valid sort model", __FUNCTION__); + return FALSE; + } + + t_model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (s_model)); + + /* Assign values */ + if (filter_model) + *filter_model = f_model; + if (sort_model) + *sort_model = s_model; + if (tny_model) + *tny_model = t_model; + + return TRUE; +} + /* Simplify checks for NULLs: */ static gboolean strings_are_equal (const gchar *a, const gchar *b) @@ -423,6 +466,42 @@ on_get_mmc_account_name (TnyStoreAccount* account, gpointer user_data) } static void +convert_parent_folders_to_dots (gchar **item_name) +{ + gint n_parents = 0; + gchar *c; + gchar *last_separator; + + if (item_name == NULL) + return; + + for (c = *item_name; *c != '\0'; c++) { + if (g_str_has_prefix (c, MODEST_FOLDER_PATH_SEPARATOR)) { + n_parents++; + } + } + + last_separator = g_strrstr (*item_name, MODEST_FOLDER_PATH_SEPARATOR); + if (last_separator != NULL) { + last_separator = last_separator + strlen (MODEST_FOLDER_PATH_SEPARATOR); + } + + if (n_parents > 0) { + GString *buffer; + gint i; + + buffer = g_string_new (""); + for (i = 0; i < n_parents; i++) { + buffer = g_string_append (buffer, MODEST_FOLDER_DOT); + } + buffer = g_string_append (buffer, last_separator); + g_free (*item_name); + *item_name = g_string_free (buffer, FALSE); + } + +} + +static void format_compact_style (gchar **item_name, GObject *instance, gboolean bold, @@ -451,6 +530,9 @@ format_compact_style (gchar **item_name, if (account == NULL) return; + /* convert parent folders to dots */ + convert_parent_folders_to_dots (item_name); + folder_name = tny_folder_get_name (folder); if (g_str_has_suffix (*item_name, folder_name)) { gchar *offset = g_strrstr (*item_name, folder_name); @@ -459,8 +541,7 @@ format_compact_style (gchar **item_name, } buffer = g_string_new (""); - buffer = g_string_append (buffer, tny_account_get_name (account)); - buffer = g_string_append (buffer, MODEST_FOLDER_PATH_SEPARATOR); + buffer = g_string_append (buffer, *item_name); if (concat_folder_name) { if (bold) buffer = g_string_append (buffer, ""); @@ -776,25 +857,25 @@ get_composite_icons (const gchar *icon_code, return retval; } -static ThreePixbufs* +static inline ThreePixbufs* get_folder_icons (TnyFolderType type, GObject *instance) { static GdkPixbuf *inbox_pixbuf = NULL, *outbox_pixbuf = NULL, *junk_pixbuf = NULL, *sent_pixbuf = NULL, *trash_pixbuf = NULL, *draft_pixbuf = NULL, - *normal_pixbuf = NULL, *anorm_pixbuf = NULL, + *normal_pixbuf = NULL, *anorm_pixbuf = NULL, *mmc_pixbuf = NULL, *ammc_pixbuf = NULL, *avirt_pixbuf = NULL; static GdkPixbuf *inbox_pixbuf_open = NULL, *outbox_pixbuf_open = NULL, *junk_pixbuf_open = NULL, *sent_pixbuf_open = NULL, *trash_pixbuf_open = NULL, *draft_pixbuf_open = NULL, - *normal_pixbuf_open = NULL, *anorm_pixbuf_open = NULL, + *normal_pixbuf_open = NULL, *anorm_pixbuf_open = NULL, *mmc_pixbuf_open = NULL, *ammc_pixbuf_open = NULL, *avirt_pixbuf_open = NULL; static GdkPixbuf *inbox_pixbuf_close = NULL, *outbox_pixbuf_close = NULL, *junk_pixbuf_close = NULL, *sent_pixbuf_close = NULL, *trash_pixbuf_close = NULL, *draft_pixbuf_close = NULL, - *normal_pixbuf_close = NULL, *anorm_pixbuf_close = NULL, + *normal_pixbuf_close = NULL, *anorm_pixbuf_close = NULL, *mmc_pixbuf_close = NULL, *ammc_pixbuf_close = NULL, *avirt_pixbuf_close = NULL; ThreePixbufs *retval = NULL; @@ -811,13 +892,21 @@ get_folder_icons (TnyFolderType type, GObject *instance) !TNY_IS_ACCOUNT (instance) && type != TNY_FOLDER_TYPE_INBOX && modest_tny_folder_store_is_remote (TNY_FOLDER_STORE (instance))) { +#ifdef MODEST_TOOLKIT_HILDON2 + return get_composite_icons (MODEST_FOLDER_ICON_ACCOUNT, + &anorm_pixbuf, + &anorm_pixbuf_open, + &anorm_pixbuf_close); +#else return get_composite_icons (MODEST_FOLDER_ICON_NORMAL, &normal_pixbuf, &normal_pixbuf_open, &normal_pixbuf_close); +#endif } switch (type) { + case TNY_FOLDER_TYPE_INVALID: g_warning ("%s: BUG: TNY_FOLDER_TYPE_INVALID", __FUNCTION__); break; @@ -883,12 +972,26 @@ get_folder_icons (TnyFolderType type, GObject *instance) &draft_pixbuf_open, &draft_pixbuf_close); break; + case TNY_FOLDER_TYPE_ARCHIVE: + retval = get_composite_icons (MODEST_FOLDER_ICON_MMC_FOLDER, + &mmc_pixbuf, + &mmc_pixbuf_open, + &mmc_pixbuf_close); + break; case TNY_FOLDER_TYPE_NORMAL: default: - retval = get_composite_icons (MODEST_FOLDER_ICON_NORMAL, - &normal_pixbuf, - &normal_pixbuf_open, - &normal_pixbuf_close); + /* Memory card folders could have an special icon */ + if (modest_tny_folder_is_memory_card_folder (TNY_FOLDER (instance))) { + retval = get_composite_icons (MODEST_FOLDER_ICON_MMC_FOLDER, + &mmc_pixbuf, + &mmc_pixbuf_open, + &mmc_pixbuf_close); + } else { + retval = get_composite_icons (MODEST_FOLDER_ICON_NORMAL, + &normal_pixbuf, + &normal_pixbuf_open, + &normal_pixbuf_close); + } break; } @@ -1017,7 +1120,7 @@ modest_folder_view_init (ModestFolderView *obj) priv->cur_folder_store = NULL; priv->visible_account_id = NULL; priv->folder_to_select = NULL; - + priv->outbox_deleted_handler = 0; priv->reexpand = TRUE; /* Initialize the local account name */ @@ -1028,6 +1131,7 @@ modest_folder_view_init (ModestFolderView *obj) priv->clipboard = modest_runtime_get_email_clipboard (); priv->hidding_ids = NULL; priv->n_selected = 0; + priv->filter = MODEST_FOLDER_VIEW_FILTER_NONE; priv->reselect = FALSE; priv->show_non_move = TRUE; @@ -1076,6 +1180,7 @@ modest_folder_view_finalize (GObject *obj) { ModestFolderViewPrivate *priv; GtkTreeSelection *sel; + TnyAccount *local_account; g_return_if_fail (obj); @@ -1086,6 +1191,16 @@ modest_folder_view_finalize (GObject *obj) priv->timer_expander = 0; } + local_account = (TnyAccount *) + modest_tny_account_store_get_local_folders_account ((ModestTnyAccountStore *)priv->account_store); + if (local_account) { + if (g_signal_handler_is_connected (local_account, + priv->outbox_deleted_handler)) + g_signal_handler_disconnect (local_account, + priv->outbox_deleted_handler); + g_object_unref (local_account); + } + if (priv->account_store) { g_signal_handler_disconnect (G_OBJECT(priv->account_store), priv->account_inserted_signal); @@ -1190,12 +1305,34 @@ modest_folder_view_set_account_store (TnyAccountStoreView *self, TnyAccountStore } static void +on_outbox_deleted_cb (ModestTnyLocalFoldersAccount *local_account, + gpointer user_data) +{ + ModestFolderView *self; + GtkTreeModel *model, *filter_model; + TnyFolder *outbox; + + self = MODEST_FOLDER_VIEW (user_data); + + if (!get_inner_models (self, &filter_model, NULL, &model)) + return; + + /* Remove outbox from model */ + outbox = modest_tny_local_folders_account_get_merged_outbox (local_account); + tny_list_remove (TNY_LIST (model), G_OBJECT (outbox)); + g_object_unref (outbox); + + /* Refilter view */ + gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filter_model)); +} + +static void on_account_inserted (TnyAccountStore *account_store, TnyAccount *account, gpointer user_data) { ModestFolderViewPrivate *priv; - GtkTreeModel *sort_model, *filter_model; + GtkTreeModel *model, *filter_model; /* Ignore transport account insertions, we're not showing them in the folder view */ @@ -1213,31 +1350,29 @@ on_account_inserted (TnyAccountStore *account_store, G_OBJECT (user_data), MODEST_CONF_FOLDER_VIEW_KEY); - if (!GTK_IS_TREE_VIEW(user_data)) { - g_warning ("BUG: %s: not a valid tree view", __FUNCTION__); - return; - } - - /* Get the inner model */ - /* check, is some rare cases, we did not get the right thing here, - * NB#84097 */ - filter_model = gtk_tree_view_get_model (GTK_TREE_VIEW (user_data)); - if (!GTK_IS_TREE_MODEL_FILTER(filter_model)) { - g_warning ("BUG: %s: not a valid filter model", __FUNCTION__); - return; - } - /* check, is some rare cases, we did not get the right thing here, - * NB#84097 */ - sort_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (filter_model)); - if (!GTK_IS_TREE_MODEL_SORT(sort_model)) { - g_warning ("BUG: %s: not a valid sort model", __FUNCTION__); + /* Get models */ + if (!get_inner_models (MODEST_FOLDER_VIEW (user_data), + &filter_model, NULL, &model)) return; - } /* Insert the account in the model */ - tny_list_append (TNY_LIST (gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (sort_model))), - G_OBJECT (account)); + tny_list_append (TNY_LIST (model), G_OBJECT (account)); + + /* When the model is a list store (plain representation) the + outbox is not a child of any account so we have to manually + delete it because removing the local folders account won't + delete it (because tny_folder_get_account() is not defined + for a merge folder */ + if (TNY_IS_GTK_FOLDER_LIST_STORE (model) && + MODEST_IS_TNY_LOCAL_FOLDERS_ACCOUNT (account)) { + + priv->outbox_deleted_handler = + g_signal_connect (account, + "outbox-deleted", + G_CALLBACK (on_outbox_deleted_cb), + user_data); + } /* Refilter the model */ gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filter_model)); @@ -1295,7 +1430,7 @@ on_account_changed (TnyAccountStore *account_store, { ModestFolderView *self; ModestFolderViewPrivate *priv; - GtkTreeModel *sort_model, *filter_model; + GtkTreeModel *model, *filter_model; GtkTreeSelection *sel; gboolean same_account; @@ -1304,26 +1439,15 @@ on_account_changed (TnyAccountStore *account_store, if (TNY_IS_TRANSPORT_ACCOUNT (tny_account)) return; - if (!MODEST_IS_FOLDER_VIEW(user_data)) { - g_warning ("BUG: %s: not a valid folder view", __FUNCTION__); - return; - } - self = MODEST_FOLDER_VIEW (user_data); priv = MODEST_FOLDER_VIEW_GET_PRIVATE (user_data); /* Get the inner model */ - filter_model = gtk_tree_view_get_model (GTK_TREE_VIEW (user_data)); - if (!GTK_IS_TREE_MODEL_FILTER(filter_model)) { - g_warning ("BUG: %s: not a valid filter model", __FUNCTION__); + if (!get_inner_models (MODEST_FOLDER_VIEW (user_data), + &filter_model, NULL, &model)) return; - } - sort_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (filter_model)); - if (!GTK_IS_TREE_MODEL_SORT(sort_model)) { - g_warning ("BUG: %s: not a valid sort model", __FUNCTION__); - return; - } + filter_model = gtk_tree_view_get_model (GTK_TREE_VIEW (user_data)); /* Invalidate the cur_folder_store only if the selected folder belongs to the account that is being removed */ @@ -1334,12 +1458,10 @@ on_account_changed (TnyAccountStore *account_store, } /* Remove the account from the model */ - tny_list_remove (TNY_LIST (gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (sort_model))), - G_OBJECT (tny_account)); + tny_list_remove (TNY_LIST (model), G_OBJECT (tny_account)); /* Insert the account in the model */ - tny_list_append (TNY_LIST (gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (sort_model))), - G_OBJECT (tny_account)); + tny_list_append (TNY_LIST (model), G_OBJECT (tny_account)); /* Refilter the model */ gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filter_model)); @@ -1357,7 +1479,7 @@ on_account_removed (TnyAccountStore *account_store, { ModestFolderView *self = NULL; ModestFolderViewPrivate *priv; - GtkTreeModel *sort_model, *filter_model; + GtkTreeModel *model, *filter_model; GtkTreeSelection *sel = NULL; gboolean same_account = FALSE; @@ -1396,21 +1518,21 @@ on_account_removed (TnyAccountStore *account_store, g_object_unref (folder_to_select_account); } - /* Remove the account from the model */ - filter_model = gtk_tree_view_get_model (GTK_TREE_VIEW (self)); - if (!GTK_IS_TREE_MODEL_FILTER(filter_model)) { - g_warning ("BUG: %s: not a valid filter model", __FUNCTION__); + if (!get_inner_models (MODEST_FOLDER_VIEW (user_data), + &filter_model, NULL, &model)) return; - } - sort_model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER (filter_model)); - if (!GTK_IS_TREE_MODEL_SORT(sort_model)) { - g_warning ("BUG: %s: not a valid sort model", __FUNCTION__); - return; + /* Disconnect the signal handler */ + if (TNY_IS_GTK_FOLDER_LIST_STORE (model) && + MODEST_IS_TNY_LOCAL_FOLDERS_ACCOUNT (account)) { + if (g_signal_handler_is_connected (account, + priv->outbox_deleted_handler)) + g_signal_handler_disconnect (account, + priv->outbox_deleted_handler); } - tny_list_remove (TNY_LIST (gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (sort_model))), - G_OBJECT (account)); + /* Remove the account from the model */ + tny_list_remove (TNY_LIST (model), G_OBJECT (account)); /* If the removed account is the currently viewed one then clear the configuration value. The new visible account will be the default account */ @@ -1551,6 +1673,7 @@ filter_row (GtkTreeModel *model, GtkTreeIter *iter, gpointer data) guint i; gboolean found = FALSE; gboolean cleared = FALSE; + ModestTnyFolderRules rules = 0; g_return_val_if_fail (MODEST_IS_FOLDER_VIEW (data), FALSE); priv = MODEST_FOLDER_VIEW_GET_PRIVATE (data); @@ -1658,6 +1781,82 @@ filter_row (GtkTreeModel *model, GtkTreeIter *iter, gpointer data) } } + /* apply special filters */ + if (retval && (priv->filter & MODEST_FOLDER_VIEW_FILTER_CAN_HAVE_FOLDERS)) { + if (TNY_IS_FOLDER (instance)) { + TnyFolderCaps capabilities; + + capabilities = tny_folder_get_caps (TNY_FOLDER (instance)); + retval = !(capabilities & TNY_FOLDER_CAPS_NOCHILDREN); + + if (retval) { + retval = ((type != TNY_FOLDER_TYPE_DRAFTS) && + (type != TNY_FOLDER_TYPE_OUTBOX) && + (type != TNY_FOLDER_TYPE_SENT)); + } + } else if (TNY_IS_ACCOUNT (instance)) { + retval = FALSE; + } + } + + if (retval && (priv->filter & MODEST_FOLDER_VIEW_FILTER_HIDE_MANDATORY_FOLDERS)) { + if (TNY_IS_FOLDER (instance)) { + TnyFolderType guess_type; + + if (TNY_FOLDER_TYPE_NORMAL) { + guess_type = modest_tny_folder_guess_folder_type (TNY_FOLDER (instance)); + } else { + guess_type = type; + } + + switch (type) { + case TNY_FOLDER_TYPE_OUTBOX: + case TNY_FOLDER_TYPE_SENT: + case TNY_FOLDER_TYPE_DRAFTS: + case TNY_FOLDER_TYPE_ARCHIVE: + case TNY_FOLDER_TYPE_INBOX: + retval = FALSE; + break; + case TNY_FOLDER_TYPE_UNKNOWN: + case TNY_FOLDER_TYPE_NORMAL: + break; + default: + break; + } + + } else if (TNY_IS_ACCOUNT (instance)) { + retval = FALSE; + } + } + + if (retval && TNY_IS_FOLDER (instance)) { + rules = modest_tny_folder_get_rules (TNY_FOLDER (instance)); + } + + if (retval && (priv->filter & MODEST_FOLDER_VIEW_FILTER_DELETABLE)) { + if (TNY_IS_FOLDER (instance)) { + retval = !(rules & MODEST_FOLDER_RULES_FOLDER_NON_DELETABLE); + } else if (TNY_IS_ACCOUNT (instance)) { + retval = FALSE; + } + } + + if (retval && (priv->filter & MODEST_FOLDER_VIEW_FILTER_RENAMEABLE)) { + if (TNY_IS_FOLDER (instance)) { + retval = !(rules & MODEST_FOLDER_RULES_FOLDER_NON_RENAMEABLE); + } else if (TNY_IS_ACCOUNT (instance)) { + retval = FALSE; + } + } + + if (retval && (priv->filter & MODEST_FOLDER_VIEW_FILTER_MOVEABLE)) { + if (TNY_IS_FOLDER (instance)) { + retval = !(rules & MODEST_FOLDER_RULES_FOLDER_NON_MOVEABLE); + } else if (TNY_IS_ACCOUNT (instance)) { + retval = FALSE; + } + } + /* Free */ g_object_unref (instance); @@ -1699,6 +1898,31 @@ modest_folder_view_update_model (ModestFolderView *self, model = tny_gtk_folder_store_tree_model_new (NULL); #endif + /* When the model is a list store (plain representation) the + outbox is not a child of any account so we have to manually + delete it because removing the local folders account won't + delete it (because tny_folder_get_account() is not defined + for a merge folder */ + if (TNY_IS_GTK_FOLDER_LIST_STORE (model)) { + TnyAccount *account; + ModestTnyAccountStore *acc_store; + + acc_store = MODEST_TNY_ACCOUNT_STORE (priv->account_store); + account = modest_tny_account_store_get_local_folders_account (acc_store); + + if (g_signal_handler_is_connected (account, + priv->outbox_deleted_handler)) + g_signal_handler_disconnect (account, + priv->outbox_deleted_handler); + + priv->outbox_deleted_handler = + g_signal_connect (account, + "outbox-deleted", + G_CALLBACK (on_outbox_deleted_cb), + self); + g_object_unref (account); + } + /* Get the accounts: */ tny_account_store_get_accounts (TNY_ACCOUNT_STORE(account_store), TNY_LIST (model), @@ -3292,3 +3516,20 @@ on_notify_style (GObject *obj, GParamSpec *spec, gpointer userdata) } } +void +modest_folder_view_set_filter (ModestFolderView *self, + ModestFolderViewFilter filter) +{ + ModestFolderViewPrivate *priv; + GtkTreeModel *filter_model; + + g_return_if_fail (MODEST_IS_FOLDER_VIEW (self)); + priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self); + + priv->filter = filter; + + filter_model = gtk_tree_view_get_model (GTK_TREE_VIEW (self)); + if (GTK_IS_TREE_MODEL_FILTER(filter_model)) { + gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filter_model)); + } +}