/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */

/*
 *  Copyright (C) 2003 Takuro Ashie
 *
 *  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.
 *
 *  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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include "kz-entry-action.h"

#include <kz-entry.h>
#include <glib/gi18n.h>

enum {
  PROP_0,
  PROP_TEXT
};

static void       dispose      (GObject *object);
static void       set_property (GObject      *object,
                                guint         prop_id,
                                const GValue *value,
                                GParamSpec   *pspec);
static void       get_property (GObject      *object,
                                guint         prop_id,
                                GValue       *value,
                                GParamSpec   *pspec);

static GtkWidget *create_menu_item              (GtkAction *action);
static GtkWidget *create_tool_item              (GtkAction *action);

static void       connect_proxy                 (GtkAction *action,
						 GtkWidget *proxy);
static void       disconnect_proxy              (GtkAction *action,
						 GtkWidget *proxy);

static GtkEntry  *kz_entry_action_real_get_entry_widget (KzEntryAction *action,
							  GtkWidget      *proxy);

G_DEFINE_TYPE(KzEntryAction, kz_entry_action, GTK_TYPE_ACTION)

static void
kz_entry_action_class_init (KzEntryActionClass *klass)
{
	GObjectClass *object_class;
	GtkActionClass *action_class;

	object_class = G_OBJECT_CLASS(klass);
	action_class = GTK_ACTION_CLASS(klass);

	object_class->dispose      = dispose;
	object_class->set_property = set_property;
	object_class->get_property = get_property;

	action_class->create_menu_item = create_menu_item;
	action_class->create_tool_item = create_tool_item;
	action_class->connect_proxy    = connect_proxy;
	action_class->disconnect_proxy = disconnect_proxy;

	action_class->toolbar_item_type = GTK_TYPE_TOOL_ITEM;

	klass->get_entry_widget = kz_entry_action_real_get_entry_widget;

	g_object_class_install_property(
		object_class,
		PROP_TEXT,
		g_param_spec_string("text",
				    _("Text"),
				    _("Text in entries."),
				    NULL,
				    G_PARAM_READWRITE));
}


static void
kz_entry_action_init (KzEntryAction *action)
{
}


static void
dispose (GObject *object)
{
	KzEntryAction *action = KZ_ENTRY_ACTION(object);

	if (action->text)
		g_free (action->text);
	action->text = NULL;

	if (G_OBJECT_CLASS (kz_entry_action_parent_class)->dispose)
		G_OBJECT_CLASS (kz_entry_action_parent_class)->dispose(object);
}


static void
set_property (GObject      *object,
              guint         prop_id,
              const GValue *value,
              GParamSpec   *pspec)
{
	KzEntryAction *action;

	action = KZ_ENTRY_ACTION(object);

	switch (prop_id)
	{
	case PROP_TEXT:
		g_free(action->text);
		action->text = g_value_dup_string(value);
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
		break;
	}
}


static void
get_property (GObject    *object,
              guint       prop_id,
              GValue     *value,
              GParamSpec *pspec)
{
	KzEntryAction *action;

	action = KZ_ENTRY_ACTION(object);

	switch (prop_id)
	{
	case PROP_TEXT:
		g_value_set_string(value, action->text);
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
		break;
	}
}

#if 0
static gboolean
cb_menu_item_entry_button_press (GtkWidget *widget)
{
	/* don't propagate to parent */
	return TRUE;
}


static gboolean
cb_menu_item_entry_button_release (GtkWidget *widget)
{
	/* don't propagate to parent */
	return TRUE;
}


static gboolean
cb_menu_item_entry_enter (GtkWidget *widget, GdkEventCrossing *event)
{
	gtk_grab_add(GTK_BIN(widget)->child);
	gtk_widget_grab_focus(GTK_BIN(widget)->child);

	return TRUE;
}


static gboolean
cb_menu_item_entry_leave (GtkWidget *widget, GdkEventCrossing *event)
{
	gtk_grab_remove(GTK_BIN(widget)->child);

	return TRUE;
}
#endif

static GtkWidget *
create_menu_item (GtkAction *action)
{
	GtkWidget *widget, *entry;

#warning FIXME! implement as our original widget and force blink cursor.
	widget = gtk_menu_item_new();
	entry = kz_entry_new();
	gtk_widget_show(entry);
	gtk_container_add(GTK_CONTAINER(widget), entry);
#if 0
	g_signal_connect_after(widget, "button-press-event",
			       G_CALLBACK(cb_menu_item_entry_button_press),
			       NULL);
	g_signal_connect_after(widget, "button-release-event",
			       G_CALLBACK(cb_menu_item_entry_button_release),
			       NULL);

	g_signal_connect(widget, "enter-notify-event",
			 G_CALLBACK(cb_menu_item_entry_enter), NULL);
	g_signal_connect(widget, "leave-notify-event",
			 G_CALLBACK(cb_menu_item_entry_leave), NULL);
#endif
	return widget;
}


static void
cb_entry_changed(GtkEditable *editable, GtkAction *action)
{
	GtkEntry *entry;
	const gchar *text;

	entry = GTK_ENTRY(editable);
	text = gtk_entry_get_text(entry);

	g_object_set(G_OBJECT(action), "text", text, NULL);
}


static void
cb_entry_activate(GtkEntry *entry, GtkAction *action)
{
	g_return_if_fail(KZ_IS_ENTRY_ACTION(action));

	gtk_action_activate(action);
}


