/* test-canvas.c
 *
 * A test application for DiaCanvas.
 */

#define G_LOG_DOMAIN "TEST"


#include "../config.h"
#include <gtk/gtk.h>
#include <diacanvas/dia-canvas-view.h>
#include <diacanvas/dia-canvas-group.h>
#include <diacanvas/dia-canvas-i18n.h>
#include <diacanvas/dia-canvas-line.h>
#include <diacanvas/dia-canvas-box.h>
#include <diacanvas/dia-canvas-text.h>
#include <diacanvas/dia-canvas-image.h>
#include <diacanvas/dia-placement-tool.h>
#include <diacanvas/dia-export-print.h>
#include <diacanvas/dia-export-svg.h>
#include <libgnomecanvas/gnome-canvas-util.h>
#include <libgnomecanvas/gnome-canvas-line.h>
#include "dia-clock.h"
#include "dia-textbox.h"

#ifdef HAVE_GNOME_PRINT_UI
#include <libgnomeprintui/gnome-print-dialog.h>
#include <libgnomeprintui/gnome-print-job-preview.h>
#endif

DiaCanvas *canvas = 0;

/* Forward declaration from prop-editor.c: */
GtkWidget *create_prop_editor (GObject *object,
			       GType    type);

enum {
	FILE_NEW,
	FILE_EXPORT_PRINT,
	FILE_EXPORT_SVG,
	FILE_CLOSE,
	FILE_QUIT,
	EDIT_UNDO,
	EDIT_REDO,
	EDIT_SELECT_ALL,
	EDIT_DEL_FOCUSED,
	EDIT_DEL_SELECTED,
	EDIT_PROPERTIES,
	VIEW_ZOOM_IN,
	VIEW_ZOOM_OUT,
	VIEW_ZOOM_100,
	VIEW_SNAP_TO_GRID,
	VIEW_EDIT_GRID,
	VIEW_NEW_AA_VIEW,
	VIEW_NEW_X_VIEW,
	VIEW_UNSET_CANVAS,
	VIEW_SET_CANVAS,
	OBJECT_ADD_LINE,
	OBJECT_ADD_BOX,
	OBJECT_RESET,
	LINE_ADD_POINT,
	LINE_ADD_SEGMENT,
	LINE_DEL_SEGMENT,
	DUMP_CANVAS,
	DUMP_VIEW
};

void
item_destroyed (gpointer data, GObject* obj)
{
	g_message ("Item destroyed: %s at 0x%p",
		   g_type_name (G_OBJECT_TYPE (obj)), obj);
}

void
canvas_snap_to_grid(DiaCanvas *canvas, gpointer data)
{
	g_message("SNAP TO GRID");
}

/* The amount of views open. */
guint view_counter = 0;

GtkWidget* display_canvas_view (GtkWidget *view);

static void menu_item_cb (gpointer callback_data,
			  guint callback_action, GtkWidget *widget);

static GtkItemFactoryEntry menu_items[] =
{
	{ "/_File", NULL, 0, 0, "<Branch>" },
	{ "/File/_New", NULL, menu_item_cb, FILE_NEW },
	{ "/File/_Export SVG", NULL, menu_item_cb, FILE_EXPORT_SVG },
#ifdef HAVE_GNOME_PRINT_UI
	{ "/File/_Export PS", NULL, menu_item_cb, FILE_EXPORT_PRINT },
#endif
	{ "/File/_Close", NULL, menu_item_cb, FILE_CLOSE },
	{ "/File/sep1", NULL, NULL, 0, "<Separator>" },
	{ "/File/_Quit", "<control>Q", menu_item_cb, FILE_QUIT },

	{ "/_Edit", NULL, 0, 0, "<Branch>" },
	{ "/Edit/_Undo", "<control>Z", menu_item_cb, EDIT_UNDO },
	{ "/Edit/_Redo", "<control>R", menu_item_cb, EDIT_REDO },
	{ "/Edit/sep1",	NULL, NULL, 0, "<Separator>" },
	{ "/Edit/Select _All", "<control>A", menu_item_cb, EDIT_SELECT_ALL },
	{ "/Edit/sep2",	NULL, NULL, 0, "<Separator>" },
	{ "/Edit/Delete f_Ocused", NULL, menu_item_cb, EDIT_DEL_FOCUSED },
	{ "/Edit/Delete _Selected", "<control>D", menu_item_cb, EDIT_DEL_SELECTED },
	{ "/Edit/Test", NULL, menu_item_cb, EDIT_PROPERTIES },

	{ "/_View", NULL, 0, 0, "<Branch>" },
	{ "/View/Zoom _In", NULL, menu_item_cb, VIEW_ZOOM_IN },
	{ "/View/Zoom _Out", NULL, menu_item_cb, VIEW_ZOOM_OUT },
	{ "/View/_Zoom 100%", NULL, menu_item_cb, VIEW_ZOOM_100 },
	{ "/View/sep1",	NULL, NULL, 0, "<Separator>" },
	{ "/View/_Snap to grid", NULL, menu_item_cb, VIEW_SNAP_TO_GRID, "<ToggleItem>" },
	{ "/View/Edit _Grid", NULL, menu_item_cb, VIEW_EDIT_GRID },
	{ "/View/sep2",	NULL, NULL, 0, "<Separator>" },
	{ "/View/New _AA view", NULL, menu_item_cb, VIEW_NEW_AA_VIEW },
	{ "/View/New _X view", NULL, menu_item_cb, VIEW_NEW_X_VIEW },
	{ "/View/sep3",	NULL, NULL, 0, "<Separator>" },
	{ "/View/Unset Canvas", NULL, menu_item_cb, VIEW_UNSET_CANVAS },
	{ "/View/Set Canvas", NULL, menu_item_cb, VIEW_SET_CANVAS },

	{ "/_Object", NULL, 0, 0, "<Branch>" },
	{ "/Object/Add _Line", NULL, menu_item_cb, OBJECT_ADD_LINE },
	{ "/Object/Add _Box", NULL, menu_item_cb, OBJECT_ADD_BOX },
	{ "/Object/sep1", NULL, NULL, 0, "<Separator>" },
	{ "/Object/_Untransform focused", NULL, menu_item_cb, OBJECT_RESET },

	{ "/_Line", NULL, 0, 0, "<Branch>" },
	{ "/Line/Add point", NULL, menu_item_cb, LINE_ADD_POINT },
	{ "/Line/Add 2nd segment", NULL, menu_item_cb, LINE_ADD_SEGMENT },
	{ "/Line/Delete 2nd segment", NULL, menu_item_cb, LINE_DEL_SEGMENT },

	{ "/_Dump", NULL, 0, 0, "<Branch>" },
	{ "/Dump/Canvas model", NULL, menu_item_cb, DUMP_CANVAS },
	{ "/Dump/Canvas view", NULL, menu_item_cb, DUMP_VIEW },
};

