/* This is -*- C -*- */
/* $Id: guppi-data-select.c,v 1.13 2002/01/19 02:45:18 trow Exp $ */

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

#include <config.h>
#include "guppi-data-select.h"

#include <string.h>

#include <gtk/gtksignal.h>
#include <gtk/gtkselection.h>
#include <gtk/gtkhbox.h>
#include <gtk/gtkframe.h>
#include <gtk/gtkdnd.h>

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

#include <libgnomeui/gnome-stock.h>

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


static GtkObjectClass *parent_class = NULL;

enum {
  ARG_0
};

enum {
  SELECTED_DATA,
  LAST_SIGNAL
};

static guint sel_signals[LAST_SIGNAL] = { 0 };

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

  default:
    break;
  };
}

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

  default:
    break;
  };
}

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

static void
guppi_data_select_finalize (GtkObject * obj)
{

  guppi_unref0 (GUPPI_DATA_SELECT (obj)->data);
  guppi_free (GUPPI_DATA_SELECT (obj)->empty_label);

  if (parent_class->finalize)
    parent_class->finalize (obj);
}

/***************************************************************************/

static void
drag_data_received (GtkWidget * w,
		    GdkDragContext * context,
		    gint x, gint y,
		    GtkSelectionData * selection_data, guint info, guint time)
{
  GuppiData *data;
  g_return_if_fail (w != NULL && GUPPI_IS_DATA_SELECT (w));

  data = *(GuppiData **) selection_data->data;
  guppi_data_select_set_selected_data (GUPPI_DATA_SELECT (w), data);
}

static void
popup_cb (GuppiDataPopup * popup, GuppiData * data, GuppiDataSelect * sel)
{
  guppi_data_select_set_selected_data (sel, data);
}

/***************************************************************************/

static void
guppi_data_select_class_init (GuppiDataSelectClass * klass)
{
  GtkObjectClass *object_class = (GtkObjectClass *) klass;
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);

  parent_class = gtk_type_class (GTK_TYPE_EVENT_BOX);

  object_class->get_arg = guppi_data_select_get_arg;
  object_class->set_arg = guppi_data_select_set_arg;
  object_class->destroy = guppi_data_select_destroy;
  object_class->finalize = guppi_data_select_finalize;

  widget_class->drag_data_received = drag_data_received;

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

  gtk_object_class_add_signals (object_class, sel_signals, LAST_SIGNAL);
}

static void
guppi_data_select_init (GuppiDataSelect * obj)
{
  obj->empty_label = guppi_strdup (_("(none)"));
}

GtkType guppi_data_select_get_type (void)
{
  static GtkType guppi_data_select_type = 0;
  if (!guppi_data_select_type) {
    static const GtkTypeInfo guppi_data_select_info = {
      "GuppiDataSelect",
      sizeof (GuppiDataSelect),
      sizeof (GuppiDataSelectClass),
      (GtkClassInitFunc) guppi_data_select_class_init,
      (GtkObjectInitFunc) guppi_data_select_init,
      NULL, NULL, (GtkClassInitFunc) NULL
    };
    guppi_data_select_type = gtk_type_unique (GTK_TYPE_EVENT_BOX,
					      &guppi_data_select_info);
  }
  return guppi_data_select_type;
}

void
guppi_data_select_construct (GuppiDataSelect * sel)
{
  GtkWidget *frame;
  GtkWidget *w;
  GtkWidget *pix;
  GtkWidget *hbox;
  static GtkTargetEntry drag_types[] = {
    {"guppi/data", 0, 0}
  };
  static gint n_drag_types = sizeof (drag_types) / sizeof (drag_types[0]);


  g_return_if_fail (sel != NULL && GUPPI_IS_DATA_SELECT (sel));
  g_return_if_fail (sel->label == NULL);	/* check for previous construction */

  hbox = gtk_hbox_new (FALSE, 2);
  gtk_widget_show (hbox);
  gtk_container_add (GTK_CONTAINER (sel), hbox);

  frame = gtk_frame_new (NULL);
  w = gtk_label_new (sel->empty_label);
  gtk_container_add (GTK_CONTAINER (frame), w);

  gtk_widget_show_all (frame);
  gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 1);
  sel->label = GTK_LABEL (w);
 
  sel->popup = w = guppi_data_popup_new ();

  /* use default message for "none" */
  guppi_data_popup_allow_none (GUPPI_DATA_POPUP (w), NULL);
  if (sel->type_fn)
    guppi_data_popup_set_allowed_type_fn (GUPPI_DATA_POPUP (w),
					  sel->type_fn, sel->user_data);
  else
    guppi_data_popup_set_allowed_type (GUPPI_DATA_POPUP (w),
				       sel->allowed_type);


  pix = gnome_stock_new_with_icon (GNOME_STOCK_MENU_FORWARD);
  gtk_container_add (GTK_CONTAINER (w), pix);
  gtk_box_pack_end (GTK_BOX (hbox), w, FALSE, FALSE, 1);
  gtk_widget_show_all (w);
  gtk_signal_connect (GTK_OBJECT (w),
		      "selected_data",
		      GTK_SIGNAL_FUNC (popup_cb), GTK_OBJECT (sel));


  gtk_drag_dest_set (GTK_WIDGET (sel),
		     GTK_DEST_DEFAULT_ALL,
		     drag_types, n_drag_types, GDK_ACTION_COPY);
}

