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

/*
 *  Copyright (C) 2003-2004 Hiroyuki Ikezoe
 *  Copyright (C) 2003 Takuro Ashie <ashie@homa.ne.jp>
 *
 *  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.
 *
 *  $Id: kz-bookmark-menu-item-list.c 2638 2006-12-02 09:22:27Z ikezoe $
 */

#include "kz-bookmark-menu-item-list.h"

#include <gtk/gtk.h>
#include <glib/gi18n.h>

#include "kazehakase.h"
#include "kz-icons.h"
#include "kz-bookmark-menu-item.h"
#include "kz-bookmark-separator-menu-item.h"
#include "kz-bookmark-folder-menu-item.h"
#include "kz-actions.h"

enum {
	PROP_0,
	PROP_MENU_SHELL,
	PROP_BOOKMARK,
	PROP_KZ_WINDOW
};

/* object class methods */
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 void	kz_bookmark_menu_item_list_disconnect_signal (KzBookmarkMenuItemList *list);
static void	kz_bookmark_menu_item_list_connect_signal    (KzBookmarkMenuItemList *list);

static void     cb_bookmark_list_updated         (KzBookmark *folder,
						  KzBookmarkMenuItemList *list);
static void     cb_bookmark_list_remove_child    (KzBookmark *folder,
						  KzBookmark *child,
						  KzBookmarkMenuItemList *list);
static void     cb_bookmark_list_insert_child  	 (KzBookmark *folder,
						  KzBookmark *child,
						  KzBookmark *sibling,
						  KzBookmarkMenuItemList *list);
static void     menu_shell_weak_notify           (KzBookmarkMenuItemList *list,
	       					  GObject *object);

G_DEFINE_TYPE(KzBookmarkMenuItemList, kz_bookmark_menu_item_list, G_TYPE_OBJECT)

static void
kz_bookmark_menu_item_list_class_init (KzBookmarkMenuItemListClass *klass)
{
	GObjectClass *gobject_class;

	gobject_class   = (GObjectClass *) klass;

	/* GObject signals */
	gobject_class->dispose      = dispose;
	gobject_class->set_property = set_property;
	gobject_class->get_property = get_property;
	
	g_object_class_install_property
		(gobject_class,
		 PROP_MENU_SHELL,
		 g_param_spec_object ("menu-shell",
				      _("GtkMenuShell"),
				      _("The GtkMenuShell object"),
				      GTK_TYPE_MENU_SHELL,
				      G_PARAM_READWRITE |
				      G_PARAM_CONSTRUCT_ONLY));
	g_object_class_install_property
		(gobject_class,
		 PROP_BOOKMARK,
		 g_param_spec_object ("bookmark",
				      _("Bookmark"),
				      _("The boomark to show"),
				      KZ_TYPE_BOOKMARK,
				      G_PARAM_READWRITE |
				      G_PARAM_CONSTRUCT_ONLY));
	g_object_class_install_property
		(gobject_class,
		 PROP_KZ_WINDOW,
		 g_param_spec_object ("kz-window",
				      _("KzWindow"),
				      _("The KzWindow to add a home button"),
				      KZ_TYPE_WINDOW,
				      G_PARAM_READWRITE |
				      G_PARAM_CONSTRUCT_ONLY));
}


static void
kz_bookmark_menu_item_list_init (KzBookmarkMenuItemList *list)
{
	list->menu_shell = NULL;
	list->folder     = NULL;
	list->kz         = NULL;

	list->initial_children = 0;
}