static int nmenu_items = sizeof (menu_items) / sizeof (menu_items[0]);

void add_line (DiaCanvasView *view);
void add_box (DiaCanvasView *view);
void print_canvas_hierarchy (DiaCanvasItem *item, int level);
void print_canvas_view_hierarchy (GnomeCanvasItem *gitem, int level);

#define PRINT_CANVAS_HIERARCHY(canvas) \
	g_print ("Dumping canvas '%s':\n", #canvas); print_canvas_hierarchy (canvas->root, 0);

#define PRINT_CANVAS_VIEW_HIERARCHY(view) \
	g_print ("Dumping canvas view '%s':\n", #view); print_canvas_view_hierarchy (GNOME_CANVAS (view)->root, 0);

static void
menu_item_cb (gpointer callback_data, guint callback_action, GtkWidget *widget)
{
	DiaCanvasView *view = callback_data;

	g_message ("ItemFactory: activated \"%s\"",
		   gtk_item_factory_path_from_widget (widget));

	dia_canvas_push_undo (view->canvas, NULL);

	switch (callback_action) {
	case FILE_NEW: {
		DiaCanvas *canvas;
		GtkWidget *new_view;

		canvas = dia_canvas_new ();
		new_view = dia_canvas_view_new (canvas,
						GNOME_CANVAS (view)->aa);
		display_canvas_view (new_view);
		canvas->allow_undo = TRUE;
		g_object_unref (canvas);
		//gtk_object_unref (new_view);
		break;
	}
	case FILE_EXPORT_SVG: {
		DiaExportSVG *svg = dia_export_svg_new ();
		GError *error;
		dia_export_svg_render (svg, canvas);
		dia_export_svg_save (svg, "test.svg", &error);
		g_object_unref (svg);
		break;
	}
#ifdef HAVE_GNOME_PRINT_UI
	case FILE_EXPORT_PRINT: {
		GtkWidget *dialog;
		gint response;
		GnomePrintJob *pj = gnome_print_job_new(NULL);
		GnomePrintContext *ctx;
		//gnome_print_master_print_to_file(pm, "test.ps");

		dialog = gnome_print_dialog_new (pj, "Sample print dialog", 0);
		/* Run the dialog */
		gtk_widget_show (dialog);
		response = gtk_dialog_run (GTK_DIALOG (dialog));
		if (response == GNOME_PRINT_DIALOG_RESPONSE_CANCEL) {
			g_print ("Printing was canceled\n");
		} else {
			gnome_print_job_print_to_file(pj, "test.ps");
			ctx = gnome_print_job_get_context (pj);
			gnome_print_beginpage(ctx, "demo");
			dia_export_print (pj, canvas);
			gnome_print_showpage(ctx);
			gnome_print_job_close(pj);

			if (response == GNOME_PRINT_DIALOG_RESPONSE_PRINT)
				gnome_print_job_print(pj);
			else if (response == GNOME_PRINT_DIALOG_RESPONSE_PREVIEW)
				gtk_widget_show (GTK_WIDGET (gnome_print_job_preview_new (pj, //gnome_print_job_get_config(pj),
							"Title goes here")));
		}
		gtk_widget_hide(dialog);
		gtk_widget_destroy (dialog);
		break;
	}
#endif
	case FILE_CLOSE:
		gtk_widget_destroy (gtk_widget_get_toplevel (GTK_WIDGET (view)));
		if (view_counter == 0)
			gtk_main_quit ();
		break;
	case FILE_QUIT:
		gtk_widget_destroy (gtk_widget_get_toplevel (GTK_WIDGET (view)));
		gtk_main_quit ();
		break;
	case EDIT_UNDO:
		dia_canvas_pop_undo (view->canvas);
		break;
	case EDIT_REDO:
		dia_canvas_pop_redo (view->canvas);
		break;
	case EDIT_SELECT_ALL: {
		dia_canvas_view_select_all (view);
		break;
	}
	case EDIT_DEL_FOCUSED:
		if (view->focus_item) {
			DiaCanvasItem *item = view->focus_item->item;
			if (item->parent)
				dia_canvas_groupable_remove (DIA_CANVAS_GROUPABLE (item->parent), item);
		}
		break;
	case EDIT_DEL_SELECTED:
		while (view->selected_items) {
			DiaCanvasItem *item;
			item = DIA_CANVAS_VIEW_ITEM (view->selected_items->data)->item;
			if (item->parent) {
				dia_canvas_groupable_remove (DIA_CANVAS_GROUPABLE (item->parent), item);
			}
		}
		break;
	case EDIT_PROPERTIES: {
		DiaCanvas *c = dia_canvas_new();
		DiaCanvasItem *b = dia_canvas_group_create_item
					(DIA_CANVAS_GROUP(c->root),
					 DIA_TYPE_CANVAS_BOX,
					 NULL);
		dia_canvas_item_request_update (b);
		g_object_unref(G_OBJECT(c));
		break;
	}
	case VIEW_ZOOM_IN: {
		GtkAdjustment *adj = g_object_get_data (G_OBJECT (view), "zoom");
		gtk_adjustment_set_value (adj, adj->value + 0.1);
		break;
	}
	case VIEW_ZOOM_OUT: {
		GtkAdjustment *adj = g_object_get_data (G_OBJECT (view), "zoom");
		gtk_adjustment_set_value (adj, adj->value - 0.1);
		break;
	}
	case VIEW_ZOOM_100: {
		GtkAdjustment *adj = g_object_get_data (G_OBJECT (view), "zoom");
		gtk_adjustment_set_value (adj, 1.0);
		break;
	}
	case VIEW_SNAP_TO_GRID:
		g_object_set (view->canvas, "snap_to_grid", GTK_CHECK_MENU_ITEM (widget)->active, NULL);
		break;
	case VIEW_EDIT_GRID:
		break;
	case VIEW_NEW_AA_VIEW: {
		GtkWidget *new_view = dia_canvas_view_new (view->canvas, TRUE);
		display_canvas_view (new_view);
		break;
	}
	case VIEW_NEW_X_VIEW: {
		GtkWidget *new_view = dia_canvas_view_new (view->canvas, FALSE);
		display_canvas_view (new_view);
		break;
	}
	case VIEW_UNSET_CANVAS:
		dia_canvas_view_unset_canvas (view);
		break;
	case VIEW_SET_CANVAS:
		dia_canvas_view_set_canvas (view, canvas);
		break;
	case OBJECT_ADD_LINE:
		add_line (view);
		break;
	case OBJECT_ADD_BOX:
		add_box (view);
		break;
	case OBJECT_RESET:
		if (view->focus_item) {
			dia_canvas_item_identity (view->focus_item->item);
		}
		break;
	case LINE_ADD_POINT:
		if (view->focus_item
		    && DIA_IS_CANVAS_LINE (view->focus_item->item)) {
			DiaPoint p;
			p.x = g_random_double_range (0.0, 50.0);
			p.y = g_random_double_range (0.0, 50.0);
			g_object_set (view->focus_item->item,
				      "add_point", &p, NULL);
		}
		break;
	case LINE_ADD_SEGMENT:
		if (view->focus_item
		    && DIA_IS_CANVAS_LINE (view->focus_item->item)) {
			g_object_set (view->focus_item->item,
				      "add_segment", 1, NULL);
		}
		break;
	case LINE_DEL_SEGMENT:
		if (view->focus_item
		    && DIA_IS_CANVAS_LINE (view->focus_item->item)) {
			g_object_set (view->focus_item->item,
				      "del_segment", 1, NULL);
		}
		break;
	case DUMP_CANVAS:
		PRINT_CANVAS_HIERARCHY (view->canvas);
		break;
	case DUMP_VIEW:
		PRINT_CANVAS_VIEW_HIERARCHY (view);
		break;
	default:
		g_assert_not_reached ();
	}
}

static gint
canvas_item_event(DiaCanvasItem *item, DiaEvent *event)
{
	if ((event->type == DIA_EVENT_2BUTTON_PRESS)
	    && (event->button.button == 3)) {
		GtkWidget *window;

		window = create_prop_editor (G_OBJECT (item), 0);
		return TRUE;
	}
	return FALSE;
}

void
display_window_destroy (GtkObject *obj, gpointer data)
{
	view_counter--;
	
	if (view_counter == 0)
		gtk_main_quit ();
}

static void
zoom_changed (GtkAdjustment *adj, gpointer data)
{
        dia_canvas_view_set_zoom (data, adj->value);
}

static gboolean
cb_unset_tool (DiaTool *tool, DiaCanvasView *view, GdkEvent *event, gpointer data)
{
	DiaPlacementTool *pltool = DIA_PLACEMENT_TOOL (tool);

	/* This function should be called after the object is created. */
	g_assert (pltool->new_object);

	g_message ("PlacementTool: new item of type `%s'.",
		   g_type_name (G_OBJECT_TYPE (pltool->new_object)));
		   
	g_object_weak_ref (G_OBJECT (pltool->new_object), item_destroyed, NULL);
		
	/* Remove tool. */
	dia_canvas_view_set_tool (data, NULL);

	return TRUE;
}

void
add_line (DiaCanvasView *view)
{
	DiaTool *tool = dia_placement_tool_new (DIA_TYPE_CANVAS_LINE,
						"color", DIA_COLOR(100, 100, 0),
						NULL);
	g_object_set (view, "tool", tool, NULL);

	/* First let the tool create the new item... Then unset it. */
	g_signal_connect (tool, "button_release_event",
				G_CALLBACK (cb_unset_tool), view);

	g_object_unref (tool);
}

void
add_box (DiaCanvasView *view)
{
	DiaTool *tool = dia_placement_tool_new (DIA_TYPE_CANVAS_BOX,
						"parent", view->canvas->root,
						"width", 0.0,
						"height", 0.0,
						"bg_color", 0xFF8FFF55,
						NULL);
	g_object_set (view, "tool", tool, NULL);

	/* First let the tool create the new item... Then unset it. */
	g_signal_connect (tool, "button_release_event",
				G_CALLBACK (cb_unset_tool), view);

	g_object_unref (tool);
}

void
add_line_random (DiaCanvasView *view)
{
	DiaCanvas *canvas = view->canvas;
	DiaCanvasItem *item;
	DiaCanvasViewItem *vitem;
	guint i;

	dia_canvas_push_undo (view->canvas, NULL);
	item = dia_canvas_item_create (DIA_TYPE_CANVAS_LINE,
			"color", DIA_COLOR_A (g_random_int_range (0, 200),
					      g_random_int_range (0, 200),
					      g_random_int_range (0, 200),
					      g_random_int_range (180, 255)),
			NULL);
	dia_canvas_groupable_add (DIA_CANVAS_GROUPABLE (canvas->root), item);
	g_object_weak_ref (G_OBJECT (item), item_destroyed, NULL);

	for (i = 0; i < g_random_int_range (2, 6); i++) {
		DiaPoint p;
		p.x = g_random_int_range (0, 200);
		p.y = g_random_int_range (0, 200);
		if (i == 0)
			g_object_set (item, "head_pos", &p, NULL);
		else if (i == 1)
			g_object_set (item, "tail_pos", &p, NULL);
		else
			g_object_set (item, "add_point", &p, NULL);
	}
	//g_signal_connect (item, "event", G_CALLBACK (canvas_item_event), NULL);

	dia_canvas_view_unselect_all (view);
	
	vitem = dia_canvas_view_find_view_item (view, item);
	g_assert (vitem != NULL);
	dia_canvas_view_focus (view, vitem);

	g_object_unref (item);
}

void
add_box_random (DiaCanvasView *view)
{
	DiaCanvas *canvas = view->canvas;
	DiaCanvasItem *item;
	DiaCanvasViewItem *vitem;
	
	dia_canvas_push_undo (view->canvas, NULL);
	item = dia_canvas_item_create (DIA_TYPE_CANVAS_BOX,
			     "width", g_random_double_range (25.0, 150.0),
			     "height", g_random_double_range (25.0, 150.0),
			     "color", DIA_COLOR_A (g_random_int_range (0, 200),
				     		   g_random_int_range (0, 200),
				     		   g_random_int_range (0, 200),
				     		   g_random_int_range (180, 255)),
			     "bg_color", DIA_COLOR_A (g_random_int_range (0, 200),
						      g_random_int_range (0, 200),
						      g_random_int_range (0, 200),
						      g_random_int_range (50, 200)),

			     NULL);
	dia_canvas_groupable_add (DIA_CANVAS_GROUPABLE (canvas->root), item);
	g_object_weak_ref (G_OBJECT (item), item_destroyed, NULL);

	dia_canvas_item_move (item, g_random_int_range (0, 255),
			      g_random_int_range (0, 255));

	dia_canvas_view_unselect_all (view);
	
	vitem = dia_canvas_view_find_view_item (view, item);
	g_assert (vitem != NULL);
	dia_canvas_view_focus (view, vitem);

	g_object_unref (item);
}

/* Create a window and some scroll bars around the canvas view */
GtkWidget*
display_canvas_view (GtkWidget *view)
{
	GtkWidget *window = 0;
	GtkWidget *vbox = 0;
	GtkWidget *hbox = 0;
	GtkWidget *table = 0;
	GtkWidget *w = 0;
	GtkWidget *frame = 0;
	GtkAdjustment *adj = 0;
	GtkAccelGroup *accel_group;
	GtkItemFactory *item_factory;

	window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
	
	gtk_window_set_title (GTK_WINDOW (window), "DiaCanvas Test");
	gtk_window_set_policy (GTK_WINDOW (window), TRUE, TRUE, FALSE);
	gtk_window_set_default_size (GTK_WINDOW (window), 400, 400);
	
	gtk_signal_connect (GTK_OBJECT (window), "destroy",
			    GTK_SIGNAL_FUNC (display_window_destroy), NULL);
	
	vbox = gtk_vbox_new (FALSE, 4);
	gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
	gtk_widget_show (vbox);

	accel_group = gtk_accel_group_new ();
	item_factory = gtk_item_factory_new (GTK_TYPE_MENU_BAR, "<main>", accel_group);
	g_object_set_data_full (G_OBJECT (window), "<main>",
				item_factory, (GDestroyNotify) g_object_unref);
	gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
	gtk_item_factory_create_items (item_factory, nmenu_items, menu_items,
				       view);
	w = gtk_item_factory_get_widget (item_factory, "<main>");
	gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 0);
	gtk_widget_show (w);

	w = gtk_label_new ("Try the canvas.");

	gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 0);
	gtk_widget_show (w);

	hbox = gtk_hbox_new (FALSE, 4);
	gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
	gtk_widget_show (hbox);

	/* Zoom */
	w = gtk_label_new ("Zoom:");
	gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0);
	gtk_widget_show (w);

	adj = GTK_ADJUSTMENT (gtk_adjustment_new (1.00, 0.05, 5.00, 0.05, 0.50, 0.50));
	gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
			    (GtkSignalFunc) zoom_changed,
			    view);
	g_object_set_data (G_OBJECT (view), "zoom", adj);

	w = gtk_spin_button_new (adj, 0.0, 2);
	gtk_widget_set_usize (w, 50, 0);
	gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 0);
	gtk_widget_show (w);

	/* Layout the stuff */
	table = gtk_table_new (2, 2, FALSE);
	gtk_table_set_row_spacings (GTK_TABLE (table), 4);
	gtk_table_set_col_spacings (GTK_TABLE (table), 4);
	gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0);
	gtk_widget_show (table);

	frame = gtk_frame_new (NULL);
	gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
	gtk_table_attach (GTK_TABLE (table), frame,
			  0, 1, 0, 1,
			  GTK_EXPAND | GTK_FILL | GTK_SHRINK,
			  GTK_EXPAND | GTK_FILL | GTK_SHRINK,
			  0, 0);
	gtk_widget_show (frame);

	//gtk_widget_set_usize (view, 600, 450);
	gnome_canvas_set_scroll_region (GNOME_CANVAS (view), 0, 0, 600, 450);
	gtk_container_add (GTK_CONTAINER (frame), view);
	GTK_WIDGET_SET_FLAGS (view, GTK_CAN_DEFAULT | GTK_CAN_FOCUS);

	gtk_widget_show (view);

	/*gtk_signal_connect_after (GTK_OBJECT (view), "key_press_event",
				  (GtkSignalFunc) key_press,
				  NULL); */

	w = gtk_hscrollbar_new (GTK_LAYOUT (view)->hadjustment);
	gtk_table_attach (GTK_TABLE (table), w,
			  0, 1, 1, 2,
			  GTK_EXPAND | GTK_FILL | GTK_SHRINK,
			  GTK_FILL,
			  0, 0);
	gtk_widget_show (w);

	w = gtk_vscrollbar_new (GTK_LAYOUT (view)->vadjustment);
	gtk_table_attach (GTK_TABLE (table), w,
			  1, 2, 0, 1,
			  GTK_FILL,
			  GTK_EXPAND | GTK_FILL | GTK_SHRINK,
			  0, 0);
	gtk_widget_show (w);


	gtk_container_add (GTK_CONTAINER (window), vbox);

	gtk_widget_show (view);
	gtk_widget_show (window);

	gtk_widget_grab_focus (view);
	gtk_widget_grab_default (view);

	view_counter++;

	return window;
}

