/* -*- mode:C; tab-width:4; -*- */
/* 
 *  Author: Tomas Frydrych <tf@o-hand.com>
 *
 *  Copyright (c) 2005 - 2006 OpenedHand Ltd - http://o-hand.com
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 */
#include "dates_callbacks.h"
#include "dates_types.h"
#include "dates_platform.h"

#include <gdk/gdkkeysyms.h>
#include <string.h>

#include <libecal/e-cal-time-util.h>
#include <libical/icaltime.h>
#include <gconf/gconf-client.h>

#ifdef WITH_HILDON
#include <libosso.h>
#include <hildon-widgets/hildon-window.h>
#include <hildon-widgets/hildon-program.h>
#include <hildon-widgets/hildon-time-editor.h>
#include <hildon-widgets/hildon-date-editor.h>
#endif

#define TIME_MARKUP "%k:%M\n<small>%d %b %Y</small>"

#define CONVERT_CHILD_ITER(_filter,_child,_iter)\
	(gtk_tree_model_filter_convert_child_iter_to_iter (\
	GTK_TREE_MODEL_FILTER (_filter), _child, _iter))

static void
dates_date_change (DatesData *data, int direction)
{
    icaltimetype *time, *oldtime;
	
    oldtime = (icaltimetype *)dates_view_get_date (data->view);
    time = g_new (icaltimetype, 1);
    g_memmove (time, oldtime, sizeof (icaltimetype));

    if (data->zoom == 16)
	time->year += direction;
    else if (data->zoom >= 11) {
	int days;
	time->month += direction;
	if (time->month > 12) {
	    time->month = 1;
	    time->year++;
	} else if (time->month < 1) {
	    time->month = 12;
	    time->year--;
	}
	days = icaltime_days_in_month (time->month, time->year);
	if (time->day > days) time->day = days;
    } else if (data->zoom >= 8)
	icaltime_adjust (time, direction * 7, 0, 0, 0);
    else
	icaltime_adjust (time, direction, 0, 0, 0);
	
    dates_view_set_date (data->view, time);
	
    g_free (time);
}

void
dates_back_cb (GtkButton *button, DatesData *data)
{
    dates_date_change (data, -1);
}

void
dates_forward_cb (GtkButton *button, DatesData *data)
{
    dates_date_change (data, 1);
}

void
dates_today_cb (GtkButton *button, DatesData *data)
{
    icaltimetype today = icaltime_today ();
    dates_view_set_date (data->view, &today);
}

void
dates_zoom_change (guint pos, DatesView *dates_view)
{
    GConfClient *client;
	
    switch (pos) {
	case 1 :
	    dates_view_set_visible_months (dates_view, 0);
	    dates_view_set_visible_days (dates_view, 1);
	    dates_view_set_visible_hours (dates_view, 4);
	    break;
	case 2 :
	    dates_view_set_visible_months (dates_view, 0);
	    dates_view_set_visible_days (dates_view, 1);
	    dates_view_set_visible_hours (dates_view, 8);
	    break;
	case 3 :
	    dates_view_set_visible_months (dates_view, 0);
	    dates_view_set_visible_days (dates_view, 1);
	    dates_view_set_visible_hours (dates_view, 12);
	    break;
	case 4 :
	    dates_view_set_visible_months (dates_view, 0);
	    dates_view_set_visible_days (dates_view, 1);
	    dates_view_set_visible_hours (dates_view, 12);
	    break;
	case 5 :
	    dates_view_set_visible_months (dates_view, 0);
	    dates_view_set_visible_days (dates_view, 2);
	    dates_view_set_visible_hours (dates_view, 12);
	    break;
	case 6 :
	    dates_view_set_visible_months (dates_view, 0);
	    dates_view_set_visible_days (dates_view, 1);
	    dates_view_set_visible_hours (dates_view, 24);
	    break;
	case 7 :
	    dates_view_set_visible_months (dates_view, 0);
	    dates_view_set_visible_days (dates_view, 5);
	    dates_view_set_visible_hours (dates_view, 12);
	    break;
	case 8 :
	    dates_view_set_visible_months (dates_view, 0);
	    dates_view_set_visible_days (dates_view, 5);
	    dates_view_set_visible_hours (dates_view, 24);
	    break;
	case 9 :
	    dates_view_set_visible_months (dates_view, 0);
	    dates_view_set_visible_days (dates_view, 7);
	    dates_view_set_visible_hours (dates_view, 12);
	    break;
	case 10 :
	    dates_view_set_visible_months (dates_view, 0);
	    dates_view_set_visible_days (dates_view, 7);
	    dates_view_set_visible_hours (dates_view, 24);
	    break;
	case 11 :
	    dates_view_set_visible_months (dates_view, 1);
	    dates_view_set_visible_days (dates_view, 7);
	    dates_view_set_visible_hours (dates_view, 24);
	    break;
	case 12 :
	    dates_view_set_visible_months (dates_view, 2);
	    dates_view_set_visible_days (dates_view, 7);
	    dates_view_set_visible_hours (dates_view, 24);
	    break;
	case 13 :
	    dates_view_set_visible_months (dates_view, 3);
	    dates_view_set_visible_days (dates_view, 7);
	    dates_view_set_visible_hours (dates_view, 24);
	    break;
	case 14 :
	    dates_view_set_visible_months (dates_view, 4);
	    dates_view_set_visible_days (dates_view, 7);
	    dates_view_set_visible_hours (dates_view, 24);
	    break;
	case 15 :
	    dates_view_set_visible_months (dates_view, 8);
	    dates_view_set_visible_days (dates_view, 7);
	    dates_view_set_visible_hours (dates_view, 24);
	    break;
	case 16 :
	    dates_view_set_visible_months (dates_view, 12);
	    dates_view_set_visible_days (dates_view, 7);
	    dates_view_set_visible_hours (dates_view, 24);
	    break;
    }
	
    client = gconf_client_get_default ();
    gconf_client_set_int (client, DATES_GCONF_ZOOM, pos, NULL);
}

/*
 * because the zoom level is persistent (via gconf) we have to ensure that
 * all values 1-16 get handled so that if in case of upgrading we load in a
 * zoom value that is not handled, the zoom buttons do not stop working
 */
void
dates_zoom_in_cb (GtkButton *button, DatesData *data)
{
    switch (data->zoom)
	{
		case 1:
		case 2:
		case 3:
		case 4:
		case 6:
			if (data->TBZoomIn)
				gtk_widget_set_sensitive (data->TBZoomIn, FALSE);

			if (data->MIZoomIn)
				gtk_widget_set_sensitive (data->MIZoomIn, FALSE);
			data->zoom = 3;
			break;

		case 5:
		case 7:
		case 8:
			data->zoom = 6;
			break;
		case 9:
		case 10:
			data->zoom = 7;
			break;
		case 11:
		case 12:
		case 13:
		case 14:
		case 15:
			data->zoom = 10;
			break;

		case 16:
			if (data->TBZoomOut)
				gtk_widget_set_sensitive (data->TBZoomOut, TRUE);
		
			if (data->MIZoomOut)
				gtk_widget_set_sensitive (data->MIZoomOut, TRUE);
			data->zoom = 11;
			break;
		default:
			return;
    }
	
    dates_zoom_change (data->zoom, data->view);
}

