/* $Id: component.c,v 1.24 2001/10/24 03:52:19 jody Exp $ */

#include "component.h"
#include "embeddable-io.h"
#include "container-filesel.h"

BonoboClientSiteClass *sample_client_site_parent_class = NULL;

void
object_print (BonoboObjectClient *object,
	      GnomePrintContext  *ctx,
	      gdouble x, gdouble y,
	      gdouble width, gdouble height)
{
	BonoboPrintClient *print_client = bonobo_print_client_get (object);
	BonoboPrintData   *print_data;

	if (!print_client)
		return;

	print_data = bonobo_print_data_new (width, height);
	bonobo_print_client_render (print_client, print_data);
	bonobo_print_data_render (ctx, x, y, print_data, 0.0, 0.0);
	bonobo_print_data_free (print_data);

	gtk_object_unref (GTK_OBJECT (print_client));
}

static void
activate_request_cb (BonoboViewFrame  *view_frame,
		     SampleClientSite *site)
{
	SampleApp *app;

	g_return_if_fail (site != NULL);
	g_return_if_fail (site->app != NULL);

	app = site->app;

	if (app->curr_view) {
		bonobo_view_frame_view_deactivate (app->curr_view);
		if (app->curr_view)
			bonobo_view_frame_set_covered (app->curr_view, FALSE);
	}

	/*
	 * Activate the View which the user clicked on.  This just
	 * sends a request to the embedded View to activate itself.
	 * When it agrees to be activated, it will notify its
	 * ViewFrame, and our view_activated_cb callback will be
	 * called.
	 *
	 * We do not uncover the View here, because it may not wish to
	 * be activated, and so we wait until it notifies us that it
	 * has been activated to uncover it.
	 */
	bonobo_view_frame_view_activate (view_frame);
}

static void
view_activated_cb (BonoboViewFrame  *view_frame,
		   gboolean          activated,
		   SampleClientSite *site)
{
	SampleApp *app = site->app;

	if (activated) {
		/*
		 * If the View is requesting to be activated, then we
		 * check whether or not there is already an active
		 * View.
		 */
		if (app->curr_view) {
			g_warning ("View requested to be activated but "
				   "there is already an active View!\n");
			return;
		}

		/*
		 * Otherwise, uncover it so that it can receive
		 * events, and set it as the active View.
		 */
		bonobo_view_frame_set_covered (view_frame, FALSE);
		app->curr_view = view_frame;
	} else {
		/*
		 * If the View is asking to be deactivated, always
		 * oblige.  We may have already deactivated it (see
		 * user_activation_request_cb), but there's no harm in
		 * doing it again.  There is always the possibility
		 * that a View will ask to be deactivated when we have
		 * not told it to deactivate itself, and that is
		 * why we cover the view here.
		 */
		bonobo_view_frame_set_covered (view_frame, TRUE);

		if (view_frame == app->curr_view)
			app->curr_view = NULL;
	}
}

static void
component_user_context_cb (BonoboViewFrame  *view_frame,
			   SampleClientSite *site)
{
	g_warning ("We need something exciting here ...");
}

void
sample_client_site_add_frame (SampleClientSite *site)
{
	BonoboViewFrame *view_frame;
	GtkWidget       *view_widget;

	/*
	 * Create the remote view and the local ViewFrame.  This also
	 * sets the BonoboUIHandler for this ViewFrame.  That way, the
	 * embedded component can get access to our UIHandler server
	 * so that it can merge menu and toolbar items when it gets
	 * activated.
	 */
	view_frame = bonobo_client_site_new_view (BONOBO_CLIENT_SITE (site),
		BONOBO_OBJREF (site->app->ui_container));
	
	/*
	 * Embed the view frame into the application.
	 */
	view_widget = bonobo_view_frame_get_wrapper (view_frame);
	gtk_box_pack_start (GTK_BOX (site->views_hbox), view_widget,
			    FALSE, FALSE, 5);

	/*
	 * The "user_activate" signal will be emitted when the user
	 * double clicks on the "cover".  The cover is a transparent
	 * window which sits on top of the component and keeps any
	 * events (mouse, keyboard) from reaching it.  When the user
	 * double clicks on the cover, the container (that's us)
	 * can choose to activate the component.
	 */
	gtk_signal_connect (GTK_OBJECT (view_frame), "user_activate",
			    GTK_SIGNAL_FUNC (activate_request_cb),
			    site);

	/*
	 * In-place activation of a component is a two-step process.
	 * After the user double clicks on the component, our signal
	 * callback (component_user_activate_request_cb()) asks the
	 * component to activate itself (see
	 * bonobo_view_frame_view_activate()).  The component can then
	 * choose to either accept or refuse activation.  When an
	 * embedded component notifies us of its decision to change
	 * its activation state, the "activated" signal is
	 * emitted from the view frame.  It is at that point that we
	 * actually remove the cover so that events can get through.
	 */
	gtk_signal_connect (GTK_OBJECT (view_frame), "activated",
			    GTK_SIGNAL_FUNC (view_activated_cb),
			    site);

	/*
	 * The "user_context" signal is emitted when the user right
	 * clicks on the wrapper.  We use it to pop up a verb menu.
	 */
	gtk_signal_connect (GTK_OBJECT (view_frame), "user_context",
			    GTK_SIGNAL_FUNC (component_user_context_cb),
			    site);

	/*
	 * Show the component.
	 */
	gtk_widget_show_all (view_widget);
}

