/* This is -*- C -*- */
/* vim: set sw=2: */

/*
 * guppi-data-popup.c
 *
 * Copyright (C) 2000 EMC Capital Management, Inc.
 *
 * Developed by Jon Trowbridge <trow@gnu.org>
 *
 * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 */

#include <config.h>
#include <gtk/gtkbutton.h>
#include <gtk/gtksignal.h>
#include <gtk/gtkmenuitem.h>
#include <gtk/gtklabel.h>

#include <libgnome/gnome-defs.h>
#include <libgnome/gnome-config.h>
#include <libgnome/gnome-i18n.h>

#include <guppi-convenient.h>
#include "guppi-data-popup.h"

static void popup_cb (GtkWidget * w, GuppiDataPopup * pop);
static GtkMenu *build_popup (GuppiDataPopup * pop, GuppiDataTreeNode * node);
static void popup (GuppiDataPopup * pop);
static void clicked (GtkButton * button);

static GtkObjectClass *parent_class = NULL;

enum {
  ARG_0
};

enum {
  SELECTED_DATA,
  LAST_SIGNAL
};

static guint pop_signals[LAST_SIGNAL] = { 0 };

static void
guppi_data_popup_get_arg (GtkObject * obj, GtkArg * arg, guint arg_id)
{
  switch (arg_id) {

  default:
    break;
  };
}

static void
guppi_data_popup_set_arg (GtkObject * obj, GtkArg * arg, guint arg_id)
{
  switch (arg_id) {

  default:
    break;
  };
}

static void
guppi_data_popup_destroy (GtkObject * obj)
{
  if (parent_class->destroy)
    parent_class->destroy (obj);
}

static void
guppi_data_popup_finalize (GtkObject * obj)
{
  if (parent_class->finalize)
    parent_class->finalize (obj);
}

static void
guppi_data_popup_class_init (GuppiDataPopupClass * klass)
{
  GtkObjectClass *object_class = (GtkObjectClass *) klass;
  GtkButtonClass *button_class = GTK_BUTTON_CLASS (klass);

  parent_class = gtk_type_class (GTK_TYPE_BUTTON);

  object_class->get_arg = guppi_data_popup_get_arg;
  object_class->set_arg = guppi_data_popup_set_arg;
  object_class->destroy = guppi_data_popup_destroy;
  object_class->finalize = guppi_data_popup_finalize;

  button_class->clicked = clicked;

  pop_signals[SELECTED_DATA] =
    gtk_signal_new ("selected_data",
		    GTK_RUN_FIRST,
		    object_class->type,
		    GTK_SIGNAL_OFFSET (GuppiDataPopupClass, selected_data),
		    gtk_marshal_NONE__POINTER,
		    GTK_TYPE_NONE, 1, GTK_TYPE_POINTER);

  gtk_object_class_add_signals (object_class, pop_signals, LAST_SIGNAL);

}

static void
guppi_data_popup_init (GuppiDataPopup * obj)
{

}

GtkType guppi_data_popup_get_type (void)
{
  static GtkType guppi_data_popup_type = 0;
  if (!guppi_data_popup_type) {
    static const GtkTypeInfo guppi_data_popup_info = {
      "GuppiDataPopup",
      sizeof (GuppiDataPopup),
      sizeof (GuppiDataPopupClass),
      (GtkClassInitFunc) guppi_data_popup_class_init,
      (GtkObjectInitFunc) guppi_data_popup_init,
      NULL, NULL, (GtkClassInitFunc) NULL
    };
    guppi_data_popup_type = gtk_type_unique (GTK_TYPE_BUTTON,
					     &guppi_data_popup_info);
  }
  return guppi_data_popup_type;
}

static void
popup_cb (GtkWidget * w, GuppiDataPopup * pop)
{
  GuppiDataTreeNode *node;

  node = (GuppiDataTreeNode *) gtk_object_get_user_data (GTK_OBJECT (w));

  gtk_signal_emit (GTK_OBJECT (pop),
		   pop_signals[SELECTED_DATA], node ? node->data : NULL);
}

static GtkMenu *
build_popup (GuppiDataPopup * pop, GuppiDataTreeNode * node)
{
  GtkMenu *menu = NULL;
  GtkWidget *w;


  /* Totally convoluted, but it works... */

  while (node) {

    w = NULL;

    if (guppi_data_popup_allowed_data (pop, node->data) || node->child) {
      w = gtk_menu_item_new_with_label (guppi_data_get_label (node->data));
      gtk_object_set_user_data (GTK_OBJECT (w), node);
    }

    if (node->child) {
      GtkMenu *submenu = build_popup (pop, node->child);

      if (submenu) {
	gtk_menu_item_set_submenu (GTK_MENU_ITEM (w), GTK_WIDGET (submenu));
      } else {
	guppi_unref0 (w);
      }

    } else {

      if (w)
	gtk_signal_connect (GTK_OBJECT (w),
			    "activate", GTK_SIGNAL_FUNC (popup_cb), pop);
    }

    if (w) {
      if (menu == NULL)
	menu = GTK_MENU (gtk_menu_new ());

      gtk_menu_append (menu, w);
      gtk_widget_show (w);
    }

    node = node->sibling_next;
  }

  return menu;
}