void
dates_zoom_out_cb (GtkButton *button, DatesData *data)
{
    switch (data->zoom)
	{
		case 1:
		case 2:
		case 3:
		case 4:
			if (data->TBZoomIn)
				gtk_widget_set_sensitive (data->TBZoomIn, TRUE);

			if (data->MIZoomIn)
				gtk_widget_set_sensitive (data->MIZoomIn, TRUE);
			data->zoom = 6;
			break;

		case 6:
			data->zoom = 7;
			break;
		case 5:
		case 7:
		case 8:
			data->zoom = 10;
			break;
		case 9:
		case 10:
			data->zoom = 11;
			break;
		case 11:
		case 12:
		case 13:
		case 14:
		case 15:
			if (data->TBZoomOut)
				gtk_widget_set_sensitive (data->TBZoomOut, FALSE);
		
			if (data->MIZoomOut)
				gtk_widget_set_sensitive (data->MIZoomOut, FALSE);
			data->zoom = 16;
			break;
		default:
			return;
    }

    dates_zoom_change (data->zoom, data->view);
}


void
dates_date_changed_cb (DatesView *view, DatesData *d)
{
    struct tm timem;
    gchar buffer[256];
    const icaltimetype *date = dates_view_get_date (view);
#ifndef WITH_HILDON
    gchar *text;
#endif
	
    timem = icaltimetype_to_tm ((icaltimetype *)date);
    strftime (buffer, 255, "%a, %F", &timem);

#ifdef WITH_HILDON
    gtk_window_set_title (GTK_WINDOW (d->main_window), buffer);
#else
    text = g_strdup_printf ("%s - %s", buffer, _("Dates"));
    gtk_window_set_title (GTK_WINDOW (d->main_window), text);
    g_free (text);
#endif

    strftime (buffer, 255, "<big><b>%A %d %B, %Y</b></big>", &timem);
    gtk_label_set_markup (GTK_LABEL (d->header_label), buffer);
}

void
dates_about_cb (GtkWidget *widget, DatesData *d)
{
	static GdkPixbuf *pixb;
	GError *error = NULL;

	/* NOTE: The hildon version of the about menu does not handle the
	 * credits button well (it is misplaced and not thematised), so we add
	 * the authors to the (c) string.
	 */
#ifndef WITH_HILDON
	const gchar *authors[] = {
		"Principal author: Chris Lord <chris@o-hand.com>",
		"Maemo port: Tomas Frydrych <tf@o-hand.com>",
		"Rob Bradford <rob@o-hand.com>",
		NULL
	};

	const gchar *licence =
		"This program is free software; you can redistribute it and/or modify\n"
		"it under the terms of the GNU General Public License as published by\n"
		"the Free Software Foundation; either version 2, or (at your option)\n"
		"any later version.\n"
		"\n"
		"This program is distributed in the hope that it will be useful,\n"
		"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
		"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
		"GNU General Public License for more details.";
#endif
	
	if (!pixb)
		pixb = gdk_pixbuf_new_from_file (
			PKGDATADIR G_DIR_SEPARATOR_S "oh-about-logo.png", &error);  

	if (!pixb) {
		g_assert (error);
		g_warning (error->message);
		g_clear_error (&error);
	}

	gtk_show_about_dialog (
			GTK_WINDOW (d->main_window),

			"copyright",
			"(c) 2006 OpenedHand Ltd",

#ifndef WITH_HILDON
			"authors",
			authors,
			
			"license",
			licence,
#endif

			"logo",
			pixb,

			"name",
			PACKAGE_NAME,
			
			"version",
			PACKAGE_VERSION,
			
			"website",
			"http://www.pimlico-project.org/dates",
			NULL);
}


static void
dates_fill_details_dialog (DatesView *view, DatesData *d)
{
    const gchar *location = NULL;
    gchar *string = NULL;
    GSList *text_list;
    ECalComponentDateTime time;
    struct tm timem;
    gchar time_text[256];
    GtkTextBuffer *buffer;
    ECalComponentText summary;
    GtkWidget *widget;

    /* Set summary entry */
    e_cal_component_get_summary (d->comp, &summary);
    widget = d->details_summary_entry;
    if (summary.value)
	gtk_entry_set_text (GTK_ENTRY (widget), summary.value);
    else if (summary.altrep)
	gtk_entry_set_text (GTK_ENTRY (widget), summary.altrep);
    else
	gtk_entry_set_text (GTK_ENTRY (widget), "");
	
    /* Set event description textview */
    /* NOTE: Docs say that only journal entries can have more than one
     * description, so just use text_list->data
     */
    e_cal_component_get_location (d->comp, &location);
    e_cal_component_get_description_list (d->comp, &text_list);
    buffer = gtk_text_view_get_buffer (
	GTK_TEXT_VIEW (d->details_textview));
    /* NOTE: If there's a location property, we move it to the description
     */
    if (location)
	string = g_strconcat (location, "\n", NULL);
    gtk_text_buffer_set_text (buffer, string ? string : "", -1);
    g_free (string);
    if (text_list) {
	ECalComponentText *desc = text_list->data;
	if (desc->value) {
	    GtkTextIter iter;
	    gtk_text_buffer_get_end_iter (buffer, &iter);
	    gtk_text_buffer_insert (buffer, &iter, desc->value, -1);
	}
	e_cal_component_free_text_list (text_list);
    }
	
    /* Set time buttons and dialog */
    e_cal_component_get_dtstart (d->comp, &time);
    timem = icaltimetype_to_tm (time.value);
    strftime (time_text, 256, TIME_MARKUP, &timem);
    gtk_label_set_markup (GTK_LABEL (d->details_start_label), time_text);
    e_cal_component_free_datetime (&time);

    e_cal_component_get_dtend (d->comp, &time);
    timem = icaltimetype_to_tm (time.value);
    strftime (time_text, 256, TIME_MARKUP, &timem);
    gtk_label_set_markup (GTK_LABEL (d->details_end_label),
			  time_text);
    e_cal_component_free_datetime (&time);
}

