Index: widgets/table/ChangeLog
===================================================================
--- widgets/table/ChangeLog	(revision 35744)
+++ widgets/table/ChangeLog	(working copy)
@@ -1,3 +1,22 @@
+2008-07-15  Milan Crha  <mcrha@redhat.com>
+
+	** Part of fix for bug #329821
+
+	* e-table-item.c: (find_cell): Do not consider last row's height
+	till the bottom.
+	* e-table-item.h: (e_table_item_compute_mouse_over):
+	* e-table-item.c: (e_table_item_compute_mouse_over):
+	* e-table-group-container.c: (etgc_compute_mouse_over),
+	(etgc_class_init):
+	* e-table-group-leaf.c: (etgl_compute_mouse_over), (etgl_class_init):
+	* e-table.h: (e_table_get_mouse_over_cell):
+	* e-table.c: (e_table_get_mouse_over_cell):
+	* e-table-group.h: (struct ETableGroupClass),
+	(e_table_group_compute_mouse_over):
+	* e-table-group.c: (e_table_group_compute_mouse_over),
+	(etg_class_init): Be able to calculate mouse-over position correctly,
+	relatively to the ETableItem.
+
 2008-06-03  Kjartan Maraas  <kmaraas@gnome.org>
 
 	* e-table-example-1.c: (main):
