/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
/*
 * Copyright (C) 2004-2005 Imendio AB
 * Copyright (C) 2001-2002 CodeFactory AB
 * Copyright (C) 2001-2002 Richard Hult <richard@imendio.com>
 * Copyright (C) 2001-2002 Mikael Hallendal <micke@imendio.com>
 * Copyright (C) 2001-2004 Alvaro del Castillo <acs@barrapunto.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 of the
 * License, 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.
 *
 * You should have received a copy of the GNU General Public
 * License along with this program; if not, write to the
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 * Boston, MA 02110-1301, USA.
 */

#include <config.h>
#include <time.h>
#include <string.h>
#include <gtk/gtk.h>
#include <glib/gi18n.h>
#include <libplanner/mrp-resource.h>
#include <libplanner/mrp-calendar.h>
#include <libplanner/mrp-time.h>
#include "libplanner/mrp-paths.h"

#include "planner-format.h"
#include "planner-resource-dialog.h"
#include "planner-util.h"

typedef struct {
	PlannerWindow *main_window;
	MrpResource   *resource;
	GtkWidget     *dialog;
	GtkWidget     *name_entry;
	GtkWidget     *short_name_entry;
	GtkWidget     *type_menu;
	GtkWidget     *email_entry;
	GtkWidget     *group_menu;
	GtkWidget     *cost_entry;
	GtkWidget     *calendar_tree_view;
	GtkWidget     *note_textview;
	GtkTextBuffer *note_buffer;

	/* Slightly ugly, keep the last selected one around so we can toggle it
	 * off later.
	 */
	MrpCalendar   *selected_calendar;
} DialogData;

typedef struct {
	DialogData    *data;
	MrpCalendar   *calendar;
	gboolean       found;
	GtkTreeIter    found_iter;
} FindCalData;

enum {
	COL_CALENDAR,
	COL_NAME,
	COL_SELECTED,
	NUM_COLS
};


static void          resource_dialog_name_changed_cb             (GtkWidget     *w,
								  DialogData    *data);
static void          resource_dialog_notify_name_cb              (MrpResource   *resource,
								  GParamSpec    *pspec,
								  GtkWidget     *dialog);
static gboolean      resource_dialog_name_focus_in_cb            (GtkWidget     *w,
								  GdkEventFocus *event,
								  DialogData    *data);
static gboolean      resource_dialog_name_focus_out_cb           (GtkWidget     *w,
								  GdkEventFocus *event,
								  DialogData    *data);
static void          resource_dialog_short_name_changed_cb       (GtkWidget     *w,
								  DialogData    *data);
static void          resource_dialog_notify_short_name_cb        (MrpResource   *resource,
								  GParamSpec    *pspec,
								  GtkWidget     *dialog);
static gboolean      resource_dialog_short_name_focus_in_cb      (GtkWidget     *w,
								  GdkEventFocus *event,
								  DialogData    *data);
static gboolean      resource_dialog_short_name_focus_out_cb     (GtkWidget     *w,
								  GdkEventFocus *event,
								  DialogData    *data);
static void          resource_dialog_type_changed_cb             (GtkWidget     *w,
								  DialogData    *data);
static void          resource_dialog_notify_type_cb              (MrpResource   *resource,
								  GParamSpec    *pspec,
								  GtkWidget     *dialog);
static void          resource_dialog_group_changed_cb            (GtkWidget     *w,
								  DialogData    *data);
static void          resource_dialog_notify_group_cb             (MrpResource   *resource,
								  GParamSpec    *pspec,
								  GtkWidget     *dialog);
static void          resource_dialog_email_changed_cb            (GtkWidget     *w,
								  DialogData    *data);
static void          resource_dialog_notify_email_cb             (MrpResource   *resource,
								  GParamSpec    *pspec,
								  GtkWidget     *dialog);
static gboolean      resource_dialog_email_focus_in_cb           (GtkWidget     *w,
								  GdkEventFocus *event,
								  DialogData    *data);
static gboolean      resource_dialog_email_focus_out_cb          (GtkWidget     *w,
								  GdkEventFocus *event,
								  DialogData    *data);
static void          resource_dialog_notify_cost_cb              (MrpResource   *resource,
								  GParamSpec    *pspec,
								  GtkWidget     *dialog);
static gboolean      resource_dialog_resource_cost_focus_in_cb   (GtkWidget     *w,
								  GdkEventFocus *event,
								  DialogData    *data);
static gboolean      resource_dialog_resource_cost_focus_out_cb  (GtkWidget     *w,
								  GdkEventFocus *event,
								  DialogData    *data);
static void          resource_dialog_notify_calendar_cb          (MrpResource   *resource,
								  GParamSpec    *pspec,
								  GtkWidget     *dialog);
static void          resource_dialog_edit_calendar_clicked_cb    (GtkWidget     *button,
								  DialogData    *data);
static void          resource_dialog_notify_note_cb              (MrpResource   *resource,
								  GParamSpec    *pspec,
								  GtkWidget     *dialog);
static void          resource_dialog_note_changed_cb             (GtkWidget     *w,
								  DialogData    *data);
static gboolean      resource_dialog_note_focus_in_cb            (GtkWidget     *w,
								  GdkEventFocus *event,
								  DialogData    *data);
static gboolean      resource_dialog_note_focus_out_cb           (GtkWidget     *w,
								  GdkEventFocus *event,
								  DialogData    *data);
static void          resource_dialog_note_stamp_clicked_cb       (GtkWidget     *w,
								  DialogData    *data);
static void          resource_dialog_build_calendar_tree_recurse (GtkTreeStore  *store,
								  GtkTreeIter   *parent,
								  MrpCalendar   *calendar);
static void          resource_dialog_build_calendar_tree         (DialogData    *data);
static void          resource_dialog_calendar_tree_changed_cb    (MrpProject    *project,
								  MrpCalendar   *root,
								  GtkWidget     *dialog);
static GtkTreeModel *resource_dialog_create_calendar_model       (DialogData    *data);
static void          resource_dialog_setup_calendar_tree_view    (DialogData    *data);
static void          resource_dialog_update_title                (DialogData    *data);
static void          resource_dialog_close_clicked_cb            (GtkWidget     *w,
								  DialogData    *data);
static void          resource_dialog_resource_removed_cb         (GtkWidget     *w,
								  DialogData    *data);


/* Keep the dialogs here so that we can just raise the dialog if it's
 * opened twice for the same resource.
 */
static GHashTable *dialogs = NULL;

#define DIALOG_GET_DATA(d) g_object_get_data ((GObject*)d, "data")

typedef struct {
	PlannerCmd   base;

	MrpResource *resource;
	gchar       *property;
	GValue      *value;
	GValue      *old_value;
} ResourceCmdEditProperty;

typedef struct {
	PlannerCmd   base;

	MrpResource *resource;
	gchar       *property;
	gchar       *note;
	gchar       *old_note;
} ResourceCmdEditNote;