void
dates_event_selected_cb (DatesView *view, DatesData *d)
{
    GtkWidget *widget;

    if (d->comp) g_object_unref (d->comp);
    d->comp = dates_view_get_selected_event (d->view);

    if (d->comp) {
	GtkTreeIter iter;
	gboolean read_only = TRUE, cal_found = FALSE;
	GtkTreeModel *model;

/*		g_debug ("Selected event RID: %s",
		e_cal_component_get_recurid_as_string (d->comp));*/

	d->cal = dates_view_get_selected_event_cal (d->view);
			
/*		widget = header_label;
		gtk_label_set_markup (GTK_LABEL (widget),
		"<big><b>Enter details</b></big>");*/
		
	/* Set the details calendar combo-box */
	widget = d->details_calendar_combobox;
	model = GTK_TREE_MODEL (d->cal_list_store);
	if (gtk_tree_model_get_iter_first (model, &iter)) {
	    do {
		ECal *c;

		gtk_tree_model_get (
		    model, &iter, COL_CALPTR, &c, -1);

		if (c != d->cal) continue;
		cal_found = TRUE;
				
		gtk_tree_model_get (model, &iter,
				    COL_NOTREADONLY, &read_only,
				    -1);
		read_only = !read_only;
		d->read_only = read_only;
		if (!read_only) {
		    GtkTreeIter filter_iter;
					
		    model = gtk_combo_box_get_model (
			GTK_COMBO_BOX (widget));
		    CONVERT_CHILD_ITER (model, &filter_iter,
					&iter);
					
		    gtk_combo_box_set_active_iter (
			GTK_COMBO_BOX (widget),
			&filter_iter);

		    gtk_widget_set_sensitive (widget, TRUE);
		} else {
#ifdef DEBUG
		    if (d->debug & DATES_DEBUG_EDIT)
			g_debug ("Read-only event"
				 " selected");
#endif
		}
		break;
	    } while (gtk_tree_model_iter_next (model, &iter));
	    if (!cal_found) {
		gtk_widget_set_sensitive (widget, FALSE);
		g_warning ("Event selected with "
			   "unknown calendar");
	    }
	} else {
	    g_warning ("Error accessing calendar list");
	}

	if (d->TBEdit)
		gtk_widget_set_sensitive (d->TBEdit, !read_only);

	if (d->TBDelete)
		gtk_widget_set_sensitive (d->TBDelete, !read_only);
	
    } else {
	d->cal = NULL;
	if (!d->waiting)
	    dates_platform_details_dlg (d, FALSE);

	if (d->TBEdit)
		gtk_widget_set_sensitive (d->TBEdit, FALSE);

	if (d->TBDelete)
		gtk_widget_set_sensitive (d->TBDelete, FALSE);
    }
}

void
dates_commit_event_cb (GtkWidget *source, DatesData *data,
		       CalObjModType type)
{
    /* Commit changes */
#ifdef DEBUG
    if (data->debug & DATES_DEBUG_EDIT)
	g_debug ("Committing event (%p) changes", data->comp);
#endif
    e_cal_component_commit_sequence (data->comp);
    e_cal_modify_object (data->cal,
			 e_cal_component_get_icalcomponent (data->comp),
			 type, NULL);
}

void
dates_event_moved_cb (DatesView *view, ECalComponent *comp, DatesData *d)
{
    ECalComponentDateTime start, end;
    struct icaldurationtype duration = icaldurationtype_null_duration ();

    if (d->comp) g_object_unref (d->comp);
    d->comp = g_object_ref (comp);

    e_cal_component_get_dtstart (d->comp, &start);
    if (!start.value->is_date) {
	e_cal_component_get_dtend (d->comp, &end);
	duration = icaltime_subtract (*end.value, *start.value);
	*end.value = icaltime_add (*start.value, duration);
	e_cal_component_set_dtstart (d->comp, &start);
	e_cal_component_set_dtend (d->comp, &end);
	e_cal_component_free_datetime (&end);
    }
    e_cal_component_free_datetime (&start);
    dates_commit_event_cb (NULL, d, CALOBJ_MOD_THIS);
}

void
dates_event_sized_cb (DatesView *view, ECalComponent *comp, DatesData *d)
{
    if (d->comp) g_object_unref (d->comp);
    d->comp = g_object_ref (comp);

    dates_commit_event_cb (NULL, d, CALOBJ_MOD_THIS);
}

static void
dates_new (DatesData *d, icalcomponent *comp, gboolean select)
{
    GError *error = NULL;
    char *uid = NULL;

    if (!d->dcal) {
	/* TODO: Prompt to create a new calendar? */
	g_warning ("No calendars loaded");
	return;
    }
	
    if (e_cal_create_object (d->dcal, comp, (char **)&uid, &error)) {
	if (!select) return;
		
	d->event_type = NEW_EVENT;

	/* Bring up details dialog ASAP */
	if (d->comp) g_object_unref (d->comp);
	d->comp = e_cal_component_new ();
	e_cal_component_set_icalcomponent (d->comp, comp);
	dates_fill_details_dialog (d->view, d);
	dates_platform_details_dlg (d, TRUE);

	/* Disable calendar combo-box */
	gtk_widget_set_sensitive (d->details_calendar_combobox, FALSE);

	/* Select new event */
	d->waiting = PENDING_CREATE;
	d->uri_uid = g_strconcat (e_cal_get_uri (d->dcal), uid, NULL);
	g_idle_add (dates_select_event_idle_cb, d);
    } else {
	g_warning ("Failed to create calendar object: %s",
		   error->message);
	icalcomponent_free (comp);
	g_error_free (error);
    }
}

void
dates_ical_drop_cb (DatesView *view, const gchar *ical, DatesData *d)
{
    icalcomponent *icalcomp, *icalcomp2;
    gint events;

    if (!d->cal_loaded) {
	/* TODO: Toggle the default calendar here maybe? */
	g_warning ("No calendars selected to add new event to");
	return;
    }
	
    icalcomp = icalcomponent_new_from_string (g_strdup (ical));
    if (!icalcomp)
	g_warning ("Error creating icalcomponent from string");

    switch (icalcomponent_isa (icalcomp)) {
	case ICAL_VEVENT_COMPONENT :
	    icalcomponent_set_uid (icalcomp, "");
	    dates_new (d, icalcomponent_new_clone (icalcomp), TRUE);
	    return;
	case ICAL_VCALENDAR_COMPONENT :
	    /* Iterate through events */
	    /* TODO: A confirmation dialog when calendar has
	     * multiple events?
	     */
	    events = icalcomponent_count_components (icalcomp,
						     ICAL_VEVENT_COMPONENT);
	    if (events == 0) {
		g_warning ("Dragged ical contains no supported "
			   "kinds.");
		break;
	    }
			
	    icalcomp2 = icalcomponent_get_first_component (icalcomp,
							   ICAL_VEVENT_COMPONENT);
	    do {
		icalcomponent_set_uid (icalcomp2, "");
		dates_new (d, icalcomponent_new_clone (
			       icalcomp2), (events == 1) ?
			   TRUE : FALSE);
	    } while ((icalcomp2 = icalcomponent_get_next_component (
			  icalcomp2, ICAL_VEVENT_COMPONENT))); 
	    break;
	default :
	    g_warning ("Dragged ical not a supported kind.");
	    break;
    }

    icalcomponent_free (icalcomp);
}

