r15691 - gnucash/branches/register-rewrite - Copy some GtkCalendar-in-a-GtkCellRenderer code from Planner.

Chris Shoemaker chris at cvs.gnucash.org
Thu Mar 8 16:40:09 EST 2007


Author: chris
Date: 2007-03-08 16:40:06 -0500 (Thu, 08 Mar 2007)
New Revision: 15691
Trac: http://svn.gnucash.org/trac/changeset/15691

Added:
   gnucash/branches/register-rewrite/src/gnome-utils/planner-cell-renderer-date.c
   gnucash/branches/register-rewrite/src/gnome-utils/planner-cell-renderer-date.h
   gnucash/branches/register-rewrite/src/gnome-utils/planner-cell-renderer-popup.c
   gnucash/branches/register-rewrite/src/gnome-utils/planner-cell-renderer-popup.h
   gnucash/branches/register-rewrite/src/gnome-utils/planner-marshal.list
   gnucash/branches/register-rewrite/src/gnome-utils/planner-popup-entry.c
   gnucash/branches/register-rewrite/src/gnome-utils/planner-popup-entry.h
Modified:
   gnucash/branches/register-rewrite/configure.in
   gnucash/branches/register-rewrite/src/gnome-utils/Makefile.am
Log:
Copy some GtkCalendar-in-a-GtkCellRenderer code from Planner.

Wholesale copy of some code from Planner that implements a GtkCalendar
in a custom GtkCellEditable popup from a GtkCellRenderer.

These files are unchanged except for one place that's commented.
Also, introduce a dependency on libplanner.  This could be brought in-tree, 
if needed.



Modified: gnucash/branches/register-rewrite/configure.in
===================================================================
--- gnucash/branches/register-rewrite/configure.in	2007-03-08 13:23:14 UTC (rev 15690)
+++ gnucash/branches/register-rewrite/configure.in	2007-03-08 21:40:06 UTC (rev 15691)
@@ -1822,6 +1822,9 @@
 fi
 ### End of gui-only checks
 
+### CAS: I don't know what the real min is.  This is just what I have.
+PKG_CHECK_MODULES(LIBPLANNER, libplanner-1 >= 0.14)
+
 ###-------------------------------------------------------------------------
 ### Selectively disable deprecated bits of glib/gdk/gtk/gnome
 ###-------------------------------------------------------------------------

Modified: gnucash/branches/register-rewrite/src/gnome-utils/Makefile.am
===================================================================
--- gnucash/branches/register-rewrite/src/gnome-utils/Makefile.am	2007-03-08 13:23:14 UTC (rev 15690)
+++ gnucash/branches/register-rewrite/src/gnome-utils/Makefile.am	2007-03-08 21:40:06 UTC (rev 15691)
@@ -22,9 +22,14 @@
   ${GUILE_INCS} \
   ${QOF_CFLAGS} \
   ${GOFFICE_CFLAGS} \
+  ${LIBPLANNER_CFLAGS} \
   ${GSF_CFLAGS}
 
 libgncmod_gnome_utils_la_SOURCES = \
+  planner-marshal.c \
+  planner-popup-entry.c \
+  planner-cell-renderer-popup.c \
+  planner-cell-renderer-date.c \
   QuickFill.c \
   account-quickfill.c \
   cursors.c \
@@ -101,6 +106,10 @@
 
 gncincludedir = ${GNC_INCLUDE_DIR}
 gncinclude_HEADERS = \
+  planner-marshal.h \
+  planner-popup-entry.h \
+  planner-cell-renderer-popup.h \
+  planner-cell-renderer-date.h \
   QuickFill.h \
   account-quickfill.h \
   dialog-account.h \
@@ -198,6 +207,7 @@
   ${QOF_LIBS} \
   ${GOFFICE_LIBS} \
   ${REGEX_LIBS} \
+  ${LIBPLANNER_LIBS} \
   ${LIBXML2_LIBS}
 
 if BUILDING_FROM_SVN
@@ -305,3 +315,14 @@
 endif
 
 INCLUDES = -DG_LOG_DOMAIN=\"gnc.gui\"
+
+planner-marshal.h: Makefile.am planner-marshal.list
+	$(GLIB_GENMARSHAL) --prefix=planner_marshal $(srcdir)/planner-marshal.list --header > xgen-gmh \
+	&& (cmp -s xgen-gmh planner-marshal.h || cp xgen-gmh planner-marshal.h) \
+	&& rm -f xgen-gmh xgen-gmh~
+
+planner-marshal.c: Makefile.am planner-marshal.list
+	(echo "#include \"planner-marshal.h\""; $(GLIB_GENMARSHAL) --prefix=planner_marshal $(srcdir)/planner-marshal.list --body) > xgen-gmc \
+	&& cp xgen-gmc planner-marshal.c \
+	&& rm -f xgen-gmc xgen-gmc~
+

