* src/widgets/modest-recpt.view.[ch]:
authorJose Dapena Paz <jdapena@igalia.com>
Mon, 5 Mar 2007 18:22:46 +0000 (18:22 +0000)
committerJose Dapena Paz <jdapena@igalia.com>
Mon, 5 Mar 2007 18:22:46 +0000 (18:22 +0000)
        * Changed a lot the structure. Now it inherits from GtkScrolledWindow,
          and contains a GtkTextView (instead of a GtkLabel).
        * This scrolled window is limited to two lines. Then this widget includes
          internal methods for this, and to manage specific scrollbuttons.
        * Removed the calculation of address bounds in a string (it's now in
          text utils).
        * Added a method modest_recpt_view_set_recipients (), as now we don't
          have the GtkLabel API set_text function.
        * Migrated the button press/release events handling to use GtkTextView
          API.
        * Scrollbar button clicks move buffer line by line.
        * Now the activate handler passes a string with the recipient list.
* src/widgets/modest-mail-header-view.[ch]:
        * Modified recpt view activate handler (now it passes a string with
          the activated address, not the recpt view object).
        * Updates to fit the new ModestRecptView api (now it's not
          a GtkLabel child, but a GtkScrolledWindow's).
        * Force allocation update of expander (to prevent a nasty effect on
          expanding more than one time the from/to recpt view. Now the
          full expander is sent to the resize and draw queues.
        * Added alignment hint for from/to label.
        * Set spacing among other headers vbox to 0.
        * Set the mail header "reallocate_redraws" to TRUE
* src/modest-msg-view.c:
        * Use the new recpt view activate API.
* src/modest-ui-actions.[ch]:
        * Added implementation of action "add to contacts". It
          gets the primary selection and calls the addressbook
          add to contacts implementation.
        * Updated API of msg_recpt_view_activated (now handler
          gets a string with the activated address).
* src/modest-text-utils.[ch]:
        * Added modest_text_utils_address_range_at_position, used
          to find addresses in a string (used for automatic selection).
* Added src/modest-address-book.h:
        * Interface to addressbook functions. Implementations fall
          in specific gnome/maemo modules.
* src/Makefile.am:
        * Add modest address book interface.
* src/maemo/modest-main-window-ui.h:
        * Added action for adding primary selection to contacts.
* Added src/maemo/modest-address-book.c:
        * Implementation for maemo of address book interface.
        * Currently it only contains stub implementations, and
          a draft implementation of add to contacts method.
* Added src/gnome/modest-address-book.c:
        * Implementation for gnome of address book interface.
        * Currently it only contains stub implementations.
* src/maemo/Makefile.am
        * Added compilation of address book implementation
* src/gnome/Makefile.am
        * Added compilation of address book implementation
* src/maemo/ui/modest-msg-view-window-ui.xml:
        * Added add to contacts menu option.
* src/maemo/ui/modest-main-window-ui.xml:
        * Added add to contacts menu option.
* src/gnome/ui/modest-main-window-ui.xml:
        * Added add to contacts menu option.
* configure.ac:
        * Added dependency on osso-address-book in MAEMO platform.

pmo-trunk-r886

22 files changed:
configure.ac
src/Makefile.am
src/gnome/Makefile.am
src/gnome/modest-address-book.c [new file with mode: 0644]
src/gnome/modest-main-window-ui.h
src/gnome/ui/modest-main-window-ui.xml
src/maemo/Makefile.am
src/maemo/modest-address-book.c [new file with mode: 0644]
src/maemo/modest-main-window-ui.h
src/maemo/ui/modest-main-window-ui.xml
src/maemo/ui/modest-msg-view-window-ui.xml
src/modest-address-book.h [new file with mode: 0644]
src/modest-text-utils.c
src/modest-text-utils.h
src/modest-ui-actions.c
src/modest-ui-actions.h
src/widgets/modest-mail-header-view.c
src/widgets/modest-mail-header-view.h
src/widgets/modest-msg-view.c
src/widgets/modest-msg-view.h
src/widgets/modest-recpt-view.c
src/widgets/modest-recpt-view.h

index e7754a3..c85b54a 100644 (file)
@@ -87,7 +87,7 @@ esac], [MODEST_PLATFORM=gnome
 AC_SUBST(MODEST_PLATFORM)
 
 if test "x$with_platform" = "xmaemo"; then
-   PKG_CHECK_MODULES(MODEST_LIBTINYMAIL_MAEMO,libtinymail-maemo-1.0 hildon-libs libosso libossomime)
+   PKG_CHECK_MODULES(MODEST_LIBTINYMAIL_MAEMO,libtinymail-maemo-1.0 hildon-libs libosso libossomime osso-addressbook-1.0)
    AC_SUBST(MODEST_LIBTINYMAIL_MAEMO_CFLAGS)
    AC_SUBST(MODEST_LIBTINYMAIL_MAEMO_LIBS) 
  
index 55a3012..1c341b9 100644 (file)
@@ -35,6 +35,7 @@ modest_SOURCES=\
        modest-account-mgr-priv.h\
        modest-account-mgr.c\
        modest-account-mgr.h\
+       modest-address-book.h\
        modest-cache-mgr.c\
        modest-cache-mgr.h\
        modest-conf.c\
index 6358395..a951862 100644 (file)
@@ -27,6 +27,7 @@ libmodest_ui_la_SOURCES=              \
        modest-account-assistant.c    \
        modest-account-assistant.h    \
        modest-account-view-window.c  \
+       modest-address-book.c          \
        modest-msg-edit-window.c      \
        modest-icon-names.h           \
        modest-main-window.c          \
diff --git a/src/gnome/modest-address-book.c b/src/gnome/modest-address-book.c
new file mode 100644 (file)
index 0000000..4dbca7d
--- /dev/null
@@ -0,0 +1,45 @@
+/* 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.
+ */
+
+/* modest-address-book.c */
+
+#include <modest-address-book.h>
+
+void
+modest_address_book_add_address (const gchar *address)
+{
+       g_message (__FUNCTION__);
+}
+
+gchar *
+modest_address_book_select_addresses (void)
+{
+       g_message (__FUNCTION__);
+       return NULL;
+}
index b62b390..ce2f341 100644 (file)
@@ -85,6 +85,7 @@ static const GtkActionEntry modest_action_entries [] = {
        { "GotoNext",     GTK_STOCK_GO_FORWARD, N_("Next"),     NULL, N_("Go to next message"), G_CALLBACK (modest_ui_actions_on_next) },
 
        /* OPTIONS */
+       { "OptionsAddToContacts", NULL, N_("A_dd to accounts"), NULL, N_("Add selection to accounts"), G_CALLBACK (modest_ui_actions_on_add_to_contacts) },
        { "OptionsAccounts",  NULL, N_("_Accounts"), NULL, N_("Manage accounts"), G_CALLBACK (modest_ui_actions_on_accounts) },
        { "OptionsContacts",  NULL, N_("_Contacts"), NULL, N_("Manage contacts"), NULL },
 
index 007e1c5..2e8f21d 100644 (file)
@@ -67,7 +67,9 @@
     </menu>
 
     <menu name="OptionsMenu" action="Options">
+      <menuitem name="OptionsAddToContactsMenu" action="OptionsAddToContacts"/>
       <menuitem name="OptionsAccountsMenu" action="OptionsAccounts"/>
+      <separator/>
       <menuitem name="OptionsContactsMenu" action="OptionsContacts"/>
     </menu>
 
     <menuitem action="ActionsFolderMoveToTrash"/>
   </popup>
 
-</ui>
\ No newline at end of file
+</ui>
index 8c726af..96e1231 100644 (file)
@@ -43,6 +43,7 @@ noinst_LTLIBRARIES=\
 
 libmodest_ui_la_SOURCES=              \
        modest-account-view-window.c  \
+       modest-address-book.c         \
        modest-icon-names.h           \
        modest-main-window.c          \
        modest-main-window-ui.h       \
diff --git a/src/maemo/modest-address-book.c b/src/maemo/modest-address-book.c
new file mode 100644 (file)
index 0000000..8babb30
--- /dev/null
@@ -0,0 +1,119 @@
+/* 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.
+ */
+
+/* modest-address-book.c */
+
+#include <modest-address-book.h>
+#include <libebook/e-book.h>
+#include <libebook/e-book-view.h>
+#include <libosso-abook/osso-abook.h>
+
+static OssoABookContactModel *contact_model =  NULL;
+static EBook *book = NULL;
+static EBookView * book_view = NULL;
+
+
+static void
+get_book_view_cb (EBook *book, EBookStatus status, EBookView *bookview, gpointer data)
+{
+       if (status != E_BOOK_ERROR_OK) {
+               g_object_unref (book);
+               book = NULL;
+               return;
+       }
+       book_view = bookview;
+
+       if (contact_model)
+               osso_abook_tree_model_set_book_view (OSSO_ABOOK_TREE_MODEL (contact_model),
+                                                    book_view);
+
+       e_book_view_start (book_view);
+}
+
+static void
+book_open_cb (EBook *view, EBookStatus status, gpointer data)
+{
+       EBookQuery *query = NULL;
+
+       if (status != E_BOOK_ERROR_OK) {
+               g_object_unref (book);
+               book = NULL;
+               return;
+       }
+       query = e_book_query_any_field_contains ("");
+       e_book_async_get_book_view (book, query, NULL, -1, get_book_view_cb, NULL);
+       e_book_query_unref (query);
+}
+
+static gboolean 
+open_addressbook ()
+{
+       book = e_book_new_system_addressbook (NULL);
+       if (!book)
+               return FALSE;
+
+       e_book_async_open (book, FALSE, book_open_cb, NULL);
+               
+}
+
+void
+modest_address_book_add_address (const gchar *address)
+{
+       OssoABookAccount *account = NULL;
+       GtkWidget *dialog = NULL;
+
+       contact_model = osso_abook_contact_model_new ();
+       if (!open_addressbook ()) {
+               if (contact_model) {
+                       g_object_unref (contact_model);
+                       contact_model = NULL;
+               }
+               return;
+       }
+       
+       account = osso_abook_account_get (EVC_EMAIL, NULL, address);
+       dialog = osso_abook_add_to_contacts_dialog_new (contact_model, account);
+       g_object_unref (account);
+       gtk_dialog_run (GTK_DIALOG (dialog));
+
+       if (contact_model) {
+               g_object_unref (contact_model);
+               contact_model = NULL;
+       }
+
+       gtk_widget_destroy (dialog);
+
+}
+
+gchar *
+modest_address_book_select_addresses (void)
+{
+       g_message (__FUNCTION__);
+}
+
index a0d7797..e299c4f 100644 (file)
@@ -95,6 +95,7 @@ static const GtkActionEntry modest_action_entries [] = {
        
        /* Tools */
        { "ToolsSettings",        NULL,      N_("Settings..."),               NULL, NULL,  NULL },
+       { "ToolsAddToContacts",        NULL,      N_("Add to contact..."),                NULL, NULL,  G_CALLBACK (modest_ui_actions_on_add_to_contacts) },
        { "ToolsContacts",        NULL,      N_("Contact..."),                NULL, NULL,  NULL },
        { "ToolsFontSettings",    NULL,      N_("Font settings..."),          NULL, NULL,  NULL },
        { "ToolsSearchMessages",  NULL,      N_("Search messages..."),        NULL, NULL,  NULL },
index 9cb7b34..55800e6 100644 (file)
@@ -87,6 +87,7 @@
     <menu name="ToolsMenu" action="Tools">
       <menuitem name="ToolsSettingsMenu" action="ToolsSettings"/>
       <separator/>
+      <menuitem name="ToolsAddToContactsMenu" action="ToolsAddToContacts"/>
       <menuitem name="ToolsContactsMenu" action="ToolsContacts"/>
       <menuitem name="ToolsFontSettingsMenu" action="ToolsFontSettings"/>
       <separator/>
index 2495c5e..5d17534 100644 (file)
       <menuitem name="EditMoveToMenu" action="EditMoveTo"/>
     </menu> 
 
+   <menu name="ToolsMenu" action="Tools">
+      <menuitem name="ToolsAddToContactsMenu" action="ToolsAddToContacts"/>
+   </menu>
+
    <menu name="CloseMenu" action="Close">
       <menuitem name="CloseWindowMenu"     action="CloseWindow"/>
     </menu>
diff --git a/src/modest-address-book.h b/src/modest-address-book.h
new file mode 100644 (file)
index 0000000..75a1a9a
--- /dev/null
@@ -0,0 +1,58 @@
+/* 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.
+ */
+
+/* modest-address-book.h */
+
+#ifndef __MODEST_ADDRESS_BOOK_H__
+#define __MODEST_ADDRESS_BOOK_H__
+
+#include <glib.h>
+
+/**
+ * modest_address_book_add_address:
+ * @address: a string
+ *
+ * launches the UI for adding @address to the addressbook
+ */
+void
+modest_address_book_add_address (const gchar *address);
+
+/**
+ * modest_address_book_select_addresses:
+ * 
+ * Shows a dialog to select some addresses from the 
+ * address book.
+ *
+ * Returns: a string with the addresses
+ */
+gchar *
+modest_address_book_select_addresses (void);
+
+
+#endif /* __MODEST_ADDRESS_BOOK_H__ */
index 038ac26..cfa6414 100644 (file)
@@ -376,6 +376,43 @@ modest_text_utils_split_addresses_list (const gchar *addresses)
 
 }
 
+void
+modest_text_utils_address_range_at_position (const gchar *recipients_list,
+                                            gint position,
+                                            gint *start,
+                                            gint *end)
+{
+       gchar *current = NULL;
+       gint range_start = 0;
+       gint range_end = 0;
+       gint index;
+       gboolean is_quoted = FALSE;
+
+       index = 0;
+       for (current = (gchar *) recipients_list; *current != '\0'; current = g_utf8_find_next_char (current, NULL)) {
+               gunichar c = g_utf8_get_char (current);
+
+               if ((c == ',') && (!is_quoted)) {
+                       if (index < position) {
+                               range_start = index + 1;
+                       } else {
+                               break;
+                       }
+               } else if (c == '\"') {
+                       is_quoted = !is_quoted;
+               } else if ((c == ' ') &&(range_start == index)) {
+                       range_start ++;
+               }
+               index ++;
+               range_end = index;
+       }
+
+       if (start)
+               *start = range_start;
+       if (end)
+               *end = range_end;
+}
+
 
 /* ******************************************************************* */
 /* ************************* UTILIY FUNCTIONS ************************ */
index e636ce0..18dea34 100644 (file)
@@ -120,6 +120,24 @@ gchar*   modest_text_utils_remove_address (const gchar *address_list,
                                           const gchar *address);
 
 /**
+ * modest_text_utils_address_range_at_position:
+ * @address_list: utf8 string containing a list of addresses
+ * @position: a gint
+ * @start: a gint pointer
+ * @end: a gint pointer
+ *
+ * Finds the start and end positions of the address at @position,
+ * in @recipients_list, a list of addresses in the format of a 
+ * recipient list in email. It stores the results in @start and
+ * @end
+ */
+void     modest_text_utils_address_range_at_position (const gchar *recipients_list,
+                                                     gint position,
+                                                     gint *start,
+                                                     gint *end);
+                                                     
+
+/**
  * modest_text_utils_convert_to_html:
  * @txt: a string which contains the message to quote
  *
index 1f23d3f..83f60ff 100644 (file)
@@ -36,6 +36,7 @@
 #include <modest-runtime.h>
 #include <modest-tny-msg.h>
 #include <modest-tny-account.h>
+#include <modest-address-book.h>
 
 #include "modest-ui-actions.h"
 
@@ -190,6 +191,19 @@ modest_ui_actions_on_quit (GtkAction *action, ModestWindow *win)
 }
 
 void
+modest_ui_actions_on_add_to_contacts (GtkAction *action, ModestWindow *win)
+{
+       GtkClipboard *clipboard = NULL;
+       gchar *selection = NULL;
+
+       clipboard = gtk_clipboard_get (GDK_SELECTION_PRIMARY);
+       selection = gtk_clipboard_wait_for_text (clipboard);
+
+       modest_address_book_add_address (selection);
+       g_free (selection);
+}
+
+void
 modest_ui_actions_on_accounts (GtkAction *action, ModestWindow *win)
 {
        /* GtkDialog *account_win; */
@@ -955,23 +969,10 @@ modest_ui_actions_on_msg_attachment_clicked (ModestMsgView *msgview, int index,
 
 void
 modest_ui_actions_on_msg_recpt_activated (ModestMsgView *msgview,
-                                         ModestRecptView *recpt_view,
+                                         const gchar *address,
                                          ModestWindow *win)
 {
-       gint start, end;
-       gchar *utf_start, *utf_end;
-       gchar *full_string = NULL;
-       gchar *substring;
-
-       gtk_label_get_selection_bounds (GTK_LABEL (recpt_view), &start, &end);
-       full_string = (gchar *) gtk_label_get_text (GTK_LABEL (recpt_view));
-       utf_start = g_utf8_offset_to_pointer (full_string, start);
-       utf_end = g_utf8_offset_to_pointer (full_string, end);
-       substring = g_strndup (utf_start, utf_end - utf_start);
-       g_message ("%s %s", __FUNCTION__, substring);
-
-       g_free (substring);
-       
+       g_message ("%s %s", __FUNCTION__, address);
 }
 
 void
index 323d7c8..542b062 100644 (file)
@@ -45,6 +45,8 @@ void     modest_ui_actions_on_quit          (GtkAction *action, ModestWindow *wi
 
 void     modest_ui_actions_on_accounts      (GtkAction *action, ModestWindow *win);
 
+void     modest_ui_actions_on_add_to_contacts   (GtkAction *action, ModestWindow *win);
+
 void     modest_ui_actions_on_new_msg       (GtkAction *action, ModestWindow *win);
 
 void     modest_ui_actions_on_open           (GtkAction *action, ModestWindow *win);
@@ -96,7 +98,7 @@ void     modest_ui_actions_on_msg_link_clicked         (ModestMsgView *msgview,
 void     modest_ui_actions_on_msg_attachment_clicked   (ModestMsgView *msgview, int index,
                                                        ModestWindow *win);
 
-void     modest_ui_actions_on_msg_recpt_activated   (ModestMsgView *msgview, ModestRecptView *recpt_view,
+void     modest_ui_actions_on_msg_recpt_activated   (ModestMsgView *msgview, const gchar *address,
                                                     ModestWindow *win);
 
 void     modest_ui_actions_on_send                     (GtkWidget *widget,
index 4e5ac27..77a3ce3 100644 (file)
@@ -64,11 +64,11 @@ struct _ModestMailHeaderViewPriv
 static guint signals[LAST_SIGNAL] = {0};
 
 static void
-activate_recpt (GtkWidget *recpt_view, gpointer user_data)
+activate_recpt (GtkWidget *recpt_view, const gchar *address, gpointer user_data)
 {
        ModestMailHeaderView * view = MODEST_MAIL_HEADER_VIEW (user_data);
 
-       g_signal_emit (G_OBJECT (view), signals[RECPT_ACTIVATED_SIGNAL], 0, recpt_view);
+       g_signal_emit (G_OBJECT (view), signals[RECPT_ACTIVATED_SIGNAL], 0, address);
 }
 
 static void
@@ -108,9 +108,7 @@ add_recpt_header (ModestMailHeaderView *widget, const gchar *field, const gchar
        gtk_label_set_markup (GTK_LABEL (label_field), field);
        gtk_misc_set_alignment (GTK_MISC (label_field), 0.0, 0.0);
        label_value = modest_recpt_view_new ();
-       gtk_label_set_text (GTK_LABEL (label_value), value);
-       gtk_label_set_selectable (GTK_LABEL (label_value), TRUE);
-       gtk_misc_set_alignment (GTK_MISC (label_value), 0.0, 0.0);
+       modest_recpt_view_set_recipients (MODEST_RECPT_VIEW(label_value), value);
        g_signal_connect (G_OBJECT (label_value), "activate", G_CALLBACK (activate_recpt), widget);
 
        gtk_box_pack_start (GTK_BOX (hbox), label_field, FALSE, FALSE, 0);
@@ -173,14 +171,14 @@ modest_mail_header_view_set_header_default (TnyHeaderView *self, TnyHeader *head
                        gchar *sent = modest_text_utils_get_display_date (tny_header_get_date_sent (header));
                        gtk_label_set_markup (GTK_LABEL (priv->fromto_label), _("<b>To:</b>"));
                        if (to)
-                               gtk_label_set_text (GTK_LABEL (priv->fromto_contents), to);
+                               modest_recpt_view_set_recipients (MODEST_RECPT_VIEW (priv->fromto_contents), to);
                        add_header (MODEST_MAIL_HEADER_VIEW (self), _("<b>Sent:</b>"), sent);
                        g_free (sent);
                } else {
                        gchar *received = modest_text_utils_get_display_date (tny_header_get_date_received (header));
                        gtk_label_set_markup (GTK_LABEL (priv->fromto_label), _("<b>From:</b>"));
                        if (from)
-                               gtk_label_set_text (GTK_LABEL (priv->fromto_contents), from);
+                               modest_recpt_view_set_recipients (MODEST_RECPT_VIEW (priv->fromto_contents), from);
                        add_header (MODEST_MAIL_HEADER_VIEW (self), _("<b>Received:</b>"), received);
                        g_free (received);
                }
@@ -214,7 +212,7 @@ modest_mail_header_view_clear_default (TnyHeaderView *self)
        clean_headers (priv->headers_vbox);
 
        gtk_label_set_text (GTK_LABEL (priv->fromto_label), "");
-       gtk_label_set_text (GTK_LABEL (priv->fromto_contents), "");
+       modest_recpt_view_set_recipients (MODEST_RECPT_VIEW (priv->fromto_contents), "");
 
        gtk_widget_hide (GTK_WIDGET(self));
 
@@ -226,6 +224,9 @@ expander_activate (GtkWidget *expander, ModestMailHeaderView *header_view)
 {
        ModestMailHeaderViewPriv *priv = MODEST_MAIL_HEADER_VIEW_GET_PRIVATE (header_view);
 
+       gtk_widget_queue_resize (GTK_WIDGET (header_view));
+       gtk_widget_queue_draw (GTK_WIDGET (header_view));
+
        if (gtk_expander_get_expanded (GTK_EXPANDER (expander))) {
                if (gtk_widget_get_parent (priv->headers_vbox) == NULL) {
                        gtk_box_pack_start (GTK_BOX(priv->main_vbox), priv->headers_vbox, TRUE, TRUE, 0);
@@ -236,8 +237,8 @@ expander_activate (GtkWidget *expander, ModestMailHeaderView *header_view)
                        gtk_container_remove (GTK_CONTAINER (priv->main_vbox), priv->headers_vbox);
                }
        }
-       gtk_widget_queue_resize (GTK_WIDGET (header_view));
-       gtk_widget_queue_draw (GTK_WIDGET (header_view));
+       gtk_widget_queue_resize (GTK_WIDGET (priv->expander));
+       gtk_widget_queue_draw (GTK_WIDGET (priv->expander));
 }
 
 /**
@@ -271,10 +272,8 @@ modest_mail_header_view_instance_init (GTypeInstance *instance, gpointer g_class
 
        fromto_hbox = gtk_hbox_new (FALSE, 12);
        priv->fromto_label = gtk_label_new (NULL);
-       priv->fromto_contents = modest_recpt_view_new ();
-       gtk_label_set_selectable (GTK_LABEL (priv->fromto_contents), TRUE);
        gtk_misc_set_alignment (GTK_MISC (priv->fromto_label), 0.0, 0.0);
-       gtk_misc_set_alignment (GTK_MISC (priv->fromto_contents), 0.0, 0.0);
+       priv->fromto_contents = modest_recpt_view_new ();
        g_signal_connect (G_OBJECT (priv->fromto_contents), "activate", G_CALLBACK (activate_recpt), instance);
 
        gtk_box_pack_start (GTK_BOX (fromto_hbox), priv->fromto_label, FALSE, FALSE, 0);
@@ -284,7 +283,7 @@ modest_mail_header_view_instance_init (GTypeInstance *instance, gpointer g_class
        priv->labels_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
        gtk_size_group_add_widget (priv->labels_size_group, priv->fromto_label);
        
-       priv->headers_vbox = gtk_vbox_new (FALSE, 1);
+       priv->headers_vbox = gtk_vbox_new (FALSE, 0);
        g_object_ref (priv->headers_vbox);
 
        expander_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
@@ -292,6 +291,8 @@ modest_mail_header_view_instance_init (GTypeInstance *instance, gpointer g_class
        gtk_size_group_add_widget (expander_group, fromto_hbox);
        g_object_unref (expander_group);
 
+       gtk_container_set_reallocate_redraws (GTK_CONTAINER (instance), TRUE);
+
        priv->is_sent = FALSE;
 
        return;
@@ -353,9 +354,9 @@ modest_mail_header_view_class_init (ModestMailHeaderViewClass *klass)
                              G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
                              G_STRUCT_OFFSET(ModestMailHeaderViewClass, recpt_activated),
                              NULL, NULL,
-                             g_cclosure_marshal_VOID__POINTER,
+                             g_cclosure_marshal_VOID__STRING,
                              G_TYPE_NONE, 1, 
-                             MODEST_TYPE_RECPT_VIEW);
+                             G_TYPE_STRING);
 
 
        return;
index d949bdc..bf76528 100644 (file)
@@ -63,7 +63,7 @@ struct _ModestMailHeaderViewClass
        void (*clear_func) (TnyHeaderView *self);
 
        /* signals */
-       void (*recpt_activated) (ModestRecptView *recpt_view);
+       void (*recpt_activated) (const gchar *address);
 };
 
 GType modest_mail_header_view_get_type (void);
index b6e25e8..7d1653d 100644 (file)
@@ -50,7 +50,7 @@ static void     modest_msg_view_class_init   (ModestMsgViewClass *klass);
 static void     modest_msg_view_init         (ModestMsgView *obj);
 static void     modest_msg_view_finalize     (GObject *obj);
 
-static void on_recpt_activated (ModestMailHeaderView *header_view, ModestRecptView *recpt_view, ModestMsgView *msg_view);
+static void on_recpt_activated (ModestMailHeaderView *header_view, const gchar *address, ModestMsgView *msg_view);
 static gboolean on_link_clicked (GtkWidget *widget, const gchar *uri, ModestMsgView *msg_view);
 static gboolean on_url_requested (GtkWidget *widget, const gchar *uri, GtkHTMLStream *stream,
                                  ModestMsgView *msg_view);
@@ -153,8 +153,8 @@ modest_msg_view_class_init (ModestMsgViewClass *klass)
                              G_SIGNAL_RUN_FIRST,
                              G_STRUCT_OFFSET(ModestMsgViewClass, recpt_activated),
                              NULL, NULL,
-                             g_cclosure_marshal_VOID__POINTER,
-                             G_TYPE_NONE, 1, MODEST_TYPE_RECPT_VIEW);
+                             g_cclosure_marshal_VOID__STRING,
+                             G_TYPE_NONE, 1, G_TYPE_STRING);
 }
 
 static void
@@ -243,10 +243,10 @@ modest_msg_view_new (TnyMsg *msg)
 
 static void
 on_recpt_activated (ModestMailHeaderView *header_view, 
-                   ModestRecptView *recpt_view,
+                   const gchar *address,
                    ModestMsgView * view)
 {
-  g_signal_emit (G_OBJECT (view), signals[RECPT_ACTIVATED_SIGNAL], 0, recpt_view);
+  g_signal_emit (G_OBJECT (view), signals[RECPT_ACTIVATED_SIGNAL], 0, address);
 }
 
 static gboolean
index 99c16b0..e348762 100644 (file)
@@ -62,7 +62,7 @@ struct _ModestMsgViewClass {
                                    gpointer user_data);
        void (*attachment_clicked) (ModestMsgView *msgview, int index,
                                    gpointer user_data);
-       void (*recpt_activated)    (ModestMsgView *msgview, ModestRecptView *recpt_view,
+       void (*recpt_activated)    (ModestMsgView *msgview, const gchar *address,
                                    gpointer user_data);
 };
 
index 9c45732..f724876 100644 (file)
@@ -34,7 +34,8 @@
 #include <string.h>
 #include <gtk/gtk.h>
 
-#include "modest-recpt-view.h"
+#include <modest-text-utils.h>
+#include <modest-recpt-view.h>
 
 static GObjectClass *parent_class = NULL;
 
@@ -48,8 +49,10 @@ typedef struct _ModestRecptViewPriv ModestRecptViewPriv;
 
 struct _ModestRecptViewPriv
 {
+       GtkWidget *text_view;
        gboolean button_pressed;
        gdouble pressed_x, pressed_y;
+       gint line_height;
 };
 
 #define MODEST_RECPT_VIEW_GET_PRIVATE(o)       \
@@ -57,6 +60,7 @@ struct _ModestRecptViewPriv
 
 static guint signals[LAST_SIGNAL] = {0};
 
+
 /**
  * modest_recpt_view_new:
  *
@@ -70,107 +74,103 @@ modest_recpt_view_new (void)
        return GTK_WIDGET (self);
 }
 
-static void
-address_bounds_at_position (const gchar *recipients_list, gint position, gint *start, gint *end)
+void
+modest_recpt_view_set_recipients (ModestRecptView *recpt_view, const gchar *recipients)
 {
-       gchar *current = NULL;
-       gint range_start = 0;
-       gint range_end = 0;
-       gint index;
-       gboolean is_quoted = FALSE;
-
-       index = 0;
-       for (current = (gchar *) recipients_list; *current != '\0'; current = g_utf8_find_next_char (current, NULL)) {
-               gunichar c = g_utf8_get_char (current);
-
-               if ((c == ',') && (!is_quoted)) {
-                       if (index < position) {
-                               range_start = index + 1;
-                       } else {
-                               break;
-                       }
-               } else if (c == '\"') {
-                       is_quoted = !is_quoted;
-               } else if ((c == ' ') &&(range_start == index)) {
-                       range_start ++;
-               }
-               index ++;
-               range_end = index;
-       }
+       GtkTextBuffer *buffer = NULL;
+       ModestRecptViewPriv *priv = MODEST_RECPT_VIEW_GET_PRIVATE (recpt_view);
+
+       buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->text_view));
+       gtk_text_buffer_set_text (buffer, recipients, -1);
+       gtk_widget_queue_resize (GTK_WIDGET (recpt_view));
 
-       if (start)
-               *start = range_start;
-       if (end)
-               *end = range_end;
 }
 
-static gboolean
+static gint
 button_press_event (GtkWidget *widget,
                    GdkEventButton *event,
                    gpointer user_data)
 {
-       ModestRecptViewPriv *priv = MODEST_RECPT_VIEW_GET_PRIVATE (MODEST_RECPT_VIEW (widget));
-
-       if (!gtk_label_get_selectable (GTK_LABEL (widget)))
-               return FALSE;
+       ModestRecptViewPriv *priv = MODEST_RECPT_VIEW_GET_PRIVATE (MODEST_RECPT_VIEW (user_data));
 
-       if (event->type == GDK_BUTTON_PRESS) {
+       if (event->type == GDK_BUTTON_PRESS && event->button == 1) {
                priv->button_pressed = TRUE;
                priv->pressed_x = event->x;
                priv->pressed_y = event->y;
        }
-       return FALSE;
+       return TRUE;
 }
 
-static gboolean
+static gint
 button_release_event (GtkWidget *widget,
-                    GdkEventButton *event,
-                    gpointer user_data)
+                     GdkEventButton *event,
+                     gpointer user_data)
 {
-       ModestRecptViewPriv *priv = MODEST_RECPT_VIEW_GET_PRIVATE (MODEST_RECPT_VIEW (widget));
-
-       if (!gtk_label_get_selectable (GTK_LABEL (widget)))
-               return TRUE;
+       ModestRecptViewPriv *priv = MODEST_RECPT_VIEW_GET_PRIVATE (MODEST_RECPT_VIEW (user_data));
 
        if (event->type != GDK_BUTTON_RELEASE)
                return TRUE;
 
        if ((priv->button_pressed) &&
-           (event->type == GDK_BUTTON_RELEASE) && 
+           (event->type == GDK_BUTTON_RELEASE) &&
            (priv->pressed_x == event->x) &&
            (priv->pressed_y == event->y)) {
                priv->button_pressed = FALSE;
                if (event->button == 1) {
-                       PangoLayout *layout = NULL;
+                       gint buffer_x, buffer_y;
                        int index;
-                       layout = gtk_label_get_layout (GTK_LABEL (widget));
-                       if (pango_layout_xy_to_index (layout, event->x*PANGO_SCALE, event->y*PANGO_SCALE, &index, NULL)) {
+                       GtkTextIter iter;
+                       gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (priv->text_view), GTK_TEXT_WINDOW_WIDGET,
+                                                              event->x, event->y, &buffer_x, &buffer_y);
+                       gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (priv->text_view), &iter, buffer_x, buffer_y);
+                       index = gtk_text_iter_get_offset (&iter);
+                       
+                       if (!gtk_text_iter_is_end (&iter)) {
                                int selection_start, selection_end;
                                gboolean selected = FALSE;
-                               if (gtk_label_get_selection_bounds (GTK_LABEL (widget),
-                                                                   &selection_start,
-                                                                   &selection_end) &&
-                                   (index >= selection_start)&&(index < selection_end)) {
+                               GtkTextIter start_iter, end_iter;
+                               GtkTextBuffer *buffer;
+
+                               buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (priv->text_view));
+                               if (gtk_text_buffer_get_selection_bounds (buffer, &start_iter, &end_iter) &&
+                                   gtk_text_iter_in_range (&iter, &start_iter, &end_iter)) {
                                        selected = TRUE;
+                               } else {
+                                       gchar *text = NULL;
+                                       GtkTextIter start_iter, end_iter;
+
+                                       gtk_text_buffer_get_start_iter (buffer, &start_iter);
+                                       gtk_text_buffer_get_end_iter (buffer, &end_iter);
+                                       text = gtk_text_buffer_get_text (buffer, &start_iter, &end_iter, FALSE);
+
+                                       modest_text_utils_address_range_at_position (text,
+                                                                                    index,
+                                                                                    &selection_start, &selection_end);
+                                       /* TODO: now gtk label tries to select more than the label as usual,
+                                        *  and we force it to recover the selected region for the defined area.
+                                        *  It should be fixed (maybe preventing gtklabel to manage selections
+                                        *  in parallel with us
+                                        */
+                                       gtk_text_buffer_get_iter_at_offset (buffer, &start_iter, selection_start);
+                                       gtk_text_buffer_get_iter_at_offset (buffer, &end_iter, selection_end);
+                                       gtk_text_buffer_select_range (buffer, &start_iter, &end_iter);
+                                       
+                                       if (text)
+                                               g_free (text);
+                                                                     
+                               }
+
+                               if (selected) {
+                                       gchar *selection;
+
+                                       gtk_text_buffer_get_selection_bounds (buffer, &start_iter, &end_iter);
+                                       selection = gtk_text_buffer_get_text (buffer, &start_iter, &end_iter, FALSE);
+                                       g_signal_emit (G_OBJECT (user_data), signals[ACTIVATE_SIGNAL], 0, selection);
+                                       g_free (selection);
                                }
 
-                               address_bounds_at_position (gtk_label_get_text (GTK_LABEL (widget)),
-                                                           index,
-                                                           &selection_start, &selection_end);
-                               /* TODO: now gtk label tries to select more than the label as usual,
-                                *  and we force it to recover the selected region for the defined area.
-                                *  It should be fixed (maybe preventing gtklabel to manage selections
-                                *  in parallel with us
-                                */
-                               gtk_label_select_region (GTK_LABEL (widget), 
-                                                        selection_start,
-                                                        selection_end);
-                               
-                               if (selected)
-                                       g_signal_emit (G_OBJECT (widget), signals[ACTIVATE_SIGNAL], 0);
-
-                               return TRUE;
                        }
+                       return TRUE;
                }
        }
        priv->button_pressed = FALSE;
@@ -178,15 +178,88 @@ button_release_event (GtkWidget *widget,
 }
 
 static void
+text_view_size_request (GtkWidget *widget,
+                       GtkRequisition *requisition,
+                       gpointer user_data)
+{
+       GtkTextBuffer *buffer = NULL;
+       GtkTextIter iter;
+       int line;
+       GdkRectangle iter_rectangle;
+       GtkWidget *text_view = GTK_WIDGET (user_data);
+       GtkAdjustment *adj = NULL;
+       ModestRecptViewPriv *priv = MODEST_RECPT_VIEW_GET_PRIVATE (widget);
+
+       buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
+
+       gtk_text_buffer_get_start_iter (buffer, &iter);
+       gtk_text_view_get_iter_location (GTK_TEXT_VIEW (text_view), &iter, &iter_rectangle);
+
+       for (line = 0; line < 2; line++) {
+               if (!gtk_text_view_forward_display_line (GTK_TEXT_VIEW (text_view), &iter))
+                       break;
+       }
+
+       gtk_text_buffer_get_start_iter (buffer, &iter);
+
+       gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (text_view), &iter, 0.0, TRUE, 0.0, 0.0);
+
+       adj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (widget));
+       if (adj != NULL) {
+               g_object_set (G_OBJECT (adj), "page-increment", (gdouble) iter_rectangle.height, "step-increment", (gdouble) iter_rectangle.height, NULL);
+               gtk_adjustment_changed (adj);
+       }
+
+       if (line > 0) {
+               requisition->height = iter_rectangle.height * 2;
+       } else {
+               requisition->height = iter_rectangle.height;
+       }
+
+       priv->line_height = iter_rectangle.height;
+       
+}
+
+static void
+view_size_allocate (GtkWidget *widget,
+                   GtkAllocation *allocation,
+                   gpointer user_data)
+{
+       GtkAdjustment *adj = NULL;
+       ModestRecptViewPriv *priv = MODEST_RECPT_VIEW_GET_PRIVATE (widget);
+
+       adj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (widget));
+       if (adj != NULL) {              
+               g_object_set (G_OBJECT (adj), "page-increment", (gdouble) priv->line_height, "step-increment", (gdouble) priv->line_height, NULL);
+       }
+       gtk_adjustment_changed (adj);
+}
+
+static void
 modest_recpt_view_instance_init (GTypeInstance *instance, gpointer g_class)
 {
+       ModestRecptViewPriv *priv = MODEST_RECPT_VIEW_GET_PRIVATE (instance);
+
+       priv->text_view = gtk_text_view_new ();
+
+       gtk_text_view_set_editable (GTK_TEXT_VIEW (priv->text_view), FALSE);
+       gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (priv->text_view), GTK_WRAP_WORD_CHAR);
+       gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (priv->text_view), 0);
+       gtk_text_view_set_pixels_below_lines (GTK_TEXT_VIEW (priv->text_view), 0);
+       gtk_text_view_set_justification (GTK_TEXT_VIEW (priv->text_view), GTK_JUSTIFY_LEFT);
+       gtk_text_view_set_left_margin (GTK_TEXT_VIEW (priv->text_view), 0);
+       gtk_text_view_set_right_margin (GTK_TEXT_VIEW (priv->text_view), 0);
+       gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (priv->text_view), FALSE);
+       gtk_drag_dest_unset (priv->text_view);
+
+       gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (instance), GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC);
 