void
dates_details_time_entry_changed (GtkEditable *entry, gchar *new_text,
				  gint new_text_length,
				  gint *position,
				  DatesData *d)
{
    gint i;
    gchar *c;
	
    for (i = 0, c = new_text; c;
	 c = g_utf8_find_next_char (c, (new_text_length != -1) ?
				    (new_text + new_text_length) : NULL)) {
	if (*c < '0' || *c > '9') {
	    g_signal_stop_emission (entry, g_signal_lookup (
					"insert-text", GTK_TYPE_EDITABLE), 0);
	    gdk_beep ();
	    break;
	}
    }
}

gboolean
dates_details_time_entry_alt (GtkArrow *source, GtkWidget *entry,
			      DatesData *d, gint limit)
{
    gboolean overflow = FALSE;
    GtkEntry *widget;
    gchar buffer[33];
    gint hour;
    GtkArrowType direction;
	
    widget = GTK_ENTRY (entry);
    gtk_widget_grab_focus (GTK_WIDGET (widget));
    hour = atoi (gtk_entry_get_text (widget));
    g_object_get (G_OBJECT (source), "arrow-type", &direction, NULL);
    if (direction == GTK_ARROW_UP)
	hour ++;
    else
	hour --;
    if (hour < 0) { hour = limit; overflow = TRUE; }
    if (hour > limit) { hour = 0; overflow = TRUE; }
    snprintf (buffer, 33, "%d", hour);
    gtk_entry_set_text (widget, buffer);
	
    return overflow;
}

void
dates_details_time_hour_cb (GtkButton *source, DatesData *d)
{
    dates_details_time_entry_alt (GTK_ARROW (gtk_bin_get_child (
						 GTK_BIN (source))), d->hour_entry, d, 23);
}

void
dates_details_time_lminute_cb (GtkButton *source, DatesData *d)
{
    dates_details_time_entry_alt (GTK_ARROW (gtk_bin_get_child (
						 GTK_BIN (source))), d->lminute_entry, d, 5);
}

void
dates_details_time_rminute_cb (GtkButton *source, DatesData *d)
{
    if (dates_details_time_entry_alt (GTK_ARROW (gtk_bin_get_child (
						     GTK_BIN (source))), d->rminute_entry, d, 9))
	dates_details_time_lminute_cb (source, d);
}
#if 0
void
dates_repeats_cb (GtkWidget *source, DatesData *d)
{
	if (GTK_IS_WINDOW (d->time_dialog) && GTK_IS_WINDOW (d->repeats_dialog))
	{
		gtk_window_set_transient_for (GTK_WINDOW (d->time_dialog),
									  GTK_WINDOW (d->repeats_dialog));
	}
	
    /* Run dialog */
	dates_platform_repeats_dlg (d, TRUE);
	
	if (GTK_IS_WINDOW (d->time_dialog) && GTK_IS_WINDOW (d->details_dialog))
	{
		gtk_window_set_transient_for (GTK_WINDOW (d->time_dialog),
									  GTK_WINDOW (d->details_dialog));
	}
}

void
dates_details_repeats_cb (GtkComboBox *combobox, DatesData *d)
{
    gint option = gtk_combo_box_get_active (combobox);
	
    if (option == OTHER)
	dates_repeats_cb (GTK_WIDGET (combobox), d);
    else {
	/* Ask for time */
	gtk_widget_show (d->time_forever_checkbutton);
	dates_platform_time_dlg (d, FALSE);
    }
}
#endif
void
dates_details_time_cb (DatesData *d, ECalComponentDateTime *time)
{
#ifndef WITH_HILDON
    gint i, hour, minute;
    gchar buffer[33];
    GtkCalendar *calendar;
	
    calendar = GTK_CALENDAR (d->time_calendar);
	
    /* Set time widgets */	
    gtk_calendar_select_month (calendar, time->value->month - 1,
			       time->value->year);
    gtk_calendar_select_day (calendar, time->value->day);

    g_snprintf (buffer, 33, "%d", time->value->hour);
    gtk_entry_set_text (GTK_ENTRY (d->hour_entry), buffer);
    i = time->value->minute / 10;
    g_snprintf (buffer, 33, "%d", i);
    gtk_entry_set_text (GTK_ENTRY (d->lminute_entry), buffer);
    i = time->value->minute - (i * 10);
    g_snprintf (buffer, 33, "%d", i);
    gtk_entry_set_text (GTK_ENTRY (d->rminute_entry), buffer);
    gtk_widget_show (d->time_table);
#else
    HildonDateEditor *date_edit = HILDON_DATE_EDITOR (d->time_date_editor);
    HildonTimeEditor *time_edit = HILDON_TIME_EDITOR (d->time_time_editor);
	
    /* Set date */
    hildon_date_editor_set_year (date_edit, time->value->year);
    hildon_date_editor_set_month (date_edit, time->value->month);
    hildon_date_editor_set_day (date_edit, time->value->day);
	
    /* Set time */
    hildon_time_editor_set_time (time_edit, time->value->hour,
				 time->value->minute, 0);
    hildon_time_editor_show_seconds (time_edit, FALSE);
#endif
	
    gtk_widget_hide (d->time_forever_checkbutton);

    /* Run dialog */
	dates_platform_time_dlg (d, TRUE);
	
    /* Retrieve time */
#ifndef WITH_HILDON
    gtk_calendar_get_date (calendar,
			   (guint *)(&time->value->year),
			   (guint *)(&time->value->month),
			   (guint *)(&time->value->day));
    time->value->month += 1;
	
    hour = atoi (gtk_entry_get_text (GTK_ENTRY (d->hour_entry)));
    if ((hour >= 0) && (hour <= 23))
	time->value->hour = hour;
    minute = (atoi (gtk_entry_get_text (GTK_ENTRY (d->lminute_entry))) * 10) +
	atoi (gtk_entry_get_text (GTK_ENTRY (d->rminute_entry)));
    if ((minute >= 0) && (minute <= 59))
	time->value->minute = minute;
#else
    time->value->year = hildon_date_editor_get_year (date_edit);
    time->value->month = hildon_date_editor_get_month (date_edit);
    time->value->day = hildon_date_editor_get_day (date_edit);
	
    hildon_time_editor_get_time (time_edit,
				 (guint *)(&time->value->hour),
				 (guint *)(&time->value->minute),
				 (guint *)(&time->value->second));
#endif
}