void
print_canvas_hierarchy (DiaCanvasItem *item, int level)
{
	int i;
	
	for (i = level; i > 0; i--)
		g_print ("|  ");
	
	g_print ("+ %s (0x%p/%d)\n", g_type_name (G_OBJECT_TYPE (item)),
		 item, G_OBJECT (item)->ref_count);

	if (DIA_IS_CANVAS_GROUPABLE (item)) {
		DiaCanvasIter iter;
		if (dia_canvas_groupable_get_iter (DIA_CANVAS_GROUPABLE (item), &iter)) do {
			DiaCanvasItem *child;
			child = dia_canvas_groupable_value (DIA_CANVAS_GROUPABLE (item), &iter);
			print_canvas_hierarchy (child, level + 1);
		} while (dia_canvas_groupable_next (DIA_CANVAS_GROUPABLE (item), &iter));
	}
}

void
print_canvas_view_hierarchy (GnomeCanvasItem *gitem, int level)
{
	int i;
	DiaCanvasViewItem *item = (DiaCanvasViewItem *) gitem;
	gdouble *a;
	GList *l;

	for (i = level; i > 0; i--)
		g_print ("|   ");
	
	g_print ("+ %s (%p->%p)", gtk_type_name (GTK_OBJECT_TYPE (item)),
		 item, DIA_IS_CANVAS_VIEW_ITEM (item) ? item->item : 0);
	if (DIA_IS_CANVAS_VIEW_ITEM (item))
		g_print (" [%c%c%c]",
			 DIA_CANVAS_VIEW_ITEM_SELECT (item) ? 's' : '-',
			 DIA_CANVAS_VIEW_ITEM_FOCUS (item) ? 'f' : '-',
			 DIA_CANVAS_VIEW_ITEM_GRAB (item) ? 'g' : '-');
	g_print ("\n");
	a = gitem->xform;
	if (a) {
		for (i = level; i >= 0; i--) g_print ("|   ");
		g_print ("    [ %f %f %f ] ", a[0], a[2], a[4]);
		g_print ("[ %f %f %f ]\n", a[1], a[3], a[5]);
	}
	if (GNOME_IS_CANVAS_GROUP (item))
		for (l = GNOME_CANVAS_GROUP (item)->item_list; l != NULL; l = l->next)
			print_canvas_view_hierarchy (GNOME_CANVAS_ITEM (l->data), level + 1);
}