typedef struct {
	PlannerCmd   base;

	MrpResource *resource;
	gfloat       cost;
	gfloat       old_cost;
} ResourceCmdEditCost;

typedef struct {
	PlannerCmd   base;

	MrpResource *resource;
	MrpCalendar *calendar;
	MrpCalendar *old_calendar;
} ResourceCmdCalendar;


static gboolean
foreach_find_calendar (GtkTreeModel *model,
		       GtkTreePath  *path,
		       GtkTreeIter  *iter,
		       FindCalData  *data)
{
	MrpCalendar *calendar;

	gtk_tree_model_get (model,
			    iter,
			    COL_CALENDAR, &calendar,
			    -1);

	if (calendar == data->calendar) {
		data->found = TRUE;
		data->found_iter = *iter;
		return TRUE;
	}

	return FALSE;
}

static gboolean
resource_dialog_find_calendar (DialogData  *data,
			       MrpCalendar *calendar,
			       GtkTreeIter *iter)
{
	GtkTreeModel *model;
	FindCalData    find_data;

	find_data.found = FALSE;
	find_data.calendar = calendar;
	find_data.data = data;

	model = gtk_tree_view_get_model (GTK_TREE_VIEW (data->calendar_tree_view));

	gtk_tree_model_foreach (model,
				(GtkTreeModelForeachFunc) foreach_find_calendar,
				&find_data);

	if (find_data.found) {
		*iter = find_data.found_iter;
		return TRUE;
	}

	return FALSE;
}

static void
resource_dialog_setup_combobox (GtkWidget *combo)
{
	GtkComboBoxText *combo_text = GTK_COMBO_BOX_TEXT (combo);

	gtk_combo_box_text_append_text (combo_text, _("Work"));
	gtk_combo_box_text_append_text (combo_text, _("Material"));
}

static void
menu_groups_name (GtkCellLayout   *layout,
                  GtkCellRenderer *cell,
                  GtkTreeModel    *model,
                  GtkTreeIter     *iter,
                  gpointer         user_data)
{
	MrpGroup *group;
	const gchar *name;

	gtk_tree_model_get (model, iter, 0, &group, -1);
	if (!group) {
		name = _("(None)");
	} else {
		name = mrp_group_get_name (group);
		if (!name) {
			name = _("(No name)");
		}
	}
	g_object_set (cell,
		      "text", name,
		      NULL);
}

static void
resource_dialog_setup_option_groups (GtkWidget *menu_groups,
				     GList     *groups)
{
	GtkListStore    *store;
	GtkTreeIter      iter;
	GList           *l;
	GtkCellRenderer *renderer;

	store = gtk_list_store_new (1, MRP_TYPE_GROUP);
	gtk_combo_box_set_model (GTK_COMBO_BOX (menu_groups), GTK_TREE_MODEL (store));
	g_object_unref (store);

	/* Put "no group" at the top. */
	gtk_list_store_append (store, &iter);
	gtk_list_store_set (store, &iter,
			    0, NULL,
			    -1);

	for (l = groups; l; l = l->next) {
		MrpGroup *group = l->data;

		gtk_list_store_append (store, &iter);
		gtk_list_store_set (store, &iter,
				    0, group,
				    -1);
	}

	renderer = gtk_cell_renderer_text_new ();
	gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (menu_groups),
				    renderer, TRUE);
	gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (menu_groups),
					    renderer,
					    menu_groups_name,
					    NULL, NULL);
}

static gint
resource_dialog_get_type_selected (GtkWidget *combo)
{
	switch (gtk_combo_box_get_active (GTK_COMBO_BOX (combo))) {
	case 0:
		return MRP_RESOURCE_TYPE_WORK;
	case 1:
		return MRP_RESOURCE_TYPE_MATERIAL;
	default:
		return MRP_RESOURCE_TYPE_NONE;
	}
}

static MrpGroup *
resource_dialog_get_group_selected (GtkWidget *combo)
{
	GtkTreeIter  iter;
	MrpGroup    *group;

	gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter);
	gtk_tree_model_get (gtk_combo_box_get_model (GTK_COMBO_BOX (combo)),
			    &iter,
			    0, &group,
			    -1);
	return group;
}

static void
resource_dialog_connect_to_resource (DialogData *data)
{
	MrpResource *resource;

	resource = data->resource;

	g_signal_connect_object (resource,
				 "notify::name",
				 G_CALLBACK (resource_dialog_notify_name_cb),
				 data->dialog,
				 0);

	g_signal_connect_object (resource,
				 "notify::short-name",
				 G_CALLBACK (resource_dialog_notify_short_name_cb),
				 data->dialog,
				 0);

	g_signal_connect_object (resource,
				 "notify::type",
				 G_CALLBACK (resource_dialog_notify_type_cb),
				 data->dialog,
				 0);

	g_signal_connect_object (resource,
				 "notify::group",
				 G_CALLBACK (resource_dialog_notify_group_cb),
				 data->dialog,
				 0);

	g_signal_connect_object (resource,
				 "notify::email",
				 G_CALLBACK (resource_dialog_notify_email_cb),
				 data->dialog,
				 0);

	g_signal_connect_object (resource,
				 "notify::cost",
				 G_CALLBACK (resource_dialog_notify_cost_cb),
				 data->dialog,
				 0);

	g_signal_connect_object (resource,
				 "notify::calendar",
				 G_CALLBACK (resource_dialog_notify_calendar_cb),
				 data->dialog,
				 0);

	g_signal_connect_object (resource,
				 "notify::note",
				 G_CALLBACK (resource_dialog_notify_note_cb),
				 data->dialog,
				 0);
}

static void
resource_dialog_close_clicked_cb (GtkWidget  *w,
				  DialogData *data)
{
	g_signal_handlers_disconnect_by_func (data->resource,
					      resource_dialog_resource_removed_cb,
					      data);
	gtk_widget_destroy (data->dialog);
}

static void
resource_dialog_resource_removed_cb (GtkWidget  *w,
				     DialogData *data)
{
	g_signal_handlers_disconnect_by_func (data->resource,
					      resource_dialog_resource_removed_cb,
					      data);
	gtk_widget_destroy (data->dialog);
}

static gboolean
resource_cmd_calendar_do (PlannerCmd *cmd_base)
{
	ResourceCmdCalendar *cmd;

	cmd = (ResourceCmdCalendar*) cmd_base;

	mrp_resource_set_calendar (cmd->resource, cmd->calendar);

	return TRUE;
}

static void
resource_cmd_calendar_undo (PlannerCmd *cmd_base)
{
	ResourceCmdCalendar *cmd;

	cmd = (ResourceCmdCalendar*) cmd_base;

	mrp_resource_set_calendar (cmd->resource, cmd->old_calendar);

}

