X-Git-Url: http://git.maemo.org/git/?p=modest;a=blobdiff_plain;f=src%2Fmaemo%2Fmodest-msg-view-window.c;h=6bad4fe987a4c2b46bcf9cdb686839a5af6f5633;hp=a2144a39de989c2d1ddcf7c29030b8e07dedf3ec;hb=004e051469e80cc145ee2fb886682bd1ff07b213;hpb=f05f3bee660640d588296a7c388c1ca71c864324 diff --git a/src/maemo/modest-msg-view-window.c b/src/maemo/modest-msg-view-window.c index a2144a3..6bad4fe 100644 --- a/src/maemo/modest-msg-view-window.c +++ b/src/maemo/modest-msg-view-window.c @@ -155,9 +155,20 @@ static gboolean msg_is_visible (TnyHeader *header, gboolean check_outbox); static void check_dimming_rules_after_change (ModestMsgViewWindow *window); +static gboolean on_fetch_image (ModestMsgView *msgview, + const gchar *uri, + TnyStream *stream, + ModestMsgViewWindow *window); + +static gboolean modest_msg_view_window_scroll_child (ModestMsgViewWindow *self, + GtkScrollType scroll_type, + gboolean horizontal, + gpointer userdata); + /* list my signals */ enum { MSG_CHANGED_SIGNAL, + SCROLL_CHILD_SIGNAL, LAST_SIGNAL }; @@ -304,11 +315,43 @@ restore_settings (ModestMsgViewWindow *self) MODEST_CONF_MSG_VIEW_WINDOW_KEY); } +static gboolean modest_msg_view_window_scroll_child (ModestMsgViewWindow *self, + GtkScrollType scroll_type, + gboolean horizontal, + gpointer userdata) +{ + ModestMsgViewWindowPrivate *priv; + gboolean return_value; + + priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE(self); + g_signal_emit_by_name (priv->main_scroll, "scroll-child", scroll_type, horizontal, &return_value); + return return_value; +} + +static void +add_scroll_binding (GtkBindingSet *binding_set, + guint keyval, + GtkScrollType scroll) +{ + guint keypad_keyval = keyval - GDK_Left + GDK_KP_Left; + + gtk_binding_entry_add_signal (binding_set, keyval, 0, + "scroll_child", 2, + GTK_TYPE_SCROLL_TYPE, scroll, + G_TYPE_BOOLEAN, FALSE); + gtk_binding_entry_add_signal (binding_set, keypad_keyval, 0, + "scroll_child", 2, + GTK_TYPE_SCROLL_TYPE, scroll, + G_TYPE_BOOLEAN, FALSE); +} + static void modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass) { GObjectClass *gobject_class; ModestWindowClass *modest_window_class; + GtkBindingSet *binding_set; + gobject_class = (GObjectClass*) klass; modest_window_class = (ModestWindowClass *) klass; @@ -322,10 +365,10 @@ modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass) modest_window_class->show_toolbar_func = modest_msg_view_window_show_toolbar; modest_window_class->disconnect_signals_func = modest_msg_view_window_disconnect_signals; - g_type_class_add_private (gobject_class, sizeof(ModestMsgViewWindowPrivate)); - modest_window_class->save_state_func = save_state; + klass->scroll_child = modest_msg_view_window_scroll_child; + signals[MSG_CHANGED_SIGNAL] = g_signal_new ("msg-changed", G_TYPE_FROM_CLASS (gobject_class), @@ -334,6 +377,26 @@ modest_msg_view_window_class_init (ModestMsgViewWindowClass *klass) NULL, NULL, modest_marshal_VOID__POINTER_POINTER, G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_POINTER); + + signals[SCROLL_CHILD_SIGNAL] = + g_signal_new ("scroll-child", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET (ModestMsgViewWindowClass, scroll_child), + NULL, NULL, + modest_marshal_BOOLEAN__ENUM_BOOLEAN, + G_TYPE_BOOLEAN, 2, GTK_TYPE_SCROLL_TYPE, G_TYPE_BOOLEAN); + + binding_set = gtk_binding_set_by_class (klass); + add_scroll_binding (binding_set, GDK_Up, GTK_SCROLL_STEP_UP); + add_scroll_binding (binding_set, GDK_Down, GTK_SCROLL_STEP_DOWN); + add_scroll_binding (binding_set, GDK_Page_Up, GTK_SCROLL_PAGE_UP); + add_scroll_binding (binding_set, GDK_Page_Down, GTK_SCROLL_PAGE_DOWN); + add_scroll_binding (binding_set, GDK_Home, GTK_SCROLL_START); + add_scroll_binding (binding_set, GDK_End, GTK_SCROLL_END); + + g_type_class_add_private (gobject_class, sizeof(ModestMsgViewWindowPrivate)); + } static void modest_header_view_observer_init( @@ -684,12 +747,13 @@ modest_msg_view_window_finalize (GObject *obj) static gboolean select_next_valid_row (GtkTreeModel *model, GtkTreeRowReference **row_reference, - gboolean cycle) + gboolean cycle, + gboolean is_outbox) { GtkTreeIter tmp_iter; GtkTreePath *path; GtkTreePath *next = NULL; - gboolean retval = FALSE; + gboolean retval = FALSE, finished; g_return_val_if_fail (gtk_tree_row_reference_valid (*row_reference), FALSE); @@ -698,19 +762,55 @@ select_next_valid_row (GtkTreeModel *model, gtk_tree_row_reference_free (*row_reference); *row_reference = NULL; - if (gtk_tree_model_iter_next (model, &tmp_iter)) { - next = gtk_tree_model_get_path (model, &tmp_iter); - *row_reference = gtk_tree_row_reference_new (model, next); - retval = TRUE; - } else if (cycle && gtk_tree_model_get_iter_first (model, &tmp_iter)) { - next = gtk_tree_model_get_path (model, &tmp_iter); - - /* Ensure that we are not selecting the same */ - if (gtk_tree_path_compare (path, next) != 0) { - *row_reference = gtk_tree_row_reference_new (model, next); - retval = TRUE; + finished = FALSE; + do { + TnyHeader *header = NULL; + + if (gtk_tree_model_iter_next (model, &tmp_iter)) { + gtk_tree_model_get (model, &tmp_iter, + TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN, + &header, -1); + + if (header) { + if (msg_is_visible (header, is_outbox)) { + next = gtk_tree_model_get_path (model, &tmp_iter); + *row_reference = gtk_tree_row_reference_new (model, next); + retval = TRUE; + finished = TRUE; + } + g_object_unref (header); + header = NULL; + } + } else if (cycle && gtk_tree_model_get_iter_first (model, &tmp_iter)) { + next = gtk_tree_model_get_path (model, &tmp_iter); + + /* Ensure that we are not selecting the same */ + if (gtk_tree_path_compare (path, next) != 0) { + gtk_tree_model_get (model, &tmp_iter, + TNY_GTK_HEADER_LIST_MODEL_INSTANCE_COLUMN, + &header, -1); + if (header) { + if (msg_is_visible (header, is_outbox)) { + *row_reference = gtk_tree_row_reference_new (model, next); + retval = TRUE; + finished = TRUE; + } + g_object_unref (header); + header = NULL; + } + } else { + /* If we ended up in the same message + then there is no valid next + message */ + finished = TRUE; + } + } else { + /* If there are no more messages and we don't + want to start again in the first one then + there is no valid next message */ + finished = TRUE; } - } + } while (!finished); /* Free */ gtk_tree_path_free (path); @@ -786,6 +886,8 @@ modest_msg_view_window_construct (ModestMsgViewWindow *self, G_CALLBACK (modest_ui_actions_on_msg_recpt_activated), obj); g_signal_connect (G_OBJECT(priv->msg_view), "link_contextual", G_CALLBACK (modest_ui_actions_on_msg_link_contextual), obj); + g_signal_connect (G_OBJECT (priv->msg_view), "fetch_image", + G_CALLBACK (on_fetch_image), obj); g_signal_connect (G_OBJECT (obj), "key-release-event", G_CALLBACK (modest_msg_view_window_key_event), @@ -885,7 +987,7 @@ modest_msg_view_window_new_with_header_model (TnyMsg *msg, if (row_reference) { priv->row_reference = gtk_tree_row_reference_copy (row_reference); priv->next_row_reference = gtk_tree_row_reference_copy (row_reference); - select_next_valid_row (model, &(priv->next_row_reference), TRUE); + select_next_valid_row (model, &(priv->next_row_reference), TRUE, priv->is_outbox); } else { priv->row_reference = NULL; priv->next_row_reference = NULL; @@ -1101,7 +1203,7 @@ modest_msg_view_window_on_row_inserted (GtkTreeModel *model, priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference); select_next_valid_row (priv->header_model, - &(priv->next_row_reference), FALSE); + &(priv->next_row_reference), FALSE, priv->is_outbox); /* Connect the remaining callbacks to become able to detect * changes in header-view. */ @@ -1144,7 +1246,7 @@ modest_msg_view_window_on_row_reordered (GtkTreeModel *header_model, gtk_tree_row_reference_free (priv->next_row_reference); } priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference); - select_next_valid_row (header_model, &(priv->next_row_reference), FALSE); + select_next_valid_row (header_model, &(priv->next_row_reference), FALSE, priv->is_outbox); already_changed = TRUE; } gtk_tree_path_free (path); @@ -1159,7 +1261,7 @@ modest_msg_view_window_on_row_reordered (GtkTreeModel *header_model, gtk_tree_row_reference_free (priv->next_row_reference); } priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference); - select_next_valid_row (header_model, &(priv->next_row_reference), FALSE); + select_next_valid_row (header_model, &(priv->next_row_reference), FALSE, priv->is_outbox); } gtk_tree_path_free (path); } @@ -1532,10 +1634,10 @@ modest_msg_view_window_key_event (GtkWidget *window, event->keyval == GDK_Page_Down || event->keyval == GDK_KP_Page_Down || event->keyval == GDK_Home || event->keyval == GDK_KP_Home || event->keyval == GDK_End || event->keyval == GDK_KP_End) { - ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window); - gboolean return_value; + /* ModestMsgViewWindowPrivate *priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window); */ + /* gboolean return_value; */ - if (event->type == GDK_KEY_RELEASE) { + if (event->type == GDK_KEY_PRESS) { GtkScrollType scroll_type; switch (event->keyval) { @@ -1560,9 +1662,9 @@ modest_msg_view_window_key_event (GtkWidget *window, default: scroll_type = GTK_SCROLL_NONE; } - g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child", - scroll_type, FALSE, &return_value); - return TRUE; + /* g_signal_emit_by_name (G_OBJECT (priv->main_scroll), "scroll-child", */ + /* scroll_type, FALSE, &return_value); */ + return FALSE; } else { return FALSE; } @@ -1634,9 +1736,16 @@ modest_msg_view_window_is_search_result (ModestMsgViewWindow *window) static gboolean msg_is_visible (TnyHeader *header, gboolean check_outbox) { - return (!(tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED)) && - ( (!check_outbox) || (modest_tny_all_send_queues_get_msg_status (header) != MODEST_TNY_SEND_QUEUE_FAILED)) ; - + if ((tny_header_get_flags(header) & TNY_HEADER_FLAG_DELETED)) + return FALSE; + if (!check_outbox) { + return TRUE; + } else { + ModestTnySendQueueStatus status; + status = modest_tny_all_send_queues_get_msg_status (header); + return ((status != MODEST_TNY_SEND_QUEUE_FAILED) && + (status != MODEST_TNY_SEND_QUEUE_SENDING)); + } } gboolean @@ -1835,7 +1944,7 @@ modest_msg_view_window_select_next_message (ModestMsgViewWindow *window) if (!gtk_tree_row_reference_valid (priv->next_row_reference)) { if (gtk_tree_row_reference_valid (priv->row_reference)) { priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference); - select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE); + select_next_valid_row (priv->header_model, &(priv->next_row_reference), FALSE, priv->is_outbox); } } if (priv->next_row_reference) @@ -1949,7 +2058,7 @@ view_msg_cb (ModestMailOperation *mail_op, gtk_tree_row_reference_free (priv->next_row_reference); } priv->next_row_reference = gtk_tree_row_reference_copy (priv->row_reference); - select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE); + select_next_valid_row (priv->header_model, &(priv->next_row_reference), TRUE, priv->is_outbox); } /* Mark header as read */ @@ -2661,7 +2770,7 @@ modest_msg_view_window_save_attachments (ModestMsgViewWindow *window, TnyList *m GList *files_to_save = NULL; GtkWidget *save_dialog = NULL; gchar *folder = NULL; - const gchar *filename = NULL; + gchar *filename = NULL; gchar *save_multiple_str = NULL; g_return_if_fail (MODEST_IS_MSG_VIEW_WINDOW (window)); @@ -2685,7 +2794,7 @@ modest_msg_view_window_save_attachments (ModestMsgViewWindow *window, TnyList *m if (!modest_tny_mime_part_is_msg (mime_part) && modest_tny_mime_part_is_attachment_for_modest (mime_part) && !tny_mime_part_is_purged (mime_part)) { - filename = tny_mime_part_get_filename (mime_part); + filename = g_strdup (tny_mime_part_get_filename (mime_part)); } else { /* TODO: show any error? */ g_warning ("Tried to save a non-file attachment"); @@ -2707,9 +2816,11 @@ modest_msg_view_window_save_attachments (ModestMsgViewWindow *window, TnyList *m g_free (folder); /* set filename */ - if (filename != NULL) + if (filename) { gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (save_dialog), filename); + g_free (filename); + } /* if multiple, set multiple string */ if (save_multiple_str) { @@ -2935,3 +3046,116 @@ static void on_move_focus (GtkWidget *widget, g_signal_stop_emission_by_name (G_OBJECT (widget), "move-focus"); } +static TnyStream * +fetch_image_open_stream (TnyStreamCache *self, gint64 *expected_size, gchar *uri) +{ + GnomeVFSResult result; + GnomeVFSHandle *handle = NULL; + GnomeVFSFileInfo *info = NULL; + TnyStream *stream; + + result = gnome_vfs_open (&handle, uri, GNOME_VFS_OPEN_READ); + if (result != GNOME_VFS_OK) { + *expected_size = 0; + return NULL; + } + + info = gnome_vfs_file_info_new (); + result = gnome_vfs_get_file_info_from_handle (handle, info, GNOME_VFS_FILE_INFO_DEFAULT); + if (result != GNOME_VFS_OK || ! (info->valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE)) { + /* We put a "safe" default size for going to cache */ + *expected_size = (300*1024); + } else { + *expected_size = info->size; + } + gnome_vfs_file_info_unref (info); + + stream = tny_vfs_stream_new (handle); + + return stream; + +} + +typedef struct { + gchar *uri; + gchar *cache_id; + TnyStream *output_stream; + GtkWidget *msg_view; +} FetchImageData; + +gboolean +on_fetch_image_idle_refresh_view (gpointer userdata) +{ + + FetchImageData *fidata = (FetchImageData *) userdata; + g_message ("REFRESH VIEW"); + if (GTK_WIDGET_DRAWABLE (fidata->msg_view)) { + g_message ("QUEUING DRAW"); + gtk_widget_queue_draw (fidata->msg_view); + } + g_object_unref (fidata->msg_view); + g_slice_free (FetchImageData, fidata); + return FALSE; +} + +static gpointer +on_fetch_image_thread (gpointer userdata) +{ + FetchImageData *fidata = (FetchImageData *) userdata; + TnyStreamCache *cache; + TnyStream *cache_stream; + + cache = modest_runtime_get_images_cache (); + cache_stream = tny_stream_cache_get_stream (cache, fidata->cache_id, (TnyStreamCacheOpenStreamFetcher) fetch_image_open_stream, (gpointer) fidata->uri); + g_free (fidata->cache_id); + g_free (fidata->uri); + + if (cache_stream != NULL) { + tny_stream_write_to_stream (cache_stream, fidata->output_stream); + tny_stream_close (cache_stream); + g_object_unref (cache_stream); + } + + tny_stream_close (fidata->output_stream); + g_object_unref (fidata->output_stream); + + + gdk_threads_enter (); + g_idle_add (on_fetch_image_idle_refresh_view, fidata); + gdk_threads_leave (); + + return NULL; +} + +static gboolean +on_fetch_image (ModestMsgView *msgview, + const gchar *uri, + TnyStream *stream, + ModestMsgViewWindow *window) +{ + const gchar *current_account; + ModestMsgViewWindowPrivate *priv; + FetchImageData *fidata; + + priv = MODEST_MSG_VIEW_WINDOW_GET_PRIVATE (window); + + current_account = modest_window_get_active_account (MODEST_WINDOW (window)); + + fidata = g_slice_new0 (FetchImageData); + fidata->msg_view = g_object_ref (msgview); + fidata->uri = g_strdup (uri); + fidata->cache_id = modest_images_cache_get_id (current_account, uri); + fidata->output_stream = g_object_ref (stream); + + if (g_thread_create (on_fetch_image_thread, fidata, FALSE, NULL) == NULL) { + g_object_unref (fidata->output_stream); + g_free (fidata->cache_id); + g_free (fidata->uri); + g_object_unref (fidata->msg_view); + g_slice_free (FetchImageData, fidata); + tny_stream_close (stream); + return FALSE; + } + + return TRUE;; +}