static void
sync_text (GtkAction *action, GParamSpec *pspec, GtkWidget *proxy)
{
	GtkEntry *entry;
	
	entry = kz_entry_action_get_entry_widget(KZ_ENTRY_ACTION(action), proxy);
	if (!entry) return;

	g_signal_handlers_block_by_func(entry,
					G_CALLBACK(cb_entry_changed),
					action);
	gtk_entry_set_text(entry,
			   KZ_ENTRY_ACTION(action)->text);
	g_signal_handlers_unblock_by_func(entry,
					  G_CALLBACK(cb_entry_changed),
					  action);
}


static GtkWidget *
create_tool_item (GtkAction *action)
{
	GtkWidget *widget, *entry;

	widget = (*GTK_ACTION_CLASS(kz_entry_action_parent_class)->create_tool_item) (action);
	gtk_tool_item_set_expand (GTK_TOOL_ITEM(widget), TRUE);

	entry = kz_entry_new();
	gtk_container_add(GTK_CONTAINER(widget), entry);
	gtk_widget_show(entry);

	return widget;
}


static GtkEntry *
kz_entry_action_real_get_entry_widget(KzEntryAction *action, GtkWidget *proxy)
{
	GtkEntry *entry = NULL;

	g_return_val_if_fail(proxy, NULL);

	if (GTK_IS_BIN(proxy))
	{
		if (GTK_IS_ENTRY(GTK_BIN(proxy)->child))
		{
			entry = GTK_ENTRY(GTK_BIN(proxy)->child);
		}
		else if (GTK_IS_COMBO_BOX(GTK_BIN(proxy)->child))
		{
			entry = GTK_ENTRY(GTK_BIN(GTK_BIN(proxy)->child)->child);
		}
	}
	else if (GTK_IS_ENTRY(proxy))
	{
		entry = GTK_ENTRY(proxy);
	}
	else if (GTK_IS_COMBO_BOX(proxy))
	{
		entry = GTK_ENTRY(GTK_BIN(proxy)->child);
	}

	if (GTK_IS_ENTRY(entry))
		return entry;

	return NULL;
}


GtkEntry *
kz_entry_action_get_entry_widget(KzEntryAction *action, GtkWidget *proxy)
{
	KzEntryActionClass *klass;

	g_return_val_if_fail(KZ_IS_ENTRY_ACTION(action), NULL);

	klass = KZ_ENTRY_ACTION_GET_CLASS(action);

	if (klass->get_entry_widget)
		return klass->get_entry_widget(action, proxy);

	return NULL;
}


static void
connect_proxy (GtkAction *action, GtkWidget *proxy)
{
	KzEntryAction *entry_action;
	GtkEntry *entry = NULL;

	entry_action = KZ_ENTRY_ACTION (action);

	entry = kz_entry_action_get_entry_widget(entry_action, proxy);
	if (GTK_IS_ENTRY(entry))
	{
		g_signal_connect(entry, "changed",
				 G_CALLBACK(cb_entry_changed), action);
		g_signal_connect(entry, "activate",
				 G_CALLBACK(cb_entry_activate), action);

		g_object_ref(action);
		g_object_set_data_full(G_OBJECT(proxy), "gtk-action", action,
				       g_object_unref);
#if 0
		/* add this widget to the list of proxies */
		action->proxies = g_slist_prepend(action->proxies, proxy);
		g_signal_connect(proxy, "destroy",
				 G_CALLBACK(gtk_action_remove_proxy), action);

		g_signal_connect_object (action, "notify::sensitive",
					 G_CALLBACK (gtk_action_sync_property),
					 proxy, 0);
		gtk_widget_set_sensitive(proxy, action->sensitive);

		g_signal_connect_object(action, "notify::visible",
					G_CALLBACK(gtk_action_sync_property),
					proxy, 0);
		if (action->visible)
			gtk_widget_show(proxy);
		else
			gtk_widget_hide(proxy);

#endif 
		/* sync entry text */
		g_signal_connect_object(action, "notify::text",
					G_CALLBACK(sync_text),
					entry, 0);

		if (entry_action->text)
			gtk_entry_set_text(entry, entry_action->text);
	}
	GTK_ACTION_CLASS (kz_entry_action_parent_class)->connect_proxy (action, proxy);
}


static void
disconnect_proxy (GtkAction *action, GtkWidget *proxy)
{
	KzEntryAction *entry_action;
	GtkEntry *entry;

	entry_action = KZ_ENTRY_ACTION (action);

	entry = kz_entry_action_get_entry_widget(entry_action, proxy);
	if (entry)
	{
		g_signal_handlers_disconnect_by_func
			(entry,  G_CALLBACK(cb_entry_changed), action);
		g_signal_handlers_disconnect_by_func
			(entry, G_CALLBACK(cb_entry_activate), action);
	}

	/* other signals will be remove by parent */
	GTK_ACTION_CLASS (kz_entry_action_parent_class)->disconnect_proxy(action, proxy);
}


void
kz_entry_action_set_text (KzEntryAction *action,
			  const gchar *text)
{
	g_return_if_fail(KZ_IS_ENTRY_ACTION(action));

	g_object_set(action, "text", text, NULL);
}


const gchar *
kz_entry_action_get_text (KzEntryAction *action)
{
	g_return_val_if_fail(KZ_IS_ENTRY_ACTION(action), NULL);

	return action->text;
}