static void
resource_cmd_calendar_free (PlannerCmd *cmd_base)
{
	ResourceCmdCalendar *cmd;

	cmd = (ResourceCmdCalendar *) cmd_base;

	g_object_unref (cmd->resource);

	if (cmd->calendar) {
		g_object_unref (cmd->calendar);
	}
	if (cmd->old_calendar) {
		g_object_unref (cmd->old_calendar);
	}
}

static PlannerCmd *
resource_cmd_edit_calendar (DialogData  *data,
			    MrpCalendar *calendar)
{
	PlannerCmd          *cmd_base;
	ResourceCmdCalendar *cmd;
	MrpCalendar         *current_calendar;

	cmd_base = planner_cmd_new (ResourceCmdCalendar,
				    _("Edit resource calendar"),
				    resource_cmd_calendar_do,
				    resource_cmd_calendar_undo,
				    resource_cmd_calendar_free);

	cmd = (ResourceCmdCalendar *) cmd_base;

	cmd->resource = g_object_ref (data->resource);

	current_calendar = mrp_resource_get_calendar (data->resource);

	if (current_calendar) {
		cmd->old_calendar = g_object_ref (current_calendar);
	} else {
		cmd->old_calendar = NULL;
	}

	if (calendar) {
		cmd->calendar = g_object_ref (calendar);
	} else {
		cmd->calendar = NULL;
	}

	planner_cmd_manager_insert_and_do (planner_window_get_cmd_manager (data->main_window),
					   cmd_base);

	return cmd_base;
}

static gboolean
resource_cmd_note_do (PlannerCmd *cmd_base)
{
	ResourceCmdEditNote *cmd;

	cmd = (ResourceCmdEditNote*) cmd_base;

	g_object_set (cmd->resource, "note", cmd->note, NULL);

	return TRUE;
}

static void
resource_cmd_note_undo (PlannerCmd *cmd_base)
{
	ResourceCmdEditNote *cmd;

	cmd = (ResourceCmdEditNote*) cmd_base;

	g_object_set (cmd->resource, "note", cmd->old_note, NULL);
}

static void
resource_cmd_note_free (PlannerCmd *cmd_base)
{
	ResourceCmdEditNote *cmd;

	cmd = (ResourceCmdEditNote*) cmd_base;

	g_free (cmd->note);
	g_free (cmd->old_note);
	g_free (cmd->property);

	g_object_unref (cmd->resource);
}

static PlannerCmd *
resource_cmd_edit_note (DialogData  *data,
			const gchar *focus_in_note)
{
	PlannerCmd          *cmd_base;
	ResourceCmdEditNote *cmd;
	gchar               *note;

	g_object_get (data->resource, "note", &note, NULL);

	if (strcmp (note, focus_in_note) == 0) {
		g_free (note);
		return NULL;
	}

	cmd_base = planner_cmd_new (ResourceCmdEditNote,
				    _("Edit resource note"),
				    resource_cmd_note_do,
				    resource_cmd_note_undo,
				    resource_cmd_note_free);

	cmd = (ResourceCmdEditNote *) cmd_base;

	cmd->property = g_strdup ("note");
	cmd->resource = g_object_ref (data->resource);

	cmd->old_note = g_strdup (focus_in_note);
	cmd->note = note;

	planner_cmd_manager_insert_and_do (planner_window_get_cmd_manager (data->main_window),
					   cmd_base);

	return cmd_base;
}

static gboolean
resource_cmd_cost_do (PlannerCmd *cmd_base)
{
	ResourceCmdEditCost *cmd;

	cmd = (ResourceCmdEditCost*) cmd_base;

	mrp_object_set (cmd->resource, "cost", cmd->cost, NULL);

	return TRUE;
}

static void
resource_cmd_cost_undo (PlannerCmd *cmd_base)
{
	ResourceCmdEditCost *cmd;

	cmd = (ResourceCmdEditCost*) cmd_base;

	mrp_object_set (cmd->resource, "cost", cmd->old_cost, NULL);
}

static void
resource_cmd_cost_free (PlannerCmd *cmd_base)
{
	ResourceCmdEditCost *cmd;

	cmd = (ResourceCmdEditCost*) cmd_base;

	g_object_unref (cmd->resource);
}

static PlannerCmd *
resource_cmd_edit_cost (DialogData  *data,
			const gchar *focus_in_cost)
{
	PlannerCmd          *cmd_base;
	ResourceCmdEditCost *cmd;
	gfloat               cost, old_cost;

	mrp_object_get (data->resource, "cost", &cost, NULL);

	old_cost = planner_parse_float (focus_in_cost);
	if (cost == old_cost) {
		return NULL;
	}

	cmd_base = planner_cmd_new (ResourceCmdEditCost,
				    _("Edit resource cost"),
				    resource_cmd_cost_do,
				    resource_cmd_cost_undo,
				    resource_cmd_cost_free);

	cmd = (ResourceCmdEditCost *) cmd_base;

	cmd->resource = g_object_ref (data->resource);

	cmd->old_cost = old_cost;
	cmd->cost = cost;

	planner_cmd_manager_insert_and_do (planner_window_get_cmd_manager (data->main_window),
					   cmd_base);

	return cmd_base;
}

static gboolean
resource_cmd_edit_property_do (PlannerCmd *cmd_base)
{
	ResourceCmdEditProperty *cmd;

	cmd = (ResourceCmdEditProperty*) cmd_base;

	g_object_set_property (G_OBJECT (cmd->resource),
			       cmd->property,
			       cmd->value);

	return TRUE;
}

static void
resource_cmd_edit_property_undo (PlannerCmd *cmd_base)
{
	ResourceCmdEditProperty *cmd;

	cmd = (ResourceCmdEditProperty*) cmd_base;

	g_object_set_property (G_OBJECT (cmd->resource),
			       cmd->property,
			       cmd->old_value);
}

static void
resource_cmd_edit_property_free (PlannerCmd *cmd_base)
{
	ResourceCmdEditProperty *cmd;

	cmd = (ResourceCmdEditProperty*) cmd_base;

	g_value_unset (cmd->value);
	g_value_unset (cmd->old_value);

	g_free (cmd->property);
	g_object_unref (cmd->resource);
}

static PlannerCmd *
resource_cmd_edit_property (PlannerWindow *main_window,
			    MrpResource   *resource,
			    const gchar   *property,
			    const GValue  *value)
{
	PlannerCmd              *cmd_base;
	ResourceCmdEditProperty *cmd;

	cmd_base = planner_cmd_new (ResourceCmdEditProperty,
				    _("Edit resource property"),
				    resource_cmd_edit_property_do,
				    resource_cmd_edit_property_undo,
				    resource_cmd_edit_property_free);

	cmd = (ResourceCmdEditProperty *) cmd_base;

	cmd->property = g_strdup (property);
	cmd->resource = g_object_ref (resource);

	cmd->value = g_new0 (GValue, 1);
	g_value_init (cmd->value, G_VALUE_TYPE (value));
	g_value_copy (value, cmd->value);

	cmd->old_value = g_new0 (GValue, 1);
	g_value_init (cmd->old_value, G_VALUE_TYPE (value));

	g_object_get_property (G_OBJECT (cmd->resource),
			       cmd->property,
			       cmd->old_value);

	planner_cmd_manager_insert_and_do (planner_window_get_cmd_manager (main_window),
					   cmd_base);

	return cmd_base;
}