static void
popup (GuppiDataPopup * pop)
{
  GtkMenu *menu;
  GuppiDataTree *tree;

  g_return_if_fail (pop != NULL && GUPPI_IS_DATA_POPUP (pop));

  tree = pop->tree;
  if (tree == NULL)
    tree = guppi_data_tree_main ();

  menu = build_popup (pop, tree->root);

  if (menu != NULL) {

    /* Build "none" menu item */
    if (pop->allow_none) {
      GtkWidget *w;
      w = gtk_menu_item_new_with_label (pop->none_label);
      gtk_widget_show (w);
      gtk_signal_connect (GTK_OBJECT (w),
			  "activate", GTK_SIGNAL_FUNC (popup_cb), pop);
      gtk_menu_prepend (menu, w);
    }

    gtk_widget_show (GTK_WIDGET (menu));
    gtk_menu_popup (menu, NULL, NULL, NULL, NULL, 1, GDK_CURRENT_TIME);
  }
}

static void
clicked (GtkButton * button)
{
  popup (GUPPI_DATA_POPUP (button));
}

void
guppi_data_popup_construct (GuppiDataPopup * popup)
{
  g_return_if_fail (popup && GUPPI_IS_DATA_POPUP (popup));

  if (popup->tree == NULL)
    popup->tree = guppi_data_tree_main ();
}

GtkWidget *
guppi_data_popup_new (void)
{
  GtkObject *obj;

  obj = guppi_type_new (GUPPI_TYPE_DATA_POPUP);

  guppi_data_popup_construct (GUPPI_DATA_POPUP (obj));

  return GTK_WIDGET (obj);
}

GtkWidget *
guppi_data_popup_new_with_label (const gchar * label)
{
  GtkWidget *popup;

  popup = guppi_data_popup_new ();

  if (label)
    gtk_container_add (GTK_CONTAINER (popup), gtk_label_new (label));

  return popup;
}

void
guppi_data_popup_disallow_none (GuppiDataPopup * popup)
{
  g_return_if_fail (popup && GUPPI_IS_DATA_POPUP (popup));

  popup->allow_none = FALSE;
  guppi_free (popup->none_label);
  popup->none_label = NULL;
}

void
guppi_data_popup_allow_none (GuppiDataPopup * popup, const gchar * str)
{
  g_return_if_fail (popup && GUPPI_IS_DATA_POPUP (popup));

  popup->allow_none = TRUE;
  guppi_free (popup->none_label);
  popup->none_label = guppi_strdup (str ? str : _("None"));
}

void
guppi_data_popup_set_allowed_type (GuppiDataPopup * popup, GtkType type)
{
  g_return_if_fail (popup && GUPPI_IS_DATA_POPUP (popup));

  popup->allowed_type = type;
  popup->type_fn = NULL;
  popup->user_data = NULL;
}

void
guppi_data_popup_set_allowed_type_fn (GuppiDataPopup * popup,
				      gboolean (*fn)(GtkType, gpointer),
				      gpointer user_data)
{
  g_return_if_fail (popup && GUPPI_IS_DATA_POPUP (popup));
  g_return_if_fail (fn);

  popup->allowed_type = 0;
  popup->type_fn = fn;
  popup->user_data = user_data;
}

void
guppi_data_popup_set_allow_all_types (GuppiDataPopup * popup)
{
  g_return_if_fail (popup && GUPPI_IS_DATA_POPUP (popup));

  guppi_data_popup_set_allowed_type (popup, (GtkType)0);
}

gboolean
guppi_data_popup_allowed_type (GuppiDataPopup * pop, GtkType type)
{
  g_return_val_if_fail (pop && GUPPI_IS_DATA_POPUP (pop), FALSE);

  if (pop->type_fn)
    return pop->type_fn (type, pop->user_data);
  else if (pop->allowed_type == 0)
    return TRUE;
  else
    return gtk_type_is_a (type, pop->allowed_type);
}

gboolean
guppi_data_popup_allowed_data (GuppiDataPopup * popup, GuppiData * data)
{
  g_return_val_if_fail (popup && GUPPI_IS_DATA_POPUP (popup), FALSE);
  g_return_val_if_fail (data != NULL || GUPPI_IS_DATA (data), FALSE);

  return data == NULL
    || guppi_data_popup_allowed_type (popup, GTK_OBJECT_TYPE (data));
}


syntax highlighted by Code2HTML, v. 0.9.1