Added: gnucash/branches/register-rewrite/src/gnome-utils/planner-cell-renderer-date.c
===================================================================
--- gnucash/branches/register-rewrite/src/gnome-utils/planner-cell-renderer-date.c	2007-03-08 13:23:14 UTC (rev 15690)
+++ gnucash/branches/register-rewrite/src/gnome-utils/planner-cell-renderer-date.c	2007-03-08 21:40:06 UTC (rev 15691)
@@ -0,0 +1,587 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2005 Imendio AB
+ * Copyright (C) 2001-2002 CodeFactory AB
+ * Copyright (C) 2001-2002 Richard Hult <richard at imendio.com>
+ * Copyright (C) 2001-2002 Mikael Hallendal <micke at imendio.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 <stdlib.h>
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtkmain.h>
+#include <gtk/gtkcellrenderertext.h>
+#include <gtk/gtkeditable.h>
+#include <gtk/gtkhseparator.h>
+#include <gtk/gtkbutton.h>
+#include <gtk/gtklabel.h>
+#include <gtk/gtkoptionmenu.h>
+#include <gtk/gtkmenuitem.h>
+#include <gtk/gtkarrow.h>
+#include <gtk/gtkwindow.h>
+#include <gtk/gtkframe.h>
+#include <gtk/gtkvbox.h>
+#include <gtk/gtkhbox.h>
+#include <gtk/gtkhbbox.h>
+#include <gtk/gtkstock.h>
+#include <gtk/gtkcalendar.h>
+#include <glib/gi18n.h>
+#include "planner-marshal.h"
+#include "planner-cell-renderer-date.h"
+#include "planner-popup-entry.h"
+/* CAS: 
+ This one function came from planner-format.c and was the only reason 
+planner-format.h was included.  I've pasted it here with one modification - 
+adding the year to the string.
+
+#include "planner-format.h"
+
+*/
+gchar * planner_format_date (mrptime date);
+gchar * 
+planner_format_date (mrptime date)
+{
+	gchar *svalue;
+
+	if (date == MRP_TIME_INVALID) {
+		svalue = g_strdup ("");	
+	} else {
+		/* i18n: this string is the date nr and month name, displayed
+		 * e.g. in the date cells in the task tree. See
+		 * libmrproject/docs/DateFormat.
+		 */
+		svalue = mrp_time_format (_("%b %e %Y"), date);//CAS: added year
+	}
+	
+	return svalue;	
+}
+
+enum {
+	PROP_0,
+	PROP_USE_CONSTRAINT,
+};
+
+static void     mcrd_init                    (PlannerCellRendererDate      *date);
+static void     mcrd_class_init              (PlannerCellRendererDateClass *class);
+static void     mcrd_set_property            (GObject                 *object,
+					      guint                    param_id,
+					      const GValue            *value,
+					      GParamSpec              *pspec);
+static void     mcrd_get_property            (GObject                 *object,
+					      guint                    param_id,
+					      GValue                  *value,
+					      GParamSpec              *pspec);
+static void     mcrd_today_clicked           (GtkWidget               *button,
+					      PlannerCellRendererDate *cell);
+static void     mcrd_selected_double_click   (GtkWidget               *calendar,
+					      PlannerCellRendererDate *cell);
+static void     mcrd_cancel_clicked          (GtkWidget               *popup_window,
+					      PlannerCellRendererDate      *cell);
+static void     mcrd_ok_clicked              (GtkWidget               *popup_window,
+					      PlannerCellRendererDate      *cell);
+static void     mcrd_day_selected            (GtkWidget               *popup_window,
+					      PlannerCellRendererDate      *cell);
+static void     mcrd_constraint_activated_cb (GtkWidget               *widget,
+					      PlannerCellRendererDate      *cell);
+GtkCellEditable *mcrd_start_editing          (GtkCellRenderer         *cell,
+					      GdkEvent                *event,
+					      GtkWidget               *widget,
+					      const gchar             *path,
+					      GdkRectangle            *background_area,
+					      GdkRectangle            *cell_area,
+					      GtkCellRendererState     flags);
+static void     mcrd_show                    (PlannerCellRendererPopup     *cell,
+					      const gchar             *path,
+					      gint                     x1,
+					      gint                     y1,
+					      gint                     x2,
+					      gint                     y2);
+static void     mcrd_hide                    (PlannerCellRendererPopup     *cell);
+static void     mcrd_setup_option_menu       (GtkWidget               *option_menu,
+					      GtkSignalFunc            func,
+					      gpointer                 user_data,
+					      gpointer                 str1, ...);
+
+
+static PlannerCellRendererPopupClass *parent_class;
+
+GType
+planner_cell_renderer_date_get_type (void)
+{
+	static GType cell_text_type = 0;
+	
+	if (!cell_text_type) {
+		static const GTypeInfo cell_text_info = {
+			sizeof (PlannerCellRendererDateClass),
+			NULL,		/* base_init */
+			NULL,		/* base_finalize */
+			(GClassInitFunc) mcrd_class_init,
+			NULL,		/* class_finalize */
+			NULL,		/* class_data */
+			sizeof (PlannerCellRendererDate),
+			0,              /* n_preallocs */
+			(GInstanceInitFunc) mcrd_init,
+		};
+		
+		cell_text_type = g_type_register_static (PLANNER_TYPE_CELL_RENDERER_POPUP,
+							 "PlannerCellRendererDate",
+							 &cell_text_info,
+							 0);
+	}
+	
+	return cell_text_type;
+}
+
+static void
+mcrd_init (PlannerCellRendererDate *date)
+{
+	PlannerCellRendererPopup *popup;
+	GtkWidget                *frame;
+	GtkWidget                *vbox;
+	GtkWidget                *hbox;
+	GtkWidget                *bbox;
+	GtkWidget                *button;
+
+	popup = PLANNER_CELL_RENDERER_POPUP (date);
+
+	frame = gtk_frame_new (NULL);
+	gtk_container_add (GTK_CONTAINER (popup->popup_window), frame);
+	gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
+
+	vbox = gtk_vbox_new (FALSE, 6);
+	gtk_container_add (GTK_CONTAINER (frame), vbox);
+	gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
+	
+	date->calendar = gtk_calendar_new ();
+	popup->focus_window = date->calendar;
+	gtk_box_pack_start (GTK_BOX (vbox), date->calendar, TRUE, TRUE, 0);
+
+	date->constraint_vbox = gtk_vbox_new (FALSE, 0);
+	gtk_box_pack_start (GTK_BOX (vbox), date->constraint_vbox, FALSE, FALSE, 0);
+	
+	hbox = gtk_hbox_new (FALSE, 6);
+	/* I18n: the verb "schedule" here. */
+	gtk_box_pack_start (GTK_BOX (hbox), gtk_label_new (_("Schedule:")),
+			    FALSE, FALSE, 0);
+	
+	date->option_menu = gtk_option_menu_new ();
+	mcrd_setup_option_menu (date->option_menu,
+				G_CALLBACK (mcrd_constraint_activated_cb),
+				date,
+				_("As soon as possible"), MRP_CONSTRAINT_ASAP,
+				_("No earlier than"), MRP_CONSTRAINT_SNET,
+				_("On fixed date"), MRP_CONSTRAINT_MSO,
+				NULL);
+	gtk_box_pack_end (GTK_BOX (hbox), date->option_menu, TRUE, TRUE, 0);
+
+	gtk_box_pack_start (GTK_BOX (date->constraint_vbox), hbox, TRUE, TRUE, 0);
+	
+	hbox = gtk_hbox_new (FALSE, 0);
+	gtk_box_pack_start (GTK_BOX (date->constraint_vbox), hbox, FALSE, FALSE, 0);
+	
+	bbox = gtk_hbutton_box_new ();
+	gtk_box_set_spacing (GTK_BOX (bbox), 6);
+	gtk_box_pack_start (GTK_BOX (vbox), bbox, FALSE, FALSE, 0);
+
+	date->today_button = gtk_button_new_with_label (_("Today"));
+	gtk_container_add (GTK_CONTAINER (bbox), date->today_button);
+	g_signal_connect (date->today_button, "clicked",
+			  G_CALLBACK (mcrd_today_clicked),
+			  date);
+	
+	button = gtk_button_new_with_label (_("Cancel"));
+	gtk_container_add (GTK_CONTAINER (bbox), button);
+	g_signal_connect (button,
+			  "clicked",
+			  G_CALLBACK (mcrd_cancel_clicked),
+			  date);
+
+	button = gtk_button_new_with_label (_("Select"));
+	gtk_container_add (GTK_CONTAINER (bbox), button);
+	g_signal_connect (button, "clicked",
+			  G_CALLBACK (mcrd_ok_clicked),
+			  date);
+
+	g_signal_connect (date->calendar, "day-selected",
+			  G_CALLBACK (mcrd_day_selected),
+			  date);
+	g_signal_connect (date->calendar, "day-selected-double-click", 
+			  G_CALLBACK (mcrd_selected_double_click),
+			  date);
+
+        gtk_widget_show_all (frame);
+}
+
+static void
+mcrd_class_init (PlannerCellRendererDateClass *class)
+{
+	PlannerCellRendererPopupClass *popup_class;
+	GtkCellRendererClass          *cell_class;
+	GObjectClass                  *gobject_class;
+
+	popup_class = PLANNER_CELL_RENDERER_POPUP_CLASS (class);
+	cell_class = GTK_CELL_RENDERER_CLASS (class);	
+	parent_class = PLANNER_CELL_RENDERER_POPUP_CLASS (g_type_class_peek_parent (class));
+	gobject_class = G_OBJECT_CLASS (class);
+
+	gobject_class->set_property = mcrd_set_property;
+	gobject_class->get_property = mcrd_get_property;
+
+	cell_class->start_editing = mcrd_start_editing;
+		
+	popup_class->show_popup = mcrd_show;
+	popup_class->hide_popup = mcrd_hide;
+
+	g_object_class_install_property (
+		gobject_class,
+                 PROP_USE_CONSTRAINT,
+                 g_param_spec_boolean ("use-constraint",
+				       NULL,
+				       NULL,
+				       TRUE,
+				       G_PARAM_READWRITE |
+				       G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+mcrd_set_property (GObject      *object,
+		   guint         param_id,
+		   const GValue *value,
+		   GParamSpec   *pspec)
+{
+	PlannerCellRendererDate *date;
+
+	date = PLANNER_CELL_RENDERER_DATE (object);
+	
+	switch (param_id) {
+	case PROP_USE_CONSTRAINT:
+		date->use_constraint = g_value_get_boolean (value);
+
+		if (date->use_constraint) {
+			gtk_widget_show (date->constraint_vbox);
+		} else {
+			gtk_widget_hide (date->constraint_vbox);
+		}
+
+		gtk_widget_set_sensitive (date->calendar, date->use_constraint);
+		gtk_widget_set_sensitive (date->today_button, date->use_constraint);
+
+		break;
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+		break;
+	}
+}
+
+static void
+mcrd_get_property (GObject    *object,
+		   guint       param_id,
+		   GValue     *value,
+		   GParamSpec *pspec)
+{
+	PlannerCellRendererDate *date;
+
+	date = PLANNER_CELL_RENDERER_DATE (object);
+	
+	switch (param_id) {
+	case PROP_USE_CONSTRAINT:
+		g_value_set_boolean (value, date->use_constraint);
+		break;
+
+	default:
+		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+		break;
+	}
+}
+
+GtkCellEditable *
+mcrd_start_editing (GtkCellRenderer      *cell,
+		    GdkEvent             *event,
+		    GtkWidget            *widget,
+		    const gchar          *path,
+		    GdkRectangle         *background_area,
+		    GdkRectangle         *cell_area,
+		    GtkCellRendererState  flags)
+{
+	PLANNER_CELL_RENDERER_POPUP (cell)->editing_canceled = TRUE;
+	
+	if (GTK_CELL_RENDERER_CLASS (parent_class)->start_editing) {
+		return GTK_CELL_RENDERER_CLASS (parent_class)->start_editing (
+							cell,
+							event,
+							widget,
+							path,
+							background_area,
+							cell_area,
+							flags);
+	}
+
+	return NULL;
+}
+
+
+static void
+mcrd_hide (PlannerCellRendererPopup *cell)
+{
+	if (parent_class->hide_popup) {
+		parent_class->hide_popup (cell);
+	}
+}
+
+static void
+mcrd_show (PlannerCellRendererPopup *cell,
+	   const gchar              *path,
+	   gint                      x1,
+	   gint                      y1,
+	   gint                      x2,
+	   gint                      y2)
+{
+	PlannerCellRendererDate *date;
+	gint                     year;
+	gint                     month;
+	gint                     day;
+	gint                     index;
+	gboolean                 sensitive;
+
+	if (parent_class->show_popup) {
+		parent_class->show_popup (cell,
+					  path,
+					  x1, y1,
+					  x2, y2);
+	}
+
+	date = PLANNER_CELL_RENDERER_DATE (cell);
+
+	mrp_time_decompose (date->time, &year, &month, &day, NULL, NULL, NULL);
+	
+	index = 0;
+	
+	switch (date->type) {
+	case MRP_CONSTRAINT_ASAP:
+		index = 0;
+		break;
+	case MRP_CONSTRAINT_SNET:
+		index = 1;
+		break;
+	case MRP_CONSTRAINT_MSO:
+		index = 2;
+		break;
+	default:
+		g_assert_not_reached ();
+	}
+
+	sensitive = (!date->use_constraint ||
+		     (date->type != MRP_CONSTRAINT_ASAP &&
+		      date->type != MRP_CONSTRAINT_ALAP));
+	
+	gtk_widget_set_sensitive (date->calendar, sensitive);
+	gtk_widget_set_sensitive (date->today_button, sensitive);
+	
+	gtk_calendar_clear_marks (GTK_CALENDAR (date->calendar));
+	gtk_calendar_select_month (GTK_CALENDAR (date->calendar),
+				   month - 1, year);
+	gtk_calendar_select_day (GTK_CALENDAR (date->calendar), day);
+	gtk_calendar_mark_day (GTK_CALENDAR (date->calendar), day);
+	
+	gtk_option_menu_set_history (GTK_OPTION_MENU (date->option_menu),
+				     index);
+}
+
+GtkCellRenderer *
+planner_cell_renderer_date_new (gboolean use_constraint)
+{
+	GObject *cell;
+
+	cell = g_object_new (PLANNER_TYPE_CELL_RENDERER_DATE,
+			     "use-constraint", use_constraint,
+			     NULL);
+	
+	return GTK_CELL_RENDERER (cell);
+}
+
+static void
+mcrd_today_clicked (GtkWidget               *button,
+		    PlannerCellRendererDate *cell)
+{
+	mrptime today;
+	gint    year, month, day;
+	
+	today = mrp_time_current_time ();
+
+	mrp_time_decompose (today, &year, &month, &day,
+			    NULL, NULL, NULL);
+	
+	gtk_calendar_clear_marks (GTK_CALENDAR (cell->calendar));
+	gtk_calendar_select_month (GTK_CALENDAR (cell->calendar),
+				   month - 1, year);
+	gtk_calendar_select_day (GTK_CALENDAR (cell->calendar), day);
+	gtk_calendar_mark_day (GTK_CALENDAR (cell->calendar), day);
+}
+
+static void
+mcrd_selected_double_click (GtkWidget               *calendar,
+			    PlannerCellRendererDate *cell)
+{
+	PlannerCellRendererPopup *popup;
+	
+	popup = PLANNER_CELL_RENDERER_POPUP (cell);
+
+	mcrd_ok_clicked (popup->popup_window, cell);
+}
+
+static void
+mcrd_cancel_clicked (GtkWidget               *popup_window,
+		     PlannerCellRendererDate *cell)
+{
+	PlannerCellRendererPopup *popup;
+	
+	popup = PLANNER_CELL_RENDERER_POPUP (cell);
+
+	popup->editing_canceled = TRUE;
+	planner_cell_renderer_popup_hide (popup);
+}
+
+static void
+mcrd_ok_clicked (GtkWidget               *popup_window,
+		 PlannerCellRendererDate *cell)
+{
+	PlannerCellRendererPopup *popup;
+	
+	popup = PLANNER_CELL_RENDERER_POPUP (cell);
+
+	mcrd_day_selected (popup_window, cell);
+
+	popup->editing_canceled = FALSE;
+	planner_cell_renderer_popup_hide (popup);
+}
+
+static void
+mcrd_day_selected (GtkWidget               *popup_window,
+		   PlannerCellRendererDate *cell)
+{
+	guint    year;
+	guint    month;
+	guint    day;
+	mrptime  t;
+	gchar   *str;
+
+	gtk_calendar_get_date (GTK_CALENDAR (cell->calendar),
+			       &year,
+			       &month,
+			       &day);
+
+	t = mrp_time_compose (year, month + 1, day, 0, 0, 0);
+
+	cell->time = t;
+
+	str = planner_format_date (t);
+	planner_popup_entry_set_text (
+		PLANNER_POPUP_ENTRY (PLANNER_CELL_RENDERER_POPUP (cell)->editable), str);
+	g_free (str);
+}
+
+static gboolean
+mcrd_grab_on_window (GdkWindow *window,
+		     guint32    activate_time)
+{
+	if ((gdk_pointer_grab (window, TRUE,
+			       GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
+			       GDK_POINTER_MOTION_MASK,
+			       NULL, NULL, activate_time) == 0)) {
+		if (gdk_keyboard_grab (window, TRUE,
+			       activate_time) == 0)
+			return TRUE;
+		else {
+			gdk_pointer_ungrab (activate_time);
+			return FALSE;
+		}
+	}
+
+	return FALSE;
+}
+
+static void
+mcrd_constraint_activated_cb (GtkWidget               *widget,
+			      PlannerCellRendererDate *cell)
+{
+	gpointer data;
+	gboolean sensitive;
+	
+	data = g_object_get_data (G_OBJECT (widget), "data");
+
+	cell->type = GPOINTER_TO_INT (data);
+
+	sensitive = (!cell->use_constraint ||
+		     (cell->type != MRP_CONSTRAINT_ASAP &&
+		      cell->type != MRP_CONSTRAINT_ALAP));
+	
+	gtk_widget_set_sensitive (cell->calendar, sensitive);
+	gtk_widget_set_sensitive (cell->today_button, sensitive);
+	
+	/* A bit hackish. Grab focus on the popup window again when the
+	 * optionmenu is activated, since focus is transferred to the optionmenu
+	 * when it's popped up.
+	 */
+	mcrd_grab_on_window (PLANNER_CELL_RENDERER_POPUP (cell)->popup_window->window,
+			     gtk_get_current_event_time ());
+}
+
+/* Utility function to use before optionmenus work with libglade again.
+ */
+
+static void
+mcrd_setup_option_menu (GtkWidget     *option_menu,
+			GtkSignalFunc  func,
+			gpointer       user_data,
+			gpointer       str1, ...)
+{
+	GtkWidget *menu, *menu_item;
+	gint       i;
+	va_list    args;
+	gpointer   str;
+	gint       type;
+
+       	menu = gtk_option_menu_get_menu (GTK_OPTION_MENU (option_menu));
+	if (menu) {
+		gtk_widget_destroy (menu);
+	}
+	
+	menu = gtk_menu_new ();
+
+	va_start (args, str1);
+	for (str = str1, i = 0; str != NULL; str = va_arg (args, gpointer), i++) {
+		menu_item = gtk_menu_item_new_with_label (str);
+		gtk_widget_show (menu_item);
+		gtk_menu_append (GTK_MENU (menu), menu_item);
+
+		type = va_arg (args, gint);
+		
+		g_object_set_data (G_OBJECT (menu_item),
+				   "data",
+				   GINT_TO_POINTER (type));
+		gtk_signal_connect (GTK_OBJECT (menu_item),
+				    "activate",
+				    func,
+				    user_data);
+	}
+	va_end (args);
+
+	gtk_widget_show (menu);
+	gtk_option_menu_set_menu (GTK_OPTION_MENU (option_menu), menu);
+}
+

Added: gnucash/branches/register-rewrite/src/gnome-utils/planner-cell-renderer-date.h
===================================================================
--- gnucash/branches/register-rewrite/src/gnome-utils/planner-cell-renderer-date.h	2007-03-08 13:23:14 UTC (rev 15690)
+++ gnucash/branches/register-rewrite/src/gnome-utils/planner-cell-renderer-date.h	2007-03-08 21:40:06 UTC (rev 15691)
@@ -0,0 +1,65 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2005 Imendio AB
+ * Copyright (C) 2001-2002 CodeFactory AB
+ * Copyright (C) 2001-2002 Richard Hult <richard at imendio.com>
+ * Copyright (C) 2001-2002 Mikael Hallendal <micke at imendio.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.
+ */
+
+#ifndef __PLANNER_CELL_RENDERER_DATE_H__
+#define __PLANNER_CELL_RENDERER_DATE_H__
+
+#include <glib-object.h>
+#include <gtk/gtkwidget.h>
+#include <libplanner/mrp-time.h>
+#include <libplanner/mrp-types.h>
+#include "planner-cell-renderer-popup.h"
+
+#define PLANNER_TYPE_CELL_RENDERER_DATE	      (planner_cell_renderer_date_get_type ())
+#define PLANNER_CELL_RENDERER_DATE(obj)	      (GTK_CHECK_CAST ((obj), PLANNER_TYPE_CELL_RENDERER_DATE, PlannerCellRendererDate))
+#define PLANNER_CELL_RENDERER_DATE_CLASS(klass)    (GTK_CHECK_CLASS_CAST ((klass), PLANNER_TYPE_CELL_RENDERER_DATE, PlannerCellRendererDateClass))
+#define PLANNER_IS_CELL_RENDERER_DATE(obj)	      (GTK_CHECK_TYPE ((obj), PLANNER_TYPE_CELL_RENDERER_DATE))
+#define PLANNER_IS_CELL_RENDERER_DATE_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((obj), PLANNER_TYPE_CELL_RENDERER_DATE))
+#define PLANNER_CELL_RENDERER_DATE_GET_CLASS(obj)  (GTK_CHECK_GET_CLASS ((obj), PLANNER_TYPE_CELL_RENDERER_DATE, PlannerCellRendererDateClass))
+
+typedef struct _PlannerCellRendererDate      PlannerCellRendererDate;
+typedef struct _PlannerCellRendererDateClass PlannerCellRendererDateClass;
+
+struct _PlannerCellRendererDate
+{
+	PlannerCellRendererPopup  parent;
+	GtkWidget                *calendar;
+	GtkWidget                *option_menu;
+	GtkWidget                *today_button;
+
+	gboolean                  use_constraint;
+	GtkWidget                *constraint_vbox;
+	mrptime                   time;
+	MrpConstraintType         type;
+};
+
+struct _PlannerCellRendererDateClass
+{
+	PlannerCellRendererPopupClass parent_class;
+};
+
+GType            planner_cell_renderer_date_get_type (void) G_GNUC_CONST;
+GtkCellRenderer *planner_cell_renderer_date_new      (gboolean use_constraint);
+
+
+#endif /* __PLANNER_CELL_RENDERER_DATE_H__ */

Added: gnucash/branches/register-rewrite/src/gnome-utils/planner-cell-renderer-popup.c
===================================================================
--- gnucash/branches/register-rewrite/src/gnome-utils/planner-cell-renderer-popup.c	2007-03-08 13:23:14 UTC (rev 15690)
+++ gnucash/branches/register-rewrite/src/gnome-utils/planner-cell-renderer-popup.c	2007-03-08 21:40:06 UTC (rev 15691)
@@ -0,0 +1,517 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2001-2002 CodeFactory AB
+ * Copyright (C) 2001-2002 Richard Hult <richard at imendio.com>
+ * Copyright (C) 2001-2002 Mikael Hallendal <micke at imendio.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 <gdk/gdkkeysyms.h>
+#include <gtk/gtkcellrenderertext.h>
+#include <gtk/gtkwindow.h>
+#include <gtk/gtkmain.h>
+#include <gtk/gtkeditable.h>
+#include <gtk/gtksignal.h>
+#include <gtk/gtkbutton.h>
+#include "planner-marshal.h"
+#include "planner-cell-renderer-popup.h"
+#include "planner-popup-entry.h"
+
+
+enum {
+	SHOW_POPUP,
+	HIDE_POPUP,
+	LAST_SIGNAL
+};
+
+static void      mcrp_init               (PlannerCellRendererPopup      *popup);
+static void      mcrp_class_init         (PlannerCellRendererPopupClass *class);
+
+static GtkCellEditable *
+mcrp_start_editing                       (GtkCellRenderer          *cell,
+					  GdkEvent                 *event,
+					  GtkWidget                *widget,
+					  const gchar              *path,
+					  GdkRectangle             *background_area,
+					  GdkRectangle             *cell_area,
+					  GtkCellRendererState      flags);
+static void      mcrp_show_popup         (PlannerCellRendererPopup      *cell,
+					  const gchar              *path,
+					  gint                      x1,
+					  gint                      y1,
+					  gint                      x2,
+					  gint                      y2);
+static void      mcrp_hide_popup         (PlannerCellRendererPopup      *cell);
+static void      mcrp_get_size           (GtkCellRenderer          *cell,
+					  GtkWidget                *widget,
+					  GdkRectangle             *cell_area,
+					  gint                     *x_offset,
+					  gint                     *y_offset,
+					  gint                     *width,
+					  gint                     *height);
+static void      mcrp_style_set           (GtkWidget               *widget,
+					   GtkStyle                *old_style,
+					   PlannerCellRendererPopup     *popup);
+static gboolean  mcrp_key_press_event    (GtkWidget                *popup_window,
+					  GdkEventKey              *event,
+					  PlannerCellRendererPopup      *cell);
+static gboolean  mcrp_button_press_event (GtkWidget                *widget,
+					  GdkEventButton           *event,
+					  PlannerCellRendererPopup      *popup);
+
+
+static GtkCellRendererTextClass *parent_class;
+static guint signals[LAST_SIGNAL];
+
+#define PLANNER_CELL_RENDERER_POPUP_PATH "planner-cell-renderer-popup-path"
+
+GType
+planner_cell_renderer_popup_get_type (void)
+{
+	static GType cell_text_type = 0;
+	
+	if (!cell_text_type) {
+		static const GTypeInfo cell_text_info = {
+			sizeof (PlannerCellRendererPopupClass),
+			NULL,		/* base_init */
+			NULL,		/* base_finalize */
+			(GClassInitFunc) mcrp_class_init,
+			NULL,		/* class_finalize */
+			NULL,		/* class_data */
+			sizeof (PlannerCellRendererPopup),
+			0,              /* n_preallocs */
+			(GInstanceInitFunc) mcrp_init,
+		};
+		
+		cell_text_type = g_type_register_static (GTK_TYPE_CELL_RENDERER_TEXT,
+							 "PlannerCellRendererPopup",
+							 &cell_text_info,
+							 0);
+	}
+	
+	return cell_text_type;
+}
+
+static void
+mcrp_init (PlannerCellRendererPopup *popup)
+{
+	popup->popup_window = gtk_window_new (GTK_WINDOW_POPUP);
+
+	popup->button_width = -1;
+	
+	g_signal_connect (popup->popup_window,
+			  "button-press-event",
+			  G_CALLBACK (mcrp_button_press_event),
+			  popup);
+
+	g_signal_connect (popup->popup_window,
+			  "key-press-event",
+			  G_CALLBACK (mcrp_key_press_event),
+			  popup);
+
+	g_signal_connect (popup->popup_window,
+			  "style-set",
+			  G_CALLBACK (mcrp_style_set),
+			  popup);
+}
+
+static void
+mcrp_class_init (PlannerCellRendererPopupClass *class)
+{
+	GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (class);
+	
+	parent_class = GTK_CELL_RENDERER_TEXT_CLASS (g_type_class_peek_parent (class));
+	
+	cell_class->start_editing = mcrp_start_editing;
+	cell_class->get_size      = mcrp_get_size;
+
+	class->show_popup = mcrp_show_popup;
+	class->hide_popup = mcrp_hide_popup;
+
+	signals[SHOW_POPUP] = g_signal_new (
+		"show-popup",
+		G_TYPE_FROM_CLASS (class),
+		G_SIGNAL_RUN_LAST,
+		G_STRUCT_OFFSET (PlannerCellRendererPopupClass, show_popup),
+		NULL, NULL,
+		planner_marshal_VOID__STRING_INT_INT_INT_INT,
+		G_TYPE_NONE, 5,
+		G_TYPE_STRING,
+		G_TYPE_INT,
+		G_TYPE_INT,
+		G_TYPE_INT,
+		G_TYPE_INT);
+
+	signals[HIDE_POPUP] = g_signal_new (
+		"hide-popup",
+		G_TYPE_FROM_CLASS (class),
+		G_SIGNAL_RUN_LAST,
+		G_STRUCT_OFFSET (PlannerCellRendererPopupClass, hide_popup),
+		NULL, NULL,
+		planner_marshal_VOID__VOID,
+		G_TYPE_NONE, 0);
+}
+
+static void
+mcrp_editing_done (GtkCellEditable     *editable,
+		   PlannerCellRendererPopup *cell)
+{
+	gchar       *path;
+	const gchar *new_text;
+
+	if (PLANNER_POPUP_ENTRY (editable)->editing_canceled ||
+	    cell->editing_canceled) {
+		return;
+	}
+	
+	path = g_object_get_data (G_OBJECT (editable),
+				  PLANNER_CELL_RENDERER_POPUP_PATH);
+	new_text = planner_popup_entry_get_text (PLANNER_POPUP_ENTRY (editable));
+
+	g_signal_emit_by_name (cell,
+			       "edited",
+			       path,
+			       new_text);
+}
+
+static void
+mcrp_style_set (GtkWidget           *widget,
+		GtkStyle            *old_style,
+		PlannerCellRendererPopup *popup)
+{
+	/* Invalidate the cache. */
+	popup->button_width = -1;
+}
+	
+static gboolean
+mcrp_grab_on_window (GdkWindow *window,
+		     guint32    activate_time)
+{
+	if ((gdk_pointer_grab (window, TRUE,
+			       GDK_BUTTON_PRESS_MASK |
+			       GDK_BUTTON_RELEASE_MASK |
+			       GDK_POINTER_MOTION_MASK,
+			       NULL, NULL, activate_time) == 0)) {
+		if (gdk_keyboard_grab (window, TRUE,
+			       activate_time) == 0)
+			return TRUE;
+		else {
+			gdk_pointer_ungrab (activate_time);
+			return FALSE;
+		}
+	}
+
+	return FALSE;
+}
+
+static void
+mcrp_show_popup (PlannerCellRendererPopup *cell,
+		 const gchar         *path,
+		 gint                 x1,
+		 gint                 y1,
+		 gint                 x2,
+		 gint                 y2)
+{
+	GtkAllocation alloc;
+	gint          x, y;
+	gint          screen_height, screen_width;
+	gint          button_height;
+
+	cell->shown = TRUE;
+
+	gtk_widget_realize (cell->popup_window);
+
+	/* I'm not sure this is ok to do, but we need to show the window to be
+	 * able to get the allocation right.
+	 */
+	gtk_window_move (GTK_WINDOW (cell->popup_window), -500, -500);
+	gtk_widget_show (cell->popup_window);
+
+	alloc = cell->popup_window->allocation;
+
+	x = x2;
+	y = y2;
+
+	button_height = y2 - y1;
+	
+	screen_height = gdk_screen_height () - y;
+	screen_width = gdk_screen_width ();
+
+	/* Check if it fits in the available height. */
+	if (alloc.height > screen_height) {
+		/* It doesn't fit, so we see if we have the minimum space needed. */
+		if (alloc.height > screen_height && y - button_height > screen_height) {
+			/* We don't, so we show the popup above the cell
+			   instead of below it. */
+			screen_height = y - button_height;
+			y -= (alloc.height + button_height);
+			if (y < 0) {
+				y = 0;
+			}
+		}
+	}
+
+	/* We try to line it up with the right edge of the column, but we don't
+	 * want it to go off the edges of the screen.
+	 */
+	if (x > screen_width) {
+		x = screen_width;
+	}
+
+	x -= alloc.width;
+	if (x < 0) {
+		x = 0;
+	}
+
+	gtk_grab_add (cell->popup_window);
+
+	gtk_window_move (GTK_WINDOW (cell->popup_window), x, y);
+	gtk_widget_show (cell->popup_window);
+
+	gtk_widget_grab_focus (cell->focus_window);
+
+	mcrp_grab_on_window (cell->popup_window->window,
+			     gtk_get_current_event_time ());
+}
+
+static void
+mcrp_hide_popup (PlannerCellRendererPopup *cell)
+{
+	gtk_grab_remove (cell->popup_window);
+	gtk_widget_hide (cell->popup_window);
+
+	if (cell->editable) {
+		gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (cell->editable));
+	}
+
+	/* This may look weird (the test), but the weak pointer will actually be
+	 * nulled out for some cells, like the date cell.
+	 */
+	if (cell->editable) {
+		gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (cell->editable));
+	}
+	
+	cell->shown = FALSE;
+	cell->editing_canceled = FALSE;
+}
+
+static void
+mcrp_arrow_clicked (GtkCellEditable     *entry,
+		    PlannerCellRendererPopup *cell)
+{
+	GtkAllocation  alloc;
+	gint           x, y;
+	const gchar   *path;
+	
+	if (cell->shown) {
+		cell->editing_canceled = TRUE;
+		planner_cell_renderer_popup_hide (cell);
+		return;
+	}
+	
+	path = g_object_get_data (G_OBJECT (entry),
+				  PLANNER_CELL_RENDERER_POPUP_PATH);
+
+	/* Temporarily grab pointer and keyboard on a window we know exists; we
+	 * do this so that the grab (with owner events == TRUE) affects
+	 * events generated when the window is mapped, such as enter
+	 * notify events on subwidgets. If the grab fails, bail out.
+	 */
+	if (!mcrp_grab_on_window (GTK_WIDGET (entry)->window,
+				  gtk_get_current_event_time ())) {
+		return;
+	}
+	
+	gtk_editable_select_region (GTK_EDITABLE (PLANNER_POPUP_ENTRY (entry)->entry), 0, 0);
+
+	gdk_window_get_origin (GTK_WIDGET (entry)->window, &x, &y);
+	
+	alloc = GTK_WIDGET (entry)->allocation;
+
+	g_signal_emit (cell, signals[SHOW_POPUP], 0,
+		       path, 
+		       x,
+		       y,
+		       x + alloc.width,
+		       y + alloc.height);
+}
+
+static GtkCellEditable *
+mcrp_start_editing (GtkCellRenderer      *cell,
+		    GdkEvent             *event,
+		    GtkWidget            *widget,
+		    const gchar          *path,
+		    GdkRectangle         *background_area,
+		    GdkRectangle         *cell_area,
+		    GtkCellRendererState  flags)
+{
+	PlannerCellRendererPopup *popup;
+	GtkWidget           *editable;
+	gchar               *text;
+	
+	popup = PLANNER_CELL_RENDERER_POPUP (cell);
+
+	/* If the cell isn't editable we return NULL. */
+	if (GTK_CELL_RENDERER_TEXT (popup)->editable == FALSE) {
+		return NULL;
+	}
+	
+	editable = g_object_new (PLANNER_TYPE_POPUP_ENTRY, NULL);
+
+	text = GTK_CELL_RENDERER_TEXT (cell)->text;
+	planner_popup_entry_set_text (PLANNER_POPUP_ENTRY (editable), text ? text : "");
+	
+	g_object_set_data_full (G_OBJECT (editable),
+				PLANNER_CELL_RENDERER_POPUP_PATH,
+				g_strdup (path),
+				g_free);
+	
+	gtk_widget_show (editable);
+
+	g_signal_connect (editable,
+			  "editing-done",
+			  G_CALLBACK (mcrp_editing_done),
+			  popup);
+
+	g_signal_connect (editable,
+			  "arrow-clicked",
+			  G_CALLBACK (mcrp_arrow_clicked),
+			  popup);
+
+	popup->editable = editable;
+
+	g_object_add_weak_pointer (G_OBJECT (popup->editable),
+				   (gpointer) &popup->editable);
+	
+	return GTK_CELL_EDITABLE (editable);
+}
+
+GtkCellRenderer *
+planner_cell_renderer_popup_new (void)
+{
+	return GTK_CELL_RENDERER (
+		g_object_new (planner_cell_renderer_popup_get_type (), NULL));
+}
+
+void
+planner_cell_renderer_popup_hide (PlannerCellRendererPopup *cell)
+{ 
+	g_return_if_fail (PLANNER_IS_CELL_RENDERER_POPUP (cell));
+	
+	g_signal_emit (cell, signals[HIDE_POPUP], 0);
+}
+
+static void
+mcrp_get_size (GtkCellRenderer *cell,
+	       GtkWidget       *widget,
+	       GdkRectangle    *cell_area,
+	       gint            *x_offset,
+	       gint            *y_offset,
+	       gint            *width,
+	       gint            *height)
+{
+	PlannerCellRendererPopup *popup;
+
+	popup = PLANNER_CELL_RENDERER_POPUP (cell);
+	
+	if (GTK_CELL_RENDERER_CLASS (parent_class)->get_size) { 
+		(* GTK_CELL_RENDERER_CLASS (parent_class)->get_size) (cell,
+								      widget,
+								      cell_area, 
+								      x_offset,
+								      y_offset,
+								      width,
+								      height);
+	}
+
+	/* We cache this because it takes really long to get the width. */
+	if (popup->button_width == -1) {
+		popup->button_width = planner_popup_get_button_width ();
+	}
+	
+	*width += popup->button_width;
+}
+
+static gboolean
+mcrp_key_press_event (GtkWidget           *popup_window,
+		      GdkEventKey         *event,
+		      PlannerCellRendererPopup *cell)
+{
+	if (event->keyval != GDK_Escape &&
+	    event->keyval != GDK_Return &&
+	    event->keyval != GDK_KP_Enter &&
+	    event->keyval != GDK_ISO_Enter &&
+	    event->keyval != GDK_3270_Enter) {
+		return FALSE;
+	}
+
+	if (event->keyval == GDK_Escape) {
+		cell->editing_canceled = TRUE;
+	} else {
+		cell->editing_canceled = FALSE;
+	}		
+	
+	planner_cell_renderer_popup_hide (cell);
+
+	return TRUE;
+}
+
+static gboolean
+mcrp_button_press_event (GtkWidget           *widget,
+			 GdkEventButton      *event,
+			 PlannerCellRendererPopup *popup)
+{
+	GtkAllocation alloc;
+	gdouble       x, y;
+	gint          xoffset, yoffset;
+	gint          x1, y1;
+	gint          x2, y2;
+
+	if (event->button != 1) {
+		return FALSE;
+	}
+	
+	/* If the event happened outside the popup, cancel editing.
+	 */
+
+	/*gdk_event_get_root_coords ((GdkEvent *) event, &x, &y);*/
+	x = event->x_root;
+	y = event->y_root;
+
+	gdk_window_get_root_origin (widget->window,
+				    &xoffset,
+				    &yoffset);
+
+	xoffset += widget->allocation.x;
+	yoffset += widget->allocation.y;
+	
+	alloc = popup->popup_window->allocation;
+	x1 = alloc.x + xoffset;
+	y1 = alloc.y + yoffset;
+	x2 = x1 + alloc.width;
+	y2 = y1 + alloc.height;
+
+	if (x > x1 && x < x2 && y > y1 && y < y2) {
+		return FALSE;
+	}
+	
+	popup->editing_canceled = TRUE;
+	planner_cell_renderer_popup_hide (popup);
+	
+	return FALSE;
+}

Added: gnucash/branches/register-rewrite/src/gnome-utils/planner-cell-renderer-popup.h
===================================================================
--- gnucash/branches/register-rewrite/src/gnome-utils/planner-cell-renderer-popup.h	2007-03-08 13:23:14 UTC (rev 15690)
+++ gnucash/branches/register-rewrite/src/gnome-utils/planner-cell-renderer-popup.h	2007-03-08 21:40:06 UTC (rev 15691)
@@ -0,0 +1,64 @@
+#ifndef __PLANNER_CELL_RENDERER_POPUP_H__
+#define __PLANNER_CELL_RENDERER_POPUP_H__
+
+#include <pango/pango.h>
+#include <gtk/gtkcellrenderertext.h>
+
+#define PLANNER_TYPE_CELL_RENDERER_POPUP		(planner_cell_renderer_popup_get_type ())
+#define PLANNER_CELL_RENDERER_POPUP(obj)		(GTK_CHECK_CAST ((obj), PLANNER_TYPE_CELL_RENDERER_POPUP, PlannerCellRendererPopup))
+#define PLANNER_CELL_RENDERER_POPUP_CLASS(klass)	(GTK_CHECK_CLASS_CAST ((klass), PLANNER_TYPE_CELL_RENDERER_POPUP, PlannerCellRendererPopupClass))
+#define PLANNER_IS_CELL_RENDERER_POPUP(obj)		(GTK_CHECK_TYPE ((obj), PLANNER_TYPE_CELL_RENDERER_POPUP))
+#define PLANNER_IS_CELL_RENDERER_POPUP_CLASS(klass)	(GTK_CHECK_CLASS_TYPE ((obj), PLANNER_TYPE_CELL_RENDERER_POPUP))
+#define PLANNER_CELL_RENDERER_POPUP_GET_CLASS(obj)   (GTK_CHECK_GET_CLASS ((obj), PLANNER_TYPE_CELL_RENDERER_POPUP, PlannerCellRendererPopupClass))
+
+typedef struct _PlannerCellRendererPopup      PlannerCellRendererPopup;
+typedef struct _PlannerCellRendererPopupClass PlannerCellRendererPopupClass;
+
+struct _PlannerCellRendererPopup
+{
+	GtkCellRendererText  parent;
+
+	/* Cached width of the popup button. */
+	gint                 button_width;
+	
+	/* The popup window. */
+	GtkWidget           *popup_window;
+
+	/* The widget that should grab focus on popup. */
+	GtkWidget           *focus_window;
+
+	/* The editable entry. */
+	GtkWidget           *editable;
+
+	gboolean             shown;
+	gboolean             editing_canceled;
+};
+
+struct _PlannerCellRendererPopupClass
+{
+	GtkCellRendererTextClass parent_class;
+	
+	void   (* show_popup) (PlannerCellRendererPopup *cell,
+			       const gchar         *path,
+			       gint                 x1,
+			       gint                 y1,
+			       gint                 x2,
+			       gint                 y2);
+	
+	void   (* hide_popup) (PlannerCellRendererPopup *cell);
+};
+
+GtkType          planner_cell_renderer_popup_get_type (void) G_GNUC_CONST;
+
+GtkCellRenderer *planner_cell_renderer_popup_new      (void);
+
+void             planner_cell_renderer_popup_show     (PlannerCellRendererPopup *cell,
+						  const gchar         *path,
+						  gint                 x1,
+						  gint                 y1,
+						  gint                 x2,
+						  gint                 y2);
+
+void             planner_cell_renderer_popup_hide     (PlannerCellRendererPopup *cell);
+
+#endif /* __PLANNER_CELL_RENDERER_POPUP_H__ */

Added: gnucash/branches/register-rewrite/src/gnome-utils/planner-marshal.list
===================================================================
--- gnucash/branches/register-rewrite/src/gnome-utils/planner-marshal.list	2007-03-08 13:23:14 UTC (rev 15690)
+++ gnucash/branches/register-rewrite/src/gnome-utils/planner-marshal.list	2007-03-08 21:40:06 UTC (rev 15691)
@@ -0,0 +1,12 @@
+VOID:VOID
+VOID:BOOLEAN
+VOID:BOOLEAN,STRING
+VOID:POINTER
+VOID:OBJECT
+VOID:STRING
+VOID:OBJECT,OBJECT
+VOID:INT,INT,INT,INT
+VOID:STRING,INT,INT,INT,INT
+VOID:DOUBLE,DOUBLE,DOUBLE,DOUBLE
+VOID:OBJECT,BOOLEAN
+OBJECT:VOID

Added: gnucash/branches/register-rewrite/src/gnome-utils/planner-popup-entry.c
===================================================================
--- gnucash/branches/register-rewrite/src/gnome-utils/planner-popup-entry.c	2007-03-08 13:23:14 UTC (rev 15690)
+++ gnucash/branches/register-rewrite/src/gnome-utils/planner-popup-entry.c	2007-03-08 21:40:06 UTC (rev 15691)
@@ -0,0 +1,270 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2001-2002 CodeFactory AB
+ * Copyright (C) 2001-2002 Richard Hult <richard at imendio.com>
+ * Copyright (C) 2001-2002 Mikael Hallendal <micke at imendio.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 <string.h>
+#include <gtk/gtkwindow.h>
+#include <gtk/gtkbutton.h>
+#include <gtk/gtkentry.h>
+#include <gtk/gtkarrow.h>
+#include <gtk/gtkhbox.h>
+#include <gtk/gtkeventbox.h>
+#include <gtk/gtkcelleditable.h>
+#include <gdk/gdkkeysyms.h>
+#include "planner-popup-entry.h"
+
+static void     planner_popup_entry_init       (PlannerPopupEntry        *entry);
+static void     planner_popup_entry_class_init (PlannerPopupEntryClass   *class);
+static void     mpw_cell_editable_init    (GtkCellEditableIface *iface);
+static gboolean mpw_key_press_event       (GtkWidget            *box,
+					   GdkEventKey          *key_event);
+
+enum {
+	ARROW_CLICKED,
+	LAST_SIGNAL
+};
+
+static GtkEventBoxClass *parent_class;
+static guint signals[LAST_SIGNAL];
+
+GtkType
+planner_popup_entry_get_type (void)
+{
+	static GtkType widget_type = 0;
+	
+	if (!widget_type) {
+		static const GTypeInfo widget_info = {
+			sizeof (PlannerPopupEntryClass),
+			NULL,		/* base_init */
+			NULL,		/* base_finalize */
+			(GClassInitFunc) planner_popup_entry_class_init,
+			NULL,		/* class_finalize */
+			NULL,		/* class_data */
+			sizeof (PlannerPopupEntry),
+			0,              /* n_preallocs */
+			(GInstanceInitFunc) planner_popup_entry_init,
+		};
+
+		static const GInterfaceInfo cell_editable_info = {
+			(GInterfaceInitFunc) mpw_cell_editable_init,    /* interface_init */
+			NULL,                                           /* interface_finalize */
+			NULL                                            /* interface_data */
+		};
+      
+		widget_type = g_type_register_static (GTK_TYPE_EVENT_BOX,
+						      "PlannerPopupEntry",
+						      &widget_info,
+						      0);
+		
+		g_type_add_interface_static (widget_type,
+					     GTK_TYPE_CELL_EDITABLE,
+					     &cell_editable_info);
+	}
+	
+	return widget_type;
+}
+
+static void
+planner_popup_entry_init (PlannerPopupEntry *widget)
+{
+	GtkWidget *arrow;
+
+	widget->hbox = gtk_hbox_new (FALSE, 0);
+	gtk_widget_show (widget->hbox);
+
+	widget->entry = g_object_new (GTK_TYPE_ENTRY, "has_frame", FALSE, NULL);
+	GTK_ENTRY (widget->entry)->is_cell_renderer = TRUE;
+	gtk_widget_show (widget->entry);
+
+	widget->button = gtk_button_new ();
+	gtk_widget_show (widget->button);
+
+	arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_OUT);
+	gtk_widget_show (arrow);
+
+	gtk_container_add (GTK_CONTAINER (widget->button), arrow);
+
+	gtk_box_pack_start (GTK_BOX (widget->hbox), widget->entry, TRUE, TRUE, 0);
+	gtk_box_pack_start (GTK_BOX (widget->hbox), widget->button, FALSE, TRUE, 0);
+
+	gtk_container_add (GTK_CONTAINER (widget), widget->hbox);
+
+	GTK_WIDGET_SET_FLAGS (widget, GTK_CAN_FOCUS);
+	gtk_widget_add_events (GTK_WIDGET (widget), GDK_KEY_PRESS_MASK);
+	gtk_widget_add_events (GTK_WIDGET (widget), GDK_KEY_RELEASE_MASK);
+}
+
+static void
+planner_popup_entry_class_init (PlannerPopupEntryClass *klass)
+{
+	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
+
+	widget_class->key_press_event = mpw_key_press_event;
+	
+	parent_class = GTK_EVENT_BOX_CLASS (g_type_class_peek_parent (klass));
+
+	signals[ARROW_CLICKED] = g_signal_new
+		("arrow-clicked",
+		 G_TYPE_FROM_CLASS (klass),
+		 G_SIGNAL_RUN_LAST,
+		 0,
+		 NULL, NULL,
+		 g_cclosure_marshal_VOID__VOID,
+		 G_TYPE_NONE, 0);
+}
+
+static void
+mpw_arrow_clicked (GtkWidget *button, PlannerPopupEntry *widget)
+{
+	g_signal_emit (widget, signals[ARROW_CLICKED], 0);
+}
+	
+/* GtkCellEditable method implementations
+ */
+static void
+gtk_cell_editable_entry_activated (GtkEntry *entry, PlannerPopupEntry *widget)
+{
+	gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (widget));
+	gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (widget));
+}
+
+static gboolean
+gtk_cell_editable_key_press_event (GtkEntry      *entry,
+				   GdkEventKey   *key_event,
+				   PlannerPopupEntry *widget)
+{
+	if (key_event->keyval == GDK_Escape) {
+		widget->editing_canceled = TRUE;
+		
+		gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (widget));
+		gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (widget));
+		
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+static gboolean
+mpw_key_press_event (GtkWidget   *box,
+		     GdkEventKey *key_event)
+{
+	PlannerPopupEntry *widget = PLANNER_POPUP_ENTRY (box);
+	GdkEvent       tmp_event;
+	
+	if (key_event->keyval == GDK_Escape) {
+		widget->editing_canceled = TRUE;
+
+		gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (widget));
+		gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (widget));
+		
+		return TRUE;
+	}
+
+	gtk_widget_grab_focus (widget->entry);
+
+	/* Hackish :/ Synthesize a key press event for the entry. */
+	memcpy (&tmp_event, key_event, sizeof (GdkEventKey));
+
+	tmp_event.key.window = widget->entry->window;
+	tmp_event.key.send_event = TRUE;
+	
+	gtk_widget_event (widget->entry, &tmp_event);
+
+	return GTK_WIDGET_CLASS (parent_class)->key_press_event (GTK_WIDGET (widget), 
+								 key_event);
+}
+
+static void
+mpw_start_editing (GtkCellEditable *cell_editable,
+		   GdkEvent        *event)
+{
+	PlannerPopupEntry *widget = PLANNER_POPUP_ENTRY (cell_editable);
+
+	gtk_editable_select_region (GTK_EDITABLE (widget->entry), 0, -1);
+
+	g_signal_connect (G_OBJECT (widget->entry),
+			  "activate",
+			  G_CALLBACK (gtk_cell_editable_entry_activated),
+			  widget);
+	g_signal_connect (G_OBJECT (widget->entry),
+			  "key_press_event",
+			  G_CALLBACK (gtk_cell_editable_key_press_event),
+			  widget);
+	g_signal_connect (G_OBJECT (widget->button),
+			  "clicked",
+			  (GCallback) mpw_arrow_clicked,
+			  widget);
+}
+
+static void
+mpw_cell_editable_init (GtkCellEditableIface *iface)
+{
+	iface->start_editing = mpw_start_editing;
+}
+
+void
+planner_popup_entry_set_text (PlannerPopupEntry *popup, const gchar *text)
+{
+	g_return_if_fail (PLANNER_IS_POPUP_ENTRY (popup));
+
+	gtk_entry_set_text (GTK_ENTRY (popup->entry), text ? text : "");
+}
+
+const gchar *
+planner_popup_entry_get_text (PlannerPopupEntry *popup)
+{
+	g_return_val_if_fail (PLANNER_IS_POPUP_ENTRY (popup), NULL);
+
+	return gtk_entry_get_text (GTK_ENTRY (popup->entry));
+}
+
+gint
+planner_popup_get_button_width (void)
+{
+	GtkWidget *window, *button, *arrow;
+	gint       width;
+
+	GtkRequisition req;
+	
+	window = gtk_window_new (GTK_WINDOW_POPUP);
+	
+	button = gtk_button_new ();
+	gtk_widget_show (button);
+	gtk_container_add (GTK_CONTAINER (window), button);
+
+	arrow = gtk_arrow_new (GTK_ARROW_DOWN, GTK_SHADOW_OUT);
+	gtk_widget_show (arrow);
+	gtk_container_add (GTK_CONTAINER (button), arrow);
+
+	gtk_window_move (GTK_WINDOW (window), -500, -500);
+	gtk_widget_show (window);
+
+	gtk_widget_size_request (window, &req);
+	
+	width = req.width;
+
+	gtk_widget_destroy (window);
+
+	return width;
+}
+