/*
   In text entries we return to the value that exists when focus in.
   The new value is already stored in the object
*/
static PlannerCmd *
resource_cmd_edit_property_focus (PlannerWindow *main_window,
				  MrpResource   *resource,
				  const gchar   *property,
				  const GValue  *focus_in_value)
{
	PlannerCmd              *cmd_base;
	ResourceCmdEditProperty *cmd;

	cmd_base = planner_cmd_new (ResourceCmdEditProperty,
				    _("Edit resource property"),
				    resource_cmd_edit_property_do,
				    resource_cmd_edit_property_undo,
				    resource_cmd_edit_property_free);

	cmd = (ResourceCmdEditProperty *) cmd_base;

	cmd->property = g_strdup (property);
	cmd->resource = g_object_ref (resource);

	cmd->value = g_new0 (GValue, 1);
	g_value_init (cmd->value, G_VALUE_TYPE (focus_in_value));
	g_object_get_property (G_OBJECT (cmd->resource),
			       cmd->property,
			       cmd->value);

	cmd->old_value = g_new0 (GValue, 1);
	g_value_init (cmd->old_value, G_VALUE_TYPE (focus_in_value));
	g_value_copy (focus_in_value, cmd->old_value);

	planner_cmd_manager_insert_and_do (planner_window_get_cmd_manager (main_window),
					   cmd_base);

	return cmd_base;
}

static void
resource_dialog_notify_name_cb (MrpResource *resource,
				GParamSpec  *pspec,
				GtkWidget   *dialog)
{
	DialogData *data;
	gchar      *name;

	g_return_if_fail (MRP_IS_RESOURCE (resource));

	data = DIALOG_GET_DATA (dialog);

	g_object_get (data->resource, "name", &name, NULL);

	g_signal_handlers_block_by_func (data->name_entry,
					 resource_dialog_name_changed_cb,
					 dialog);

	gtk_entry_set_text (GTK_ENTRY (data->name_entry), name);

	resource_dialog_update_title (data);

	g_signal_handlers_unblock_by_func (data->name_entry,
					   resource_dialog_name_changed_cb,
					   dialog);

	g_free (name);
}

static void
resource_dialog_name_changed_cb (GtkWidget  *w,
				 DialogData *data)
{
	const gchar  *name;

	g_assert (MRP_IS_RESOURCE (data->resource));

	name = gtk_entry_get_text (GTK_ENTRY (w));

	g_signal_handlers_block_by_func (data->resource,
					 resource_dialog_notify_name_cb,
					 data->dialog);

	g_object_set (data->resource, "name", name, NULL);

	resource_dialog_update_title (data);

	g_signal_handlers_unblock_by_func (data->resource,
					   resource_dialog_notify_name_cb,
					   data->dialog);
}

static gboolean
resource_dialog_name_focus_out_cb (GtkWidget     *w,
				   GdkEventFocus *event,
				   DialogData    *data)
{
	gchar        *focus_in_name;
	GValue        value = { 0 };

	g_assert (MRP_IS_RESOURCE (data->resource));

	focus_in_name = g_object_get_data (G_OBJECT (data->resource),"focus_in_name");

	g_value_init (&value, G_TYPE_STRING);
	g_value_set_string (&value, focus_in_name);

	resource_cmd_edit_property_focus (data->main_window,
					  data->resource, "name", &value);

	g_free (focus_in_name);

	return FALSE;
}

static gboolean
resource_dialog_name_focus_in_cb (GtkWidget     *w,
				  GdkEventFocus *event,
				  DialogData    *data)
{
	gchar  *name;

	name = g_strdup (gtk_entry_get_text (GTK_ENTRY (w)));

	g_object_set_data (G_OBJECT (data->resource), "focus_in_name", name);

	return FALSE;
}

static void
resource_dialog_short_name_changed_cb (GtkWidget  *w,
				       DialogData *data)
{
	const gchar *short_name;

	short_name = gtk_entry_get_text (GTK_ENTRY (w));

	g_signal_handlers_block_by_func (data->resource,
					 resource_dialog_notify_short_name_cb,
					 data->dialog);

	g_object_set (data->resource, "short_name", short_name, NULL);

	g_signal_handlers_unblock_by_func (data->resource,
					   resource_dialog_notify_short_name_cb,
					   data->dialog);
}

static void
resource_dialog_notify_short_name_cb (MrpResource *resource,
				      GParamSpec  *pspec,
				      GtkWidget   *dialog)
{
	DialogData *data;
	gchar      *short_name;

	g_return_if_fail (MRP_IS_RESOURCE (resource));

	data = DIALOG_GET_DATA (dialog);

	g_object_get (data->resource, "short_name", &short_name, NULL);

	g_signal_handlers_block_by_func (data->short_name_entry,
					 resource_dialog_short_name_changed_cb,
					 dialog);

	gtk_entry_set_text (GTK_ENTRY (data->short_name_entry), short_name);

	g_signal_handlers_unblock_by_func (data->short_name_entry,
					   resource_dialog_short_name_changed_cb,
					   dialog);

	g_free (short_name);
}

static gboolean
resource_dialog_short_name_focus_out_cb (GtkWidget     *w,
					 GdkEventFocus *event,
					 DialogData    *data)
{
	gchar        *focus_in_short_name;
	GValue        value = { 0 };

	g_assert (MRP_IS_RESOURCE (data->resource));

	focus_in_short_name = g_object_get_data (G_OBJECT (data->resource),
						 "focus_in_short_name");

	g_value_init (&value, G_TYPE_STRING);
	g_value_set_string (&value, focus_in_short_name);

	resource_cmd_edit_property_focus (data->main_window,
					  data->resource, "short_name", &value);

	g_free (focus_in_short_name);

	return FALSE;
}

static gboolean
resource_dialog_short_name_focus_in_cb (GtkWidget     *w,
					GdkEventFocus *event,
					DialogData    *data)
{
	gchar *name;

	name = g_strdup (gtk_entry_get_text (GTK_ENTRY (w)));

	g_object_set_data (G_OBJECT (data->resource), "focus_in_short_name", name);

	return FALSE;
}

