From: Jose Dapena Paz Date: Sun, 1 Apr 2007 13:03:27 +0000 (+0000) Subject: * src/maemo/modest-msg-edit-window.c: added support for rich editing X-Git-Tag: git_migration_finished~3965 X-Git-Url: http://git.maemo.org/git/?p=modest;a=commitdiff_plain;h=f65cf12510835b6adb63cf583872995940d6daa4 * src/maemo/modest-msg-edit-window.c: added support for rich editing (using wpeditor library). * Includes support for toggling bold/italics, adding bullet lists, inserting images, changing font color, size and face. * src/maemo/modest-icon-names.h: * Added icon for bullet lists in edit window. * src/gnome/modest-icon-names.h: * Added icon for bullet lists in edit window. * src/maemo/ui/modest-msg-edit-window-ui.xml: * Added menu formatting actions (inserting images, alignments, background color, bullet lists). * Added toolbar formatting actions (bold, italics, bullet lists), and a place holder for font properties elements in toolbar. * src/maemo/ui/modest-msg-view-window-ui.xml: * Added menu actions for messages (not implemented yet, includes replying, deleting, and others. * src/gnome/modest-msg-edit-window.c: * Modified methods to send mail to support the new API supporting rich text editting. Anyway the Gnome client does not support this yet. * src/widgets/modest-mail-header-view.[ch]: * Now date/time field separates the Time: value as a new field, and it's always shown independent from being a mail sent another day. * Preliminar support for showing priority icons in subjects. Now subject is showin as a GTKHBox, with a first part for priority icon (currently not used) and a second part for the subject itself. * Changed order of header fields (recipients in special) to accomplish the UI specs. * Added new method to add custom headers (header data implemented with a widget). This is used for adding attachments list as a header. * src/widgets/modest-msg-edit-window.h: * Added support for exposing rich text editing format. * Added src/widgets/modest-attachment-view.[ch]: * Widget showing an only attachment, with its size and icon. It's a refactoring of previous attachments view, splitting in specific widgets each attachment. * src/widgets/modest-attachments-view.[ch]: big rework of this widget. * Now the "activated" signal passes a TnyMimePart instead of an attachmetn index. * Now it's a GtkVBox with the attachments one per line. They include the new ModestAttachmentView for showing each mime part. * src/widgets/modest-msg-edit-window-ui.h: * Added support for rich editing actions. * src/widgets/Makefile.am: * Added compilation of new ModestAttachmentView widget. * src/widgets/modest-msg-view.[ch]: * Now attachments signal returns a TnyMimePart instead of an index. * Now attachments are shown as a header, using the new modest_header_view_add_custom_header method. * src/modest-tny-msg.[ch]: * Support for sending html-formatted mails. * src/modest-mail-operations.[ch]: * Now ..._send_new_mail gets both plain text and html versions of the message, to allow sending rich text messages. * src/modest-runtime.c: * Add bullet list icons. * src/modest-main.c: * Use the new _send_new_mail api supporting rich text messages (sends a NULL html field, as the command line API is only supporting plain text sends). * src/modest-ui-actions.[ch]: * Update on_msg_attachment_clicked, as now it gets a TnyMimePart instead of an index. * (modest_ui_actions_on_send): updated to handle rich text messages (those with html and raw text versions). * Methods for rich text editor actions: ..._on_toggle_bold, ..._on_toggle_italics, ..._on_toggle_bullets, ..._on_change_justify, ..._on_select_editor_color, ..._on_select_editor_background_color, ..._on_insert_image. pmo-trunk-r1469 --- diff --git a/src/gnome/modest-icon-names.h b/src/gnome/modest-icon-names.h index 6fddd7d..75f5833 100644 --- a/src/gnome/modest-icon-names.h +++ b/src/gnome/modest-icon-names.h @@ -75,6 +75,7 @@ /* #define MODEST_TOOLBAR_ICON_NEXT PIXMAP_PREFIX "forward.png" */ /* #define MODEST_TOOLBAR_ICON_PREV PIXMAP_PREFIX "back.png" */ #define MODEST_TOOLBAR_ICON_STOP PIXMAP_PREFIX "stock-stop.png" +#define MODEST_TOOLBAR_ICON_FORMAT_BULLETS PIXMAP_PREFIX "qgn_list_gene_bullets" /* Stock icon names */ #define MODEST_STOCK_MAIL_SEND "modest-stock-mail-send" diff --git a/src/gnome/modest-msg-edit-window.c b/src/gnome/modest-msg-edit-window.c index 2ed3095..62d56a0 100644 --- a/src/gnome/modest-msg-edit-window.c +++ b/src/gnome/modest-msg-edit-window.c @@ -402,7 +402,9 @@ modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window) data->cc = (gchar*) gtk_entry_get_text (GTK_ENTRY(priv->cc_field)); data->bcc = (gchar*) gtk_entry_get_text (GTK_ENTRY(priv->bcc_field)); data->subject = (gchar*) gtk_entry_get_text (GTK_ENTRY(priv->subject_field)); - data->body = gtk_text_buffer_get_text (buf, &b, &e, FALSE); + data->plain_body = gtk_text_buffer_get_text (buf, &b, &e, FALSE); + /* No rich supported yet, then html body is NULL */ + data->html_body = NULL; return data; } @@ -414,6 +416,76 @@ modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window, g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window)); g_free (data->from); - g_free (data->body); + g_free (data->plain_body); + g_free (data->html_body); g_slice_free (MsgData, data); } + +/* Rich formatting API functions */ +ModestMsgEditFormat +modest_msg_edit_window_get_format (ModestMsgEditWindow *self) +{ + return MODEST_MSG_EDIT_FORMAT_TEXT; +} + +void +modest_msg_edit_window_set_format (ModestMsgEditWindow *self, + ModestMsgEditFormat format) +{ + switch (format) { + case MODEST_MSG_EDIT_FORMAT_TEXT: + break; + case MODEST_MSG_EDIT_FORMAT_HTML: + g_message ("HTML format not supported in Gnome ModestMsgEditWindow"); + break; + default: + break; + } +} + +ModestMsgEditFormatState * +modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self) +{ + ModestMsgEditFormatState *format_state; + + g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL); + + format_state = g_new0 (ModestMsgEditFormatState, 1); + + return format_state; +} + +void +modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self, + const ModestMsgEditFormatState *format_state) +{ + g_return_if_fail (MODEST_MSG_EDIT_WINDOW (self)); + + /* Ends silently as set_format_state should do nothing when edit window format + is not HTML */ + return; +} + +void +modest_msg_edit_window_select_color (ModestMsgEditWindow *window) +{ + g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window)); + + g_message ("Select color operation is not supported"); +} + +void +modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window) +{ + g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window)); + + g_message ("Select background color operation is not supported"); +} + +void +modest_msg_edit_window_insert_image (ModestMsgEditWindow *window) +{ + g_return_if_fail (MODEST_MSG_EDIT_WINDOW (window)); + + g_message ("Insert image operation is not supported"); +} diff --git a/src/maemo/modest-icon-names.h b/src/maemo/modest-icon-names.h index 3dd8b1e..4ce0b0b 100644 --- a/src/maemo/modest-icon-names.h +++ b/src/maemo/modest-icon-names.h @@ -71,6 +71,7 @@ #define MODEST_TOOLBAR_ICON_REPLY_ALL "qgn_toolb_messagin_replytoall" #define MODEST_TOOLBAR_ICON_FORWARD "qgn_toolb_messagin_forward" #define MODEST_TOOLBAR_ICON_DELETE "qgn_toolb_messagin_delete" +#define MODEST_TOOLBAR_ICON_FORMAT_BULLETS "qgn_list_gene_bullets" /* Stock icon names */ #define MODEST_STOCK_MAIL_SEND "modest-stock-mail-send" diff --git a/src/maemo/modest-msg-edit-window.c b/src/maemo/modest-msg-edit-window.c index 3ff45da..dc6cf2f 100644 --- a/src/maemo/modest-msg-edit-window.c +++ b/src/maemo/modest-msg-edit-window.c @@ -27,6 +27,8 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include +#include +#include #include #include @@ -46,11 +48,29 @@ #include "modest-tny-platform-factory.h" #include "modest-tny-msg.h" #include +#include +#include +#include +#include +#include + +#define DEFAULT_FONT_SIZE 3 +#define DEFAULT_FONT 2 +#define DEFAULT_SIZE_COMBOBOX_WIDTH 80 static void modest_msg_edit_window_class_init (ModestMsgEditWindowClass *klass); static void modest_msg_edit_window_init (ModestMsgEditWindow *obj); static void modest_msg_edit_window_finalize (GObject *obj); +static void text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window); +static void modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window, + gpointer userdata); +static void modest_msg_edit_window_size_combobox_change (ModestMsgEditWindow *window, + gpointer userdata); +static void modest_msg_edit_window_font_combobox_change (ModestMsgEditWindow *window, + gpointer userdata); +static void modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window); + /* list my signals */ enum { /* MY_SIGNAL_1, */ @@ -66,6 +86,15 @@ struct _ModestMsgEditWindowPrivate { GtkWidget *cc_field; GtkWidget *bcc_field; GtkWidget *subject_field; + + GtkTextBuffer *text_buffer; + + GtkWidget *font_color_button; + GtkWidget *size_combobox; + GtkWidget *font_combobox; + + gint last_cid; + GList *attachments; }; #define MODEST_MSG_EDIT_WINDOW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), \ @@ -97,6 +126,8 @@ modest_msg_edit_window_get_type (void) my_type = g_type_register_static (MODEST_TYPE_WINDOW, "ModestMsgEditWindow", &my_info, 0); + + wp_text_buffer_library_init (); } return my_type; } @@ -125,6 +156,8 @@ modest_msg_edit_window_init (ModestMsgEditWindow *obj) priv->cc_field = NULL; priv->bcc_field = NULL; priv->subject_field = NULL; + priv->attachments = NULL; + priv->last_cid = 0; } @@ -183,6 +216,7 @@ init_window (ModestMsgEditWindow *obj) GtkWidget *to_button, *cc_button, *bcc_button; GtkWidget *header_table; GtkWidget *main_vbox; + GtkWidget *body_scroll; ModestMsgEditWindowPrivate *priv; ModestPairList *protos; @@ -217,12 +251,25 @@ init_window (ModestMsgEditWindow *obj) gtk_table_attach_defaults (GTK_TABLE(header_table), priv->bcc_field, 1,2,3,4); gtk_table_attach_defaults (GTK_TABLE(header_table), priv->subject_field,1,2,4,5); - priv->msg_body = gtk_text_view_new (); + priv->msg_body = wp_text_view_new (); + gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->msg_body), GTK_WRAP_WORD_CHAR); + priv->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->msg_body)); + g_object_set (priv->text_buffer, "font_scale", 1.0, NULL); + wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE); + gtk_text_buffer_set_can_paste_rich_text (priv->text_buffer, TRUE); + wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE); + g_signal_connect (G_OBJECT (priv->text_buffer), "refresh_attributes", + G_CALLBACK (text_buffer_refresh_attributes), obj); + + body_scroll = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (body_scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (body_scroll), GTK_SHADOW_IN); + gtk_container_add (GTK_CONTAINER (body_scroll), priv->msg_body); main_vbox = gtk_vbox_new (FALSE, 6); gtk_box_pack_start (GTK_BOX(main_vbox), header_table, FALSE, FALSE, 6); - gtk_box_pack_start (GTK_BOX(main_vbox), priv->msg_body, TRUE, TRUE, 6); + gtk_box_pack_start (GTK_BOX(main_vbox), body_scroll, TRUE, TRUE, 6); gtk_widget_show_all (GTK_WIDGET(main_vbox)); @@ -277,15 +324,13 @@ menubar_to_menu (GtkUIManager *ui_manager) } -#if 0 static void set_msg (ModestMsgEditWindow *self, TnyMsg *msg) { TnyHeader *header; - GtkTextBuffer *buf; - const gchar *to, *cc, *bcc, *subject; + const gchar *to, *cc, *bcc, *subject, *body; ModestMsgEditWindowPrivate *priv; - + g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self)); g_return_if_fail (TNY_IS_MSG (msg)); @@ -306,10 +351,29 @@ set_msg (ModestMsgEditWindow *self, TnyMsg *msg) if (subject) gtk_entry_set_text (GTK_ENTRY(priv->subject_field), subject); - buf = gtk_text_view_get_buffer (GTK_TEXT_VIEW(priv->msg_body)); - gtk_text_buffer_set_text (buf, - (const gchar *) modest_tny_msg_get_body (msg, FALSE), - -1); + gtk_text_buffer_set_can_paste_rich_text (priv->text_buffer, TRUE); + wp_text_buffer_reset_buffer (WP_TEXT_BUFFER (priv->text_buffer), TRUE); + body = modest_tny_msg_get_body (msg, FALSE); + if ((body!=NULL) && (body[0] != '\0')) { + wp_text_buffer_load_document_begin (WP_TEXT_BUFFER (priv->text_buffer), TRUE); + wp_text_buffer_load_document_write (WP_TEXT_BUFFER (priv->text_buffer), + (gchar *) body, + -1); + wp_text_buffer_load_document_end (WP_TEXT_BUFFER (priv->text_buffer)); + } else { + WPTextBufferFormat fmt = {0}; + + fmt.font_size = DEFAULT_FONT_SIZE; + fmt.font = DEFAULT_FONT; + fmt.rich_text = 1; + fmt.text_position = TEXT_POSITION_NORMAL; + fmt.justification = 0; + fmt.cs.font_size = 1; + fmt.cs.font = 1; + fmt.cs.text_position = 1; + fmt.cs.justification = 1; + wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), &fmt); + } /* TODO: lower priority, select in the From: combo to the value that comes from msg <- not sure, should it be @@ -317,9 +381,62 @@ set_msg (ModestMsgEditWindow *self, TnyMsg *msg) /* TODO: set attachments */ } -#endif - +static void +modest_msg_edit_window_setup_toolbar (ModestMsgEditWindow *window) +{ + ModestWindowPrivate *parent_priv = MODEST_WINDOW_GET_PRIVATE (window); + ModestMsgEditWindowPrivate *priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window); + GtkWidget *font_placeholder; + GtkWidget *tool_item; + gint insert_index; + gint size_index; + gint font_index; + + /* Toolbar */ + parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar"); + hildon_window_add_toolbar (HILDON_WINDOW (window), GTK_TOOLBAR (parent_priv->toolbar)); + + /* should we hide the toolbar? */ + if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_TOOLBAR, NULL)) + gtk_widget_hide (parent_priv->toolbar); + + /* Font management toolbar elements */ + font_placeholder = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar/FontAttributes"); + insert_index = gtk_toolbar_get_item_index(GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM(font_placeholder)); + + /* font color */ + tool_item = GTK_WIDGET (gtk_tool_item_new ()); + priv->font_color_button = hildon_color_button_new (); + gtk_container_add (GTK_CONTAINER (tool_item), priv->font_color_button); + gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index); + g_signal_connect_swapped (G_OBJECT (priv->font_color_button), "notify::color", G_CALLBACK (modest_msg_edit_window_color_button_change), window); + + /* font_size */ + priv->size_combobox = gtk_combo_box_new_text (); + gtk_widget_set_size_request (priv->size_combobox, DEFAULT_SIZE_COMBOBOX_WIDTH, -1); + for (size_index = 0; size_index < WP_FONT_SIZE_COUNT; size_index++) { + gchar size_text[5]; + snprintf(size_text, sizeof(size_text), "%d", wp_font_size[size_index]); + gtk_combo_box_append_text (GTK_COMBO_BOX (priv->size_combobox), size_text); + } + gtk_combo_box_set_active (GTK_COMBO_BOX (priv->size_combobox), wp_get_font_size_index(12, 4)); + tool_item = GTK_WIDGET (gtk_tool_item_new ()); + gtk_container_add (GTK_CONTAINER (tool_item), priv->size_combobox); + gtk_toolbar_insert(GTK_TOOLBAR(parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index); + g_signal_connect_swapped (G_OBJECT (priv->size_combobox), "changed", G_CALLBACK (modest_msg_edit_window_size_combobox_change), window); + + priv->font_combobox = gtk_combo_box_new_text (); + for (font_index = 0; font_index < wp_get_font_count (); font_index++) { + gtk_combo_box_append_text (GTK_COMBO_BOX (priv->font_combobox), wp_get_font_name (font_index)); + } + tool_item = GTK_WIDGET (gtk_tool_item_new ()); + gtk_container_add (GTK_CONTAINER (tool_item), priv->font_combobox); + gtk_toolbar_insert (GTK_TOOLBAR (parent_priv->toolbar), GTK_TOOL_ITEM (tool_item), insert_index); + g_signal_connect_swapped (G_OBJECT (priv->font_combobox), "changed", G_CALLBACK (modest_msg_edit_window_font_combobox_change), window); +} + + ModestWindow* modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name) @@ -349,6 +466,12 @@ modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name) modest_msg_edit_toggle_action_entries, G_N_ELEMENTS (modest_msg_edit_toggle_action_entries), obj); + gtk_action_group_add_radio_actions (action_group, + modest_msg_edit_alignment_radio_action_entries, + G_N_ELEMENTS (modest_msg_edit_alignment_radio_action_entries), + GTK_JUSTIFY_LEFT, + G_CALLBACK (modest_ui_actions_on_change_justify), + obj); gtk_ui_manager_insert_action_group (parent_priv->ui_manager, action_group, 0); g_object_unref (action_group); @@ -365,14 +488,6 @@ modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name) gtk_ui_manager_get_accel_group (parent_priv->ui_manager)); - /* Toolbar */ - parent_priv->toolbar = gtk_ui_manager_get_widget (parent_priv->ui_manager, "/ToolBar"); - hildon_window_add_toolbar (HILDON_WINDOW (obj), GTK_TOOLBAR (parent_priv->toolbar)); - - /* should we hide the toolbar? */ - if (!modest_conf_get_bool (modest_runtime_get_conf (), MODEST_CONF_SHOW_TOOLBAR, NULL)) - gtk_widget_hide (parent_priv->toolbar); - /* Menubar */ parent_priv->menubar = menubar_to_menu (parent_priv->ui_manager); @@ -380,7 +495,7 @@ modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name) /* Init window */ init_window (MODEST_MSG_EDIT_WINDOW(obj)); - + restore_settings (MODEST_MSG_EDIT_WINDOW(obj)); gtk_window_set_title (GTK_WINDOW(obj), "Modest"); @@ -390,9 +505,40 @@ modest_msg_edit_window_new (TnyMsg *msg, const gchar *account_name) G_CALLBACK(on_delete_event), obj); modest_window_set_active_account (MODEST_WINDOW(obj), account_name); + + modest_msg_edit_window_setup_toolbar (MODEST_MSG_EDIT_WINDOW (obj)); + + set_msg (MODEST_MSG_EDIT_WINDOW (obj), msg); + + text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (obj)); + return (ModestWindow*)obj; } +static gint +get_formatted_data_cb (const gchar *buffer, gpointer user_data) +{ + GString **string_buffer = (GString **) user_data; + + *string_buffer = g_string_append (*string_buffer, buffer); + + return 0; +} + +static gchar * +get_formatted_data (ModestMsgEditWindow *edit_window) +{ + ModestMsgEditWindowPrivate *priv; + GString *string_buffer = g_string_new (""); + + priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (edit_window); + + wp_text_buffer_save_document (WP_TEXT_BUFFER(priv->text_buffer), get_formatted_data_cb, &string_buffer); + + return g_string_free (string_buffer, FALSE); + +} + MsgData * modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window) { @@ -420,7 +566,9 @@ modest_msg_edit_window_get_msg_data (ModestMsgEditWindow *edit_window) data->cc = (gchar*) gtk_entry_get_text (GTK_ENTRY(priv->cc_field)); data->bcc = (gchar*) gtk_entry_get_text (GTK_ENTRY(priv->bcc_field)); data->subject = (gchar*) gtk_entry_get_text (GTK_ENTRY(priv->subject_field)); - data->body = gtk_text_buffer_get_text (buf, &b, &e, FALSE); + data->plain_body = (gchar *) gtk_text_buffer_get_text (priv->text_buffer, &b, &e, FALSE); + data->html_body = get_formatted_data (edit_window); + data->attachments = priv->attachments; return data; } @@ -432,6 +580,405 @@ modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *edit_window, g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (edit_window)); g_free (data->from); - g_free (data->body); + g_free (data->html_body); + g_free (data->plain_body); g_slice_free (MsgData, data); } + +ModestMsgEditFormat +modest_msg_edit_window_get_format (ModestMsgEditWindow *self) +{ + gboolean rich_text; + ModestMsgEditWindowPrivate *priv = NULL; + g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), MODEST_MSG_EDIT_FORMAT_HTML); + + priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self); + + rich_text = wp_text_buffer_is_rich_text (WP_TEXT_BUFFER (priv->text_buffer)); + if (rich_text) + return MODEST_MSG_EDIT_FORMAT_HTML; + else + return MODEST_MSG_EDIT_FORMAT_TEXT; +} + +void +modest_msg_edit_window_set_format (ModestMsgEditWindow *self, + ModestMsgEditFormat format) +{ + ModestMsgEditWindowPrivate *priv; + + g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self)); + priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self); + + switch (format) { + case MODEST_MSG_EDIT_FORMAT_HTML: + wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), TRUE); + break; + case MODEST_MSG_EDIT_FORMAT_TEXT: + wp_text_buffer_enable_rich_text (WP_TEXT_BUFFER (priv->text_buffer), FALSE); + break; + default: + g_return_if_reached (); + } +} + +ModestMsgEditFormatState * +modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self) +{ + ModestMsgEditFormatState *format_state = NULL; + ModestMsgEditWindowPrivate *priv; + WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1); + + g_return_val_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self), NULL); + priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self); + + wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, TRUE); + + format_state = g_new0 (ModestMsgEditFormatState, 1); + format_state->bold = buffer_format->bold&0x1; + format_state->italics = buffer_format->italic&0x1; + format_state->bullet = buffer_format->bullet&0x1; + format_state->color = buffer_format->color; + format_state->font_size = buffer_format->font_size; + format_state->font_family = wp_get_font_name (buffer_format->font); + format_state->justification = buffer_format->justification; + g_free (buffer_format); + + return format_state; + +} + +void +modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self, + const ModestMsgEditFormatState *format_state) +{ + ModestMsgEditWindowPrivate *priv; + WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1); + WPTextBufferFormat *current_format = g_new0 (WPTextBufferFormat, 1); + g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (self)); + g_return_if_fail (format_state != NULL); + + priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (self); + gtk_widget_grab_focus (priv->msg_body); + buffer_format->bold = (format_state->bold != FALSE); + buffer_format->italic = (format_state->italics != FALSE); + buffer_format->color = format_state->color; + buffer_format->font_size = format_state->font_size; + buffer_format->font = wp_get_font_index (format_state->font_family, 0); + buffer_format->justification = format_state->justification; + buffer_format->bullet = format_state->bullet; + + wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), current_format, TRUE); + + buffer_format->cs.bold = ((buffer_format->bold&0x1) != (current_format->bold&0x1)); + buffer_format->cs.italic = ((buffer_format->italic&0x1) != (current_format->italic&0x1)); + buffer_format->cs.color = gdk_color_equal(&(buffer_format->color), &(current_format->color)); + buffer_format->cs.font_size = (buffer_format->font_size != current_format->font_size); + buffer_format->cs.font = (buffer_format->font != current_format->font); + buffer_format->cs.justification = (buffer_format->justification != current_format->justification); + buffer_format->cs.bullet = (buffer_format->bullet != current_format->bullet); + + wp_text_buffer_freeze (WP_TEXT_BUFFER (priv->text_buffer)); + if (buffer_format->cs.bold) { + wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->bold&0x1)); + } + if (buffer_format->cs.italic) { + wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_ITALIC, (gpointer) (buffer_format->italic&0x1)); + } + if (buffer_format->cs.color) { + wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) (&(buffer_format->color))); + } + if (buffer_format->cs.font_size) { + wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->font_size)); + } + if (buffer_format->cs.justification) { + switch (buffer_format->justification) { + case GTK_JUSTIFY_LEFT: + wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_LEFT, (gpointer) TRUE); + break; + case GTK_JUSTIFY_CENTER: + wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_CENTER, (gpointer) TRUE); + break; + case GTK_JUSTIFY_RIGHT: + wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_RIGHT, (gpointer) TRUE); + break; + default: + break; + } + + } + if (buffer_format->cs.font) { + wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BOLD, (gpointer) (buffer_format->font)); + } + if (buffer_format->cs.bullet) { + wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_BULLET, (gpointer) (buffer_format->bullet)); + } +/* wp_text_buffer_set_format (WP_TEXT_BUFFER (priv->text_buffer), buffer_format); */ + wp_text_buffer_thaw (WP_TEXT_BUFFER (priv->text_buffer)); + + g_free (current_format); + +} + +static void +toggle_action_set_active_block_notify (GtkToggleAction *action, + gboolean value) +{ + GSList *proxies = NULL; + + for (proxies = gtk_action_get_proxies (GTK_ACTION (action)); + proxies != NULL; proxies = g_slist_next (proxies)) { + GtkWidget *widget = (GtkWidget *) proxies->data; + gtk_action_block_activate_from (GTK_ACTION (action), widget); + } + + gtk_toggle_action_set_active (action, value); + + for (proxies = gtk_action_get_proxies (GTK_ACTION (action)); + proxies != NULL; proxies = g_slist_next (proxies)) { + GtkWidget *widget = (GtkWidget *) proxies->data; + gtk_action_unblock_activate_from (GTK_ACTION (action), widget); + } +} + +static void +text_buffer_refresh_attributes (WPTextBuffer *buffer, ModestMsgEditWindow *window) +{ + WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1); + GtkAction *action; + ModestWindowPrivate *parent_priv; + ModestMsgEditWindowPrivate *priv; + + parent_priv = MODEST_WINDOW_GET_PRIVATE (window); + priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window); + + wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE); + + action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBold"); + toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bold); + + action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsItalics"); + toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->italic); + + action = gtk_ui_manager_get_action (parent_priv->ui_manager, "/ToolBar/ActionsBulletedList"); + toggle_action_set_active_block_notify (GTK_TOGGLE_ACTION (action), buffer_format->bullet); + + g_signal_handlers_block_by_func (G_OBJECT (priv->font_color_button), + G_CALLBACK (modest_msg_edit_window_color_button_change), + window); + hildon_color_button_set_color (HILDON_COLOR_BUTTON (priv->font_color_button), & (buffer_format->color)); + g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_color_button), + G_CALLBACK (modest_msg_edit_window_color_button_change), + window); + + g_signal_handlers_block_by_func (G_OBJECT (priv->size_combobox), + G_CALLBACK (modest_msg_edit_window_size_combobox_change), + window); + gtk_combo_box_set_active (GTK_COMBO_BOX (priv->size_combobox), buffer_format->font_size); + g_signal_handlers_unblock_by_func (G_OBJECT (priv->size_combobox), + G_CALLBACK (modest_msg_edit_window_size_combobox_change), + window); + + g_signal_handlers_block_by_func (G_OBJECT (priv->font_combobox), + G_CALLBACK (modest_msg_edit_window_font_combobox_change), + window); + gtk_combo_box_set_active (GTK_COMBO_BOX (priv->font_combobox), buffer_format->font); + g_signal_handlers_unblock_by_func (G_OBJECT (priv->font_combobox), + G_CALLBACK (modest_msg_edit_window_font_combobox_change), + window); + + g_free (buffer_format); + +} + +void +modest_msg_edit_window_select_color (ModestMsgEditWindow *window) +{ + + WPTextBufferFormat *buffer_format = g_new0 (WPTextBufferFormat, 1); + ModestMsgEditWindowPrivate *priv; + GtkWidget *dialog = NULL; + gint response; + const GdkColor *new_color = NULL; + + priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window); + wp_text_buffer_get_attributes (WP_TEXT_BUFFER (priv->text_buffer), buffer_format, FALSE); + + dialog = hildon_color_selector_new (GTK_WINDOW (window)); + hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), & (buffer_format->color)); + g_free (buffer_format); + + response = gtk_dialog_run (GTK_DIALOG (dialog)); + switch (response) { + case GTK_RESPONSE_OK: + new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog)); + break; + default: + break; + } + gtk_widget_destroy (dialog); + + if (new_color != NULL) + wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color); + +} + +void +modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window) +{ + + ModestMsgEditWindowPrivate *priv; + GtkWidget *dialog = NULL; + gint response; + const GdkColor *old_color = NULL; + const GdkColor *new_color = NULL; + + priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window); + old_color = wp_text_buffer_get_background_color (WP_TEXT_BUFFER (priv->text_buffer)); + + dialog = hildon_color_selector_new (GTK_WINDOW (window)); + hildon_color_selector_set_color (HILDON_COLOR_SELECTOR (dialog), (GdkColor *) old_color); + + response = gtk_dialog_run (GTK_DIALOG (dialog)); + switch (response) { + case GTK_RESPONSE_OK: + new_color = hildon_color_selector_get_color (HILDON_COLOR_SELECTOR (dialog)); + break; + default: + break; + } + gtk_widget_destroy (dialog); + + if (new_color != NULL) + wp_text_buffer_set_background_color (WP_TEXT_BUFFER (priv->text_buffer), new_color); + +} + +void +modest_msg_edit_window_insert_image (ModestMsgEditWindow *window) +{ + + ModestMsgEditWindowPrivate *priv; + GtkWidget *dialog = NULL; + gint response; + gchar *filename; + + priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window); + + dialog = hildon_file_chooser_dialog_new (GTK_WINDOW (window), GTK_FILE_CHOOSER_ACTION_OPEN); + + response = gtk_dialog_run (GTK_DIALOG (dialog)); + switch (response) { + case GTK_RESPONSE_OK: + filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); + break; + default: + break; + } + gtk_widget_destroy (dialog); + + if (filename) { + GdkPixbuf *pixbuf = NULL; + GtkTextIter position; + GtkTextMark *insert_mark; + + pixbuf = gdk_pixbuf_new_from_file (filename, NULL); + if (pixbuf) { + gint image_file_id; + GdkPixbufFormat *pixbuf_format; + + image_file_id = g_open (filename, O_RDONLY, 0); + pixbuf_format = gdk_pixbuf_get_file_info (filename, NULL, NULL); + if ((image_file_id != -1)&&(pixbuf_format != NULL)) { + TnyMimePart *image_part; + TnyStream *image_stream; + gchar **mime_types; + gchar *mime_type; + gchar *basename; + gchar *content_id; + + mime_types = gdk_pixbuf_format_get_mime_types (pixbuf_format); + if ((mime_types != NULL) && (mime_types[0] != NULL)) { + mime_type = mime_types[0]; + } else { + mime_type = "image/unknown"; + } + image_part = tny_platform_factory_new_mime_part + (modest_runtime_get_platform_factory ()); + image_stream = TNY_STREAM (tny_fs_stream_new (image_file_id)); + + tny_mime_part_construct_from_stream (image_part, image_stream, mime_type); + g_strfreev (mime_types); + + content_id = g_strdup_printf ("%d", priv->last_cid); + tny_mime_part_set_content_id (image_part, content_id); + g_free (content_id); + priv->last_cid++; + + basename = g_path_get_basename (filename); + tny_mime_part_set_filename (image_part, basename); + g_free (basename); + + insert_mark = gtk_text_buffer_get_insert (GTK_TEXT_BUFFER (priv->text_buffer)); + gtk_text_buffer_get_iter_at_mark (GTK_TEXT_BUFFER (priv->text_buffer), &position, insert_mark); + wp_text_buffer_insert_image (WP_TEXT_BUFFER (priv->text_buffer), &position, g_strdup (tny_mime_part_get_content_id (image_part)), pixbuf); + priv->attachments = g_list_prepend (priv->attachments, image_part); + } else if (image_file_id == -1) { + close (image_file_id); + } + } + } + + +} + +static void +modest_msg_edit_window_color_button_change (ModestMsgEditWindow *window, + gpointer userdata) +{ + ModestMsgEditWindowPrivate *priv; + GdkColor *new_color; + + priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window); + new_color = hildon_color_button_get_color (HILDON_COLOR_BUTTON (priv->font_color_button)); + + wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FORECOLOR, (gpointer) new_color); + gtk_window_set_focus (GTK_WINDOW (window), priv->msg_body); + +} + +static void +modest_msg_edit_window_size_combobox_change (ModestMsgEditWindow *window, + gpointer userdata) +{ + ModestMsgEditWindowPrivate *priv; + gint new_size_index; + + priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window); + gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body)); + + new_size_index = gtk_combo_box_get_active (GTK_COMBO_BOX (priv->size_combobox)); + + if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT_SIZE, (gpointer) new_size_index)) + wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body)); + + text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window));; +} + +static void +modest_msg_edit_window_font_combobox_change (ModestMsgEditWindow *window, + gpointer userdata) +{ + ModestMsgEditWindowPrivate *priv; + gint new_font_index; + + priv = MODEST_MSG_EDIT_WINDOW_GET_PRIVATE (window); + gtk_widget_grab_focus (GTK_WIDGET (priv->msg_body)); + + new_font_index = gtk_combo_box_get_active (GTK_COMBO_BOX (priv->font_combobox)); + + if (!wp_text_buffer_set_attribute (WP_TEXT_BUFFER (priv->text_buffer), WPT_FONT, (gpointer) new_font_index)) + wp_text_view_reset_and_show_im (WP_TEXT_VIEW (priv->msg_body)); + + text_buffer_refresh_attributes (WP_TEXT_BUFFER (priv->text_buffer), MODEST_MSG_EDIT_WINDOW (window)); +} diff --git a/src/maemo/ui/modest-msg-edit-window-ui.xml b/src/maemo/ui/modest-msg-edit-window-ui.xml index 040fdaa..27ef8fd 100644 --- a/src/maemo/ui/modest-msg-edit-window-ui.xml +++ b/src/maemo/ui/modest-msg-edit-window-ui.xml @@ -38,10 +38,31 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/maemo/ui/modest-msg-view-window-ui.xml b/src/maemo/ui/modest-msg-view-window-ui.xml index 5d17534..92247fa 100644 --- a/src/maemo/ui/modest-msg-view-window-ui.xml +++ b/src/maemo/ui/modest-msg-view-window-ui.xml @@ -31,10 +31,20 @@ + + + + + + + + + + + + - - diff --git a/src/modest-mail-operation.c b/src/modest-mail-operation.c index 97a76fa..c4d5b05 100644 --- a/src/modest-mail-operation.c +++ b/src/modest-mail-operation.c @@ -223,11 +223,13 @@ modest_mail_operation_send_new_mail (ModestMailOperation *self, TnyTransportAccount *transport_account, const gchar *from, const gchar *to, const gchar *cc, const gchar *bcc, - const gchar *subject, const gchar *body, + const gchar *subject, const gchar *plain_body, + const gchar *html_body, const GList *attachments_list) { TnyMsg *new_msg; ModestMailOperationPrivate *priv = NULL; + GList *node = NULL; g_return_if_fail (MODEST_IS_MAIL_OPERATION (self)); g_return_if_fail (TNY_IS_TRANSPORT_ACCOUNT (transport_account)); @@ -242,7 +244,11 @@ modest_mail_operation_send_new_mail (ModestMailOperation *self, return; } - new_msg = modest_tny_msg_new (to, from, cc, bcc, subject, body, NULL); /* FIXME: attachments */ + if (html_body == NULL) { + new_msg = modest_tny_msg_new (to, from, cc, bcc, subject, plain_body, (GSList *) attachments_list); /* FIXME: attachments */ + } else { + new_msg = modest_tny_msg_new_html_plain (to, from, cc, bcc, subject, html_body, plain_body, (GSList *) attachments_list); + } if (!new_msg) { g_printerr ("modest: failed to create a new msg\n"); return; diff --git a/src/modest-mail-operation.h b/src/modest-mail-operation.h index c3ec8d2..c5f49fb 100644 --- a/src/modest-mail-operation.h +++ b/src/modest-mail-operation.h @@ -104,7 +104,9 @@ void modest_mail_operation_send_mail (ModestMailOperation *self, * @cc: a comma-separated list of email addresses where to send a carbon copy * @bcc: a comma-separated list of email addresses where to send a blind carbon copy * @subject: the subject of the new mail - * @body: the body of the new mail + * @plain_body: the plain text body of the new mail. + * @html_body: the html version of the body of the new mail. If NULL, the mail will + * be sent with the plain body only. * @attachments_list: a #GList of attachments, each attachment must be a #TnyMimePart * * Sends a new mail message using the provided @@ -119,7 +121,8 @@ void modest_mail_operation_send_new_mail (ModestMailOperation *self, const gchar *cc, const gchar *bcc, const gchar *subject, - const gchar *body, + const gchar *plain_body, + const gchar *html_body, const GList *attachments_list); /** diff --git a/src/modest-main.c b/src/modest-main.c index 6dd6a61..dc211c7 100644 --- a/src/modest-main.c +++ b/src/modest-main.c @@ -280,7 +280,7 @@ send_mail (const gchar* account_name, mail_operation = modest_mail_operation_new (); modest_mail_operation_send_new_mail (mail_operation, account, from_string, mailto, - cc, bcc, subject, body, + cc, bcc, subject, body, NULL, NULL); if (modest_mail_operation_get_status (mail_operation) == MODEST_MAIL_OPERATION_STATUS_FAILED) { diff --git a/src/modest-runtime.c b/src/modest-runtime.c index 499a8c6..ea1710b 100644 --- a/src/modest-runtime.c +++ b/src/modest-runtime.c @@ -570,6 +570,7 @@ init_stock_icons (void) /* MODEST_TOOLBAR_ICON_NEXT, */ /* MODEST_TOOLBAR_ICON_PREV, */ /* MODEST_TOOLBAR_ICON_STOP */ + MODEST_TOOLBAR_ICON_FORMAT_BULLETS, }; registered = TRUE; diff --git a/src/modest-tny-msg.c b/src/modest-tny-msg.c index 6a4f827..d168d40 100644 --- a/src/modest-tny-msg.c +++ b/src/modest-tny-msg.c @@ -46,6 +46,7 @@ static TnyMimePart * add_body_part (TnyMsg *msg, const gchar *body, const gchar *content_type, gboolean has_attachments); +static TnyMimePart * add_html_body_part (TnyMsg *msg, const gchar *body); static void add_attachments (TnyMsg *msg, GList *attachments_list); static char * get_content_type(const gchar *s); static gboolean is_ascii(const gchar *s); @@ -76,6 +77,43 @@ modest_tny_msg_new (const gchar* mailto, const gchar* from, const gchar *cc, /* Add the body of the new mail */ add_body_part (new_msg, body, content_type, (attachments ? TRUE: FALSE)); + g_free (content_type); + + /* Add attachments */ + add_attachments (new_msg, (GList*) attachments); + + return new_msg; +} + +TnyMsg* +modest_tny_msg_new_html_plain (const gchar* mailto, const gchar* from, const gchar *cc, + const gchar *bcc, const gchar* subject, + const gchar *html_body, const gchar *plain_body, + GSList *attachments) +{ + TnyPlatformFactory *fact; + TnyMsg *new_msg; + TnyHeader *header; + gchar *content_type; + + /* Create new msg */ + fact = modest_runtime_get_platform_factory (); + new_msg = tny_platform_factory_new_msg (fact); + header = tny_msg_get_header (new_msg); + + tny_header_set_from (TNY_HEADER (header), from); + tny_header_set_replyto (TNY_HEADER (header), from); + tny_header_set_to (TNY_HEADER (header), mailto); + tny_header_set_cc (TNY_HEADER (header), cc); + tny_header_set_bcc (TNY_HEADER (header), bcc); + tny_header_set_subject (TNY_HEADER (header), subject); + + content_type = get_content_type(plain_body); + + /* Add the body of the new mail */ + add_html_body_part (new_msg, html_body); + add_body_part (new_msg, plain_body, content_type, TRUE); + g_free (content_type); /* Add attachments */ add_attachments (new_msg, (GList*) attachments); @@ -125,6 +163,39 @@ add_body_part (TnyMsg *msg, return text_body_part; } +static TnyMimePart * +add_html_body_part (TnyMsg *msg, + const gchar *body) +{ + TnyMimePart *html_body_part = NULL; + TnyStream *html_body_stream; + + /* Create the stream */ + html_body_stream = TNY_STREAM (tny_camel_stream_new + (camel_stream_mem_new_with_buffer + (body, strlen(body)))); + + /* Create body part if needed */ + html_body_part = tny_platform_factory_new_mime_part + (modest_runtime_get_platform_factory ()); + + /* Construct MIME part */ + tny_stream_reset (html_body_stream); + tny_mime_part_construct_from_stream (html_body_part, + html_body_stream, + "text/html; charset=utf-8"); + tny_stream_reset (html_body_stream); + + /* Add part if needed */ + tny_mime_part_add_part (TNY_MIME_PART (msg), html_body_part); + g_object_unref (G_OBJECT(html_body_part)); + + /* Clean */ + g_object_unref (html_body_stream); + + return html_body_part; +} + static void add_attachments (TnyMsg *msg, GList *attachments_list) { @@ -132,6 +203,7 @@ add_attachments (TnyMsg *msg, GList *attachments_list) TnyMimePart *attachment_part, *old_attachment; const gchar *attachment_content_type; const gchar *attachment_filename; + const gchar *attachment_cid; TnyStream *attachment_stream; for (pos = (GList *)attachments_list; pos; pos = pos->next) { @@ -143,6 +215,7 @@ add_attachments (TnyMsg *msg, GList *attachments_list) modest_runtime_get_platform_factory()); attachment_content_type = tny_mime_part_get_content_type (old_attachment); + attachment_cid = tny_mime_part_get_content_id (old_attachment); tny_mime_part_construct_from_stream (attachment_part, attachment_stream, @@ -150,6 +223,7 @@ add_attachments (TnyMsg *msg, GList *attachments_list) tny_stream_reset (attachment_stream); tny_mime_part_set_filename (attachment_part, attachment_filename); + tny_mime_part_set_content_id (attachment_part, attachment_cid); tny_mime_part_add_part (TNY_MIME_PART (msg), attachment_part); /* g_object_unref (attachment_part); */ diff --git a/src/modest-tny-msg.h b/src/modest-tny-msg.h index 250c6f8..d443a53 100644 --- a/src/modest-tny-msg.h +++ b/src/modest-tny-msg.h @@ -80,6 +80,26 @@ TnyMsg* modest_tny_msg_new (const gchar* mailto, const gchar* mailfrom, const gc GSList *attachments); /** + * modest_tny_msg_new_html_plain: + * @mailto: recipient for the message + * @mailfrom: sender of this message + * @cc: Cc: address for the message + * @bcc: Bcc: address for the message + * @subject: subject for the message + * @html_body: body for the message in HTML + * @plain_body: body for the message in plain text + * @attachments: a list of attachments (local URIs) + * + * create a new TnyMsg with the given parameters + * + * Returns: a new TnyMsg (free with g_object_unref) + */ +TnyMsg* modest_tny_msg_new_html_plain (const gchar* mailto, const gchar* mailfrom, const gchar *cc, + const gchar *bcc, const gchar* subject, + const gchar *html_body, const gchar *plain_body, + GSList *attachments); + +/** * modest_tny_msg_find_body_part: * @self: a message * @want_html: prefer HTML-part when there are multiple body parts? diff --git a/src/modest-ui-actions.c b/src/modest-ui-actions.c index 032a094..7aec591 100644 --- a/src/modest-ui-actions.c +++ b/src/modest-ui-actions.c @@ -960,7 +960,7 @@ modest_ui_actions_on_msg_link_clicked (ModestMsgView *msgview, const gchar* link } void -modest_ui_actions_on_msg_attachment_clicked (ModestMsgView *msgview, int index, +modest_ui_actions_on_msg_attachment_clicked (ModestMsgView *msgview, TnyMimePart *mime_part, ModestWindow *win) { g_message (__FUNCTION__); @@ -1021,8 +1021,9 @@ modest_ui_actions_on_send (GtkWidget *widget, ModestMsgEditWindow *edit_window) data->cc, data->bcc, data->subject, - data->body, - NULL); + data->plain_body, + data->html_body, + data->attachments); /* Frees */ g_free (from); g_free (account_name); @@ -1036,6 +1037,131 @@ modest_ui_actions_on_send (GtkWidget *widget, ModestMsgEditWindow *edit_window) gtk_widget_destroy (GTK_WIDGET (edit_window)); } +void +modest_ui_actions_on_toggle_bold (GtkToggleAction *action, + ModestMsgEditWindow *window) +{ + ModestMsgEditFormatState *format_state = NULL; + + g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window)); + g_return_if_fail (GTK_IS_TOGGLE_ACTION (action)); + + if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW (window)) == MODEST_MSG_EDIT_FORMAT_TEXT) + return; + + format_state = modest_msg_edit_window_get_format_state (window); + g_return_if_fail (format_state != NULL); + + format_state->bold = gtk_toggle_action_get_active (action); + modest_msg_edit_window_set_format_state (window, format_state); + g_free (format_state); + +} + +void +modest_ui_actions_on_toggle_italics (GtkToggleAction *action, + ModestMsgEditWindow *window) +{ + ModestMsgEditFormatState *format_state = NULL; + + g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window)); + g_return_if_fail (GTK_IS_TOGGLE_ACTION (action)); + + if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT) + return; + + format_state = modest_msg_edit_window_get_format_state (window); + g_return_if_fail (format_state != NULL); + + format_state->italics = gtk_toggle_action_get_active (action); + modest_msg_edit_window_set_format_state (window, format_state); + g_free (format_state); + +} + +void +modest_ui_actions_on_toggle_bullets (GtkToggleAction *action, + ModestMsgEditWindow *window) +{ + ModestMsgEditFormatState *format_state = NULL; + + g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window)); + g_return_if_fail (GTK_IS_TOGGLE_ACTION (action)); + + if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW (window)) == MODEST_MSG_EDIT_FORMAT_TEXT) + return; + + format_state = modest_msg_edit_window_get_format_state (window); + g_return_if_fail (format_state != NULL); + + format_state->bullet = gtk_toggle_action_get_active (action); + modest_msg_edit_window_set_format_state (window, format_state); + g_free (format_state); + +} + +void +modest_ui_actions_on_change_justify (GtkRadioAction *action, + GtkRadioAction *selected, + ModestMsgEditWindow *window) +{ + ModestMsgEditFormatState *format_state = NULL; + GtkJustification value; + + g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window)); + + if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT) + return; + + value = gtk_radio_action_get_current_value (selected); + + format_state = modest_msg_edit_window_get_format_state (window); + g_return_if_fail (format_state != NULL); + + format_state->justification = value; + modest_msg_edit_window_set_format_state (window, format_state); + g_free (format_state); +} + +void +modest_ui_actions_on_select_editor_color (GtkAction *action, + ModestMsgEditWindow *window) +{ + g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window)); + g_return_if_fail (GTK_IS_ACTION (action)); + + if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT) + return; + + modest_msg_edit_window_select_color (window); +} + +void +modest_ui_actions_on_select_editor_background_color (GtkAction *action, + ModestMsgEditWindow *window) +{ + g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window)); + g_return_if_fail (GTK_IS_ACTION (action)); + + if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT) + return; + + modest_msg_edit_window_select_background_color (window); +} + +void +modest_ui_actions_on_insert_image (GtkAction *action, + ModestMsgEditWindow *window) +{ + g_return_if_fail (MODEST_IS_MSG_EDIT_WINDOW (window)); + g_return_if_fail (GTK_IS_ACTION (action)); + + if (modest_msg_edit_window_get_format (MODEST_MSG_EDIT_WINDOW(window)) == MODEST_MSG_EDIT_FORMAT_TEXT) + return; + + modest_msg_edit_window_insert_image (window); +} + /* * Shows a dialog with an entry that asks for some text. The returned * value must be freed by the caller. The dialog window title will be diff --git a/src/modest-ui-actions.h b/src/modest-ui-actions.h index 542b062..2add3e1 100644 --- a/src/modest-ui-actions.h +++ b/src/modest-ui-actions.h @@ -95,7 +95,7 @@ void modest_ui_actions_on_msg_link_hover (ModestMsgView *msgview, void modest_ui_actions_on_msg_link_clicked (ModestMsgView *msgview, const gchar* link, ModestWindow *win); -void modest_ui_actions_on_msg_attachment_clicked (ModestMsgView *msgview, int index, +void modest_ui_actions_on_msg_attachment_clicked (ModestMsgView *msgview, TnyMimePart *mime_part, ModestWindow *win); void modest_ui_actions_on_msg_recpt_activated (ModestMsgView *msgview, const gchar *address, @@ -104,6 +104,28 @@ void modest_ui_actions_on_msg_recpt_activated (ModestMsgView *msgview, con void modest_ui_actions_on_send (GtkWidget *widget, ModestMsgEditWindow *edit_window); +void modest_ui_actions_on_toggle_bold (GtkToggleAction *action, + ModestMsgEditWindow *window); + +void modest_ui_actions_on_toggle_italics (GtkToggleAction *action, + ModestMsgEditWindow *window); + +void modest_ui_actions_on_toggle_bullets (GtkToggleAction *action, + ModestMsgEditWindow *window); + +void modest_ui_actions_on_change_justify (GtkRadioAction *action, + GtkRadioAction *selected, + ModestMsgEditWindow *window); + +void modest_ui_actions_on_select_editor_color (GtkAction *action, + ModestMsgEditWindow *window); + +void modest_ui_actions_on_select_editor_background_color (GtkAction *action, + ModestMsgEditWindow *window); + +void modest_ui_actions_on_insert_image (GtkAction *action, + ModestMsgEditWindow *window); + void modest_ui_actions_on_send_receive (GtkAction *action, ModestWindow *win); void modest_ui_actions_on_new_folder (GtkAction *action, diff --git a/src/widgets/Makefile.am b/src/widgets/Makefile.am index 08d11d5..1a49d87 100644 --- a/src/widgets/Makefile.am +++ b/src/widgets/Makefile.am @@ -20,6 +20,8 @@ libmodest_widgets_la_SOURCES= \ modest-account-view-window.h \ modest-account-view.c \ modest-account-view.h \ + modest-attachment-view.c \ + modest-attachment-view.h \ modest-attachments-view.c \ modest-attachments-view.h \ modest-combo-box.c \ diff --git a/src/widgets/modest-attachment-view.c b/src/widgets/modest-attachment-view.c new file mode 100644 index 0000000..29a8e7b --- /dev/null +++ b/src/widgets/modest-attachment-view.c @@ -0,0 +1,496 @@ +/* Copyright (c) 2007, Nokia Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Nokia Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +//#include + +#include +#include +#include + +static GObjectClass *parent_class = NULL; + +/* signals */ +enum { + ACTIVATE_SIGNAL, + LAST_SIGNAL +}; + +typedef struct _ModestAttachmentViewPriv ModestAttachmentViewPriv; + +struct _ModestAttachmentViewPriv +{ + TnyMimePart *mime_part; + + GtkWidget *icon; + GtkWidget *filename_view; + GtkWidget *size_view; + + guint get_size_idle_id; + TnyStream *get_size_stream; + guint size; + + PangoLayout *layout_full_filename; + + gboolean button_pressed; + gdouble pressed_x, pressed_y; +}; + +#define UNKNOWN_FILE_ICON "qgn_list_gene_unknown_file" +#define GET_SIZE_BUFFER_SIZE 128 + +#define MODEST_ATTACHMENT_VIEW_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), MODEST_TYPE_ATTACHMENT_VIEW, ModestAttachmentViewPriv)) + +static guint signals[LAST_SIGNAL] = {0}; + +/* TnyMimePartView functions */ +static TnyMimePart *modest_attachment_view_get_part (TnyMimePartView *self); +static TnyMimePart *modest_attachment_view_get_part_default (TnyMimePartView *self); +static void modest_attachment_view_set_part (TnyMimePartView *self, TnyMimePart *mime_part); +static void modest_attachment_view_set_part_default (TnyMimePartView *self, TnyMimePart *mime_part); +static void modest_attachment_view_clear (TnyMimePartView *self); +static void modest_attachment_view_clear_default (TnyMimePartView *self); + +/* Gtk events */ +static gint button_press_event (GtkWidget *widget, GdkEventButton *event, gpointer user_data); +static gint button_release_event (GtkWidget *widget, GdkEventButton *event, gpointer user_data); +static void size_allocate (GtkWidget *widget, GtkAllocation *allocation); + +/* GObject and GInterface management */ +static void modest_attachment_view_instance_init (GTypeInstance *instance, gpointer g_class); +static void modest_attachment_view_finalize (GObject *object); +static void modest_attachment_view_class_init (ModestAttachmentViewClass *klass); +static void tny_mime_part_view_init (gpointer g, gpointer iface_data); + + + +static gboolean get_size_idle_func (gpointer data); +static void update_filename_request (ModestAttachmentView *self); + + + +static TnyMimePart * +modest_attachment_view_get_part (TnyMimePartView *self) +{ + return MODEST_ATTACHMENT_VIEW_GET_CLASS (self)->get_part_func (self); +} + +static TnyMimePart * +modest_attachment_view_get_part_default (TnyMimePartView *self) +{ + ModestAttachmentViewPriv *priv = MODEST_ATTACHMENT_VIEW_GET_PRIVATE (self); + + if (priv->mime_part) + return TNY_MIME_PART (g_object_ref (priv->mime_part)); + else + return NULL; +} + +static void +update_filename_request (ModestAttachmentView *self) +{ + ModestAttachmentViewPriv *priv = MODEST_ATTACHMENT_VIEW_GET_PRIVATE (self); + gint width, height; + + pango_layout_set_text (PANGO_LAYOUT (priv->layout_full_filename), + gtk_label_get_text (GTK_LABEL (priv->filename_view)), -1); + + pango_layout_get_pixel_size (priv->layout_full_filename, &width, &height); + +} + +static void +modest_attachment_view_set_part (TnyMimePartView *self, TnyMimePart *mime_part) +{ + MODEST_ATTACHMENT_VIEW_GET_CLASS (self)->set_part_func (self, mime_part); + return; +} + + +static gboolean +get_size_idle_func (gpointer data) +{ + ModestAttachmentView *self = (ModestAttachmentView *) data; + ModestAttachmentViewPriv *priv = MODEST_ATTACHMENT_VIEW_GET_PRIVATE (self); + gssize readed_size; + gchar read_buffer[GET_SIZE_BUFFER_SIZE]; + gchar *size_string; + + if (priv->get_size_stream == NULL) { + priv->get_size_stream = tny_mime_part_get_stream (priv->mime_part); + } + + readed_size = tny_stream_read (priv->get_size_stream, read_buffer, GET_SIZE_BUFFER_SIZE); + priv->size += readed_size; + + if (tny_stream_is_eos (priv->get_size_stream)) { + size_string = g_strdup_printf (" (%d kb)", priv->size / 1024); + gtk_label_set_text (GTK_LABEL (priv->size_view), size_string); + g_free (size_string); + + g_object_unref (priv->get_size_stream); + + gtk_widget_queue_resize (priv->size_view); + priv->get_size_stream = NULL; + priv->get_size_idle_id = 0; + } + + return (priv->get_size_stream != NULL); + +} + +static void +modest_attachment_view_set_part_default (TnyMimePartView *self, TnyMimePart *mime_part) +{ + ModestAttachmentViewPriv *priv = NULL; + const gchar *filename; + gchar *file_icon_name; + + g_return_if_fail (TNY_IS_MIME_PART_VIEW (self)); + g_return_if_fail (TNY_IS_MIME_PART (mime_part)); + priv = MODEST_ATTACHMENT_VIEW_GET_PRIVATE (self); + + if (priv->mime_part != NULL) { + g_object_unref (priv->mime_part); + } + + priv->mime_part = mime_part; + + if (priv->get_size_idle_id != 0) { + g_source_remove (priv->get_size_idle_id); + priv->get_size_idle_id = 0; + } + + if (priv->get_size_stream != NULL) { + g_object_unref (priv->get_size_stream); + priv->get_size_stream = NULL; + } + + priv->size = 0; + + filename = tny_mime_part_get_filename (mime_part); + file_icon_name = modest_platform_get_file_icon_name (filename, + tny_mime_part_get_content_type (mime_part), + NULL); + + if (file_icon_name) { + gtk_image_set_from_icon_name (GTK_IMAGE (priv->icon), file_icon_name, GTK_ICON_SIZE_MENU); + g_free (file_icon_name); + } else { + gtk_image_set_from_icon_name (GTK_IMAGE (priv->icon), UNKNOWN_FILE_ICON, GTK_ICON_SIZE_MENU); + } + + gtk_label_set_text (GTK_LABEL (priv->filename_view), filename); + update_filename_request (MODEST_ATTACHMENT_VIEW (self)); + + gtk_label_set_text (GTK_LABEL (priv->size_view), " "); + + priv->get_size_idle_id = g_idle_add ((GSourceFunc) get_size_idle_func, (gpointer) self); + + gtk_widget_queue_draw (GTK_WIDGET (self)); +} + +static void +modest_attachment_view_clear (TnyMimePartView *self) +{ + MODEST_ATTACHMENT_VIEW_GET_CLASS (self)->clear_func (self); + return; +} + +static void +modest_attachment_view_clear_default (TnyMimePartView *self) +{ + ModestAttachmentViewPriv *priv = MODEST_ATTACHMENT_VIEW_GET_PRIVATE (self); + + if (priv->mime_part != NULL) { + g_object_unref (priv->mime_part); + priv->mime_part = NULL; + } + + if (priv->get_size_idle_id != 0) { + g_source_remove (priv->get_size_idle_id); + priv->get_size_idle_id = 0; + } + + if (priv->get_size_stream != NULL) { + g_object_unref (priv->get_size_stream); + priv->get_size_stream = NULL; + } + + priv->size = 0; + + gtk_image_set_from_icon_name (GTK_IMAGE (priv->icon), + UNKNOWN_FILE_ICON, + GTK_ICON_SIZE_MENU); + gtk_label_set_text (GTK_LABEL (priv->filename_view), ""); + update_filename_request (MODEST_ATTACHMENT_VIEW(self)); + gtk_label_set_text (GTK_LABEL (priv->size_view), " "); + + gtk_widget_queue_draw (GTK_WIDGET (self)); +} + +static gint +button_press_event (GtkWidget *widget, + GdkEventButton *event, + gpointer user_data) +{ + ModestAttachmentViewPriv *priv = MODEST_ATTACHMENT_VIEW_GET_PRIVATE (MODEST_ATTACHMENT_VIEW (user_data)); + + if (event->type == GDK_BUTTON_PRESS && event->button == 1) { + priv->button_pressed = TRUE; + priv->pressed_x = event->x; + priv->pressed_y = event->y; + } + return TRUE; +} + +static gint +button_release_event (GtkWidget *widget, + GdkEventButton *event, + gpointer user_data) +{ + ModestAttachmentViewPriv *priv = MODEST_ATTACHMENT_VIEW_GET_PRIVATE (MODEST_ATTACHMENT_VIEW (user_data)); + + if (event->type != GDK_BUTTON_RELEASE) + return TRUE; + + if ((priv->button_pressed) && + (event->type == GDK_BUTTON_RELEASE) && + (priv->pressed_x == event->x) && + (priv->pressed_y == event->y)) { + priv->button_pressed = FALSE; + if (event->button == 1) { + g_signal_emit (G_OBJECT (user_data), signals[ACTIVATE_SIGNAL], 0); + return TRUE; + } + } + priv->button_pressed = FALSE; + return TRUE; +} + + + +/** + * modest_attachment_view_new: + * @mime_part: a #TnyMimePart + * + * Constructor for attachment view widget. + * + * Return value: a new #ModestAttachmentView instance implemented for Gtk+ + **/ +GtkWidget* +modest_attachment_view_new (TnyMimePart *mime_part) +{ + ModestAttachmentView *self = g_object_new (MODEST_TYPE_ATTACHMENT_VIEW, + "homogeneous", FALSE, + "spacing", 0, + NULL); + + modest_attachment_view_set_part (TNY_MIME_PART_VIEW (self), mime_part); + + return GTK_WIDGET (self); +} + +static void +modest_attachment_view_instance_init (GTypeInstance *instance, gpointer g_class) +{ + ModestAttachmentViewPriv *priv = MODEST_ATTACHMENT_VIEW_GET_PRIVATE (instance); + PangoContext *context; + GtkWidget *icon_eventbox; + + priv->mime_part = NULL; + priv->icon = gtk_image_new (); + priv->filename_view = gtk_label_new (""); + gtk_label_set_line_wrap (GTK_LABEL (priv->filename_view), FALSE); + gtk_label_set_ellipsize (GTK_LABEL (priv->filename_view), PANGO_ELLIPSIZE_END); + gtk_label_set_single_line_mode (GTK_LABEL (priv->filename_view), TRUE); + gtk_label_set_selectable (GTK_LABEL (priv->filename_view), TRUE); + priv->size_view = gtk_label_new (" "); + gtk_label_set_line_wrap (GTK_LABEL (priv->size_view), FALSE); + gtk_label_set_selectable (GTK_LABEL (priv->size_view), TRUE); + gtk_misc_set_alignment (GTK_MISC (priv->size_view), 0.0, 0.5); + gtk_misc_set_alignment (GTK_MISC (priv->filename_view), 0.0, 0.5); + + priv->get_size_idle_id = 0; + priv->get_size_stream = NULL; + priv->size = 0; + + icon_eventbox = gtk_event_box_new (); + + gtk_container_add (GTK_CONTAINER (icon_eventbox), priv->icon); + gtk_box_pack_start (GTK_BOX (instance), icon_eventbox, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (instance), priv->filename_view, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (instance), priv->size_view, FALSE, FALSE, 0); + + context = gtk_widget_get_pango_context (priv->filename_view); + priv->layout_full_filename = pango_layout_new (context); + + g_signal_connect (G_OBJECT (priv->filename_view), "button-press-event", G_CALLBACK (button_press_event), instance); + g_signal_connect (G_OBJECT (priv->filename_view), "button-release-event", G_CALLBACK (button_release_event), instance); + g_signal_connect (G_OBJECT (priv->size_view), "button-press-event", G_CALLBACK (button_press_event), instance); + g_signal_connect (G_OBJECT (priv->size_view), "button-release-event", G_CALLBACK (button_release_event), instance); + g_signal_connect (G_OBJECT (icon_eventbox), "button-press-event", G_CALLBACK (button_press_event), instance); + g_signal_connect (G_OBJECT (icon_eventbox), "button-release-event", G_CALLBACK (button_release_event), instance); + + return; +} + +static void +modest_attachment_view_finalize (GObject *object) +{ + ModestAttachmentViewPriv *priv = MODEST_ATTACHMENT_VIEW_GET_PRIVATE (object); + + if (priv->get_size_idle_id) { + g_source_remove (priv->get_size_idle_id); + priv->get_size_idle_id = 0; + } + + if (priv->get_size_stream != NULL) { + g_object_unref (priv->get_size_stream); + priv->get_size_stream = NULL; + } + + if (G_LIKELY (priv->mime_part)) { + g_object_unref (G_OBJECT (priv->mime_part)); + priv->mime_part = NULL; + } + + (*parent_class->finalize) (object); + + return; +} + +static void +size_allocate (GtkWidget *widget, GtkAllocation *allocation) +{ + ModestAttachmentViewPriv *priv = MODEST_ATTACHMENT_VIEW_GET_PRIVATE (widget); + gint width, width_diff; + + GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation); + pango_layout_get_pixel_size (priv->layout_full_filename, &width, NULL); + width_diff = priv->filename_view->allocation.width - width; + if (width_diff > 0) { + GtkAllocation filename_alloc, filesize_alloc; + filename_alloc = priv->filename_view->allocation; + filesize_alloc = priv->size_view->allocation; + filename_alloc.width -= width_diff; + filesize_alloc.width += width_diff; + filesize_alloc.x -= width_diff; + gtk_widget_size_allocate (priv->filename_view, &filename_alloc); + gtk_widget_size_allocate (priv->size_view, &filesize_alloc); + } + +} + + +static void +modest_attachment_view_class_init (ModestAttachmentViewClass *klass) +{ + GObjectClass *object_class; + GtkWidgetClass *widget_class; + + parent_class = g_type_class_peek_parent (klass); + object_class = (GObjectClass*) klass; + widget_class = GTK_WIDGET_CLASS (klass); + + object_class->finalize = modest_attachment_view_finalize; + + klass->get_part_func = modest_attachment_view_get_part_default; + klass->set_part_func = modest_attachment_view_set_part_default; + klass->clear_func = modest_attachment_view_clear_default; + klass->activate = NULL; + + widget_class->size_allocate = size_allocate; + + g_type_class_add_private (object_class, sizeof (ModestAttachmentViewPriv)); + + signals[ACTIVATE_SIGNAL] = + g_signal_new ("activate", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, + G_STRUCT_OFFSET(ModestAttachmentViewClass, activate), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + return; +} + +static void +tny_mime_part_view_init (gpointer g, gpointer iface_data) +{ + TnyMimePartViewIface *klass = (TnyMimePartViewIface *)g; + + klass->get_part_func = modest_attachment_view_get_part; + klass->set_part_func = modest_attachment_view_set_part; + klass->clear_func = modest_attachment_view_clear; + + return; +} + +GType +modest_attachment_view_get_type (void) +{ + static GType type = 0; + + if (G_UNLIKELY(type == 0)) + { + static const GTypeInfo info = + { + sizeof (ModestAttachmentViewClass), + NULL, /* base_init */ + NULL, /* base_finalize */ + (GClassInitFunc) modest_attachment_view_class_init, /* class_init */ + NULL, /* class_finalize */ + NULL, /* class_data */ + sizeof (ModestAttachmentView), + 0, /* n_preallocs */ + modest_attachment_view_instance_init /* instance_init */ + }; + + static const GInterfaceInfo tny_mime_part_view_info = + { + (GInterfaceInitFunc) tny_mime_part_view_init, /* interface_init */ + NULL, /* interface_finalize */ + NULL /* interface_data */ + }; + + type = g_type_register_static (GTK_TYPE_HBOX, + "ModestAttachmentView", + &info, 0); + + g_type_add_interface_static (type, TNY_TYPE_MIME_PART_VIEW, + &tny_mime_part_view_info); + + } + + return type; +} diff --git a/src/widgets/modest-attachment-view.h b/src/widgets/modest-attachment-view.h new file mode 100644 index 0000000..fe6416e --- /dev/null +++ b/src/widgets/modest-attachment-view.h @@ -0,0 +1,73 @@ +/* Copyright (c) 2007, Nokia Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Nokia Corporation nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef MODEST_ATTACHMENT_VIEW_H +#define MODEST_ATTACHMENT_VIEW_H +#include +#include +#include + +G_BEGIN_DECLS + +#define MODEST_TYPE_ATTACHMENT_VIEW (modest_attachment_view_get_type ()) +#define MODEST_ATTACHMENT_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MODEST_TYPE_ATTACHMENT_VIEW, ModestAttachmentView)) +#define MODEST_ATTACHMENT_VIEW_CLASS(vtable) (G_TYPE_CHECK_CLASS_CAST ((vtable), MODEST_TYPE_ATTACHMENT_VIEW, ModestAttachmentViewClass)) +#define MODEST_IS_ATTACHMENT_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MODEST_TYPE_ATTACHMENT_VIEW)) +#define MODEST_IS_ATTACHMENT_VIEW_CLASS(vtable) (G_TYPE_CHECK_CLASS_TYPE ((vtable), MODEST_TYPE_ATTACHMENT_VIEW)) +#define MODEST_ATTACHMENT_VIEW_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), MODEST_TYPE_ATTACHMENT_VIEW, ModestAttachmentViewClass)) + +typedef struct _ModestAttachmentView ModestAttachmentView; +typedef struct _ModestAttachmentViewClass ModestAttachmentViewClass; + +struct _ModestAttachmentView +{ + GtkHBox parent; + +}; + +struct _ModestAttachmentViewClass +{ + GtkHBoxClass parent_class; + + /* virtual methods */ + TnyMimePart* (*get_part_func) (TnyMimePartView *self); + void (*set_part_func) (TnyMimePartView *self, TnyMimePart *part); + void (*clear_func) (TnyMimePartView *self); + + /* signals */ + void (*activate) (ModestAttachmentView *attachment_view); +}; + +GType modest_attachment_view_get_type (void); + +GtkWidget* modest_attachment_view_new (TnyMimePart *mime_part); + +G_END_DECLS + +#endif diff --git a/src/widgets/modest-attachments-view.c b/src/widgets/modest-attachments-view.c index 8be4f73..d07635e 100644 --- a/src/widgets/modest-attachments-view.c +++ b/src/widgets/modest-attachments-view.c @@ -39,6 +39,7 @@ #include #include +#include #include static GObjectClass *parent_class = NULL; @@ -61,6 +62,16 @@ struct _ModestAttachmentsViewPriv static guint signals[LAST_SIGNAL] = {0}; +static void +activate_attachment (ModestAttachmentView *attachment_view, + gpointer userdata) +{ + TnyMimePart *mime_part; + + mime_part = tny_mime_part_view_get_part (TNY_MIME_PART_VIEW (attachment_view)); + g_signal_emit (G_OBJECT (userdata), signals[ACTIVATE_SIGNAL], 0, mime_part); + g_object_unref (mime_part); +} /** * modest_attachments_view_new: @@ -73,7 +84,11 @@ static guint signals[LAST_SIGNAL] = {0}; GtkWidget* modest_attachments_view_new (TnyMsg *msg) { - ModestAttachmentsView *self = g_object_new (MODEST_TYPE_ATTACHMENTS_VIEW, NULL); + ModestAttachmentsView *self = g_object_new (MODEST_TYPE_ATTACHMENTS_VIEW, + "homogeneous", FALSE, + "spacing", 0, + "resize-mode", GTK_RESIZE_PARENT, + NULL); modest_attachments_view_set_message (self, msg); @@ -86,11 +101,7 @@ modest_attachments_view_set_message (ModestAttachmentsView *attachments_view, Tn ModestAttachmentsViewPriv *priv = MODEST_ATTACHMENTS_VIEW_GET_PRIVATE (attachments_view); TnyList *parts; TnyIterator *iter; - gint index = 0; - GtkTextBuffer *buffer = NULL; gboolean has_first = FALSE; - GtkTextIter text_iter; - gint icon_height; if (priv->msg) g_object_unref (priv->msg); @@ -98,13 +109,10 @@ modest_attachments_view_set_message (ModestAttachmentsView *attachments_view, Tn g_object_ref (G_OBJECT(msg)); priv->msg = msg; - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (attachments_view)); - gtk_text_buffer_set_text (buffer, "", -1); - gtk_text_buffer_get_end_iter (buffer, &text_iter); + gtk_container_foreach (GTK_CONTAINER (attachments_view), (GtkCallback) gtk_widget_destroy, NULL); + if (priv->msg == NULL) { - gtk_widget_hide (GTK_WIDGET (attachments_view)); return; } @@ -112,121 +120,30 @@ modest_attachments_view_set_message (ModestAttachmentsView *attachments_view, Tn tny_mime_part_get_parts (TNY_MIME_PART (priv->msg), parts); iter = tny_list_create_iterator (parts); - gtk_icon_size_lookup (GTK_ICON_SIZE_BUTTON, NULL, &icon_height); - while (!tny_iterator_is_done (iter)) { TnyMimePart *part; - ++index; part = TNY_MIME_PART (tny_iterator_get_current (iter)); if (tny_mime_part_is_attachment (part)) { - const gchar *filename = tny_mime_part_get_filename (part); - gchar *file_icon_name = - modest_platform_get_file_icon_name (filename, tny_mime_part_get_content_type(part) , NULL); - GdkPixbuf *pixbuf = NULL; - GtkTextTag *tag = NULL; - - if (has_first) { - gtk_text_buffer_insert (buffer, &text_iter, ", ", -1); - gtk_text_buffer_get_end_iter (buffer, &text_iter); - } - - tag = gtk_text_buffer_create_tag (buffer, NULL, - "underline", PANGO_UNDERLINE_SINGLE, - "foreground", "blue", - NULL); - - g_object_set_data (G_OBJECT (tag), "attachment-index", GINT_TO_POINTER (index)); - g_object_set_data (G_OBJECT (tag), "attachment-set", GINT_TO_POINTER (TRUE)); - - if (file_icon_name) { - pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (), file_icon_name, - icon_height, GTK_ICON_LOOKUP_USE_BUILTIN, NULL); - if (pixbuf) { - GtkTextTag *pixbuf_tag; - GtkTextIter iter2; - pixbuf_tag = gtk_text_buffer_create_tag (buffer, NULL, NULL); - g_object_set_data (G_OBJECT (pixbuf_tag), "attachment-index", GINT_TO_POINTER (index)); - g_object_set_data (G_OBJECT (pixbuf_tag), "attachment-set", GINT_TO_POINTER (TRUE)); - gtk_text_buffer_insert_pixbuf (buffer, &text_iter, pixbuf); - iter2 = text_iter; - gtk_text_iter_backward_char (&iter2); - gtk_text_buffer_apply_tag (buffer, pixbuf_tag, &iter2, &text_iter); - gtk_text_buffer_get_end_iter (buffer, &text_iter); - } - } - gtk_text_buffer_insert_with_tags (buffer, &text_iter, filename, -1, tag, NULL); - gtk_text_buffer_get_end_iter (buffer, &text_iter); - if (file_icon_name) - g_free (file_icon_name); + GtkWidget *att_view = NULL; + att_view = modest_attachment_view_new (part); + gtk_box_pack_end (GTK_BOX (attachments_view), att_view, FALSE, FALSE, 0); + gtk_widget_show_all (att_view); + g_signal_connect (G_OBJECT (att_view), "activate", G_CALLBACK (activate_attachment), (gpointer) attachments_view); has_first = TRUE; } g_object_unref (part); tny_iterator_next (iter); } - if (has_first) - gtk_widget_show (GTK_WIDGET (attachments_view)); - else - gtk_widget_hide (GTK_WIDGET (attachments_view)); - -} - -static gboolean -button_release_event (GtkWidget *widget, - GdkEventButton *event, - gpointer user_data) -{ - gint buffer_x, buffer_y; - GtkTextIter iter; - GSList *tags = NULL; - GSList *node = NULL; - - if ((event->type != GDK_BUTTON_RELEASE) - || (event->button != 1)) - return FALSE; - - gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (widget), GTK_TEXT_WINDOW_WIDGET, - event->x, event->y, &buffer_x, &buffer_y); - gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (widget), &iter, buffer_x, buffer_y); - - tags = gtk_text_iter_get_tags (&iter); - - for (node = tags; node != NULL; node = g_slist_next (node)) { - GtkTextTag *tag = node->data; - gboolean is_attachment = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tag), "attachment-set")); - - if (is_attachment) { - gint attachment_index = 0; + gtk_widget_queue_draw (GTK_WIDGET (attachments_view)); - attachment_index = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (tag), "attachment-index")); - g_signal_emit (G_OBJECT (widget), signals[ACTIVATE_SIGNAL], 0, - attachment_index); - break; - } - - } - return FALSE; } static void modest_attachments_view_instance_init (GTypeInstance *instance, gpointer g_class) { ModestAttachmentsViewPriv *priv = MODEST_ATTACHMENTS_VIEW_GET_PRIVATE (instance); - GtkTextBuffer *buffer = NULL; - - gtk_text_view_set_editable (GTK_TEXT_VIEW (instance), FALSE); - gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (instance), GTK_WRAP_WORD_CHAR); - gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (instance), 0); - gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (instance), 0); - gtk_text_view_set_justification (GTK_TEXT_VIEW (instance), GTK_JUSTIFY_LEFT); - gtk_text_view_set_left_margin (GTK_TEXT_VIEW (instance), 0); - gtk_text_view_set_right_margin (GTK_TEXT_VIEW (instance), 0); - gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (instance), FALSE); - - buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (instance)); - - g_signal_connect (G_OBJECT (instance), "button-release-event", G_CALLBACK (button_release_event), NULL); priv->msg = NULL; @@ -270,8 +187,8 @@ modest_attachments_view_class_init (ModestAttachmentsViewClass *klass) G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION, G_STRUCT_OFFSET(ModestAttachmentsViewClass, activate), NULL, NULL, - g_cclosure_marshal_VOID__INT, - G_TYPE_NONE, 1, G_TYPE_INT); + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_OBJECT); return; } @@ -296,7 +213,7 @@ modest_attachments_view_get_type (void) modest_attachments_view_instance_init /* instance_init */ }; - type = g_type_register_static (GTK_TYPE_TEXT_VIEW, + type = g_type_register_static (GTK_TYPE_VBOX, "ModestAttachmentsView", &info, 0); diff --git a/src/widgets/modest-attachments-view.h b/src/widgets/modest-attachments-view.h index fe11722..c4472e1 100644 --- a/src/widgets/modest-attachments-view.h +++ b/src/widgets/modest-attachments-view.h @@ -47,15 +47,15 @@ typedef struct _ModestAttachmentsViewClass ModestAttachmentsViewClass; struct _ModestAttachmentsView { - GtkTextView parent; + GtkVBox parent; }; struct _ModestAttachmentsViewClass { - GtkTextViewClass parent_class; + GtkVBoxClass parent_class; - void (*activate) (ModestAttachmentsView *attachments_view, gint index); + void (*activate) (ModestAttachmentsView *attachments_view, TnyMimePart *mime_part); }; GType modest_attachments_view_get_type (void); diff --git a/src/widgets/modest-mail-header-view.c b/src/widgets/modest-mail-header-view.c index 54720fd..93d0e2c 100644 --- a/src/widgets/modest-mail-header-view.c +++ b/src/widgets/modest-mail-header-view.c @@ -65,6 +65,56 @@ struct _ModestMailHeaderViewPriv static guint signals[LAST_SIGNAL] = {0}; static void +add_date_time_header (ModestMailHeaderView *mail_header, const gchar *name, time_t date) +{ + const guint BUF_SIZE = 64; + gchar date_buf [BUF_SIZE]; + gchar time_buf [BUF_SIZE]; + + ModestMailHeaderViewPriv *priv = MODEST_MAIL_HEADER_VIEW_GET_PRIVATE (mail_header); + GtkWidget *hbox, *date_hbox, *time_hbox; + GtkWidget *label; + gchar *bolded_field = NULL; + + modest_text_utils_strftime (date_buf, BUF_SIZE, "%x", date); + modest_text_utils_strftime (time_buf, BUF_SIZE, "%X", date); + + hbox = gtk_hbox_new (FALSE, 48); + date_hbox = gtk_hbox_new (FALSE, 12); + time_hbox = gtk_hbox_new (FALSE, 12); + + label = gtk_label_new (NULL); + bolded_field = g_strconcat ("", name, "", NULL); + gtk_label_set_markup (GTK_LABEL (label), bolded_field); + g_free (bolded_field); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0); + gtk_box_pack_start (GTK_BOX (date_hbox), label, FALSE, FALSE, 0); + gtk_size_group_add_widget (priv->labels_size_group, label); + + label = gtk_label_new(date_buf); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0); + gtk_box_pack_start (GTK_BOX (date_hbox), label, TRUE, TRUE, 0); + + gtk_box_pack_start (GTK_BOX (hbox), date_hbox, FALSE, FALSE, 0); + + label = gtk_label_new(NULL); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0); + bolded_field = g_strconcat ("", _("mail_va_time"), "", NULL); + gtk_label_set_markup (GTK_LABEL (label), bolded_field); + g_free (bolded_field); + gtk_box_pack_start (GTK_BOX (time_hbox), label, FALSE, FALSE, 0); + + label = gtk_label_new(time_buf); + gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.0); + gtk_box_pack_start (GTK_BOX (time_hbox), label, TRUE, TRUE, 0); + + gtk_box_pack_start (GTK_BOX (hbox), time_hbox, TRUE, TRUE, 0); + + gtk_box_pack_start (GTK_BOX (priv->headers_vbox), hbox, FALSE, FALSE, 0); + gtk_widget_show (hbox); +} + +static void activate_recpt (GtkWidget *recpt_view, const gchar *address, gpointer user_data) { ModestMailHeaderView * view = MODEST_MAIL_HEADER_VIEW (user_data); @@ -203,6 +253,7 @@ modest_mail_header_view_set_header_default (TnyHeaderView *self, TnyHeader *head if (header && G_IS_OBJECT (header)) { const gchar *to, *from, *subject, *bcc, *cc; + GtkWidget *subject_box, *subject_label; g_object_ref (G_OBJECT (header)); priv->header = header; @@ -216,34 +267,55 @@ modest_mail_header_view_set_header_default (TnyHeaderView *self, TnyHeader *head cc = tny_header_get_cc (header); bcc = tny_header_get_bcc (header); + subject_box = gtk_hbox_new (FALSE, 12); + subject_label = gtk_label_new (NULL); if (subject) - add_header (MODEST_MAIL_HEADER_VIEW (self), _("mail_va_subject"), subject); + gtk_label_set_text (GTK_LABEL (subject_label), subject); + else + gtk_label_set_text (GTK_LABEL (subject_label), _("mail_va_no_subject")); + gtk_label_set_single_line_mode (GTK_LABEL (subject_label), TRUE); + gtk_label_set_ellipsize (GTK_LABEL (subject_label), PANGO_ELLIPSIZE_END); + gtk_label_set_selectable (GTK_LABEL (subject_label), TRUE); + gtk_misc_set_alignment (GTK_MISC (subject_label), 0.0, 0.0); + + /* TODO: code disabled until we can get real priority information from message */ +/* if (tny_header_get_flags (header) & TNY_HEADER_FLAG_PRIORITY) { */ +/* GtkWidget *priority_icon = gtk_image_new_from_icon_name ("qgn_list_messaging_high", GTK_ICON_SIZE_MENU); */ +/* gtk_box_pack_start (GTK_BOX (subject_box), priority_icon, FALSE, FALSE, 0); */ +/* } */ + gtk_box_pack_start (GTK_BOX (subject_box), subject_label, TRUE, TRUE, 0); if (priv->is_outgoing) { - gchar *sent = modest_text_utils_get_display_date (tny_header_get_date_sent (header)); gchar *bolded_label = g_strconcat ("", _("mail_va_to"), "", NULL); gtk_label_set_markup (GTK_LABEL (priv->fromto_label), bolded_label); g_free (bolded_label); if (to) modest_recpt_view_set_recipients (MODEST_RECPT_VIEW (priv->fromto_contents), to); + if (cc) + add_recpt_header (MODEST_MAIL_HEADER_VIEW (self), _("mail_va_cc"), cc); + if (bcc) + add_recpt_header (MODEST_MAIL_HEADER_VIEW (self), _("mail_va_hotfix1"), bcc); + if (priv->is_draft&& from) + add_recpt_header (MODEST_MAIL_HEADER_VIEW (self), _("mail_va_from"), from); + modest_mail_header_view_add_custom_header (MODEST_MAIL_HEADER_VIEW (self), _("mail_va_subject"), subject_box, TRUE, TRUE); if (priv->is_draft) - add_header (MODEST_MAIL_HEADER_VIEW (self), _("fixme_Last saved:"), sent); + add_date_time_header (MODEST_MAIL_HEADER_VIEW (self), _("fixme_Last saved:"), tny_header_get_date_sent (header)); else - add_header (MODEST_MAIL_HEADER_VIEW (self), _("fixme_Sent:"), sent); - g_free (sent); + add_date_time_header (MODEST_MAIL_HEADER_VIEW (self), _("fixme_Sent:"), tny_header_get_date_sent (header)); } else { - gchar *received = modest_text_utils_get_display_date (tny_header_get_date_received (header)); gchar *bolded_label = g_strconcat ("", _("mail_va_from"), "", NULL); gtk_label_set_markup (GTK_LABEL (priv->fromto_label), bolded_label); g_free (bolded_label); if (from) modest_recpt_view_set_recipients (MODEST_RECPT_VIEW (priv->fromto_contents), from); - add_header (MODEST_MAIL_HEADER_VIEW (self), _("fixme_Received:"), received); - g_free (received); + if (cc) + add_recpt_header (MODEST_MAIL_HEADER_VIEW (self), _("mail_va_cc"), cc); + if (bcc) + add_recpt_header (MODEST_MAIL_HEADER_VIEW (self), _("mail_va_hotfix1"), bcc); + if (to) + add_recpt_header (MODEST_MAIL_HEADER_VIEW (self), _("mail_va_to"), to); + modest_mail_header_view_add_custom_header (MODEST_MAIL_HEADER_VIEW (self), _("mail_va_subject"), subject_box, TRUE, TRUE); + add_date_time_header (MODEST_MAIL_HEADER_VIEW (self), _("fixme_Received:"), tny_header_get_date_received (header)); } - if (cc) - add_recpt_header (MODEST_MAIL_HEADER_VIEW (self), _("mail_va_cc"), cc); - if (bcc) - add_recpt_header (MODEST_MAIL_HEADER_VIEW (self), _("mail_va_hotfix1"), bcc); } gtk_widget_show_all (GTK_WIDGET (self)); @@ -299,6 +371,46 @@ expander_activate (GtkWidget *expander, ModestMailHeaderView *header_view) gtk_widget_queue_draw (GTK_WIDGET (priv->expander)); } +const GtkWidget * +modest_mail_header_view_add_custom_header (ModestMailHeaderView *header_view, + const gchar *label, + GtkWidget *custom_widget, + gboolean with_expander, + gboolean start) +{ + ModestMailHeaderViewPriv *priv; + g_return_val_if_fail (MODEST_IS_MAIL_HEADER_VIEW (header_view), NULL); + GtkWidget *hbox; + GtkWidget *label_field; + gchar *bolded_field = NULL; + + priv = MODEST_MAIL_HEADER_VIEW_GET_PRIVATE (header_view); + hbox = gtk_hbox_new (FALSE, 12); + label_field = gtk_label_new (NULL); + if (label != NULL) + bolded_field = g_strconcat ("", label, "", NULL); + gtk_label_set_markup (GTK_LABEL (label_field), bolded_field); + g_free (bolded_field); + gtk_misc_set_alignment (GTK_MISC (label_field), 0.0, 0.0); + gtk_box_pack_start (GTK_BOX (hbox), label_field, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (hbox), custom_widget, TRUE, TRUE, 0); + gtk_size_group_add_widget (priv->labels_size_group, label_field); + + if (with_expander) { + if (start) + gtk_box_pack_start (GTK_BOX (priv->headers_vbox), hbox, FALSE, FALSE, 0); + else + gtk_box_pack_end (GTK_BOX (priv->headers_vbox), hbox, FALSE, FALSE, 0); + } else { + if (start) + gtk_box_pack_start (GTK_BOX (priv->main_vbox), hbox, FALSE, FALSE, 0); + else + gtk_box_pack_end (GTK_BOX (priv->main_vbox), hbox, FALSE, FALSE, 0); + } + + return hbox; +} + /** * modest_mail_header_view_new: * diff --git a/src/widgets/modest-mail-header-view.h b/src/widgets/modest-mail-header-view.h index bf76528..ff2a3a5 100644 --- a/src/widgets/modest-mail-header-view.h +++ b/src/widgets/modest-mail-header-view.h @@ -69,6 +69,12 @@ struct _ModestMailHeaderViewClass GType modest_mail_header_view_get_type (void); TnyHeaderView* modest_mail_header_view_new (void); +const GtkWidget *modest_mail_header_view_add_custom_header (ModestMailHeaderView *header_view, + const gchar *label, + GtkWidget *custom_widget, + gboolean with_expander, + gboolean start); + G_END_DECLS #endif diff --git a/src/widgets/modest-msg-edit-window-ui.h b/src/widgets/modest-msg-edit-window-ui.h index 3a6ae4d..d10bcd0 100644 --- a/src/widgets/modest-msg-edit-window-ui.h +++ b/src/widgets/modest-msg-edit-window-ui.h @@ -42,9 +42,14 @@ static const GtkActionEntry modest_msg_edit_action_entries [] = { { "View", NULL, N_("_View") }, { "Insert", NULL, N_("_Insert") }, { "Format", NULL, N_("For_mat") }, + { "Alignment", NULL, N_("_Alignment") }, + { "Attachments", NULL, N_("Attachments") }, /* ACTIONS */ { "ActionsSend", MODEST_STOCK_MAIL_SEND, N_("Send"), NULL, N_("Send a message"), G_CALLBACK (modest_ui_actions_on_send) }, + { "ActionsFontColor", GTK_STOCK_SELECT_COLOR, N_("Color"), NULL, N_("Change text color"), G_CALLBACK (modest_ui_actions_on_select_editor_color)}, + { "BackgroundColor", GTK_STOCK_SELECT_COLOR, N_("Background color"), NULL, N_("Change background color"), G_CALLBACK (modest_ui_actions_on_select_editor_background_color)}, + { "InsertImage", NULL, N_("Insert image..."), NULL, N_("Insert image"), G_CALLBACK (modest_ui_actions_on_insert_image)}, }; static const GtkToggleActionEntry modest_msg_edit_toggle_action_entries [] = { @@ -53,6 +58,17 @@ static const GtkToggleActionEntry modest_msg_edit_toggle_action_entries [] = { { "ViewToField", NULL, N_("To: field"), NULL, N_("Shows the To: field"), NULL, TRUE }, { "ViewCcField", NULL, N_("Cc: field"), NULL, N_("Shows the Cc: field"), NULL, TRUE }, { "ViewBccField", NULL, N_("Bcc: filed"), NULL, N_("Shows the Bcc: field"), NULL, FALSE }, + + /* Rich text editor functions */ + { "ActionsBold", GTK_STOCK_BOLD, N_("Bold"), NULL, N_("Use bold"), G_CALLBACK (modest_ui_actions_on_toggle_bold), FALSE }, + { "ActionsItalics", GTK_STOCK_ITALIC, N_("Italics"), NULL, N_("Use italics"), G_CALLBACK (modest_ui_actions_on_toggle_italics), FALSE }, + { "ActionsBulletedList", MODEST_TOOLBAR_ICON_FORMAT_BULLETS, N_("Bullet list"), NULL, N_("Add a bullet list"), G_CALLBACK (modest_ui_actions_on_toggle_bullets), FALSE }, +}; + +static const GtkRadioActionEntry modest_msg_edit_alignment_radio_action_entries [] = { + { "AlignmentLeft", NULL, N_("Left"), NULL, N_("Align to the left"), GTK_JUSTIFY_LEFT }, + { "AlignmentCenter", NULL, N_("Center"), NULL, N_("Align to the center"), GTK_JUSTIFY_CENTER }, + { "AlignmentRight", NULL, N_("Right"), NULL, N_("Align to the right"), GTK_JUSTIFY_RIGHT }, }; G_END_DECLS diff --git a/src/widgets/modest-msg-edit-window.h b/src/widgets/modest-msg-edit-window.h index 575d493..4d91d4a 100644 --- a/src/widgets/modest-msg-edit-window.h +++ b/src/widgets/modest-msg-edit-window.h @@ -65,10 +65,26 @@ typedef enum { MODEST_EDIT_TYPE_NUM } ModestEditType; +typedef enum { + MODEST_MSG_EDIT_FORMAT_TEXT, + MODEST_MSG_EDIT_FORMAT_HTML +} ModestMsgEditFormat; + typedef struct { - gchar *from, *to, *cc, *bcc, *subject, *body; + gchar *from, *to, *cc, *bcc, *subject, *plain_body, *html_body; + GList *attachments; } MsgData; +typedef struct { + gboolean bold; + gboolean italics; + gboolean bullet; + GdkColor color; + const gchar *font_family; + gint font_size; + GtkJustification justification; +} ModestMsgEditFormatState; + /** * modest_msg_edit_window_get_type: @@ -113,6 +129,73 @@ MsgData * modest_msg_edit_window_get_msg_data (ModestMsgE **/ void modest_msg_edit_window_free_msg_data (ModestMsgEditWindow *self, MsgData *data); + +/** + * modest_msg_edit_window_get_format: + * @self: a #ModestMsgEditWindow + * + * obtains the format type of the message body. + * + * Returns: a #ModestMsgEditFormat + **/ +ModestMsgEditFormat modest_msg_edit_window_get_format (ModestMsgEditWindow *self); + +/** + * modest_msg_edit_window_set_format: + * @self: a #ModestMsgEditWindow + * @format: a #ModestMsgEditFormat + * + * set the @format of the edit window message body. + **/ +void modest_msg_edit_window_set_format (ModestMsgEditWindow *self, + ModestMsgEditFormat format); + +/** + * modest_msg_edit_window_get_format_state: + * @self: a #ModestMsgEditWindow + * + * get the current format state (the format attributes the text user inserts + * will get). + * + * Returns: a #ModestMsgEditFormatState structure that should be freed with g_free(). + **/ +ModestMsgEditFormatState *modest_msg_edit_window_get_format_state (ModestMsgEditWindow *self); + +/** + * modest_msg_edit_window_set_format_state: + * @self: a #ModestMsgEditWindow + * @format_state: a #ModestMsgEditWindowFormatState + * + * sets a new format state (the format attributes the text user inserts + * will get). + **/ +void modest_msg_edit_window_set_format_state (ModestMsgEditWindow *self, + const ModestMsgEditFormatState *format_state); + +/** + * modest_msg_edit_window_select_color: + * @self: a #ModestMsgEditWindow + * + * show color selection dialog and update text color + */ +void modest_msg_edit_window_select_color (ModestMsgEditWindow *window); + +/** + * modest_msg_edit_window_select_background_color: + * @self: a #ModestMsgEditWindow + * + * show color selection dialog and update background color + */ +void modest_msg_edit_window_select_background_color (ModestMsgEditWindow *window); + +/** + * modest_msg_edit_window_insert_image: + * @self: a #ModestMsgEditWindow + * + * show a file selection dialog to insert an image + */ +void modest_msg_edit_window_insert_image (ModestMsgEditWindow *window); + G_END_DECLS #endif /* __MODEST_MSG_EDIT_WINDOW_H__ */ diff --git a/src/widgets/modest-msg-view.c b/src/widgets/modest-msg-view.c index e726529..ae6112b 100644 --- a/src/widgets/modest-msg-view.c +++ b/src/widgets/modest-msg-view.c @@ -57,7 +57,7 @@ static void get_property (GObject *object, guint prop_id, GValue *value, GPa /* headers signals */ static void on_recpt_activated (ModestMailHeaderView *header_view, const gchar *address, ModestMsgView *msg_view); -static void on_attachment_activated (ModestAttachmentsView * att_view, gint index, gpointer); +static void on_attachment_activated (ModestAttachmentsView * att_view, TnyMimePart *mime_part, gpointer userdata); /* GtkHtml signals */ static gboolean on_link_clicked (GtkWidget *widget, const gchar *uri, ModestMsgView *msg_view); @@ -113,6 +113,7 @@ struct _ModestMsgViewPrivate { /* embedded elements */ GtkWidget *headers_box; GtkWidget *html_scroll; + GtkWidget *attachments_box; /* internal adjustments for set_scroll_adjustments */ GtkAdjustment *hadj; @@ -230,8 +231,8 @@ modest_msg_view_class_init (ModestMsgViewClass *klass) G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET(ModestMsgViewClass, attachment_clicked), NULL, NULL, - g_cclosure_marshal_VOID__POINTER, - G_TYPE_NONE, 1, G_TYPE_INT); + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_OBJECT); signals[LINK_HOVER_SIGNAL] = g_signal_new ("link_hover", @@ -857,7 +858,6 @@ modest_msg_view_init (ModestMsgView *obj) gtk_widget_set_no_show_all (priv->mail_header_view, TRUE); priv->attachments_view = GTK_WIDGET(modest_attachments_view_new (NULL)); - gtk_widget_set_no_show_all (priv->attachments_view, TRUE); priv->sig1 = g_signal_connect (G_OBJECT(priv->gtkhtml), "link_clicked", G_CALLBACK(on_link_clicked), obj); @@ -1058,8 +1058,13 @@ modest_msg_view_new (TnyMsg *msg) if (priv->mail_header_view) gtk_box_pack_start (GTK_BOX(priv->headers_box), priv->mail_header_view, FALSE, FALSE, 0); - if (priv->attachments_view) - gtk_box_pack_start (GTK_BOX(priv->headers_box), priv->attachments_view, FALSE, FALSE, 0); + if (priv->attachments_view) { + priv->attachments_box = (GtkWidget *) modest_mail_header_view_add_custom_header (MODEST_MAIL_HEADER_VIEW (priv->mail_header_view), + _("Attachments:"), priv->attachments_view, + FALSE, FALSE); + gtk_widget_hide_all (priv->attachments_box); +/* gtk_widget_set_no_show_all (priv->attachments_box, TRUE); */ + } gtk_widget_set_parent (priv->headers_box, GTK_WIDGET (self)); @@ -1082,18 +1087,11 @@ on_recpt_activated (ModestMailHeaderView *header_view, } static void -on_attachment_activated (ModestAttachmentsView * att_view, gint index, gpointer msg_view) +on_attachment_activated (ModestAttachmentsView * att_view, TnyMimePart *mime_part, gpointer msg_view) { - - if (index == 0) { - /* index is 1-based, so 0 indicates an error */ - g_printerr ("modest: invalid attachment index: %d\n", index); - return; - } - g_signal_emit (G_OBJECT(msg_view), signals[ATTACHMENT_CLICKED_SIGNAL], - 0, index); + 0, mime_part); } static gboolean @@ -1297,8 +1295,7 @@ modest_msg_view_set_message (ModestMsgView *self, TnyMsg *msg) tny_header_view_clear (TNY_HEADER_VIEW (priv->mail_header_view)); modest_attachments_view_set_message (MODEST_ATTACHMENTS_VIEW (priv->attachments_view), NULL); gtk_widget_hide_all (priv->mail_header_view); - gtk_widget_hide_all (priv->attachments_view); - gtk_widget_set_no_show_all (priv->attachments_view, TRUE); + gtk_widget_hide_all (priv->attachments_box); gtk_widget_set_no_show_all (priv->mail_header_view, TRUE); set_empty_message (self); gtk_widget_queue_resize (GTK_WIDGET(self)); @@ -1315,16 +1312,29 @@ modest_msg_view_set_message (ModestMsgView *self, TnyMsg *msg) body = modest_tny_msg_find_body_part (msg,TRUE); if (body) { + GList *att_children; if (tny_mime_part_content_type_is (body, "text/html")) set_html_message (self, body, msg); else set_text_message (self, body, msg); + + att_children = gtk_container_get_children (GTK_CONTAINER (priv->attachments_view)); + if (att_children != NULL) { + gtk_widget_show_all (priv->attachments_box); + g_list_free (att_children); + } else { + gtk_widget_hide_all (priv->attachments_box); + } + } else set_empty_message (self); gtk_widget_show (priv->gtkhtml); + gtk_widget_set_no_show_all (priv->attachments_box, TRUE); gtk_widget_show_all (priv->mail_header_view); - gtk_widget_show_all (priv->attachments_view); + gtk_widget_set_no_show_all (priv->attachments_box, FALSE); +/* gtk_widget_show_all (priv->attachments_box); */ +/* gtk_widget_show_all (priv->attachments_box); */ gtk_widget_set_no_show_all (priv->mail_header_view, TRUE); gtk_widget_queue_resize (GTK_WIDGET(self)); gtk_widget_queue_draw (GTK_WIDGET(self)); diff --git a/src/widgets/modest-msg-view.h b/src/widgets/modest-msg-view.h index e02dfaf..8e34f4f 100644 --- a/src/widgets/modest-msg-view.h +++ b/src/widgets/modest-msg-view.h @@ -64,7 +64,7 @@ struct _ModestMsgViewClass { gpointer user_data); void (*link_clicked) (ModestMsgView *msgview, const gchar* link, gpointer user_data); - void (*attachment_clicked) (ModestMsgView *msgview, int index, + void (*attachment_clicked) (ModestMsgView *msgview, TnyMimePart *mime_part, gpointer user_data); void (*recpt_activated) (ModestMsgView *msgview, const gchar *address, gpointer user_data);