static void
visible_cb (DiaCanvasItem *item, gpointer data)
{
	g_message ("Visibility = %d", item->flags & DIA_VISIBLE);
}

static void
undo_cb (DiaCanvas *canvas, gpointer data)
{
	g_message ("Undo statistics: %d/%d", dia_canvas_get_undo_depth(canvas),
			dia_canvas_get_redo_depth (canvas));
}

static void
focus_cb (DiaCanvasView *view, DiaCanvasViewItem *item)
{
	g_message("Focused item = %s", item ? G_OBJECT_TYPE_NAME (item->item) : "NULL");
}

static void
select_cb (DiaCanvasView *view, DiaCanvasViewItem *item)
{
	g_message("Selected item = %s", item ? G_OBJECT_TYPE_NAME (item->item) : "NULL");
}

static void
unselect_cb (DiaCanvasView *view, DiaCanvasViewItem *item)
{
	g_message("Unselected item = %s", item ? G_OBJECT_TYPE_NAME (item->item) : "NULL");
}

int
main (int argc, char* argv[])
{
	GtkWidget	*view = 0;
	GtkWidget	*window = 0;
	DiaCanvasItem	*item = 0;
	DiaCanvasItem	*box = 0;
	DiaPoint p1 = {0.0, 0.0}, p2 = {60.0, 40.0}, p3 = {40.0, 60.0};
	DiaRectangle extents = { -300.0, -300.0, 300.0, 300.0 };
	GdkPixbuf *pixbuf;
	GError *error = NULL;
	//PangoContext *context;
	PangoFontDescription *font_desc;
	//PangoLayout *text;
	gchar *text;

	g_message ("start of main...");

#ifdef ENABLE_NLS
	/* initialise localisation */
	bindtextdomain (PACKAGE, "../po");
	textdomain (PACKAGE);
#endif

	gtk_init (&argc, &argv);
	
	gtk_widget_push_colormap (gdk_rgb_get_cmap ());

	pixbuf = gdk_pixbuf_new_from_file ("./image.png", &error);
	if (error) {
		g_error ("Could not load image.png");
	}

	canvas = g_object_new (DIA_TYPE_CANVAS,
	//			"snap_to_grid", TRUE,
				"static_extents", FALSE,
				"extents", &extents,
				"grid_bg", DIA_COLOR (200,250,250),
	//			"grid_int_x", 23.0,
	//			"grid_int_y", 23.0,
	//			"grid_ofs_x", 10.0,
	//			"grid_ofs_y", 13.0,
				NULL);

	gtk_widget_pop_colormap ();
	
	g_signal_connect (canvas, "undo", G_CALLBACK (undo_cb), NULL);
	g_signal_connect (canvas, "notify::snap-to-grid",
			  G_CALLBACK (canvas_snap_to_grid), NULL);

	//dia_canvas_set_static_extents (canvas, TRUE);
	//dia_canvas_set_extents (canvas, &extents);

	//dia_canvas_set_snap_to_grid (canvas, TRUE);

	PRINT_CANVAS_HIERARCHY (canvas);

	/* Create a standard X canvas. */
	//view1 = dia_canvas_view_new (canvas, FALSE);
	//display_canvas_view (view1);
	//gtk_widget_set_events (GTK_WIDGET (view1), CANVAS_EVENT_MASK);
	//gtk_signal_connect (GTK_OBJECT (view1), "event",
	//		    GTK_SIGNAL_FUNC (test_event), NULL);
	
	//dia_canvas_view_set_zoom (DIA_CANVAS_VIEW (view1), 2.1);
	//dia_canvas_view_set_zoom (DIA_CANVAS_VIEW (view1), 1.0 /2.1);

	g_message ("creating object...");

	/* Draw a bezier curve. */
	/*
	item = dia_canvas_item_new (DIA_CANVAS_GROUP (canvas->root),
				   DIA_TYPE_CANVAS_BEZIER,
				   NULL);
	dia_canvas_item_move (item, 60.0, 60.0);
	*/

	/* Draw an element */
	item = dia_canvas_item_create (dia_canvas_box_get_type (),
			     "width", 75.0,
			     "height", 75.0,
			     "color", DIA_COLOR_A (100, 50, 180, 250),
			     NULL);
	dia_canvas_groupable_add (DIA_CANVAS_GROUPABLE (canvas->root), item);
	g_object_weak_ref (G_OBJECT (item), item_destroyed, NULL);

	dia_canvas_item_rotate (item, 15.0);
	dia_canvas_item_move (item, 50.0, 50.0);
	g_signal_connect (item, "event", G_CALLBACK (canvas_item_event), NULL);
	/* Box is user later to connect a line to it. */
	box = item;
	g_object_unref (item);
	g_assert (G_OBJECT (item)->ref_count == 1);

	/* Draw an element */
	item = dia_canvas_item_create (dia_canvas_box_get_type (),
			     //"width", 150.0,
			     //"height", 100.0,
			     //"color", DIA_COLOR_A (160, 50, 120, 190),
			     NULL);
	dia_canvas_groupable_add (DIA_CANVAS_GROUPABLE (canvas->root), item);
	g_object_weak_ref (G_OBJECT (item), item_destroyed, NULL);

	dia_canvas_item_move (item, 50.0, 50.0);
	g_signal_connect (item, "event", G_CALLBACK (canvas_item_event), NULL);
	g_object_unref (item);
	g_assert (G_OBJECT (item)->ref_count == 1);

	/* A nice semi-transparent line */
	item = dia_canvas_item_create (dia_canvas_line_get_type (),
				   "head_pos", &p1,
				   "tail_pos", &p2,
				   "add_point", &p3,
				   "add_point", &p2,
				   "add_point", &p3,
				   "color", DIA_COLOR_A (200, 50, 70, 200),
				   "orthogonal",  TRUE,
				   "horizontal", TRUE,
				   NULL);
	dia_canvas_groupable_add (DIA_CANVAS_GROUPABLE (canvas->root), item);
	g_object_weak_ref (G_OBJECT (item), item_destroyed, NULL);

	dia_canvas_item_move (item, 30.0, 0.0);
	g_signal_connect (item, "event", G_CALLBACK (canvas_item_event), NULL);
	//dia_canvas_item_flip (item, TRUE, FALSE);
	//dia_canvas_item_rotate (item, 35.0);
	g_object_unref (item);
	g_assert (G_OBJECT (item)->ref_count == 1);


	/* Another line */
	item = dia_canvas_item_create (dia_canvas_line_get_type (),
				   "head_pos", &p2,
				   "tail_pos", &p3,
				   "add_point", &p1,
				   "color", DIA_COLOR_A (0, 0, 70, 255),
				   "cap", DIA_CAP_BUTT,
				   "has_head", TRUE,
				   "head_a", 0.5,
				   "head_b", 15.0,
				   "head_c", 10.0,
				   "head_d", 0.01, /* Do not make it 0.0! */
				   "head_color", DIA_COLOR_A (0, 0, 70, 255),
				   "head_fill_color", DIA_COLOR_A (0, 0, 70, 150),
				   NULL);
	dia_canvas_groupable_add (DIA_CANVAS_GROUPABLE (canvas->root), item);
	g_object_weak_ref (G_OBJECT (item), item_destroyed, NULL);

	g_signal_connect (item, "event", G_CALLBACK (canvas_item_event), NULL);
	dia_canvas_item_move (item, 0, 50.0);
	g_object_unref (item);
	g_assert (G_OBJECT (item)->ref_count == 1);

	/* Connect the first handle of the line to box. The handle should be
	 * moved and a connection should be established. */
	dia_canvas_item_connect (box, item->handles->data);

	/* Add an image */
	g_message ("Adding an image of %f x %f.", 
			     (gdouble) gdk_pixbuf_get_width (pixbuf),
			     (gdouble) gdk_pixbuf_get_height (pixbuf));
	item = dia_canvas_item_create (dia_canvas_image_get_type (),
			     "image", pixbuf,
			     "width", (gdouble) gdk_pixbuf_get_width (pixbuf),
			     "height", (gdouble) gdk_pixbuf_get_height (pixbuf),
			     NULL);
	dia_canvas_groupable_add (DIA_CANVAS_GROUPABLE (canvas->root), item);
	g_object_weak_ref (G_OBJECT (item), item_destroyed, NULL);

	//dia_canvas_item_rotate (item, 154.0);
	dia_canvas_item_move (item, 100.0, 100.0);
	g_signal_connect (item, "event", G_CALLBACK (canvas_item_event), NULL);
	g_signal_connect (item, "notify::parent", G_CALLBACK (visible_cb), NULL);
	g_object_unref (item);
	g_assert (G_OBJECT (item)->ref_count == 1);

	/* And a clock :-) */
	item = dia_canvas_item_create (dia_clock_get_type (),
				    "width", 100.0,
				    "height", 100.0,
				    NULL);
	dia_canvas_groupable_add (DIA_CANVAS_GROUPABLE (canvas->root), item);
	g_object_weak_ref (G_OBJECT (item), item_destroyed, NULL);

	dia_canvas_item_move (item, 100.0, 100.0);
	dia_canvas_item_request_update (item);
	g_signal_connect (item, "event", G_CALLBACK (canvas_item_event), NULL);
	g_object_unref (item);
	g_assert (G_OBJECT (item)->ref_count == 1);
	/* Draw an ellipse */
	/*item = dia_canvas_item_new (DIA_CANVAS_GROUP (canvas->root),
			     dia_canvas_ellipse_get_type (),
			     NULL);
	dia_canvas_item_rotate (item, 35.0);
	*/

	g_message ("done...");

	PRINT_CANVAS_HIERARCHY (canvas);
	
	/* Create a view */
	view = dia_canvas_view_new (NULL, TRUE);
	window = display_canvas_view (view);
	g_object_set (view, "canvas", canvas, NULL);

	g_signal_connect (view, "focus_item", G_CALLBACK (focus_cb), NULL);
	g_signal_connect (view, "select_item", G_CALLBACK (select_cb), NULL);
	g_signal_connect (view, "unselect_item", G_CALLBACK (unselect_cb), NULL);

	/* Add some text */
	//font_desc = pango_font_description_from_string ("times new roman");
	font_desc = pango_font_description_from_string ("sans 20");
	//pango_font_description_set_size (font_desc, 25 * PANGO_SCALE);
	g_message ("The font we have: %s.", pango_font_description_get_family (font_desc));

	//text = "Hello world!\nThis is a nice example text that does word wrapping among a lot of other things.";
	text = "<b>Hello world!</b>\nThis is a nice <i>example</i> text that does word wrapping among a lot of other things.";
	item = dia_canvas_item_create (DIA_TYPE_TEXTBOX,
				    "width", 200.0,
				    "height", 30.0,
				    NULL);
	dia_canvas_groupable_add (DIA_CANVAS_GROUPABLE (canvas->root), item);
	g_object_weak_ref (G_OBJECT (item), item_destroyed, NULL);
	/* TODO: This is a hack! */
	g_object_set (DIA_TEXTBOX (item)->text,
		      "font", font_desc,
		      "text", text,
		      "editable", FALSE,
		      "markup", TRUE,
		      NULL);
	dia_canvas_item_move (item, 10.0, 10.0);
	g_signal_connect (item, "event", G_CALLBACK (canvas_item_event), NULL);
	g_object_unref (item);
	g_assert (G_OBJECT (item)->ref_count == 1);

	/* A piece of centered text */
	item = dia_canvas_item_create (DIA_TYPE_TEXTBOX,
				    "width", 200.0,
				    "height", 40.0,
				    NULL);
	dia_canvas_groupable_add (DIA_CANVAS_GROUPABLE (canvas->root), item);
	g_object_weak_ref (G_OBJECT (item), item_destroyed, NULL);
	/* TODO: This is a hack! */
	g_object_set (DIA_TEXTBOX (item)->text,
		      "font", font_desc,
		      "text", "center",
		      "width", 200.0,
		      "alignment", PANGO_ALIGN_CENTER,
		      "multiline", 0,
		      NULL);
	dia_canvas_item_move (item, 10.0, 150.0);
	g_signal_connect (item, "event", G_CALLBACK (canvas_item_event), NULL);
	g_object_unref (item);
	g_assert (G_OBJECT (item)->ref_count == 1);

	/* A piece of right aligned text */
	item = dia_canvas_item_create (DIA_TYPE_TEXTBOX,
				    "width", 200.0,
				    "height", 40.0,
				    NULL);
	dia_canvas_groupable_add (DIA_CANVAS_GROUPABLE (canvas->root), item);
	g_object_weak_ref (G_OBJECT (item), item_destroyed, NULL);
	/* TODO: This is a hack! */
	g_object_set (DIA_TEXTBOX (item)->text,
		      "font", font_desc,
		      "text", "right aligned text",
		      "width", 200.0,
		      "alignment", PANGO_ALIGN_RIGHT,
		      "multiline", 0,
		      NULL);
	dia_canvas_item_move (item, 10.0, 180.0);
	g_signal_connect (item, "event", G_CALLBACK (canvas_item_event), NULL);
	g_object_unref (item);
	g_assert (G_OBJECT (item)->ref_count == 1);

	pango_font_description_free (font_desc);

	//dia_canvas_view_set_zoom (DIA_CANVAS_VIEW (view), 3.171);
	PRINT_CANVAS_VIEW_HIERARCHY (view);

	//g_message ("unrefing %x...", (guint) item);
	//dia_canvas_group_remove_item ((DiaCanvasGroup*) item->parent, item);
	//g_object_unref (item);

	//PRINT_CANVAS_VIEW_HIERARCHY (view);

	/* Debug dump to stdout */
	//dia_persistent_factory_dump (canvas->factory);
	
	canvas->allow_undo = TRUE;

	g_message ("Going into main...");
	gtk_main ();

	/* It looks like GTK+ crashes if a window is destroyed... I can't see
	 * any error in my code (DiaCanvasView), so maybe GnomeCanvas is in
	 * error... */
	//g_object_unref (view);
	//g_object_unref (window2);
	PRINT_CANVAS_HIERARCHY (canvas);
	g_message ("Canvas ref: %d", G_OBJECT(canvas)->ref_count);
	g_object_unref (canvas);

	return 0;
}