Index: widgets/table/e-table-item.c
===================================================================
--- widgets/table/e-table-item.c	(revision 35744)
+++ widgets/table/e-table-item.c	(working copy)
@@ -2171,12 +2171,15 @@ find_cell (ETableItem *eti, double x, do
 		y1 = y2 = height_extra;
 		if (y < height_extra)
 			return FALSE;
-		for (row = 0; row < rows - 1; row++, y1 = y2){
+		for (row = 0; row < rows; row++, y1 = y2) {
 			y2 += ETI_ROW_HEIGHT (eti, row) + height_extra;
 
 			if (y <= y2)
 				break;
 		}
+
+		if (row == rows)
+			return FALSE;
 	}
 	*view_col_res = col;
 	if (x1_res)
@@ -3442,6 +3445,37 @@ e_table_item_compute_location (ETableIte
 	eti->grabbed_row = grabbed_row;
 }
 
+/**
+ * e_table_item_compute_mouse_over:
+ * Similar to e_table_item_compute_location, only here recalculating
+ * the position inside the item too.
+ **/
+void
+e_table_item_compute_mouse_over (ETableItem        *eti,
+				 int                x,
+				 int                y,
+				 int               *row,
+				 int               *col)
+{
+	double realx, realy;
+	/* Save the grabbed row but make sure that we don't get flawed
+           results because the cursor is grabbed. */
+	int grabbed_row = eti->grabbed_row;
+	eti->grabbed_row = -1;
+
+	realx = x;
+	realy = y;
+
+	gnome_canvas_item_w2i (GNOME_CANVAS_ITEM (eti), &realx, &realy);
+
+	if (!find_cell (eti, (int)realx, (int)realy, col, row, NULL, NULL)) {
+		*row = -1;
+		*col = -1;
+	}
+
+	eti->grabbed_row = grabbed_row;
+}
+
 void
 e_table_item_get_cell_geometry   (ETableItem        *eti,
 				  int               *row,
Index: widgets/table/e-table-item.h
===================================================================
--- widgets/table/e-table-item.h	(revision 35744)
+++ widgets/table/e-table-item.h	(working copy)
@@ -214,6 +214,11 @@ void        e_table_item_compute_locatio
 					      int               *y,
 					      int               *row,
 					      int               *col);
+void        e_table_item_compute_mouse_over  (ETableItem        *eti,
+					      int                x,
+					      int                y,
+					      int               *row,
+					      int               *col);
 void        e_table_item_get_cell_geometry   (ETableItem        *eti,
 					      int               *row,
 					      int               *col,
Index: widgets/table/e-table-group-container.c
===================================================================
--- widgets/table/e-table-group-container.c	(revision 35744)
+++ widgets/table/e-table-group-container.c	(working copy)
@@ -689,6 +689,32 @@ etgc_compute_location (ETableGroup *etg,
 }
 
 static void
+etgc_compute_mouse_over (ETableGroup *etg, int x, int y, int *row, int *col)
+{
+	ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER(etg);
+
+	if (row)
+		*row = -1;
+	if (col)
+		*col = -1;
+
+	x -= GROUP_INDENT;
+	y -= TITLE_HEIGHT;
+
+	if (x >= 0 && y >= 0 && etgc->children) {
+		GList *list;
+		for (list = etgc->children; list; list = list->next) {
+			ETableGroupContainerChildNode *child_node = (ETableGroupContainerChildNode *)list->data;
+			ETableGroup *child = child_node->child;
+
+			e_table_group_compute_mouse_over (child, x, y, row, col);
+			if ((*row != -1) && (*col != -1))
+				return;
+		}
+	}
+}
+
+static void
 etgc_get_cell_geometry (ETableGroup *etg, int *row, int *col, int *x, int *y, int *width, int *height)
 {
 	ETableGroupContainer *etgc = E_TABLE_GROUP_CONTAINER(etg);
@@ -889,6 +915,7 @@ etgc_class_init (ETableGroupContainerCla
 	e_group_class->get_focus_column = etgc_get_focus_column;
 	e_group_class->get_printable = etgc_get_printable;
 	e_group_class->compute_location = etgc_compute_location;
+	e_group_class->compute_mouse_over = etgc_compute_mouse_over;
 	e_group_class->get_cell_geometry = etgc_get_cell_geometry;
 
 	g_object_class_install_property (object_class, PROP_TABLE_ALTERNATING_ROW_COLORS,
Index: widgets/table/e-table-group-leaf.c
===================================================================
--- widgets/table/e-table-group-leaf.c	(revision 35744)
+++ widgets/table/e-table-group-leaf.c	(working copy)
@@ -408,6 +408,14 @@ etgl_compute_location (ETableGroup *etg,
 }
 
 static void
+etgl_compute_mouse_over (ETableGroup *etg, int x, int y, int *row, int *col)
+{
+	ETableGroupLeaf *etgl = E_TABLE_GROUP_LEAF (etg);
+
+	e_table_item_compute_mouse_over (etgl->item, x, y, row, col);
+}
+
+static void
 etgl_get_cell_geometry (ETableGroup *etg, int *row, int *col, int *x, int *y, int *width, int *height)
 {
 	ETableGroupLeaf *etgl = E_TABLE_GROUP_LEAF (etg);
@@ -565,6 +573,7 @@ etgl_class_init (ETableGroupLeafClass *k
 	e_group_class->get_focus_column = etgl_get_focus_column;
 	e_group_class->get_printable = etgl_get_printable;
 	e_group_class->compute_location = etgl_compute_location;
+	e_group_class->compute_mouse_over = etgl_compute_mouse_over;
 	e_group_class->get_cell_geometry = etgl_get_cell_geometry;
 
 	g_object_class_install_property (object_class, PROP_TABLE_ALTERNATING_ROW_COLORS,
Index: widgets/table/e-table.c
===================================================================
--- widgets/table/e-table.c	(revision 35744)
+++ widgets/table/e-table.c	(working copy)
@@ -2414,6 +2414,24 @@ e_table_get_cell_geometry (ETable *table
 }
 
 /**
+ * e_table_get_mouse_over_cell:
+ * Similar to e_table_get_cell_at, only here we recalculate x,y relatively to each item.
+ **/
+void
+e_table_get_mouse_over_cell (ETable *table, int x, int y, int *row, int *col)
+{
+	g_return_if_fail (table != NULL);
+	g_return_if_fail (E_IS_TABLE (table));
+
+	x += GTK_LAYOUT (table->table_canvas)->hadjustment->value;
+	y += GTK_LAYOUT (table->table_canvas)->vadjustment->value;
+
+	y -= E_TABLE_HEADER_ITEM (table->header_item)->height;
+
+	e_table_group_compute_mouse_over (table->group, x, y, row, col);
+}
+
+/**
  * e_table_get_selection_model:
  * @table: The #ETable to query
  *
Index: widgets/table/e-table.h
===================================================================
--- widgets/table/e-table.h	(revision 35744)
+++ widgets/table/e-table.h	(working copy)
@@ -283,6 +283,7 @@ void             e_table_get_cell_at    
 						    int                   y,
 						    int                  *row_return,
 						    int                  *col_return);
+void e_table_get_mouse_over_cell (ETable *table, int x, int y, int *row, int *col);
 void             e_table_get_cell_geometry         (ETable               *table,
 						    int                   row,
 						    int                   col,
Index: widgets/table/e-table-group.c
===================================================================
--- widgets/table/e-table-group.c	(revision 35744)
+++ widgets/table/e-table-group.c	(working copy)
@@ -382,6 +382,16 @@ e_table_group_compute_location (ETableGr
 	ETG_CLASS (etg)->compute_location (etg, x, y, row, col);
 }
 
+void
+e_table_group_compute_mouse_over (ETableGroup *etg, int x, int y, int *row, int *col)
+{
+	g_return_if_fail (etg != NULL);
+	g_return_if_fail (E_IS_TABLE_GROUP (etg));
+
+	g_return_if_fail (ETG_CLASS (etg)->compute_mouse_over != NULL);
+	ETG_CLASS (etg)->compute_mouse_over (etg, x, y, row, col);
+}
+
 /**
  * e_table_group_get_position
  * @eti: %ETableGroup to look in.
@@ -639,6 +649,7 @@ etg_class_init (ETableGroupClass *klass)
 	klass->get_focus = etg_get_focus;
 	klass->get_printable = NULL;
 	klass->compute_location = NULL;
+	klass->compute_mouse_over = NULL;
 	klass->get_cell_geometry = NULL;
 
 	etg_signals [CURSOR_CHANGE] =
Index: widgets/table/e-table-group.h
===================================================================
--- widgets/table/e-table-group.h	(revision 35744)
+++ widgets/table/e-table-group.h	(working copy)
@@ -90,6 +90,7 @@ typedef struct {
 	gint        (*get_focus_column)      (ETableGroup *etg);
 	EPrintable *(*get_printable)         (ETableGroup *etg);
 	void        (*compute_location)      (ETableGroup *etg, int *x, int *y, int *row, int *col);
+	void        (*compute_mouse_over)    (ETableGroup *etg, int x, int y, int *row, int *col);
 	void        (*get_cell_geometry)     (ETableGroup *etg, int *row, int *col, int *x, int *y, int *width, int *height);
 
 } ETableGroupClass;
@@ -122,6 +123,11 @@ void          e_table_group_compute_loca
 					       int               *y,
 					       int               *row,
 					       int               *col);
+void          e_table_group_compute_mouse_over(ETableGroup       *etg,
+					       int                x,
+					       int                y,
+					       int               *row,
+					       int               *col);
 void          e_table_group_get_cell_geometry (ETableGroup       *etg,
 					       int               *row,
 					       int               *col,
Index: calendar/gui/e-calendar-table.c
===================================================================
--- calendar/gui/e-calendar-table.c	(revision 35744)
+++ calendar/gui/e-calendar-table.c	(working copy)
@@ -37,6 +37,7 @@
 #include <glib/gi18n.h>
 #include <glib/gstdio.h>
 #include <gnome.h>
+#include <gtk/gtktooltip.h>
 #include <misc/e-gui-utils.h>
 #include <table/e-cell-checkbox.h>
 #include <table/e-cell-toggle.h>
@@ -46,6 +47,8 @@
 #include <e-util/e-util-private.h>
 #include <misc/e-cell-date-edit.h>
 #include <misc/e-cell-percent.h>
+#include <libecal/e-cal-time-util.h>
+#include <libedataserver/e-time-utils.h>
 
 #include "calendar-component.h"
 #include "calendar-config.h"
@@ -54,6 +57,7 @@
 #include "dialogs/task-editor.h"
 #include "e-cal-model-tasks.h"
 #include "e-calendar-table.h"
+#include "e-calendar-view.h"
 #include "e-cell-date-edit-text.h"
 #include "e-comp-editor-registry.h"
 #include "print.h"
@@ -260,6 +264,201 @@ row_appended_cb (ECalModel *model, ECale
 }
 
 static void
+get_time_as_text (struct icaltimetype *tt, icaltimezone *f_zone, icaltimezone *t_zone, char *buff, int buff_len)
+{
+        struct tm tmp_tm;
+
+	buff [0] = 0;
+
+	tmp_tm = icaltimetype_to_tm_with_zone (tt, f_zone, t_zone);
+        e_time_format_date_and_time (&tmp_tm,
+                                     calendar_config_get_24_hour_format (),
+                                     FALSE, FALSE,
+                                     buff, buff_len);
+}
+
+static gboolean
+query_tooltip_cb (GtkWidget *widget, gint x, gint y, gboolean keyboard_mode, GtkTooltip *tooltip, gpointer user_data)
+{
+	ECalendarTable *cal_table;
+	ECalModelComponent *comp;
+	int row = -1, col = -1;
+	GtkWidget *box, *l, *w;
+	GtkStyle *style = gtk_widget_get_default_style ();
+	char *tmp;
+	const char *str;
+	GString *tmp2;
+	char buff[1001];
+	gboolean free_text = FALSE;
+	ECalComponent *new_comp;
+	ECalComponentOrganizer organizer;
+	ECalComponentDateTime dtstart, dtdue;
+	icaltimezone *zone, *default_zone;
+	GSList *desc, *p;
+	int len;
+
+	if (keyboard_mode)
+		return FALSE;
+
+	g_return_val_if_fail (widget != NULL, FALSE);
+	g_return_val_if_fail (E_IS_CALENDAR_TABLE (user_data), FALSE);
+	g_return_val_if_fail (tooltip != NULL, FALSE);
+
+	cal_table = E_CALENDAR_TABLE (user_data);
+
+	e_table_get_mouse_over_cell (e_calendar_table_get_table (cal_table), x, y, &row, &col);
+	if (row == -1)
+		return FALSE;
+
+	comp = e_cal_model_get_component_at (cal_table->model, row);
+	if (!comp || !comp->icalcomp)
+		return FALSE;
+
+	new_comp = e_cal_component_new ();
+	if (!e_cal_component_set_icalcomponent (new_comp, icalcomponent_new_clone (comp->icalcomp))) {
+		g_object_unref (new_comp);
+		return FALSE;
+	}
+
+	box = gtk_vbox_new (FALSE, 0);
+
+	str = e_calendar_view_get_icalcomponent_summary (comp->client, comp->icalcomp, &free_text);
+	if (!(str && *str)) {
+		if (free_text)
+			g_free ((char *)str);
+		free_text = FALSE;
+		str = _("* No Summary *");
+	}
+
+	l = gtk_label_new (NULL);
+	tmp = g_markup_printf_escaped ("<b>%s</b>", str);
+	gtk_label_set_line_wrap (GTK_LABEL (l), TRUE);
+	gtk_label_set_markup (GTK_LABEL (l), tmp);
+	gtk_misc_set_alignment (GTK_MISC (l), 0.0, 0.5);
+	w = gtk_event_box_new ();
+
+	gtk_widget_modify_bg (w, GTK_STATE_NORMAL, &(style->bg[GTK_STATE_SELECTED]));
+	gtk_widget_modify_fg (l, GTK_STATE_NORMAL, &(style->text[GTK_STATE_SELECTED]));
+	gtk_container_add (GTK_CONTAINER (w), l);
+	gtk_box_pack_start (GTK_BOX (box), w, TRUE, TRUE, 0);
+	g_free (tmp);
+
+	if (free_text)
+		g_free ((char *)str);
+	free_text = FALSE;
+
+	w = gtk_event_box_new ();
+	gtk_widget_modify_bg (w, GTK_STATE_NORMAL, &(style->bg[GTK_STATE_NORMAL]));
+
+	l = gtk_vbox_new (FALSE, 0);
+	gtk_container_add (GTK_CONTAINER (w), l);
+	gtk_box_pack_start (GTK_BOX (box), w, FALSE, FALSE, 0);
+	w = l;
+
+	e_cal_component_get_organizer (new_comp, &organizer);
+	if (organizer.cn) {
+		char *ptr ;
+		ptr = strchr( organizer.value, ':');
+
+		if (ptr) {
+			ptr++;
+			/* To Translators: It will display "Organiser: NameOfTheUser <email@ofuser.com>" */
+			tmp = g_strdup_printf (_("Organizer: %s <%s>"), organizer.cn, ptr);
+		} else {
+			/* With SunOne accounts, there may be no ':' in organiser.value */
+			tmp = g_strdup_printf (_("Organizer: %s"), organizer.cn);
+		}
+
+		l = gtk_label_new (tmp);
+		gtk_label_set_line_wrap (GTK_LABEL (l), FALSE);
+		gtk_misc_set_alignment (GTK_MISC (l), 0.0, 0.5);
+		gtk_box_pack_start (GTK_BOX (w), l, FALSE, FALSE, 0);
+		g_free (tmp);
+	}
+
+	e_cal_component_get_dtstart (new_comp, &dtstart);
+	e_cal_component_get_due (new_comp, &dtdue);
+
+	default_zone = e_cal_model_get_timezone  (cal_table->model);
+
+	if (dtstart.tzid) {
+		zone = icalcomponent_get_timezone (e_cal_component_get_icalcomponent (new_comp), dtstart.tzid);
+		if (!zone)
+			e_cal_get_timezone (comp->client, dtstart.tzid, &zone, NULL);
+		if (!zone)
+			zone = default_zone;
+	} else {
+		zone = NULL;
+	}
+
+	tmp2 = g_string_new ("");
+
+	if (dtstart.value) {
+		get_time_as_text (dtstart.value, zone, default_zone, buff, 1000);
+
+		if (buff [0]) {
+			g_string_append (tmp2, _("Start: "));
+			g_string_append (tmp2, buff);
+		}
+	}
+
+	if (dtdue.value) {
+		get_time_as_text (dtdue.value, zone, default_zone, buff, 1000);
+
+		if (buff [0]) {
+			if (tmp2->len)
+				g_string_append (tmp2, "; ");
+
+			g_string_append (tmp2, _("Due: "));
+			g_string_append (tmp2, buff);
+		}
+	}
+
+	if (tmp2->len) {
+		l = gtk_label_new (tmp2->str);
+		gtk_misc_set_alignment (GTK_MISC (l), 0.0, 0.5);
+		gtk_box_pack_start (GTK_BOX (w), l, FALSE, FALSE, 0);
+	}
+
+	g_string_free (tmp2, TRUE);
+
+	e_cal_component_free_datetime (&dtstart);
+	e_cal_component_free_datetime (&dtdue);
+
+	tmp2 = g_string_new ("");
+	e_cal_component_get_description_list (new_comp, &desc);
+	for (len = 0, p = desc; p != NULL; p = p->next) {
+		ECalComponentText *text = p->data;
+
+		if (text->value != NULL) {
+			len += strlen (text->value);
+			g_string_append (tmp2, text->value);
+			if (len > 1024) {
+				g_string_set_size (tmp2, 1020);
+				g_string_append (tmp2, "...");
+				break;
+			}
+		}
+	}
+	e_cal_component_free_text_list (desc);
+
+	if (tmp2->len) {
+		l = gtk_label_new (tmp2->str);
+		gtk_misc_set_alignment (GTK_MISC (l), 0.0, 0.5);
+		gtk_box_pack_start (GTK_BOX (box), l, FALSE, FALSE, 0);
+	}
+
+	g_string_free (tmp2, TRUE);
+
+	gtk_widget_show_all (box);
+	gtk_tooltip_set_custom (tooltip, box);
+
+	g_object_unref (new_comp);
+
+	return TRUE;
+}
+
+static void
 e_calendar_table_init (ECalendarTable *cal_table)
 {
 	GtkWidget *table;
@@ -489,6 +688,8 @@ e_calendar_table_init (ECalendarTable *c
 	g_signal_connect (e_table, "right_click", G_CALLBACK (e_calendar_table_on_right_click), cal_table);
 	g_signal_connect (e_table, "key_press", G_CALLBACK (e_calendar_table_on_key_press), cal_table);
 	g_signal_connect (e_table, "popup_menu", G_CALLBACK (e_calendar_table_on_popup_menu), cal_table);
+	g_signal_connect (e_table, "query-tooltip", G_CALLBACK (query_tooltip_cb), cal_table);
+	gtk_widget_set_has_tooltip (GTK_WIDGET (e_table), TRUE);
 
 	a11y = gtk_widget_get_accessible ((GtkWidget *)e_table);
 	if (a11y)
Index: calendar/ChangeLog
===================================================================
--- calendar/ChangeLog	(revision 35744)
+++ calendar/ChangeLog	(working copy)
@@ -1,3 +1,10 @@
+2008-07-15  Milan Crha  <mcrha@redhat.com>
+
+	** Fix for bug #329821
+
+	* gui/e-calendar-table.c: (get_time_as_text), (query_tooltip_cb),
+	(e_calendar_table_init): Show tooltips over task's table.
+
 2008-17-14  Paolo Borelli  <pborelli@katamail.com>
 
 	** Fix for bug #542889
