Fix for bug NB#81584.
[modest] / src / widgets / modest-recpt-view.c
index 9c45732..cb8511c 100644 (file)
 
 #include <glib/gi18n-lib.h>
 
 
 #include <glib/gi18n-lib.h>
 
-#include <string.h>
-#include <gtk/gtk.h>
+#include <gtk/gtkwidget.h>
 
 
-#include "modest-recpt-view.h"
+#include <modest-text-utils.h>
+#include <modest-recpt-view.h>
+
+#define RECPT_VIEW_CLICK_AREA_THRESHOLD 32
 
 static GObjectClass *parent_class = NULL;
 
 
 static GObjectClass *parent_class = NULL;
 
@@ -57,6 +59,14 @@ struct _ModestRecptViewPriv
 
 static guint signals[LAST_SIGNAL] = {0};
 
 
 static guint signals[LAST_SIGNAL] = {0};
 
+/* static functions: GObject */
+static void modest_recpt_view_instance_init (GTypeInstance *instance, gpointer g_class);
+static void modest_recpt_view_finalize (GObject *object);
+static void modest_recpt_view_class_init (ModestRecptViewClass *klass);
+/* static functions: GtkWidget */
+static gint button_press_event (GtkWidget *widget, GdkEventButton *event, gpointer user_data);
+static gint button_release_event (GtkWidget *widget, GdkEventButton *event, gpointer user_data);
+
 /**
  * modest_recpt_view_new:
  *
 /**
  * modest_recpt_view_new:
  *
@@ -70,107 +80,121 @@ modest_recpt_view_new (void)
        return GTK_WIDGET (self);
 }
 
        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;
+       const GtkWidget *text_view = NULL;
+       GtkTextBuffer *buffer = NULL;
+       gchar *std_recipients;
+
+       text_view = modest_scroll_text_get_text_view (MODEST_SCROLL_TEXT (recpt_view));
+       buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (text_view));
+
+       if (recipients == NULL) {
+               std_recipients = NULL;
+       } else {
+               std_recipients = modest_text_utils_address_with_standard_length (recipients);
        }
 
        }
 
-       if (start)
-               *start = range_start;
-       if (end)
-               *end = range_end;
+       gtk_text_buffer_set_text (buffer, std_recipients, -1);
+       g_free (std_recipients);
+       if (GTK_WIDGET_REALIZED (recpt_view))
+               gtk_widget_queue_resize (GTK_WIDGET (recpt_view));
+
 }
 
 }
 
-static gboolean
+static gint
 button_press_event (GtkWidget *widget,
                    GdkEventButton *event,
                    gpointer user_data)
 {
 button_press_event (GtkWidget *widget,
                    GdkEventButton *event,
                    gpointer user_data)
 {
-       ModestRecptViewPriv *priv = MODEST_RECPT_VIEW_GET_PRIVATE (MODEST_RECPT_VIEW (widget));
+       ModestRecptViewPriv *priv = MODEST_RECPT_VIEW_GET_PRIVATE (MODEST_RECPT_VIEW (user_data));
 
 
-       if (!gtk_label_get_selectable (GTK_LABEL (widget)))
-               return FALSE;
-
-       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;
        }
                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,
 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));
+       ModestRecptViewPriv *priv = MODEST_RECPT_VIEW_GET_PRIVATE (MODEST_RECPT_VIEW (user_data));
+       const GtkWidget *text_view = NULL;
 
 
-       if (!gtk_label_get_selectable (GTK_LABEL (widget)))
-               return TRUE;
+       text_view = modest_scroll_text_get_text_view (MODEST_SCROLL_TEXT (user_data));
 
        if (event->type != GDK_BUTTON_RELEASE)
                return TRUE;
 
        if ((priv->button_pressed) &&
 
        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)) {
+           (event->type == GDK_BUTTON_RELEASE) &&
+           ((event->x >= priv->pressed_x - RECPT_VIEW_CLICK_AREA_THRESHOLD)&&
+            (event->x <= priv->pressed_x + RECPT_VIEW_CLICK_AREA_THRESHOLD)) &&
+           ((event->y >= priv->pressed_y - RECPT_VIEW_CLICK_AREA_THRESHOLD)&&
+            (event->y <= priv->pressed_y + RECPT_VIEW_CLICK_AREA_THRESHOLD))) {
                priv->button_pressed = FALSE;
                if (event->button == 1) {
                priv->button_pressed = FALSE;
                if (event->button == 1) {
-                       PangoLayout *layout = NULL;
+                       gint buffer_x, buffer_y;
                        int index;
                        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)) {
-                               int selection_start, selection_end;
+                       GtkTextIter iter;
+                       gtk_widget_grab_focus (GTK_WIDGET (text_view));
+                       gtk_text_view_window_to_buffer_coords (GTK_TEXT_VIEW (text_view), GTK_TEXT_WINDOW_WIDGET,
+                                                              event->x, event->y, &buffer_x, &buffer_y);
+                       gtk_text_view_get_iter_at_location (GTK_TEXT_VIEW (text_view), &iter, buffer_x, buffer_y);
+                       index = gtk_text_iter_get_offset (&iter);
+                       
+                       if (!gtk_text_iter_is_end (&iter)) {
+                               guint selection_start, selection_end;
                                gboolean selected = FALSE;
                                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 (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;
                                        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);
+
+                                       /* text will not be NULL, but source code checkers should be satisfied */
+                                       if (text) {
+                                               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);
+                                               
+                                               g_free (text);
+                                       }                     
                                }
                                }
-
-                               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);
+                               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);
+                               }
 
 
-                               return TRUE;
                        }
                        }
+                       return TRUE;
                }
        }
        priv->button_pressed = FALSE;
                }
        }
        priv->button_pressed = FALSE;
@@ -180,13 +204,12 @@ button_release_event (GtkWidget *widget,
 static void
 modest_recpt_view_instance_init (GTypeInstance *instance, gpointer g_class)
 {
 static void
 modest_recpt_view_instance_init (GTypeInstance *instance, gpointer g_class)
 {
+       const GtkTextView *text_view = NULL;
 
 
-       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);
+       text_view = GTK_TEXT_VIEW(modest_scroll_text_get_text_view (MODEST_SCROLL_TEXT (instance)));
 
 
-       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 (text_view), "button-press-event", G_CALLBACK (button_press_event), instance);
+       g_signal_connect_after (G_OBJECT (text_view), "button-release-event", G_CALLBACK (button_release_event), instance);
 
        return;
 }
 
        return;
 }
@@ -203,9 +226,11 @@ static void
 modest_recpt_view_class_init (ModestRecptViewClass *klass)
 {
        GObjectClass *object_class;
 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;
 
        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;
 
 
        object_class->finalize = modest_recpt_view_finalize;
 
@@ -219,8 +244,8 @@ modest_recpt_view_class_init (ModestRecptViewClass *klass)
                              G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
                              G_STRUCT_OFFSET(ModestRecptViewClass, activate),
                              NULL, NULL,
                              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;
 }
        
        return;
 }
@@ -245,7 +270,7 @@ modest_recpt_view_get_type (void)
                  modest_recpt_view_instance_init    /* instance_init */
                };
 
                  modest_recpt_view_instance_init    /* instance_init */
                };
 
-               type = g_type_register_static (GTK_TYPE_LABEL,
+               type = g_type_register_static (MODEST_TYPE_SCROLL_TEXT,
                        "ModestRecptView",
                        &info, 0);
 
                        "ModestRecptView",
                        &info, 0);