static void
sample_site_del_frame (SampleClientSite *site)
{
	BonoboViewFrame *view;

	g_return_if_fail (site != NULL);
	g_return_if_fail (site->parent.view_frames != NULL);

	view = site->parent.view_frames->data;

	gtk_container_remove (GTK_CONTAINER (site->views_hbox),
			      bonobo_view_frame_get_wrapper (view));

	bonobo_object_unref (BONOBO_OBJECT (view));
}

static void
add_frame_cb (GtkWidget *caller, SampleClientSite *site)
{
	sample_client_site_add_frame (site);
}

static void
del_frame_cb (GtkWidget *caller, SampleClientSite *site)
{
	sample_site_del_frame (site);
}

static void
del_cb (GtkWidget *caller, SampleClientSite *site)
{
	bonobo_object_unref (BONOBO_OBJECT (site));
}

static void
load_stream_cb (GtkWidget *caller, SampleClientSite *site)
{
	GtkWidget *fs = site->app->fileselection;
	gchar *filename = g_strdup (gtk_file_selection_get_filename
				    (GTK_FILE_SELECTION (fs)));
	gtk_widget_destroy (fs);

	if (filename) {
		CORBA_Environment ev;
		Bonobo_PersistStream persist;
		BonoboStream *stream;

		stream = bonobo_stream_open ("fs", filename, 
					     Bonobo_Storage_READ, 0644);

		if (!stream) {
			gchar *error_msg;

			error_msg =
			    g_strdup_printf (_("Could not open file %s"),
					     filename);
			gnome_warning_dialog (error_msg);
			g_free (error_msg);

			return;
		}

		/*
		 * Now get the PersistStream interface off the embedded
		 * component.
		 */
		persist = bonobo_object_client_query_interface (
			bonobo_client_site_get_embeddable (BONOBO_CLIENT_SITE (site)),
			"IDL:Bonobo/PersistStream:1.0", NULL);

		/*
		 * If the component doesn't support PersistStream (and it
		 * really ought to -- we query it to see if it supports
		 * PersistStream before we even give the user the option of
		 * loading data into it with PersistStream), then we destroy
		 * the stream we created and bail.
		 */
		if (persist == CORBA_OBJECT_NIL) {
			gnome_warning_dialog (_
					      ("The component now claims that it "
					       "doesn't support PersistStream!"));
			bonobo_object_unref (BONOBO_OBJECT (stream));
			g_free (filename);
			return;
		}

		CORBA_exception_init (&ev);

		/*
		 * Load the file into the component using PersistStream.
		 */
		Bonobo_PersistStream_load (persist, BONOBO_OBJREF (stream),
					   "", &ev);

		if (ev._major != CORBA_NO_EXCEPTION) {
			char *msg = bonobo_exception_get_text (&ev);
			gnome_warning_dialog (msg);
			g_free (msg);
		}

		/*
		 * Now we destroy the PersistStream object.
		 */
		Bonobo_Unknown_unref (persist, &ev);
		CORBA_Object_release (persist, &ev);

		bonobo_object_unref (BONOBO_OBJECT (stream));

		CORBA_exception_free (&ev);
	}

	g_free (filename);
}

static void
fill_cb (GtkWidget *caller, SampleClientSite *site)
{
	container_request_file (site->app, FALSE,
				load_stream_cb, site);
}

static void
sample_client_site_destroy (GtkObject *object)
{
	SampleClientSite *site = SAMPLE_CLIENT_SITE (object);

	site->app->components = g_list_remove (
		site->app->components, site);

/* FIXME: unref the server as we pop it in */
/*	bonobo_object_unref (BONOBO_OBJECT (component->server));*/

	if (site->obj_id) {
		g_free (site->obj_id);
		site->obj_id = NULL;
	}
	gtk_widget_destroy (site->frame);
	GTK_OBJECT_CLASS (sample_client_site_parent_class)->destroy
		(GTK_OBJECT (site));
}