GtkWidget *
guppi_data_select_new (void)
{
  return guppi_data_select_new_by_type (0);
}

GtkWidget *
guppi_data_select_new_by_type (GtkType type)
{
  GuppiDataSelect *sel =
    GUPPI_DATA_SELECT (guppi_type_new (guppi_data_select_get_type ()));

  sel->allowed_type = type;
  guppi_data_select_construct (sel);

  return GTK_WIDGET (sel);
}

GtkWidget *
guppi_data_select_new_by_type_fn (gboolean (*type_fn)(GtkType, gpointer),
				  gpointer user_data)
{
  GuppiDataSelect *sel;

  g_return_val_if_fail (type_fn, NULL);

  sel = GUPPI_DATA_SELECT (guppi_type_new (guppi_data_select_get_type ()));
  
  sel->type_fn = type_fn;
  sel->user_data = user_data;
  guppi_data_select_construct (sel);

  return GTK_WIDGET (sel);
}

void
guppi_data_select_set_empty_label (GuppiDataSelect * sel, const gchar * txt)
{
  g_return_if_fail (sel != NULL && GUPPI_IS_DATA_SELECT (sel));

  guppi_free (sel->empty_label);
  sel->empty_label = guppi_strdup (txt);
  if (sel->label && sel->data == NULL)
    gtk_label_set_text (sel->label, sel->empty_label);
}

void
guppi_data_select_set_allowed_type (GuppiDataSelect * sel, GtkType type)
{
  g_return_if_fail (sel && GUPPI_IS_DATA_SELECT (sel));
  
  sel->allowed_type = type;
  sel->type_fn = NULL;
  sel->user_data = NULL;

  guppi_data_popup_set_allowed_type (GUPPI_DATA_POPUP (sel->popup), type);
}

void
guppi_data_select_set_allowed_type_fn (GuppiDataSelect * sel,
				       gboolean (*fn)(GtkType, gpointer),
				       gpointer user_data)
{
  g_return_if_fail (sel && GUPPI_IS_DATA_SELECT (sel));

  sel->allowed_type = 0;
  sel->type_fn = fn;
  sel->user_data = user_data;

  guppi_data_popup_set_allowed_type_fn (GUPPI_DATA_POPUP (sel->popup),
					fn, user_data);
}

void
guppi_data_select_set_allow_all_types (GuppiDataSelect * sel)
{
  guppi_data_select_set_allowed_type (sel, (GtkType)0);
}

gboolean 
guppi_data_select_allowed_type (GuppiDataSelect * sel, GtkType type)
{
  g_return_val_if_fail (sel != NULL && GUPPI_IS_DATA_SELECT (sel), FALSE);

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

gboolean 
guppi_data_select_allowed_data (GuppiDataSelect * sel, GuppiData * d)
{
  g_return_val_if_fail (sel != NULL && GUPPI_IS_DATA_SELECT (sel), FALSE);
  g_return_val_if_fail (d == NULL || GUPPI_IS_DATA (d), FALSE);

  return d == NULL
    || guppi_data_select_allowed_type (sel, GTK_OBJECT_TYPE (d));
}

GuppiData *
guppi_data_select_get_selected_data (GuppiDataSelect * sel)
{
  g_return_val_if_fail (sel != NULL && GUPPI_IS_DATA_SELECT (sel), NULL);

  return sel->data;
}

void
guppi_data_select_set_selected_data (GuppiDataSelect * sel, GuppiData * d)
{
  g_return_if_fail (sel != NULL && GUPPI_IS_DATA_SELECT (sel));
  g_return_if_fail (d == NULL || GUPPI_IS_DATA (d));

  if (!guppi_data_select_allowed_data (sel, d))
    return;

  if (sel->data != d) {
    guppi_refcounting_assign (sel->data, d);
    gtk_label_set_text (sel->label,
			d ? guppi_data_get_label (d) : sel->empty_label);
    gtk_signal_emit (GTK_OBJECT (sel), sel_signals[SELECTED_DATA], d);
  }
}

GtkWidget *
guppi_data_select_glade_custom_func (gchar * name,
				     gchar * type_restriction,
				     gchar * label, gint d2, gint d3)
{
  GtkType type = (GtkType) 0;
  GtkWidget *w;

  if (type_restriction != NULL) {
    type = gtk_type_from_name (type_restriction);
    if (strcmp (type_restriction, gtk_type_name (type))) {
      g_warning ("Failed to find type %s, got %d (%s)",
		 type_restriction, type, gtk_type_name (type));
    }
  }

  w = guppi_data_select_new_by_type (type);
  guppi_data_select_set_empty_label (GUPPI_DATA_SELECT (w), label);

  return w;
}



/* $Id: guppi-data-select.c,v 1.13 2002/01/19 02:45:18 trow Exp $ */


syntax highlighted by Code2HTML, v. 0.9.1