void
dates_details_update_time_label (DatesData *d, GtkWidget *label,
				 struct icaltimetype *time)
{
    struct tm timem;
    gchar time_text[256];

    timem = icaltimetype_to_tm (time);
    strftime (time_text, 255, TIME_MARKUP, &timem);
    gtk_label_set_markup (GTK_LABEL (label), time_text);
}

void
dates_details_time_start_cb (GtkWidget *source, DatesData *d)
{
    ECalComponentDateTime start, end;
    struct icaltimetype ostart;
	
    e_cal_component_get_dtstart (d->comp, &start);
    ostart = *start.value;
    dates_details_time_cb (d, &start);
	
    /* If start >= end, adjust end */
    e_cal_component_get_dtend (d->comp, &end);
    if (icaltime_compare (*start.value, *end.value) >= 0) {
	struct icaldurationtype duration =
	    icaltime_subtract (*start.value, ostart);
	*end.value = icaltime_add (*end.value, duration);
	e_cal_component_set_dtend (d->comp, &end);

	dates_details_update_time_label (d, d->details_end_label,
					 end.value);
    }
	
    e_cal_component_set_dtstart (d->comp, &start);
    dates_details_update_time_label (d, d->details_start_label,
				     start.value);

    e_cal_component_free_datetime (&start);
    e_cal_component_free_datetime (&end);
}

void
dates_details_time_end_cb (GtkWidget *source, DatesData *d)
{
    ECalComponentDateTime start, end;
    struct icaltimetype oend;
	
    e_cal_component_get_dtend (d->comp, &end);
    oend = *end.value;
    dates_details_time_cb (d, &end);
	
    /* If end <= start, adjust start */
    e_cal_component_get_dtstart (d->comp, &start);
    if (icaltime_compare (*end.value, *start.value) <= 0) {
	struct icaldurationtype duration =
	    icaltime_subtract (*end.value, oend);
	*start.value = icaltime_add (*end.value, duration);
	e_cal_component_set_dtstart (d->comp, &start);

	dates_details_update_time_label (d, d->details_start_label,
					 start.value);
    }
	
    e_cal_component_set_dtend (d->comp, &end);
    dates_details_update_time_label (d, d->details_end_label,
				     end.value);

    e_cal_component_free_datetime (&end);
    e_cal_component_free_datetime (&start);
}

void
dates_edit_cb (GtkWidget *source, DatesData *d)
{
    if (d->read_only) return;
    /* TODO: Handle recurring events */
    if (e_cal_component_has_recurrences (d->comp)) return;
    dates_fill_details_dialog (d->view, d);
	dates_platform_details_dlg (d, TRUE);
}

static void
dates_save_changes (DatesData *d)
{
    ECalComponentText text;
    const gchar *old_location = NULL;
    gchar *desc;
    GSList *desc_list;
    GtkTextIter start, middle, end;
    GtkTextBuffer *buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (
							  d->details_textview));
    GtkWidget *widget;
    ECalComponentText summary, new_summary;
	
    gtk_text_buffer_get_start_iter (buffer, &start);
    e_cal_component_get_location (d->comp, &old_location);
    /* If there was a location field set, try not to overwrite it */
    if (old_location) {
	gtk_text_buffer_get_iter_at_line (buffer, &middle, 1);
	desc = gtk_text_buffer_get_text (
	    buffer, &start, &middle, FALSE);
	if (desc) {
	    /* Strip the trailing new-line, if necessary */
	    gchar *strip;
	    if ((strip = g_utf8_strchr (desc, -1, '\n')))
		*strip = '\0';
			
	    e_cal_component_set_location (d->comp, desc);
	    g_free (desc);
	}
	start = middle;
    }

    /* Set the rest of the description */	
    gtk_text_buffer_get_end_iter (buffer, &end);
    desc = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
    text.value = desc ? desc : "";
    text.altrep = NULL;
    desc_list = g_slist_prepend (NULL, &text);
    e_cal_component_set_description_list (d->comp, desc_list);
    g_free (desc);
    g_slist_free (desc_list);
	
    widget = d->details_summary_entry;
    e_cal_component_get_summary (d->comp, &summary);
    new_summary.altrep = summary.altrep;
    new_summary.value = g_strdup (gtk_entry_get_text (GTK_ENTRY (widget)));
    e_cal_component_set_summary (d->comp, &new_summary);

    dates_commit_event_cb (NULL, d, CALOBJ_MOD_ALL);
}

/* From contacts src/contacts-utils.c */
static GList *
contacts_set_widget_desensitive_recurse (GtkWidget *widget, GList **widgets)
{
	if (GTK_IS_WIDGET (widget)) {
		if (GTK_WIDGET_SENSITIVE (widget) &&
		    GTK_WIDGET_VISIBLE (widget)) {
			gtk_widget_set_sensitive (widget, FALSE);
			*widgets = g_list_append (*widgets, widget);
		}
		
		if (GTK_IS_TABLE (widget) || GTK_IS_HBOX (widget) ||
		    GTK_IS_VBOX (widget) || GTK_IS_EVENT_BOX (widget)) {
			GList *c, *children = gtk_container_get_children (
				GTK_CONTAINER (widget));
			
			for (c = children; c; c = c->next) {
				contacts_set_widget_desensitive_recurse (
					c->data, widgets);
			}
			g_list_free (children);
		}
	}
	
	return *widgets;
}

GList *
contacts_set_widgets_desensitive (GtkWidget *widget)
{
	GList *list = NULL;
	
	contacts_set_widget_desensitive_recurse (widget, &list);
	
	return list;
}

static void
contacts_set_widgets_sensitive (GList *widgets)
{
	GList *w;
	
	for (w = widgets; w; w = w->next) {
		gtk_widget_set_sensitive (GTK_WIDGET (w->data), TRUE);
	}
}

void
dates_details_ok_cb (GtkWidget *source, DatesData *d)
{
    if (d->waiting == NONE) {
	d->event_type = NORMAL;
	d->waiting = NONE;
	dates_save_changes (d);
	dates_platform_details_dlg (d, FALSE);
    } else {
	d->widgets = contacts_set_widgets_desensitive (d->details_dialog);
	d->waiting = PENDING_CHANGE;
    }
}