static void
resource_dialog_notify_type_cb (MrpResource *resource,
				GParamSpec  *pspec,
				GtkWidget   *dialog)
{
	DialogData      *data;
	MrpResourceType  type;
	gint             index = 0;

	g_return_if_fail (MRP_IS_RESOURCE (resource));

	data = DIALOG_GET_DATA (dialog);

	g_object_get (data->resource, "type", &type, NULL);

	g_signal_handlers_block_by_func (data->type_menu,
					 resource_dialog_type_changed_cb,
					 data->dialog);

	switch (type) {
	case MRP_RESOURCE_TYPE_NONE:
	case MRP_RESOURCE_TYPE_WORK:
		index = 0;
		break;
	case MRP_RESOURCE_TYPE_MATERIAL:
		index = 1;
		break;
	}

	gtk_combo_box_set_active (GTK_COMBO_BOX (data->type_menu), index);

	g_signal_handlers_unblock_by_func (data->type_menu,
					   resource_dialog_type_changed_cb,
					   data->dialog);
}

static void
resource_dialog_type_changed_cb (GtkWidget  *w,
				 DialogData *data)
{
	MrpResourceType  type;
	GValue           value = { 0 };

	type = resource_dialog_get_type_selected (data->type_menu);

	g_value_init (&value, G_TYPE_INT);
	g_value_set_int (&value, type);

	g_signal_handlers_block_by_func (data->resource,
					 resource_dialog_notify_type_cb,
					 data->dialog);

	resource_cmd_edit_property (data->main_window, data->resource, "type", &value);

	g_signal_handlers_unblock_by_func (data->resource,
					   resource_dialog_notify_type_cb,
					   data->dialog);
	g_value_unset (&value);
}

static void
resource_dialog_notify_group_cb (MrpResource *resource,
				 GParamSpec  *pspec,
				 GtkWidget   *dialog)
{
	DialogData *data;
	MrpProject *project;
	MrpGroup   *group;
	GList      *groups;
	gint        index;

	g_return_if_fail (MRP_IS_RESOURCE (resource));

	data = DIALOG_GET_DATA (dialog);

	g_object_get (resource,
		      "group",   &group,
		      "project", &project,
		      NULL);

	g_signal_handlers_block_by_func (data->group_menu,
					 resource_dialog_group_changed_cb,
					 dialog);

	groups = mrp_project_get_groups (project);
	if (groups == NULL) {
		index = 0;
	} else {
		index = g_list_index (groups, group) + 1;
	}

	gtk_combo_box_set_active (GTK_COMBO_BOX (data->group_menu), index);

	g_signal_handlers_unblock_by_func (data->group_menu,
					   resource_dialog_group_changed_cb,
					   dialog);
}

static void
resource_dialog_group_changed_cb (GtkWidget  *w,
				  DialogData *data)
{
	MrpGroup    *group;
	GValue       value = { 0 };

	group = resource_dialog_get_group_selected (data->group_menu);

	g_value_init (&value, MRP_TYPE_GROUP);
	g_value_set_object (&value, group);

	g_signal_handlers_block_by_func (data->resource,
					 resource_dialog_notify_group_cb,
					 data->dialog);

	resource_cmd_edit_property (data->main_window, data->resource, "group", &value);

	g_signal_handlers_unblock_by_func (data->resource,
					   resource_dialog_notify_group_cb,
					   data->dialog);
	g_value_unset (&value);
}

static void
resource_dialog_email_changed_cb (GtkWidget  *w,
				  DialogData *data)
{
	const gchar *email;
	GValue       value = { 0 };

	email = gtk_entry_get_text (GTK_ENTRY (w));

	g_value_init (&value, G_TYPE_STRING);
	g_value_set_string (&value, email);

	g_signal_handlers_block_by_func (data->resource,
					 resource_dialog_notify_email_cb,
					 data->dialog);

	g_object_set (data->resource, "email", email, NULL);

	g_signal_handlers_unblock_by_func (data->resource,
					   resource_dialog_notify_email_cb,
					   data->dialog);
	g_value_unset (&value);
}

static gboolean
resource_dialog_email_focus_out_cb (GtkWidget     *w,
				    GdkEventFocus *event,
				    DialogData    *data)
{
	gchar      *focus_in_email;
	GValue      value = { 0 };

	g_assert (MRP_IS_RESOURCE (data->resource));

	focus_in_email = g_object_get_data (G_OBJECT (data->resource), "focus_in_email");

	g_value_init (&value, G_TYPE_STRING);
	g_value_set_string (&value, focus_in_email);

	resource_cmd_edit_property_focus (data->main_window,
					  data->resource, "email", &value);

	g_free (focus_in_email);

	return FALSE;
}

static gboolean
resource_dialog_email_focus_in_cb (GtkWidget     *w,
				   GdkEventFocus *event,
				   DialogData    *data)
{
	gchar *email;

	email = g_strdup (gtk_entry_get_text (GTK_ENTRY (w)));

	g_object_set_data (G_OBJECT (data->resource),  "focus_in_email", email);

	return FALSE;
}

static void
resource_dialog_notify_email_cb (MrpResource *resource,
				 GParamSpec  *pspec,
				 GtkWidget   *dialog)
{
	DialogData *data;
	gchar      *email;

	g_return_if_fail (MRP_IS_RESOURCE (resource));

	data = DIALOG_GET_DATA (dialog);

	g_object_get (data->resource, "email", &email, NULL);

	g_signal_handlers_block_by_func (data->email_entry,
					 resource_dialog_email_changed_cb,
					 dialog);

	gtk_entry_set_text (GTK_ENTRY (data->email_entry), email);

	g_signal_handlers_unblock_by_func (data->email_entry,
					   resource_dialog_email_changed_cb,
					   dialog);

	g_free (email);
}

static gboolean
resource_dialog_resource_cost_focus_out_cb (GtkWidget     *w,
					    GdkEventFocus *event,
					    DialogData    *data)
{
	gchar      *focus_in_cost;

	focus_in_cost = g_object_get_data (G_OBJECT (data->resource), "focus_in_cost");

	resource_cmd_edit_cost (data, focus_in_cost);

	g_free (focus_in_cost);

	return FALSE;
}

static gboolean
resource_dialog_resource_cost_focus_in_cb (GtkWidget     *w,
					   GdkEventFocus *event,
					   DialogData    *data)
{
	gchar *cost;

	cost = g_strdup (gtk_entry_get_text (GTK_ENTRY (w)));

	g_object_set_data (G_OBJECT (data->resource), "focus_in_cost", cost);

	return FALSE;
}

static void
resource_dialog_cost_changed_cb (GtkWidget  *w,
				 DialogData *data)
{
	const gchar *cost;
	gfloat       fvalue;
	GValue       value = { 0 };

	cost = gtk_entry_get_text (GTK_ENTRY (w));

	fvalue = planner_parse_float (cost);

	g_value_init (&value, G_TYPE_FLOAT);
	g_value_set_float (&value, fvalue);

	g_signal_handlers_block_by_func (data->resource,
					 resource_dialog_notify_cost_cb,
					 data->dialog);

	mrp_object_set (data->resource, "cost", fvalue, NULL);

	g_signal_handlers_unblock_by_func (data->resource,
					   resource_dialog_notify_cost_cb,
					   data->dialog);
	g_value_unset (&value);
}

