* Added a new signal that notifies about changes in the visible account id
[modest] / src / widgets / modest-folder-view.c
index a803c9d..5775a80 100644 (file)
@@ -44,6 +44,7 @@
 #include <tny-camel-folder.h>
 #include <tny-simple-list.h>
 #include <tny-camel-account.h>
+#include <modest-defs.h>
 #include <modest-tny-account.h>
 #include <modest-tny-folder.h>
 #include <modest-tny-local-folders-account.h>
@@ -189,6 +190,7 @@ static void         on_display_name_changed (ModestAccountMgr *self,
 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     inbox_is_special (TnyFolderStore *folder_store);
 
 static gboolean     get_inner_models        (ModestFolderView *self,
                                             GtkTreeModel **filter_model,
@@ -199,6 +201,7 @@ enum {
        FOLDER_SELECTION_CHANGED_SIGNAL,
        FOLDER_DISPLAY_NAME_CHANGED_SIGNAL,
        FOLDER_ACTIVATED_SIGNAL,
+       VISIBLE_ACCOUNT_CHANGED_SIGNAL,
        LAST_SIGNAL
 };
 
@@ -234,6 +237,7 @@ struct _ModestFolderViewPrivate {
 
        gboolean  reselect; /* we use this to force a reselection of the INBOX */
        gboolean  show_non_move;
+       TnyList   *list_to_move;
        gboolean  reexpand; /* next time we expose, we'll expand all root folders */
 
        GtkCellRenderer *messages_renderer;
@@ -336,6 +340,19 @@ modest_folder_view_class_init (ModestFolderViewClass *klass)
                              g_cclosure_marshal_VOID__POINTER,
                              G_TYPE_NONE, 1, G_TYPE_POINTER);
 
+       /*
+        * Emitted whenever the visible account changes
+        */
+       signals[VISIBLE_ACCOUNT_CHANGED_SIGNAL] =
+               g_signal_new ("visible-account-changed",
+                             G_TYPE_FROM_CLASS (gobject_class),
+                             G_SIGNAL_RUN_FIRST,
+                             G_STRUCT_OFFSET (ModestFolderViewClass,
+                                              visible_account_changed),
+                             NULL, NULL,
+                             g_cclosure_marshal_VOID__STRING,
+                             G_TYPE_NONE, 1, G_TYPE_STRING);
+
        treeview_class->select_cursor_parent = NULL;
 
 #ifdef MODEST_TOOLKIT_HILDON2
@@ -499,7 +516,7 @@ convert_parent_folders_to_dots (gchar **item_name)
 }
 
 static void
-format_compact_style (gchar **item_name, 
+format_compact_style (gchar **item_name,
                      GObject *instance,
                      gboolean bold,
                      gboolean multiaccount,
@@ -603,15 +620,11 @@ text_cell_data  (GtkTreeViewColumn *column,
                        }
                }
 
-               if (type == TNY_FOLDER_TYPE_INBOX) {
-                       g_free (fname);
-                       fname = g_strdup (_("mcen_me_folder_inbox"));
-               }
-
-               /* note: we cannot reliably get the counts from the tree model, we need
-                * to use explicit calls on tny_folder for some reason.
-                */
-               /* Select the number to show: the unread or unsent messages. in case of outbox/drafts, show all */
+               /* note: we cannot reliably get the counts from the
+                * tree model, we need to use explicit calls on
+                * tny_folder for some reason. Select the number to
+                * show: the unread or unsent messages. in case of
+                * outbox/drafts, show all */
                if ((type == TNY_FOLDER_TYPE_DRAFTS) ||
                    (type == TNY_FOLDER_TYPE_OUTBOX) ||
                    (type == TNY_FOLDER_TYPE_MERGE)) { /* _OUTBOX actually returns _MERGE... */
@@ -884,6 +897,13 @@ get_folder_icons (TnyFolderType type, GObject *instance)
                type = modest_tny_folder_guess_folder_type (TNY_FOLDER (instance));
        }
 
+       /* It's not enough with check the folder type. We need to
+          ensure that we're not giving a special folder icon to a
+          normal folder with the same name than a special folder */
+       if (TNY_IS_FOLDER (instance) &&
+           get_cmp_pos (type, TNY_FOLDER (instance)) ==  4)
+               type = TNY_FOLDER_TYPE_NORMAL;
+
        /* Remote folders should not be treated as special folders */
        if (TNY_IS_FOLDER_STORE (instance) &&
            !TNY_IS_ACCOUNT (instance) &&
@@ -1059,6 +1079,12 @@ add_columns (GtkWidget *treeview)
 
        /* Set icon and text render function */
        renderer = gtk_cell_renderer_pixbuf_new();
+#ifdef MODEST_TOOLKIT_HILDON2
+       g_object_set (renderer,
+                     "xpad", MODEST_MARGIN_DEFAULT,
+                     "ypad", MODEST_MARGIN_DEFAULT,
+                     NULL);
+#endif
        gtk_tree_view_column_pack_start (column, renderer, FALSE);
        gtk_tree_view_column_set_cell_data_func(column, renderer,
                                                icon_cell_data, treeview, NULL);
@@ -1067,6 +1093,7 @@ add_columns (GtkWidget *treeview)
        g_object_set (renderer, 
 #ifdef MODEST_TOOLKIT_HILDON2
                      "ellipsize", PANGO_ELLIPSIZE_MIDDLE,
+                     "ypad", MODEST_MARGIN_DEFAULT,
 #else
                      "ellipsize", PANGO_ELLIPSIZE_END,
 #endif
@@ -1077,8 +1104,14 @@ add_columns (GtkWidget *treeview)
 
        priv->messages_renderer = gtk_cell_renderer_text_new ();
        g_object_set (priv->messages_renderer, 
+#ifdef MODEST_TOOLKIT_HILDON2
+                     "yalign", 0.0,
+                     "ypad", MODEST_MARGIN_DEFAULT,
+                     "xpad", MODEST_MARGIN_DOUBLE,
+#else
                      "scale", PANGO_SCALE_X_SMALL,
                      "scale-set", TRUE,
+#endif
                      "alignment", PANGO_ALIGN_RIGHT,
                      "align-set", TRUE,
                      "xalign", 1.0,
@@ -1131,6 +1164,7 @@ modest_folder_view_init (ModestFolderView *obj)
        priv->filter = MODEST_FOLDER_VIEW_FILTER_NONE;
        priv->reselect = FALSE;
        priv->show_non_move = TRUE;
+       priv->list_to_move = NULL;
 
        /* Build treeview */
        add_columns (GTK_WIDGET (obj));
@@ -1244,6 +1278,11 @@ modest_folder_view_finalize (GObject *obj)
                priv->cur_folder_store = NULL;
        }
 
+       if (priv->list_to_move) {
+               g_object_unref (priv->list_to_move);
+               priv->list_to_move = NULL;
+       }
+
        /* Clear hidding array created by cut operation */
        _clear_hidding_filter (MODEST_FOLDER_VIEW (obj));
 
@@ -1654,6 +1693,135 @@ expand_root_items (ModestFolderView *self)
        gtk_tree_path_free (path);
 }
 
+static gboolean
+is_parent_of (TnyFolder *a, TnyFolder *b)
+{
+       const gchar *a_id;
+       gboolean retval = FALSE;
+
+       a_id = tny_folder_get_id (a);
+       if (a_id) {
+               gchar *string_to_match;
+               const gchar *b_id;
+
+               string_to_match = g_strconcat (a_id, "/", NULL);
+               b_id = tny_folder_get_id (b);
+               retval = g_str_has_prefix (b_id, string_to_match);
+               g_free (string_to_match);
+       }
+       
+       return retval;
+}
+
+typedef struct _ForeachFolderInfo {
+       gchar *needle;
+       gboolean found;
+} ForeachFolderInfo;
+
+static gboolean 
+foreach_folder_with_id (GtkTreeModel *model,
+                       GtkTreePath *path,
+                       GtkTreeIter *iter,
+                       gpointer data)
+{
+       ForeachFolderInfo *info;
+       GObject *instance;
+
+       info = (ForeachFolderInfo *) data;
+       gtk_tree_model_get (model, iter,
+                           INSTANCE_COLUMN, &instance,
+                           -1);
+
+       if (TNY_IS_FOLDER (instance)) {
+               const gchar *id;
+               gchar *collate;
+               id = tny_folder_get_id (TNY_FOLDER (instance));
+               if (id) {
+                       collate = g_utf8_collate_key (id, -1);
+                       info->found = !strcmp (info->needle, collate);
+                       g_free (collate);
+               }
+       }
+
+       return info->found;
+       
+}
+
+
+static gboolean
+has_folder_with_id (ModestFolderView *self, const gchar *id)
+{
+       GtkTreeModel *model;
+       ForeachFolderInfo info = {NULL, FALSE};
+
+       model = gtk_tree_view_get_model (GTK_TREE_VIEW (self));
+       info.needle = g_utf8_collate_key (id, -1);
+       
+       gtk_tree_model_foreach (model, foreach_folder_with_id, &info);
+       g_free (info.needle);
+
+       return info.found;
+}
+
+static gboolean
+has_child_with_name_of (ModestFolderView *self, TnyFolder *a, TnyFolder *b)
+{
+       const gchar *a_id;
+       gboolean retval = FALSE;
+
+       a_id = tny_folder_get_id (a);
+       if (a_id) {
+               const gchar *b_id;
+               b_id = tny_folder_get_id (b);
+               
+               if (b_id) {
+                       const gchar *last_bar;
+                       gchar *string_to_match;
+                       last_bar = g_strrstr (b_id, "/");
+                       if (last_bar)
+                               last_bar++;
+                       else
+                               last_bar = b_id;
+                       string_to_match = g_strconcat (a_id, "/", last_bar, NULL);
+                       retval = has_folder_with_id (self, string_to_match);
+                       g_free (string_to_match);
+               }
+       }
+
+       return retval;
+}
+
+static gboolean
+check_move_to_this_folder_valid (ModestFolderView *self, TnyFolder *folder)
+{
+       ModestFolderViewPrivate *priv;
+       TnyIterator *iterator;
+       gboolean retval = TRUE;
+
+       g_return_val_if_fail (MODEST_IS_FOLDER_VIEW (self), FALSE);
+       priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
+
+       for (iterator = tny_list_create_iterator (priv->list_to_move);
+            retval && !tny_iterator_is_done (iterator);
+            tny_iterator_next (iterator)) {
+               GObject *instance;
+               instance = tny_iterator_get_current (iterator);
+               if (instance == (GObject *) folder) {
+                       retval = FALSE;
+               } else if (TNY_IS_FOLDER (instance)) {
+                       retval = !is_parent_of (TNY_FOLDER (instance), folder);
+                       if (retval) {
+                               retval = !has_child_with_name_of (self, folder, TNY_FOLDER (instance));
+                       }
+               }
+               g_object_unref (instance);
+       }
+       g_object_unref (iterator);
+
+       return retval;
+}
+
+
 /*
  * We use this function to implement the
  * MODEST_FOLDER_VIEW_STYLE_SHOW_ONE style. We only show the default
@@ -1751,7 +1919,12 @@ filter_row (GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
        /* If this is a move to dialog, hide Sent, Outbox and Drafts
        folder as no message can be move there according to UI specs */
        if (!priv->show_non_move) {
-               if (TNY_IS_FOLDER (instance) && 
+               if (priv->list_to_move && 
+                   tny_list_get_length (priv->list_to_move) > 0 &&
+                   TNY_IS_FOLDER (instance)) {
+                       retval = check_move_to_this_folder_valid (MODEST_FOLDER_VIEW (data), TNY_FOLDER (instance));
+               }
+               if (retval && TNY_IS_FOLDER (instance) && 
                    modest_tny_folder_is_local_folder (TNY_FOLDER (instance))) {
                        switch (type) {
                        case TNY_FOLDER_TYPE_OUTBOX:
@@ -2104,6 +2277,32 @@ get_cmp_rows_type_pos (GObject *folder)
        }
 }
 
+static gboolean
+inbox_is_special (TnyFolderStore *folder_store)
+{
+       gboolean is_special = TRUE;
+
+       if (TNY_IS_FOLDER (folder_store)) {
+               const gchar *id;
+               gchar *downcase;
+               gchar *last_bar;
+               gchar *last_inbox_bar;
+
+               id = tny_folder_get_id (TNY_FOLDER (folder_store));
+               downcase = g_utf8_strdown (id, -1);
+               last_bar = g_strrstr (downcase, "/");
+               if (last_bar) {
+                       last_inbox_bar = g_strrstr  (downcase, "inbox/");
+                       if ((last_inbox_bar == NULL) || (last_inbox_bar + 5 != last_bar))
+                               is_special = FALSE;
+               } else {
+                       is_special = FALSE;
+               }
+               g_free (downcase);
+       }
+       return is_special;
+}
+
 static gint
 get_cmp_pos (TnyFolderType t, TnyFolder *folder_store)
 {
@@ -2124,23 +2323,7 @@ get_cmp_pos (TnyFolderType t, TnyFolder *folder_store)
                 * inbox of the account, or if it's a submailbox inbox. To do
                 * this we'll apply an heuristic rule: Find last "/" and check
                 * if it's preceeded by another Inbox */
-               if (is_special && TNY_IS_FOLDER (folder_store)) {
-                       const gchar *id;
-                       gchar *downcase;
-                       gchar *last_bar;
-                       gchar *last_inbox_bar;
-
-                       id = tny_folder_get_id (TNY_FOLDER (folder_store));
-                       downcase = g_utf8_strdown (id, -1);
-                       last_bar = g_strrstr (downcase, "/");
-                       if (last_bar) {
-                               last_inbox_bar = g_strrstr  (downcase, "inbox/");
-                               if ((last_inbox_bar == NULL) || (last_inbox_bar + 5 != last_bar))
-                                       is_special = FALSE;
-                       }
-                       g_free (downcase);
-               }
-
+               is_special = is_special && !inbox_is_special (TNY_FOLDER_STORE (folder_store));
                g_object_unref (account);
                return is_special?0:4;
        }
@@ -3101,6 +3284,11 @@ modest_folder_view_set_account_id_of_visible_server_account (ModestFolderView *s
        /* Save settings to gconf */
        modest_widget_memory_save (modest_runtime_get_conf (), G_OBJECT(self),
                                   MODEST_CONF_FOLDER_VIEW_KEY);
+
+       /* Notify observers */
+       g_signal_emit (G_OBJECT(self),
+                      signals[VISIBLE_ACCOUNT_CHANGED_SIGNAL], 0,
+                      account_id);
 }
 
 const gchar *
@@ -3529,18 +3717,39 @@ update_style (ModestFolderView *self)
 {
        ModestFolderViewPrivate *priv;
        GdkColor style_color;
+       PangoAttrList *attr_list;
+       GtkStyle *style;
+       PangoAttribute *attr;
 
        g_return_if_fail (MODEST_IS_FOLDER_VIEW (self));
        priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
 
+       /* Set color */
+
+       attr_list = pango_attr_list_new ();
        if (!gtk_style_lookup_color (GTK_WIDGET (self)->style, "SecondaryTextColor", &style_color)) {
                gdk_color_parse ("grey", &style_color);
        }
+       attr = pango_attr_foreground_new (style_color.red, style_color.green, style_color.blue);
+       pango_attr_list_insert (attr_list, attr);
+       
+       /* set font */
+       style = gtk_rc_get_style_by_paths (gtk_widget_get_settings
+                                          (GTK_WIDGET(self)),
+                                          "SmallSystemFont", NULL,
+                                          G_TYPE_NONE);
+       if (style) {
+               attr = pango_attr_font_desc_new (pango_font_description_copy
+                                                (style->font_desc));
+               pango_attr_list_insert (attr_list, attr);
 
-       g_object_set (G_OBJECT (priv->messages_renderer),
-                     "foreground-gdk", &style_color,
-                     "foreground-set", TRUE,
-                     NULL);
+               g_object_set (G_OBJECT (priv->messages_renderer),
+                             "foreground-gdk", &style_color,
+                             "foreground-set", TRUE,
+                             "attributes", attr_list,
+                             NULL);
+               pango_attr_list_unref (attr_list);
+       }
 }
 
 static void 
@@ -3587,3 +3796,54 @@ modest_folder_view_unset_filter (ModestFolderView *self,
                gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (filter_model));  
        }
 }
+
+gboolean
+modest_folder_view_any_folder_fulfils_rules (ModestFolderView *self,
+                                            ModestTnyFolderRules rules)
+{
+       GtkTreeModel *filter_model;
+       GtkTreeIter iter;
+       gboolean fulfil = FALSE;
+
+       if (!get_inner_models (self, &filter_model, NULL, NULL))
+               return FALSE;
+
+       if (!gtk_tree_model_get_iter_first (filter_model, &iter))
+               return FALSE;
+
+       do {
+               TnyFolderStore *folder;
+
+               gtk_tree_model_get (filter_model, &iter, INSTANCE_COLUMN, &folder, -1);
+               if (folder) {
+                       if (TNY_IS_FOLDER (folder)) {
+                               ModestTnyFolderRules folder_rules = modest_tny_folder_get_rules (TNY_FOLDER (folder));
+                               /* Folder rules are negative: non_writable, non_deletable... */
+                               if (!(folder_rules & rules))
+                                       fulfil = TRUE;
+                       }
+                       g_object_unref (folder);
+               }
+
+       } while (gtk_tree_model_iter_next (filter_model, &iter) && !fulfil);
+
+       return fulfil;
+}
+
+void 
+modest_folder_view_set_list_to_move (ModestFolderView *self,
+                                    TnyList *list)
+{
+       ModestFolderViewPrivate *priv;
+
+       g_return_if_fail (MODEST_IS_FOLDER_VIEW (self));
+       priv = MODEST_FOLDER_VIEW_GET_PRIVATE (self);
+
+       if (priv->list_to_move)
+               g_object_unref (priv->list_to_move);
+
+       if (list)
+               g_object_ref (list);
+
+       priv->list_to_move = list;
+}