void
dates_delete_cb (GtkWidget *source, DatesData *d)
{
    ECalComponentText summary;
    GtkWidget *widget;
    const char *value;

    e_cal_component_get_summary (d->comp, &summary);
    widget = d->details_dialog;
    if (GTK_WIDGET_VISIBLE (widget))
	value = gtk_entry_get_text (GTK_ENTRY (d->details_summary_entry));
    else if (summary.value)
	value = summary.value;
    else if (summary.altrep)
	value = summary.altrep;
    else {
	g_warning ("Deleting event with no summary");
	value = "Unknown event";
    }
		
    widget = gtk_message_dialog_new (
	GTK_WINDOW (d->main_window),
	GTK_DIALOG_MODAL,
	GTK_MESSAGE_QUESTION,
	GTK_BUTTONS_NONE,
	_("Are you sure you want to delete event '%s'?"),
	value);
    gtk_dialog_add_buttons (GTK_DIALOG (widget),
			    _("Keep event"), GTK_RESPONSE_NO,
			    _("Delete event"), GTK_RESPONSE_YES,
			    NULL);
	
    if (gtk_dialog_run (GTK_DIALOG (widget)) == GTK_RESPONSE_YES) {
	/* Reset event type, in case this was a new event */
	d->event_type = NORMAL;
		
	if (d->waiting == NONE) {
	    const char *uid = NULL;
	    e_cal_component_get_uid (d->comp, &uid);
	    e_cal_remove_object (d->cal, uid, NULL);

	    /* Hide the details dialog, in case we deleted
	     * from there.
	     */
	    dates_platform_details_dlg (d, FALSE);
	} else {
	    d->widgets = contacts_set_widgets_desensitive (
		d->details_dialog);
	    d->waiting = PENDING_DELETE;
	}
    }
	
    gtk_widget_destroy (widget);
}

void
dates_details_cancel_cb (GtkWidget *source, DatesData *d)
{
    if (d->event_type == NEW_EVENT) {
	if (d->waiting == NONE) {
	    const char *uid = NULL;
	    d->event_type = NORMAL;
	    e_cal_component_get_uid (d->comp, &uid);
	    e_cal_remove_object (d->cal, uid, NULL);
	} else {
	    d->widgets = contacts_set_widgets_desensitive (
		d->details_dialog);
	    d->waiting = PENDING_DELETE;
	    return;
	}
    }

	dates_platform_details_dlg (d, FALSE);
}

gboolean
dates_details_close_cb (GtkWidget *widget, GdkEvent *event, DatesData *d)
{
    dates_details_cancel_cb (widget, d);
    return TRUE;
}


gboolean
dates_select_event_idle_cb (gpointer data)
{
    DatesData *d = data;
    gboolean selected =
	dates_view_set_selected_event (d->view, d->uri_uid, NULL);
	
    if (selected) {
	const char *uid = NULL;
	g_free (d->uri_uid);
	d->uri_uid = NULL;
	
	if (d->widgets) {
	    contacts_set_widgets_sensitive (d->widgets);
	    g_list_free (d->widgets);
	    d->widgets = NULL;
	}
	switch (d->waiting) {
	    case NONE :
	    case PENDING_CREATE :
		break;
	    case PENDING_DELETE :
		e_cal_component_get_uid (d->comp, &uid);
		e_cal_remove_object (d->cal, uid, NULL);
	    dates_platform_details_dlg (d, FALSE);
		break;
	    case PENDING_CHANGE :
		dates_save_changes (d);
		gtk_widget_hide (d->details_dialog);
		break;
	    case PENDING_CAL_CHANGE :
		break;
	    default:
		g_warning ("Unknown pending state");
	}
	d->waiting = NONE;
    }
	
    return !selected;
}

void
dates_new_cb (GtkWidget *source, DatesData *d)
{
    icalcomponent *comp;
    struct icalperiodtype period;

    if (!dates_view_get_selected_period (d->view, &period)) {
	struct icaltimetype date, now;

	/* Create a default time event */
	date = *(dates_view_get_date (d->view));
	now = icaltime_current_time_with_zone (date.zone);
	date.is_date = FALSE;
	now.is_date = FALSE;
	period.duration = icaldurationtype_null_duration ();
	period.duration.minutes = 0;

	/* New events default to starting at 9am */
	period.duration.hours = 9;
	period.start = icaltime_add (
	    date, period.duration);
		
	/* NOTE: 11 is the magic number where we're viewing a 
	 * month or more. See dates_zoom_change.
	 */
	period.duration.hours = (d->zoom >= 11) ? 8 : 2;
	period.end = icaltime_add (period.start, period.duration);
    }
	
    comp = icalcomponent_new_vevent ();
    icalcomponent_set_dtstart (comp, period.start);
    icalcomponent_set_dtend (comp, period.end);
    icalcomponent_set_summary (comp, _("New event"));
    dates_new (d, comp, TRUE);
}

void
dates_calendar_combo_changed_cb (GtkComboBox *widget, DatesData *d)
{
    ECal *c;
    ECalComponent *comp = d->comp;
    GtkTreeIter iter;
	
    gtk_combo_box_get_active_iter (widget, &iter);
    gtk_tree_model_get (gtk_combo_box_get_model (widget),
			&iter, COL_CALPTR, &c, -1);
	
    if (c != d->cal) {
	/* Move event between calendars */
	const char *uid = NULL;
		
	g_object_ref (comp);
	if (!d->waiting)
	    d->waiting = PENDING_CAL_CHANGE;
	e_cal_component_get_uid (comp, &uid);
	e_cal_remove_object (d->cal, uid, NULL);
		
	/* TODO: Error checking */
	e_cal_create_object (c,
			     e_cal_component_get_icalcomponent (comp),
			     (char **)&uid, NULL);
	g_object_unref (comp);
	d->uri_uid = g_strconcat (e_cal_get_uri (c), uid, NULL);
	d->widgets = contacts_set_widgets_desensitive (d->details_dialog);
	g_idle_add (dates_select_event_idle_cb, d);
    }
}

/* snippet from evolution/calendar/gui/calendar-component.c:294 */
static gboolean
is_in_uids (GSList *uids, ESource *source)
{
	GSList *l;

	for (l = uids; l; l = l->next)
	{
		const char *uid = l->data;
		if (strcmp (uid, e_source_peek_uid (source)) == 0)
			return TRUE;
	}

	return FALSE;
}