static void
resource_dialog_notify_cost_cb (MrpResource *resource,
				GParamSpec  *pspec,
				GtkWidget   *dialog)
{
	DialogData *data;
	gfloat      cost;
	gchar      *str;

	g_return_if_fail (MRP_IS_RESOURCE (resource));

	data = DIALOG_GET_DATA (dialog);

	g_object_get (data->resource, "cost", &cost, NULL);

	g_signal_handlers_block_by_func (data->cost_entry,
					 resource_dialog_cost_changed_cb,
					 dialog);

	str = planner_format_float (cost, 2, FALSE);

	gtk_entry_set_text (GTK_ENTRY (data->cost_entry), str);
	g_free (str);

	g_signal_handlers_unblock_by_func (data->cost_entry,
					   resource_dialog_cost_changed_cb,
					   dialog);
}

static void
resource_dialog_notify_calendar_cb (MrpResource *resource,
				    GParamSpec  *pspec,
				    GtkWidget   *dialog)
{
	DialogData   *data;
	MrpCalendar  *calendar;
	GtkTreeIter   iter;
	GtkTreeModel *model;

	g_return_if_fail (MRP_IS_RESOURCE (resource));

	data = DIALOG_GET_DATA (dialog);

	model = gtk_tree_view_get_model (GTK_TREE_VIEW (data->calendar_tree_view));

	/* Toggle the old calendar off. */
	if (resource_dialog_find_calendar (data, data->selected_calendar, &iter)) {
		gtk_tree_store_set (GTK_TREE_STORE (model),
				    &iter,
				    COL_SELECTED, FALSE,
				    -1);
	}

	calendar = mrp_resource_get_calendar (data->resource);

	/* Find the iter of the new calendar so we can toggle it on. */
	if (resource_dialog_find_calendar (data, calendar, &iter)) {
		gtk_tree_store_set (GTK_TREE_STORE (model),
				    &iter,
				    COL_SELECTED, TRUE,
				    -1);

		data->selected_calendar = calendar;
	}
}

static void
resource_dialog_edit_calendar_clicked_cb (GtkWidget  *button,
					  DialogData *data)
{
	planner_window_show_calendar_dialog (data->main_window);
}

static gboolean
resource_dialog_note_focus_out_cb (GtkWidget     *w,
				   GdkEventFocus *event,
				   DialogData    *data)
{
	gchar      *focus_in_note;

	focus_in_note = g_object_get_data (G_OBJECT (data->resource),"focus_in_note");

	resource_cmd_edit_note (data, focus_in_note);

	g_free (focus_in_note);

	return FALSE;
}

static gboolean
resource_dialog_note_focus_in_cb (GtkWidget     *w,
				  GdkEventFocus *event,
				  DialogData    *data)
{
	gchar *note;

	g_object_get (data->resource, "note", &note, NULL);

	gtk_text_buffer_set_text (data->note_buffer, note, -1);

	g_object_set_data (G_OBJECT (data->resource), "focus_in_note", note);

	return FALSE;
}

static void
resource_dialog_notify_note_cb (MrpResource *resource,
				GParamSpec  *pspec,
				GtkWidget   *dialog)
{
	DialogData *data;
	gchar      *note;

	g_return_if_fail (MRP_IS_RESOURCE (resource));
	g_return_if_fail (GTK_IS_DIALOG (dialog));

	data = DIALOG_GET_DATA (dialog);

	g_object_get (resource, "note", &note, NULL);

	g_signal_handlers_block_by_func (data->note_buffer,
					 resource_dialog_note_changed_cb,
					 data);

	gtk_text_buffer_set_text (data->note_buffer, note, -1);

	g_signal_handlers_unblock_by_func (data->note_buffer,
					   resource_dialog_note_changed_cb,
					   data);

	g_free (note);
}

static void
resource_dialog_note_changed_cb (GtkWidget  *w,
				 DialogData *data)
{
	const gchar   *note;
	GtkTextIter    start, end;
	GtkTextBuffer *buffer;

	buffer = GTK_TEXT_BUFFER (w);

	gtk_text_buffer_get_bounds (buffer, &start, &end);

	note = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);

	g_signal_handlers_block_by_func (data->resource,
					 resource_dialog_notify_note_cb,
					 data->dialog);

	g_object_set (data->resource, "note", note, NULL);

	g_signal_handlers_unblock_by_func (data->resource,
					   resource_dialog_notify_note_cb,
					   data->dialog);
}

static void
resource_dialog_note_stamp_clicked_cb (GtkWidget  *w,
				       DialogData *data)
{
	time_t         t;
	struct tm     *tm;
	gchar          stamp[128];
	gchar         *utf8, *note, *note_old;
	GtkTextMark   *mark;
	GtkTextIter    start, end;

	g_object_get (data->resource, "note", &note_old, NULL);

	gtk_text_buffer_set_text (data->note_buffer, note_old, -1);

	t = time (NULL);
	tm = localtime (&t);

	/* i18n: time stamp format for notes in task dialog, see strftime(3) for
	 * a detailed description. */
	strftime (stamp, sizeof (stamp), _("%a %d %b %Y, %H:%M\n"), tm);

	utf8 = g_locale_to_utf8 (stamp, -1, NULL, NULL, NULL);

	gtk_text_buffer_get_end_iter (data->note_buffer, &end);

	if (!gtk_text_iter_starts_line (&end)) {
		gtk_text_buffer_insert (data->note_buffer, &end, "\n", 1);
		gtk_text_buffer_get_end_iter (data->note_buffer, &end);
	}

	gtk_text_buffer_insert (data->note_buffer, &end, utf8, -11);

	g_free (utf8);

	gtk_text_buffer_get_end_iter (data->note_buffer, &end);

	mark = gtk_text_buffer_create_mark (data->note_buffer,
					    NULL,
					    &end,
					    TRUE);

	gtk_text_view_scroll_mark_onscreen (GTK_TEXT_VIEW (data->note_textview), mark);

	gtk_text_buffer_get_bounds (data->note_buffer, &start, &end);
	note = gtk_text_buffer_get_text (data->note_buffer, &start, &end, FALSE);

	if (g_getenv ("PLANNER_DEBUG_UNDO_RESOURCE")) {
		g_message ("New note with stamp: %s", note);
	}

	g_object_set (data->resource, "note", note, NULL);

	resource_cmd_edit_note (data, note_old);

	g_free (note_old);
}

static void
resource_dialog_calendar_toggled_cb (GtkCellRendererToggle *cell,
				     const gchar           *path_str,
				     DialogData            *data)
{
	GtkTreePath  *path;
	GtkTreeModel *model;
	GtkTreeIter   iter;
	gboolean      selected;
	MrpCalendar  *calendar;

	if (g_getenv ("PLANNER_DEBUG_UNDO_RESOURCE")) {
		g_message ("Changing the calendar for the resource %s",
			   mrp_resource_get_name (data->resource));
	}

	path = gtk_tree_path_new_from_string (path_str);

	model = gtk_tree_view_get_model (GTK_TREE_VIEW (data->calendar_tree_view));

	gtk_tree_model_get_iter (model, &iter, path);

	gtk_tree_model_get (model,
			    &iter,
			    COL_SELECTED, &selected,
			    COL_CALENDAR, &calendar,
			    -1);

	if (!selected) {
		resource_cmd_edit_calendar (data, calendar);
	}

	gtk_tree_path_free (path);
}