-       gtk_label_set_justify (GTK_LABEL (instance), GTK_JUSTIFY_LEFT);
-       gtk_label_set_line_wrap (GTK_LABEL (instance), TRUE);
-       gtk_label_set_selectable (GTK_LABEL (instance), TRUE);
+       gtk_container_add (GTK_CONTAINER (instance), priv->text_view);
 
-       g_signal_connect (G_OBJECT (instance), "button-press-event", G_CALLBACK(button_press_event), NULL);
-       g_signal_connect (G_OBJECT (instance), "button-release-event", G_CALLBACK(button_release_event), NULL);
+       g_signal_connect (G_OBJECT (instance), "size-request", G_CALLBACK (text_view_size_request), priv->text_view);
+       g_signal_connect (G_OBJECT (instance), "size-allocate", G_CALLBACK (view_size_allocate), NULL);
+       g_signal_connect (G_OBJECT (priv->text_view), "button-press-event", G_CALLBACK (button_press_event), instance);
+       g_signal_connect (G_OBJECT (priv->text_view), "button-release-event", G_CALLBACK (button_release_event), instance);
 
        return;
 }
@@ -203,9 +276,11 @@ static void
 modest_recpt_view_class_init (ModestRecptViewClass *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_recpt_view_finalize;
 
@@ -219,8 +294,8 @@ modest_recpt_view_class_init (ModestRecptViewClass *klass)
                              G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
                              G_STRUCT_OFFSET(ModestRecptViewClass, activate),
                              NULL, NULL,
-                             g_cclosure_marshal_VOID__VOID,
-                             G_TYPE_NONE, 0);
+                             g_cclosure_marshal_VOID__STRING,
+                             G_TYPE_NONE, 1, G_TYPE_STRING);
        
        return;
 }
@@ -245,7 +320,7 @@ modest_recpt_view_get_type (void)
                  modest_recpt_view_instance_init    /* instance_init */
                };
 
-               type = g_type_register_static (GTK_TYPE_LABEL,
+               type = g_type_register_static (GTK_TYPE_SCROLLED_WINDOW,
                        "ModestRecptView",
                        &info, 0);
 
index 021d24b..3810f7a 100644 (file)
@@ -46,21 +46,23 @@ typedef struct _ModestRecptViewClass ModestRecptViewClass;
 
 struct _ModestRecptView
 {
-       GtkLabel parent;
+       GtkScrolledWindow parent;
 
 };
 
 struct _ModestRecptViewClass
 {
-       GtkLabelClass parent_class;
+       GtkScrolledWindowClass parent_class;
 
-       void (*activate)           (ModestRecptView *recpt_view);
+       void (*activate)           (ModestRecptView *recpt_view, const gchar *address);
 };
 
 GType modest_recpt_view_get_type (void);
 
 GtkWidget* modest_recpt_view_new (void);
 
+void modest_recpt_view_set_recipients (ModestRecptView *recpt_view, const gchar *recipients);
+
 G_END_DECLS
 
 #endif