Added: gnucash/branches/register-rewrite/src/gnome-utils/planner-popup-entry.h
===================================================================
--- gnucash/branches/register-rewrite/src/gnome-utils/planner-popup-entry.h	2007-03-08 13:23:14 UTC (rev 15690)
+++ gnucash/branches/register-rewrite/src/gnome-utils/planner-popup-entry.h	2007-03-08 21:40:06 UTC (rev 15691)
@@ -0,0 +1,67 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2001-2002 CodeFactory AB
+ * Copyright (C) 2001-2002 Richard Hult <richard at imendio.com>
+ * Copyright (C) 2001-2002 Mikael Hallendal <micke at imendio.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.
+ */
+
+#ifndef __PLANNER_POPUP_ENTRY_H__
+#define __PLANNER_POPUP_ENTRY_H__
+
+#include <pango/pango.h>
+#include <gtk/gtkeventbox.h>
+
+#define PLANNER_TYPE_POPUP_ENTRY		(planner_popup_entry_get_type ())
+#define PLANNER_POPUP_ENTRY(obj)		(GTK_CHECK_CAST ((obj), PLANNER_TYPE_POPUP_ENTRY, PlannerPopupEntry))
+#define PLANNER_POPUP_ENTRY_CLASS(klass)	(GTK_CHECK_CLASS_CAST ((klass), PLANNER_TYPE_POPUP_ENTRY, PlannerPopupEntryClass))
+#define PLANNER_IS_POPUP_ENTRY(obj)		(GTK_CHECK_TYPE ((obj), PLANNER_TYPE_POPUP_ENTRY))
+#define PLANNER_IS_POPUP_ENTRY_CLASS(klass)	(GTK_CHECK_CLASS_TYPE ((obj), PLANNER_TYPE_POPUP_ENTRY))
+#define PLANNER_POPUP_ENTRY_GET_CLASS(obj)	(GTK_CHECK_GET_CLASS ((obj), PLANNER_TYPE_POPUP_ENTRY, PlannerPopupEntryClass))
+
+typedef struct _PlannerPopupEntry      PlannerPopupEntry;
+typedef struct _PlannerPopupEntryClass PlannerPopupEntryClass;
+
+struct _PlannerPopupEntry
+{
+	GtkEventBox  parent;
+
+	GtkWidget   *hbox;
+	GtkWidget   *button;
+	GtkWidget   *entry;
+
+	gboolean     editing_canceled;
+};
+
+struct _PlannerPopupEntryClass
+{
+	GtkEventBoxClass parent_class;
+};
+
+GtkType      planner_popup_entry_get_type   (void) G_GNUC_CONST;
+
+GtkWidget   *planner_popup_entry_new        (void);
+
+void         planner_popup_entry_set_text   (PlannerPopupEntry *popup,
+					const gchar  *text);
+
+const gchar *planner_popup_entry_get_text   (PlannerPopupEntry *popup);
+
+gint         planner_popup_get_button_width (void);
+
+
+#endif /* __PLANNER_POPUP_ENTRY_H__ */



More information about the gnucash-changes mailing list