static void
resource_dialog_build_calendar_tree_recurse (GtkTreeStore *store,
					     GtkTreeIter  *parent,
					     MrpCalendar  *calendar)
{
	GtkTreeIter  iter;
	const gchar *name;
	GList       *children, *l;

	name = mrp_calendar_get_name (calendar);

	gtk_tree_store_append (store, &iter, parent);
	gtk_tree_store_set (store,
			    &iter,
			    COL_NAME, name,
			    COL_CALENDAR, calendar,
			    COL_SELECTED, FALSE,
			    -1);

	children = mrp_calendar_get_children (calendar);
	for (l = children; l; l = l->next) {
		resource_dialog_build_calendar_tree_recurse (store, &iter, l->data);
	}
}

static void
resource_dialog_build_calendar_tree (DialogData *data)
{
	MrpProject   *project;
	MrpCalendar  *root;
	GtkTreeStore *store;
	GtkTreeIter   iter;
	GList        *children, *l;
	MrpCalendar  *calendar;

	project = planner_window_get_project (data->main_window);
	root = mrp_project_get_root_calendar (project);

	store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (data->calendar_tree_view)));

	gtk_tree_store_append (store, &iter, NULL);
	gtk_tree_store_set (store,
			    &iter,
			    COL_NAME, _("None (use project default)"),
			    COL_CALENDAR, NULL,
			    COL_SELECTED, FALSE,
			    -1);

	children = mrp_calendar_get_children (root);
	for (l = children; l; l = l->next) {
		resource_dialog_build_calendar_tree_recurse (store, NULL, l->data);
	}

	gtk_tree_view_expand_all (GTK_TREE_VIEW (data->calendar_tree_view));

	calendar = mrp_resource_get_calendar (data->resource);

	/* Select the current calendar. */
	if (resource_dialog_find_calendar (data, calendar, &iter)) {
		gtk_tree_store_set (store,
				    &iter,
				    COL_SELECTED, TRUE,
				    -1);

		data->selected_calendar = calendar;
	}
}

static void
resource_dialog_calendar_tree_changed_cb (MrpProject  *project,
					  MrpCalendar *root,
					  GtkWidget   *dialog)
{
	DialogData   *data;
	GtkTreeView  *tree_view;
	GtkTreeStore *store;

	data = DIALOG_GET_DATA (dialog);

	tree_view = GTK_TREE_VIEW (data->calendar_tree_view);
	store = GTK_TREE_STORE (gtk_tree_view_get_model (tree_view));

	gtk_tree_store_clear (store);

	resource_dialog_build_calendar_tree (data);
}

static GtkTreeModel *
resource_dialog_create_calendar_model (DialogData *data)
{
	MrpProject   *project;
	GtkTreeStore *store;

	project = planner_window_get_project (data->main_window);

	store = gtk_tree_store_new (NUM_COLS,
				    G_TYPE_OBJECT,
				    G_TYPE_STRING,
				    G_TYPE_BOOLEAN);

	g_signal_connect_object (project,
				 "calendar_tree_changed",
				 G_CALLBACK (resource_dialog_calendar_tree_changed_cb),
				 data->dialog,
				 0);

	return GTK_TREE_MODEL (store);
}

static void
resource_dialog_setup_calendar_tree_view (DialogData *data)
{
	GtkTreeView       *tree_view;
	GtkTreeModel      *model;
	GtkCellRenderer   *cell;
	GtkTreeViewColumn *col;

	tree_view = GTK_TREE_VIEW (data->calendar_tree_view);

	model = resource_dialog_create_calendar_model (data);
	gtk_tree_view_set_model (tree_view, model);
	g_object_unref (model);

	col = gtk_tree_view_column_new ();

	cell = gtk_cell_renderer_toggle_new ();
	g_object_set (cell,
		      "activatable", TRUE,
		      "radio", TRUE,
		      NULL);

	g_signal_connect (cell,
			  "toggled",
			  G_CALLBACK (resource_dialog_calendar_toggled_cb),
			  data);

	gtk_tree_view_column_pack_start (col, cell, FALSE);

	gtk_tree_view_column_set_attributes (col,
					     cell,
					     "active", COL_SELECTED,
					     NULL);

	cell = gtk_cell_renderer_text_new ();
	gtk_tree_view_column_pack_start (col, cell, FALSE);

	gtk_tree_view_column_set_attributes (col,
					     cell,
					     "text", COL_NAME,
					     NULL);

	gtk_tree_view_append_column (tree_view, col);

	resource_dialog_build_calendar_tree (data);
}

static void
resource_dialog_update_title (DialogData *data)
{
	gchar *title;
	gchar *name;

	g_object_get (data->resource, "name", &name, NULL);

	if (!name || strlen (name) == 0) {
		title = g_strdup (_("Edit resource properties"));
	} else {
		title = g_strconcat (name, " - ", _("Edit resource properties"), NULL);
	}

	gtk_window_set_title (GTK_WINDOW (data->dialog), title);

	g_free (name);
	g_free (title);
}

static void
resource_dialog_parent_destroy_cb (GtkWidget *parent,
				   GtkWidget *dialog)
{
	if (g_getenv ("PLANNER_DEBUG_UNDO_RESOURCE")) {
		g_message ("Destroying the resource dialog widget ...");
	}

	gtk_widget_destroy (dialog);
}

static void
resource_dialog_destroy_cb (GtkWidget  *parent,
			    DialogData *data)
{
	g_hash_table_remove (dialogs, data->resource);
}