static void
dispose (GObject *object)
{
	KzBookmarkMenuItemList *list;

	list = KZ_BOOKMARK_MENU_ITEM_LIST(object);
	
	if (list->menu_shell)
	{
		list->menu_shell = NULL;
	}

	if (list->folder)
	{
		kz_bookmark_menu_item_list_disconnect_signal(list);
		g_object_unref(list->folder);
		list->folder = NULL;
	}

	if (list->kz)
	{
		g_object_unref(list->kz);
		list->kz = NULL;
	}

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


static void
set_property (GObject         *object,
              guint            prop_id,
              const GValue    *value,
              GParamSpec      *pspec)
{
	KzBookmarkMenuItemList *list = KZ_BOOKMARK_MENU_ITEM_LIST(object);
	GList *children;
  
	switch (prop_id)
	{
	case PROP_MENU_SHELL:
		list->menu_shell = g_value_get_object(value);
		children = gtk_container_get_children(GTK_CONTAINER(list->menu_shell));
		list->initial_children = g_list_length(children);
		g_list_free(children);
		g_object_weak_ref(G_OBJECT(list->menu_shell), (GWeakNotify)menu_shell_weak_notify, list);
		break;
	case PROP_BOOKMARK:
		list->folder = g_object_ref(g_value_get_object(value));
		kz_bookmark_menu_item_list_connect_signal(list);
		break;
	case PROP_KZ_WINDOW:
		list->kz = g_object_ref(g_value_get_object(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)
{
	KzBookmarkMenuItemList *list = KZ_BOOKMARK_MENU_ITEM_LIST(object);

	switch (prop_id)
	{
	case PROP_MENU_SHELL:
		g_value_set_object(value, list->menu_shell);
		break;
	case PROP_BOOKMARK:
		g_value_set_object(value, list->folder);
		break;
	case PROP_KZ_WINDOW:
		g_value_set_object(value, list->kz);
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
		break;
	}
}


KzBookmarkMenuItemList *
kz_bookmark_menu_item_list_new (GtkMenuShell *menu_shell, KzWindow *kz, KzBookmark *bookmark)
{
	KzBookmarkMenuItemList *list;

	g_return_val_if_fail(KZ_IS_WINDOW(kz), NULL);
	g_return_val_if_fail(KZ_IS_BOOKMARK(bookmark), NULL);

	list = g_object_new(KZ_TYPE_BOOKMARK_MENU_ITEM_LIST,
			    "menu-shell", menu_shell,
			    "bookmark",   bookmark,
			    "kz-window",  kz,
			    NULL);

	return list;
}


static void
kz_bookmark_menu_item_list_connect_signal (KzBookmarkMenuItemList *list)
{
	g_signal_connect(list->folder, "children-reordered",
			 G_CALLBACK(cb_bookmark_list_updated),
			 list);	
	g_signal_connect(list->folder, "insert-child",
			 G_CALLBACK(cb_bookmark_list_insert_child),
			 list);
	g_signal_connect(list->folder, "remove-child",
			 G_CALLBACK(cb_bookmark_list_remove_child),
			 list);	
}


static void
kz_bookmark_menu_item_list_disconnect_signal (KzBookmarkMenuItemList *list)
{
	g_signal_handlers_disconnect_by_func
		(list->folder,
		 G_CALLBACK(cb_bookmark_list_updated), list);
	g_signal_handlers_disconnect_by_func
		(list->folder,
		 G_CALLBACK(cb_bookmark_list_insert_child), list);
	g_signal_handlers_disconnect_by_func
		(list->folder,
		 G_CALLBACK(cb_bookmark_list_remove_child), list);
}


static void
cb_bookmark_list_updated (KzBookmark *folder, KzBookmarkMenuItemList *list)
{
}


static void
cb_bookmark_list_insert_child  (KzBookmark *folder,
				KzBookmark *child,
				KzBookmark *sibling,
				KzBookmarkMenuItemList *list)
{
	gint index = -1;
	GList *children;
	GtkWidget *widget;
	KzWindow *kz;
	
	g_return_if_fail(KZ_IS_BOOKMARK(child));

	kz = list->kz;

	if (sibling)
	{
		children = kz_bookmark_get_children(folder);
		index = g_list_index(children, sibling); 
		g_list_free(children);
	}

	if (kz_bookmark_is_folder(child))
		widget = kz_bookmark_folder_menu_item_new(kz, child);
	else if (kz_bookmark_is_separator(child))
		widget = kz_bookmark_separator_menu_item_new(kz, child);
	else
		widget = kz_bookmark_menu_item_new(kz, child);

	gtk_widget_show(widget);
	if (index < 0)
	{
		gtk_menu_shell_append(GTK_MENU_SHELL(list->menu_shell),
				      widget);
	}
	else
	{
		gtk_menu_shell_insert(GTK_MENU_SHELL(list->menu_shell),
				      widget, list->initial_children + index);
	}
}


static void
cb_bookmark_list_remove_child  (KzBookmark *folder,
				KzBookmark *child,
				KzBookmarkMenuItemList *list)
{
	gint index;
	GList *children;
	GtkWidget *widget;

	g_return_if_fail(KZ_IS_BOOKMARK(child));

	children = kz_bookmark_get_children(folder);
	index = g_list_index(children, child); 
	g_list_free(children);

	if (index == -1) return;

	children = list->menu_shell->children;

	widget = g_list_nth_data(children, list->initial_children + index);

	if (GTK_IS_WIDGET(widget))
		gtk_widget_destroy(widget);
}


static void     
menu_shell_weak_notify (KzBookmarkMenuItemList *list, GObject *object)
{
	g_object_unref(list);
}