void
dates_cal_open_cb (ECal *ecal, ECalendarStatus status, DatesData *d)
{
    gboolean read_only;
    GError *error = NULL;
    const char *ecal_name;
    ESource *source;
    ESourceGroup *group;
    GtkTreeIter iter;
    gchar *primary_uid;
    GSList *selected_list;
    gboolean selected;
	gchar * cal_name;
	
#ifdef DEBUG
    if (d->debug & DATES_DEBUG_CALENDAR)
	g_debug ("Calendar opened, setting up...");
#endif

    if (status != E_CALENDAR_STATUS_OK)
	{
		g_warning ("Error '%d' opening ecal", status);
		g_object_unref (ecal);
		if (d->first_load) {
			GtkWidget *dialog = gtk_message_dialog_new (
				GTK_WINDOW (d->main_window),
				GTK_DIALOG_MODAL | GTK_DIALOG_NO_SEPARATOR,
				GTK_MESSAGE_ERROR,
				GTK_BUTTONS_CLOSE,
				"Dates failed to open the system calendar. "
				"You will not be able to view or create "
				"events; this may be remedied by restarting.");
			gtk_dialog_run (GTK_DIALOG (dialog));
		}
		return;
    }
	
    source = e_cal_get_source (ecal);

    ecal_name = e_source_peek_name (source);

    if (!e_cal_is_read_only (ecal, &read_only, &error))
	{
		g_warning ("Error querying calendar's read-only status: %s",
				   error->message);
		g_error_free (error);
		g_object_unref (ecal);
		return;
    }

	/* 
	 * Work around the fact that eds-dbus seems to be returning the wrong
	 * value for e_cal_is_read_only on the calendar itself for the http
	 * backend. But on the events themselves it is fine
	 */
	group = e_source_peek_group (source);
	if (strncmp (e_source_group_peek_base_uri (group), "webcal://", 9) == 0)
		read_only = TRUE;
	
    selected_list = gconf_client_get_list (gconf_client_get_default (),
					   CALENDAR_GCONF_SELECTED, GCONF_VALUE_STRING, NULL);
#ifdef DEBUG
		if (d->debug & DATES_DEBUG_CALENDAR)
			g_debug ("selected_list %p: is in uids %d",
					 selected_list,
					 is_in_uids (selected_list, source));
#endif
	
    if (selected_list && is_in_uids (selected_list, source))
	{
		dates_view_add_calendar (d->view, ecal);
		g_signal_connect (G_OBJECT (ecal), "backend_died",
						  G_CALLBACK (dates_backend_died_cb), d);
		selected = TRUE;
    }
	else
	{
		selected = FALSE;
    }
	
    if ((!read_only) && (selected))
	{
		if (!d->dcal)
			d->dcal = ecal;
		else
		{
			/* Find out if it's the default calendar */
			primary_uid = gconf_client_get_string (
				gconf_client_get_default (),
				CALENDAR_GCONF_PRIMARY, NULL);
			if (primary_uid) {
				if (strcmp (e_source_peek_uid (source),
							primary_uid) == 0)
					d->dcal = ecal;
				g_free (primary_uid);
			}
		}

		d->cal_loaded = TRUE;
	
		if (d->TBNew)
		{
#ifdef DEBUG
			if (d->debug & DATES_DEBUG_CALENDAR)
				g_debug ("*** Setting TBNew button sensitive ***");
#endif
			gtk_widget_set_sensitive (d->TBNew, TRUE);
		}
    }
	else
	{
#ifdef DEBUG
		if (d->debug & DATES_DEBUG_CALENDAR)
			g_debug ("*** RO %d, Selected %d ***", read_only, selected);
#endif
	}

	if (ecal_name && !read_only)
		cal_name = g_strdup (ecal_name);
	else if (ecal_name)
		cal_name = g_strconcat (ecal_name, _(" (Read Only)"), NULL);
	else if (!read_only)
		cal_name = g_strdup (_("Unknown"));
	else
		cal_name = g_strconcat (_("Unknown"), _(" (Read Only)"), NULL);
		
    gtk_list_store_insert_with_values (d->cal_list_store, &iter, G_MAXINT,
								COL_CALNAME, cal_name,
								COL_CALPTR, ecal,
								COL_NOTREADONLY, !read_only,
								COL_SELECTED, selected,
								-1);

	g_free (cal_name);
	
#ifdef DEBUG
    if (d->debug & DATES_DEBUG_CALENDAR)
		g_debug ("Calendar added.");
#endif

	dates_platform_cal_open (d);
}

/* The following function taken from gnome clock-applet
 * (gnome-panel/applets/clock/calendar-sources.c)
 */
ECal *
dates_load_esource (ESource        *esource,
	      ECalSourceType  source_type,
	      GSList         *existing_clients,
	      DatesData      *d)
{
    ECal   *retval;
    GError *error;


    if (existing_clients)
    {
	GSList *l;

	for (l = existing_clients; l; l = l->next)
	{
	    ECal *client = E_CAL (l->data);

	    if (e_source_equal (esource, e_cal_get_source (client)))
	    {
#ifdef DEBUG
		if (d->debug & DATES_DEBUG_CALENDAR)
		    g_debug ("load_esource: found existing source, returning that");
#endif
		return g_object_ref (client);
	    }
	}
    }

    retval = e_cal_new (esource, source_type);
    if (!retval)
    {
	g_warning ("Could not load source '%s' from '%s'\n",
		   e_source_peek_name (esource),
		   e_source_get_uri (esource));
	return NULL;
    }

    error = NULL;
    if (!e_cal_open (retval, FALSE, &error))
    {
	g_assert (error != NULL);
	g_warning ("Cannot open calendar from uri '%s': %s\n",
		   e_cal_get_uri (retval), error->message);
	g_error_free (error);
	g_object_unref (retval);
	return NULL;
    }
#ifdef DEBUG
    if (d->debug & DATES_DEBUG_CALENDAR)
	g_debug ("Loaded calendar from uri '%s'",
		 e_cal_get_uri (retval));
#endif

    /* 
     * Set the calendar mode to CAL_MODE_REMOTE. This is necessary to get the
     * remote (webcal) calendars to work. It doesn't seem to have any effect
     * on the file backend.
     */
    e_cal_set_mode (retval, CAL_MODE_REMOTE);

    return retval;
}

void
dates_backend_died_cb (ECal *client, DatesData *d)
{
#ifdef DEBUG
    if (d->debug & DATES_DEBUG_CALENDAR)
	g_debug ("Calendar died, removing");
#endif
    dates_view_remove_calendar (d->view, client);
}

void
dates_sources_changed_cb (ESourceList *cal_list, DatesData *d)
{
#ifdef DEBUG
    if (d->debug & DATES_DEBUG_CALENDAR)
	g_debug ("Sources changed, reloading calendars");
#endif
	if (d->first_load)
	{
		d->first_load = FALSE;
		dates_autoselect_calendars (d, cal_list);
	}

    dates_update_calendars (cal_list, d);
}