GtkWidget *
planner_resource_dialog_new (PlannerWindow *window,
			     MrpResource  *resource)
{
	GtkBuilder      *builder;
	GtkWidget       *dialog;
	GtkWidget       *w;
	DialogData      *data;
	gchar           *name, *short_name, *email;
	MrpProject      *project;
	MrpGroup        *group;
	MrpResourceType  type;
	gfloat           cost;
	GList           *groups;
	gint             index = 0;
	gchar           *note;

	g_return_val_if_fail (PLANNER_IS_WINDOW (window), NULL);
	g_return_val_if_fail (MRP_IS_RESOURCE (resource), NULL);

	if (!dialogs) {
		dialogs = g_hash_table_new (NULL, NULL);
	}

	dialog = g_hash_table_lookup (dialogs, resource);
	if (dialog) {
		gtk_window_present (GTK_WINDOW (dialog));
		return dialog;
	}

	g_object_get (resource, "project", &project, NULL);

	builder = gtk_builder_new_from_resource ("/app/drey/Planner/ui/resource-dialog.ui");

	dialog = GTK_WIDGET (gtk_builder_get_object (builder, "resource_dialog"));

	data = g_new0 (DialogData, 1);

	data->main_window = window;
	data->dialog = dialog;
	data->resource = resource;

	g_hash_table_insert (dialogs, resource, dialog);

	g_signal_connect (dialog,
			  "destroy",
			  G_CALLBACK (resource_dialog_destroy_cb),
			  data);

	g_signal_connect_object (window,
				 "destroy",
				 G_CALLBACK (resource_dialog_parent_destroy_cb),
				 dialog,
				 0);

	g_signal_connect (resource,
			  "removed",
			  G_CALLBACK (resource_dialog_resource_removed_cb),
			  data);


	data->name_entry = GTK_WIDGET (gtk_builder_get_object (builder, "entry_name"));
	data->short_name_entry = GTK_WIDGET (gtk_builder_get_object (builder, "entry_short_name"));
	data->type_menu = GTK_WIDGET (gtk_builder_get_object (builder, "menu_type"));
	data->group_menu = GTK_WIDGET (gtk_builder_get_object (builder, "menu_group"));
	data->email_entry = GTK_WIDGET (gtk_builder_get_object (builder, "entry_email"));
	data->cost_entry = GTK_WIDGET (gtk_builder_get_object (builder, "entry_cost"));
	data->calendar_tree_view = GTK_WIDGET (gtk_builder_get_object (builder, "calendar_treeview"));
	data->note_textview = GTK_WIDGET (gtk_builder_get_object (builder, "note_textview"));

	data->note_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (data->note_textview));

	resource_dialog_setup_calendar_tree_view (data);

	g_object_get (data->resource, "note", &note, NULL);
	if (note) {
		gtk_text_buffer_set_text (data->note_buffer, note, -1);
		g_free (note);
	}

	g_signal_connect (data->note_buffer,
			  "changed",
			  G_CALLBACK (resource_dialog_note_changed_cb),
			  data);

	g_signal_connect (data->note_textview,
			  "focus_out_event",
			  G_CALLBACK (resource_dialog_note_focus_out_cb),
			  data);

	g_signal_connect (data->note_textview,
			  "focus_in_event",
			  G_CALLBACK (resource_dialog_note_focus_in_cb),
			  data);


	w = GTK_WIDGET (gtk_builder_get_object (builder, "calendar_button"));
	g_signal_connect (w,
			  "clicked",
			  G_CALLBACK (resource_dialog_edit_calendar_clicked_cb),
			  data);

	w = GTK_WIDGET (gtk_builder_get_object (builder, "stamp_button"));
	g_signal_connect (w,
			  "clicked",
			  G_CALLBACK (resource_dialog_note_stamp_clicked_cb),
			  data);

	w = GTK_WIDGET (gtk_builder_get_object (builder, "close_button"));
	g_signal_connect (w,
			  "clicked",
			  G_CALLBACK (resource_dialog_close_clicked_cb),
			  data);

	g_object_set_data_full (G_OBJECT (dialog),
				"data", data,
				g_free);

	mrp_object_get (MRP_OBJECT (resource),
			"name",  &name,
			"short_name",  &short_name,
			"type",  &type,
			"group", &group,
			"email", &email,
			"cost",  &cost,
			NULL);

	gtk_entry_set_text (GTK_ENTRY (data->name_entry), name);
	g_signal_connect (data->name_entry,
			  "changed",
			  G_CALLBACK (resource_dialog_name_changed_cb),
			  data);

	g_signal_connect (data->name_entry,
			  "focus_out_event",
			  G_CALLBACK (resource_dialog_name_focus_out_cb),
			  data);

	g_signal_connect (data->name_entry,
			  "focus_in_event",
			  G_CALLBACK (resource_dialog_name_focus_in_cb),
			  data);

	gtk_entry_set_text (GTK_ENTRY (data->short_name_entry), short_name);

	g_signal_connect (data->short_name_entry,
			  "changed",
			  G_CALLBACK (resource_dialog_short_name_changed_cb),
			  data);

	g_signal_connect (data->short_name_entry,
			  "focus_out_event",
			  G_CALLBACK (resource_dialog_short_name_focus_out_cb),
			  data);

	g_signal_connect (data->short_name_entry,
			  "focus_in_event",
			  G_CALLBACK (resource_dialog_short_name_focus_in_cb),
			  data);

	resource_dialog_setup_combobox (data->type_menu);

	/* Select the right type. */
	switch (type) {
	case MRP_RESOURCE_TYPE_NONE:
	case MRP_RESOURCE_TYPE_WORK:
		index = 0;
		break;
	case MRP_RESOURCE_TYPE_MATERIAL:
		index = 1;
		break;
	}

	gtk_combo_box_set_active (GTK_COMBO_BOX (data->type_menu), index);

	g_signal_connect (data->type_menu,
			  "changed",
			  G_CALLBACK (resource_dialog_type_changed_cb),
			  data);

	groups = mrp_project_get_groups (project);
	resource_dialog_setup_option_groups (data->group_menu, groups);

	/* Select the right group. + 1 is for the empty group at the top. */
	if (groups == NULL) {
		index = 0;
	} else {
		index = g_list_index (groups, group) + 1;
	}

	gtk_combo_box_set_active (GTK_COMBO_BOX (data->group_menu), index);

	g_signal_connect (data->group_menu,
			  "changed",
			  G_CALLBACK (resource_dialog_group_changed_cb),
			  data);

	gtk_entry_set_text (GTK_ENTRY (data->email_entry), email);

	g_signal_connect (data->email_entry,
			  "changed",
			  G_CALLBACK (resource_dialog_email_changed_cb),
			  data);

	g_signal_connect (data->email_entry,
			  "focus_out_event",
			  G_CALLBACK (resource_dialog_email_focus_out_cb),
			  data);

	g_signal_connect (data->email_entry,
			  "focus_in_event",
			  G_CALLBACK (resource_dialog_email_focus_in_cb),
			  data);

	gtk_entry_set_text (GTK_ENTRY (data->cost_entry),
			    planner_format_float (cost, 2, FALSE));

	g_signal_connect (data->cost_entry,
			  "changed",
			  G_CALLBACK (resource_dialog_cost_changed_cb),
			  data);

	g_signal_connect (data->cost_entry,
			  "focus_out_event",
			  G_CALLBACK (resource_dialog_resource_cost_focus_out_cb),
			  data);

	g_signal_connect (data->cost_entry,
			  "focus_in_event",
			  G_CALLBACK (resource_dialog_resource_cost_focus_in_cb),
			  data);


	g_free (name);
	g_free (short_name);
	g_free (email);

	resource_dialog_connect_to_resource (data);

	resource_dialog_update_title (data);

	g_object_unref (builder);

	return dialog;
}