static void
sample_client_site_class_init (SampleClientSiteClass *klass)
{
	BonoboObjectClass *gobject_class = (BonoboObjectClass *) klass;
	GtkObjectClass *object_class = (GtkObjectClass *) gobject_class;
	
	sample_client_site_parent_class = gtk_type_class (
		bonobo_client_site_get_type ());

	object_class->destroy = sample_client_site_destroy;
}

static void 
sample_client_site_init (GtkObject *object)
{
	/* nothing to do */
}

BONOBO_X_TYPE_FUNC (SampleClientSite, 
		      bonobo_client_site_get_type (),
		      sample_client_site);

static void
site_create_widgets (SampleClientSite *site)
{
	GtkWidget *frame;
	GtkWidget *vbox, *hbox;
	GtkWidget *new_view_button, *del_view_button;
	GtkWidget *del_comp_button, *fill_comp_button;

	g_return_if_fail (site != NULL);

	/* Display widgets */
	frame = site->frame = gtk_frame_new (site->obj_id);
	vbox = gtk_vbox_new (FALSE, 10);
	hbox = gtk_hbox_new (TRUE, 5);
	new_view_button = gtk_button_new_with_label ("New view");
	del_view_button = gtk_button_new_with_label ("Remove view");
	del_comp_button = gtk_button_new_with_label ("Remove component");

	/* The views of the component */
	site->views_hbox = gtk_hbox_new (FALSE, 2);
	gtk_signal_connect (GTK_OBJECT (new_view_button), "clicked",
			    GTK_SIGNAL_FUNC (add_frame_cb), site);
	gtk_signal_connect (GTK_OBJECT (del_view_button), "clicked",
			    GTK_SIGNAL_FUNC (del_frame_cb), site);
	gtk_signal_connect (GTK_OBJECT (del_comp_button), "clicked",
 			    GTK_SIGNAL_FUNC (del_cb), site);

	gtk_container_add (GTK_CONTAINER (hbox), new_view_button);
	gtk_container_add (GTK_CONTAINER (hbox), del_view_button);
	gtk_container_add (GTK_CONTAINER (hbox), del_comp_button);

	if (bonobo_object_client_has_interface (
		bonobo_client_site_get_embeddable (BONOBO_CLIENT_SITE (site)),
		"IDL:Bonobo/PersistStream:1.0", NULL)) {

		fill_comp_button =
		    gtk_button_new_with_label ("Fill with stream");
		gtk_container_add (GTK_CONTAINER (hbox), fill_comp_button);

		gtk_signal_connect (GTK_OBJECT (fill_comp_button),
				    "clicked", GTK_SIGNAL_FUNC (fill_cb),
				    site);
	}


	gtk_container_add (GTK_CONTAINER (vbox),  site->views_hbox);
	gtk_container_add (GTK_CONTAINER (vbox),  hbox);
	gtk_container_add (GTK_CONTAINER (frame), vbox);
}

GtkWidget *
sample_client_site_get_widget (SampleClientSite *site)
{
	g_return_val_if_fail (site != NULL, NULL);

	return site->frame;
}

SampleClientSite *
sample_client_site_new (BonoboItemContainer *container,
			SampleApp           *app,
			BonoboObjectClient  *embeddable,
			const char          *embeddable_id)
{
	SampleClientSite *site;

	g_return_val_if_fail (app != NULL, NULL);
	g_return_val_if_fail (embeddable_id != NULL, NULL);
	g_return_val_if_fail (BONOBO_IS_OBJECT_CLIENT (embeddable), NULL);
	g_return_val_if_fail (BONOBO_IS_ITEM_CONTAINER (container), NULL);
	
	site = gtk_type_new (sample_client_site_get_type ());
	
	site = SAMPLE_CLIENT_SITE (bonobo_client_site_construct (
		BONOBO_CLIENT_SITE (site), container));

	if (site) {
		bonobo_client_site_bind_embeddable (BONOBO_CLIENT_SITE (site),
						    embeddable);
		bonobo_object_unref (BONOBO_OBJECT (embeddable));

		site->app = app;
		g_free (site->obj_id);
		site->obj_id = g_strdup (embeddable_id);

		site_create_widgets (site);
	}

	return site;
}


syntax highlighted by Code2HTML, v. 0.9.1