void
dates_update_calendars (ESourceList *cal_list, DatesData *d)
{
    GSList *groups, *g;

    /* TODO: Don't reload *all* calendars on update */
    d->dcal = NULL;
    gtk_list_store_clear (d->cal_list_store);
    dates_view_remove_all_calendars (d->view);
    groups = e_source_list_peek_groups (cal_list);

#ifdef DEBUG
    if (d->debug & DATES_DEBUG_CALENDAR)
	g_debug ("Updating Calendars");
#endif

    /* Disable creating of calendars until we know there's a valid
     * calendar to add events to.
     */
	d->cal_loaded = FALSE;
	
	if (d->TBNew)
	{
#ifdef DEBUG
		if (d->debug & DATES_DEBUG_CALENDAR)
			g_debug ("*** Setting TBNew button insensitive ***");
#endif
		gtk_widget_set_sensitive (d->TBNew, FALSE);
	}
	
    for (g = groups; g; g = g->next) {
	GSList *sources, *s;
#ifdef DEBUG
	if (d->debug & DATES_DEBUG_CALENDAR)
	    g_debug ("Group %s (%s)",
		     e_source_group_peek_name (
			 E_SOURCE_GROUP (g->data)),
		     e_source_group_peek_base_uri (
			 E_SOURCE_GROUP (g->data)));
#endif
	sources = e_source_group_peek_sources (
	    E_SOURCE_GROUP (g->data));
	for (s = sources; s; s = s->next) {
	    ESource *source = E_SOURCE (s->data);
	    ECal *ecal;
			
	    ecal = dates_load_esource (source,
				 E_CAL_SOURCE_TYPE_EVENT, NULL, d);
	    if (!ecal) {
#ifdef DEBUG
		if (d->debug & DATES_DEBUG_CALENDAR)
		    g_debug ("No EVENTS in this source");
#endif
		continue;
	    }

#ifdef DEBUG
	    if (d->debug & DATES_DEBUG_CALENDAR)
		g_debug ("Found EVENTS in this source");
#endif

	    g_signal_connect (G_OBJECT (ecal), "cal_opened",
			      G_CALLBACK (dates_cal_open_cb), d);

	    e_cal_open_async (ecal, FALSE);
	    
	    /* 
	     * Set the calendar mode to CAL_MODE_REMOTE. This is necessary to get the
	     * remote (webcal) calendars to work. It doesn't seem to have any effect
	     * on the file backend.
	     */
	    e_cal_set_mode (ecal, CAL_MODE_REMOTE);
	}
    }	
}

void
dates_gconf_selected_cb (GConfClient *client, guint cnxn_id, GConfEntry *entry,
			 gpointer user_data)
{
    DatesData *d = (DatesData *)user_data;
	
    dates_update_calendars (d->source_list, d);
}

void
dates_calendars_dialog_cb (GtkButton *button, DatesData *d)
{
	dates_platform_calendars_dlg (d, TRUE);
}

void
dates_window_state_cb (GtkWidget *widget, GdkEventVisibility *event,
		       DatesData *d)
{
    GtkWidget *header = d->header_eventbox;
    if (gdk_window_get_state (widget->window) &
	GDK_WINDOW_STATE_FULLSCREEN) {
	gtk_widget_show (header);
    } else {
	gtk_widget_hide (header);
    }
}

gboolean
dates_cal_key_press_cb (GtkWidget *widget, GdkEventKey *event, DatesData *d)
{
    switch (event->keyval) {
	case GDK_3270_Enter :
	case GDK_ISO_Enter :
	case GDK_KP_Enter :
	case GDK_Return :
	    if (d->cal_loaded)
		dates_new_cb (widget, d);
	    return TRUE;
    }
    return FALSE;
}

gboolean
dates_key_press_cb (GtkWidget *widget, GdkEventKey *event, DatesData *d)
{
    switch (event->keyval) {
#ifdef WITH_HILDON
	case HILDON_HARDKEY_FULLSCREEN: {
	    GtkWidget *window = d->main_window;
	    GtkWidget *header = d->header_eventbox;
	    if (!(gdk_window_get_state (window->window) &
		  GDK_WINDOW_STATE_FULLSCREEN)) {
		gtk_window_fullscreen (GTK_WINDOW (widget));
		gtk_widget_show (header);
	    } else {
		gtk_window_unfullscreen (GTK_WINDOW (widget));
		gtk_widget_hide (header);
	    }
	    return TRUE;
	}
	case HILDON_HARDKEY_DECREASE:
	    dates_zoom_out_cb (NULL, d);
	    return TRUE;
	case HILDON_HARDKEY_INCREASE:
	    dates_zoom_in_cb (NULL, d);
	    return TRUE;
#else
	case GDK_KP_Subtract :
	case GDK_minus :
	    if (event->state & GDK_CONTROL_MASK) {
		dates_zoom_out_cb (NULL, d);
		return TRUE;
	    } else
		return FALSE;
	case GDK_KP_Add :
	case GDK_plus :
	    if (event->state & GDK_CONTROL_MASK) {
		dates_zoom_in_cb (NULL, d);
		return TRUE;
	    } else
		return FALSE;
#endif
    }
	
    return FALSE;
}

gboolean
dates_button_press_cb (GtkWidget	*widget,
		       GdkEventButton	*event,
		       DatesData	*d)
{
	if ((event->button != 1) || (event->type != GDK_2BUTTON_PRESS) ||
	    (d->comp))
		return FALSE;
	
	if (d->cal_loaded)
		dates_new_cb (widget, d);
	
	return TRUE;
}

void
dates_autoselect_calendars (DatesData *d, ESourceList * cal_list)
{
	GSList *selected_list;

	if (!cal_list)
		return;

	selected_list = gconf_client_get_list (gconf_client_get_default (),
					       CALENDAR_GCONF_SELECTED,
					       GCONF_VALUE_STRING, NULL);

	if (!selected_list) {
		/* select all available calendars */
		GSList *list = NULL, *groups, *g;
		groups = e_source_list_peek_groups (cal_list);
#ifdef DEBUG
		if (d->debug & DATES_DEBUG_CALENDAR)
			g_debug ("Attempting to autoselect");
#endif
		
		for (g = groups; g; g = g->next) {
			GSList *sources, *s;
			sources =
				e_source_group_peek_sources (E_SOURCE_GROUP (g->data));
			for (s = sources; s; s = s->next) {
				ESource *source = E_SOURCE (s->data);
				ECal *ecal;
				gchar * uid;
			
				ecal = dates_load_esource (source,
							   E_CAL_SOURCE_TYPE_EVENT,
							   NULL, d);
				if (!ecal)
				{
#ifdef DEBUG
					if (d->debug & DATES_DEBUG_CALENDAR)
						g_debug ("No ecal");
#endif
					
					continue;
				}
				
				uid = (gchar *)e_source_peek_uid (e_cal_get_source (ecal));
				list = g_slist_prepend (list, uid);
			}
		}

		if (list)
		{
#ifdef DEBUG
			if (d->debug & DATES_DEBUG_CALENDAR)
				g_debug ("Setting new list");
#endif
			gconf_client_set_list (gconf_client_get_default (),
					       CALENDAR_GCONF_SELECTED,
					       GCONF_VALUE_STRING,
					       list, NULL);
		}
	}
	else
#ifdef DEBUG
		if (d->debug & DATES_DEBUG_CALENDAR)
			g_debug ("Have selected list");
#endif
}
