r15709 - gnucash/trunk - Convert the check printing code from Scheme to C. Add support for

David Hampton hampton at cvs.gnucash.org
Mon Mar 12 23:43:27 EDT 2007


Author: hampton
Date: 2007-03-12 23:43:24 -0400 (Mon, 12 Mar 2007)
New Revision: 15709
Trac: http://svn.gnucash.org/trac/changeset/15709

Added:
   gnucash/trunk/checks/
   gnucash/trunk/checks/Makefile.am
   gnucash/trunk/checks/deluxe.chk
   gnucash/trunk/checks/gnomeprint/
   gnucash/trunk/checks/gnomeprint/deluxe.chk
   gnucash/trunk/checks/gnomeprint/quicken.chk
   gnucash/trunk/checks/gnomeprint/quicken_wallet.chk
   gnucash/trunk/checks/quicken.chk
   gnucash/trunk/checks/quicken_wallet.chk
Removed:
   gnucash/trunk/src/scm/printing/
Modified:
   gnucash/trunk/Makefile.am
   gnucash/trunk/configure.in
   gnucash/trunk/src/app-utils/app-utils.i
   gnucash/trunk/src/app-utils/gnc-ui-util.c
   gnucash/trunk/src/app-utils/gnc-ui-util.h
   gnucash/trunk/src/gnome/dialog-print-check.c
   gnucash/trunk/src/gnome/glade/print.glade
   gnucash/trunk/src/scm/Makefile.am
   gnucash/trunk/src/scm/main.scm
Log:
Convert the check printing code from Scheme to C.  Add support for
using the GtkPrint API when compiled against gtk+ 2.10 or later.  Add
support for reading check description files instead of hard coding
check descriptions.


Modified: gnucash/trunk/Makefile.am
===================================================================
--- gnucash/trunk/Makefile.am	2007-03-13 01:18:42 UTC (rev 15708)
+++ gnucash/trunk/Makefile.am	2007-03-13 03:43:24 UTC (rev 15709)
@@ -1,5 +1,5 @@
 
-SUBDIRS = . doc lib src intl-scm packaging po accounts
+SUBDIRS = . doc lib src intl-scm packaging po accounts checks
 
 docdir = ${GNC_DOC_INSTALL_DIR}
 

Added: gnucash/trunk/checks/Makefile.am
===================================================================
--- gnucash/trunk/checks/Makefile.am	2007-03-13 01:18:42 UTC (rev 15708)
+++ gnucash/trunk/checks/Makefile.am	2007-03-13 03:43:24 UTC (rev 15709)
@@ -0,0 +1,17 @@
+
+checksdir = ${GNC_CHECKS_DIR}
+
+if HAVE_GTK_2_10
+checks_DATA = \
+	deluxe.chk \
+	quicken.chk \
+	quicken_wallet.chk
+else
+checks_DATA = \
+	gnomeprint/deluxe.chk \
+	gnomeprint/quicken.chk \
+	gnomeprint/quicken_wallet.chk
+endif
+
+EXTRA_DIST = \
+  ${checks_DATA}

Added: gnucash/trunk/checks/deluxe.chk
===================================================================
--- gnucash/trunk/checks/deluxe.chk	2007-03-13 01:18:42 UTC (rev 15708)
+++ gnucash/trunk/checks/deluxe.chk	2007-03-13 03:43:24 UTC (rev 15709)
@@ -0,0 +1,22 @@
+[Top]
+Title = Deluxe(tm) Personal Checks US-Letter
+Rotation = -90.0
+Translation = 4;492
+Show_Grid = 0
+Show_Boxes = 0
+
+[Check Items]
+Type_1 = PAYEE
+Coords_1 = 126.0;85.0
+
+Type_2 = AMOUNT_WORDS
+Coords_2 = 90.0;107.0
+
+Type_3 = AMOUNT_NUMBER
+Coords_3 = 395.0;85.0
+
+Type_4 = DATE
+Coords_4 = 343.0;54.0
+
+Type_5 = MEMO
+Coords_5 = 100.0;159.0

Added: gnucash/trunk/checks/gnomeprint/deluxe.chk
===================================================================
--- gnucash/trunk/checks/gnomeprint/deluxe.chk	2007-03-13 01:18:42 UTC (rev 15708)
+++ gnucash/trunk/checks/gnomeprint/deluxe.chk	2007-03-13 03:43:24 UTC (rev 15709)
@@ -0,0 +1,22 @@
+[Top]
+Title = Deluxe(tm) Personal Checks US-Letter
+Rotation = 90
+Translation = 232;300
+Show_Grid = 0
+Show_Boxes = 0
+
+[Check Items]
+Type_1 = PAYEE
+Coords_1 = 126.0;147.0
+
+Type_2 = AMOUNT_WORDS
+Coords_2 = 90.0;125.0
+
+Type_3 = AMOUNT_NUMBER
+Coords_3 = 395.0;147.0
+
+Type_4 = DATE
+Coords_4 = 343.0;178.0
+
+Type_5 = MEMO
+Coords_5 = 100.0;73.0

Added: gnucash/trunk/checks/gnomeprint/quicken.chk
===================================================================
--- gnucash/trunk/checks/gnomeprint/quicken.chk	2007-03-13 01:18:42 UTC (rev 15708)
+++ gnucash/trunk/checks/gnomeprint/quicken.chk	2007-03-13 03:43:24 UTC (rev 15709)
@@ -0,0 +1,28 @@
+[Top]
+Title = Quicken/QuickBooks (tm) US-Letter
+Rotation = 0.0
+Translation = 0.0;0.0
+Show_Grid = 0
+Show_Boxes = 0
+
+[Check Positions]
+Height = 252.0
+Name_1 = Top
+Name_2 = Middle
+Name_3 = Bottom
+
+[Check Items]
+Type_1 = PAYEE
+Coords_1 = 90.0;150.0;400.0;20.0
+
+Type_2 = AMOUNT_WORDS
+Coords_2 = 90.0;120.0
+
+Type_3 = AMOUNT_NUMBER
+Coords_3 = 500.0;150.0
+
+Type_4 = DATE
+Coords_4 = 500.0;185.0
+
+Type_5 = MEMO
+Coords_5 = 50.0;40.0

Added: gnucash/trunk/checks/gnomeprint/quicken_wallet.chk
===================================================================
--- gnucash/trunk/checks/gnomeprint/quicken_wallet.chk	2007-03-13 01:18:42 UTC (rev 15708)
+++ gnucash/trunk/checks/gnomeprint/quicken_wallet.chk	2007-03-13 03:43:24 UTC (rev 15709)
@@ -0,0 +1,40 @@
+[Top]
+Title = Quicken(tm) Wallet Checks w/ side stub
+Rotation = 0.0
+Translation = 0.0;0.0
+Show_Grid = 0
+Show_Boxes = 0
+
+[Check Positions]
+Height = 204.0
+Name_1 = Top
+Name_2 = Middle
+Name_3 = Bottom
+
+[Check Items]
+Type_1 = PAYEE
+Coords_1 = 231.0;140.0
+
+Type_2 = AMOUNT_WORDS
+Coords_2 = 195.0;125.0
+
+Type_3 = AMOUNT_NUMBER
+Coords_3 = 518.0;137.0
+
+Type_4 = DATE
+Coords_4 = 504.0;151.0
+
+Type_5 = MEMO
+Coords_5 = 216.0;37.0
+
+Type_6 = DATE
+Coords_6 = 36.0;151.0
+
+Type_7 = PAYEE
+Coords_7 = 26.0;126.0
+
+Type_8 = AMOUNT_NUMBER
+Coords_8 = 50.0;90.0
+
+Type_9 = MEMO
+Coords_9 = 28.0;65.0

Added: gnucash/trunk/checks/quicken.chk
===================================================================
--- gnucash/trunk/checks/quicken.chk	2007-03-13 01:18:42 UTC (rev 15708)
+++ gnucash/trunk/checks/quicken.chk	2007-03-13 03:43:24 UTC (rev 15709)
@@ -0,0 +1,28 @@
+[Top]
+Title = Quicken/QuickBooks (tm) US-Letter
+Rotation = 0.0
+Translation = 0.0;4.0
+Show_Grid = 0
+Show_Boxes = 0
+
+[Check Positions]
+Height = 252.0
+Name_1 = Top
+Name_2 = Middle
+Name_3 = Bottom
+
+[Check Items]
+Type_1 = PAYEE
+Coords_1 = 90.0;102.0;400.0;20.0
+
+Type_2 = AMOUNT_WORDS
+Coords_2 = 90.0;132.0
+
+Type_3 = AMOUNT_NUMBER
+Coords_3 = 500.0;102.0
+
+Type_4 = DATE
+Coords_4 = 500.0;67.0
+
+Type_5 = MEMO
+Coords_5 = 50.0;212.0

Added: gnucash/trunk/checks/quicken_wallet.chk
===================================================================
--- gnucash/trunk/checks/quicken_wallet.chk	2007-03-13 01:18:42 UTC (rev 15708)
+++ gnucash/trunk/checks/quicken_wallet.chk	2007-03-13 03:43:24 UTC (rev 15709)
@@ -0,0 +1,40 @@
+[Top]
+Title = Quicken(tm) Wallet Checks w/ side stub
+Rotation = 0.0
+Translation = 0.0;4.0
+Show_Grid = 0
+Show_Boxes = 0
+
+[Check Positions]
+Height = 204.0
+Name_1 = Top
+Name_2 = Middle
+Name_3 = Bottom
+
+[Check Items]
+Type_1 = PAYEE
+Coords_1 = 231.0;64.0
+
+Type_2 = AMOUNT_WORDS
+Coords_2 = 195.0;79.0
+
+Type_3 = AMOUNT_NUMBER
+Coords_3 = 518.0;67.0
+
+Type_4 = DATE
+Coords_4 = 504.0;53.0
+
+Type_5 = MEMO
+Coords_5 = 216.0;167.0
+
+Type_6 = DATE
+Coords_6 = 36.0;53.0
+
+Type_7 = PAYEE
+Coords_7 = 26.0;78.0
+
+Type_8 = AMOUNT_NUMBER
+Coords_8 = 50.0;114.0
+
+Type_9 = MEMO
+Coords_9 = 28.0;139.0

Modified: gnucash/trunk/configure.in
===================================================================
--- gnucash/trunk/configure.in	2007-03-13 01:18:42 UTC (rev 15708)
+++ gnucash/trunk/configure.in	2007-03-13 03:43:24 UTC (rev 15709)
@@ -572,11 +572,13 @@
 GNC_LIBEXECDIR='${libexecdir}/gnucash'
 
 GNC_ACCOUNTS_DIR='${GNC_SHAREDIR}/accounts'
+GNC_CHECKS_DIR='${GNC_SHAREDIR}/checks'
 GNC_GLADE_DIR='${GNC_SHAREDIR}/glade'
 GNC_UI_DIR='${GNC_SHAREDIR}/ui'
 GNC_PIXMAP_DIR='${GNC_SHAREDIR}/pixmaps'
 
 AC_SUBST(GNC_ACCOUNTS_DIR)
+AC_SUBST(GNC_CHECKS_DIR)
 AC_SUBST(GNC_CONFIGDIR)
 AC_SUBST(GNC_DOC_INSTALL_DIR)
 AC_SUBST(GNC_GLADE_DIR)
@@ -1401,6 +1403,7 @@
           accounts/pt_PT/Makefile
           accounts/sk/Makefile
           accounts/tr_TR/Makefile
+          checks/Makefile
           doc/Makefile
           doc/examples/Makefile
           intl-scm/Makefile
@@ -1497,7 +1500,6 @@
           src/report/utility-reports/test/Makefile
           src/scm/Makefile
           src/scm/gnumeric/Makefile
-          src/scm/printing/Makefile
           src/tax/Makefile
           src/tax/us/Makefile
           src/tax/us/test/Makefile

Modified: gnucash/trunk/src/app-utils/app-utils.i
===================================================================
--- gnucash/trunk/src/app-utils/app-utils.i	2007-03-13 01:18:42 UTC (rev 15708)
+++ gnucash/trunk/src/app-utils/app-utils.i	2007-03-13 03:43:24 UTC (rev 15709)
@@ -70,6 +70,9 @@
 GNCPrintAmountInfo gnc_share_print_info_places (int decplaces);
 const char * xaccPrintAmount (gnc_numeric val, GNCPrintAmountInfo info);
 
+gchar *number_to_words(gdouble val, gint64 denom);
+const gchar *printable_value (gdouble val, gint denom);
+
 gboolean gnc_reverse_balance (const Account *account);
 
 gboolean gnc_is_euro_currency(const gnc_commodity * currency);

Modified: gnucash/trunk/src/app-utils/gnc-ui-util.c
===================================================================
--- gnucash/trunk/src/app-utils/gnc-ui-util.c	2007-03-13 01:18:42 UTC (rev 15708)
+++ gnucash/trunk/src/app-utils/gnc-ui-util.c	2007-03-13 03:43:24 UTC (rev 15709)
@@ -1569,6 +1569,113 @@
 
 
 /********************************************************************\
+ ********************************************************************/
+
+#define FUDGE .00001
+
+static gchar *small_numbers[] = {
+  N_("Zero"), N_("One"), N_("Two"), N_("Three"), N_("Four"),
+  N_("Five"), N_("Six"), N_("Seven"), N_("Eight"), N_("Nine"),
+  N_("Ten"), N_("Eleven"), N_("Twelve"), N_("Thirteen"), N_("Fourteen"),
+  N_("Fifteen"), N_("Sixteen"), N_("Seventeen"), N_("Eighteen"), N_("Nineteen"),
+  N_("Twenty")};
+static gchar *medium_numbers[] = {
+  N_("Zero"), N_("Ten"), N_("Twenty"), N_("Thirty"), N_("Forty"),
+  N_("Fifty"), N_("Sixty"), N_("Seventy"), N_("Eighty"), N_("Ninety")};
+static gchar *big_numbers[] = {
+  N_("Hundred"), N_("Thousand"), N_("Million"), N_("Billion"),
+  N_("Trillion"), N_("Quadrillion"), N_("Quintillion")};
+
+static gchar *
+integer_to_words(gint64 val)
+{
+  gint64 log_val, pow_val, this_part;
+  GString *result;
+  gchar *tmp;
+
+  if (val == 0)
+    return g_strdup("zero");
+  if (val < 0)
+    val = -val;
+
+  result = g_string_sized_new(100);
+
+  while (val >= 1000) {
+    log_val = log10(val) / 3 + FUDGE;
+    pow_val = exp10(log_val * 3) + FUDGE;
+    this_part = val / pow_val;
+    val -= this_part * pow_val;
+    tmp = integer_to_words(this_part);
+    g_string_append_printf(result, "%s %s ", tmp,
+                           gettext(big_numbers[log_val]));
+    g_free(tmp);
+  }
+
+  if (val >= 100) {
+    this_part = val / 100;
+    val -= this_part * 100;
+    g_string_append_printf(result, "%s %s ",
+                           gettext(small_numbers[this_part]),
+                           gettext(big_numbers[0]));
+  }
+
+  if (val > 20) {
+    this_part = val / 10;
+    val -= this_part * 10;
+    g_string_append(result, gettext(medium_numbers[this_part]));
+    g_string_append_c(result, ' ');
+  }
+
+  if (val > 0) {
+    this_part = val;
+    val -= this_part;
+    g_string_append(result, gettext(small_numbers[this_part]));
+    g_string_append_c(result, ' ');
+  }
+
+  result = g_string_truncate(result, result->len - 1);
+  return g_string_free(result, FALSE);
+}
+
+gchar *
+number_to_words(gdouble val, gint64 denom)
+{
+  gint64 int_part, frac_part;
+  gchar *int_string, *full_string;
+
+  if (val < 0) val = -val;
+  if (denom < 0) denom = -denom;
+
+  int_part = trunc(val);
+  frac_part = round((val - int_part) * denom);
+
+  int_string = integer_to_words(int_part);
+  full_string =
+    g_strdup_printf(_("%s and %lld/%lld"), int_string, frac_part, denom);
+  g_free(int_string);
+  return full_string;
+}
+
+gchar *
+numeric_to_words(gnc_numeric val)
+{
+  return number_to_words(gnc_numeric_to_double(val),
+                         gnc_numeric_denom(val));
+}
+
+const gchar *
+printable_value (gdouble val, gint denom)
+{
+  GNCPrintAmountInfo info;
+  gnc_numeric num;
+
+  num = gnc_numeric_create(round(val * denom), denom);
+  info = gnc_share_print_info_places(log10(denom));
+  return xaccPrintAmount (num, info);
+}
+
+
+/********************************************************************\
  * xaccParseAmount                                                  *
  *   parses amount strings using locale data                        *
  *                                                                  *

Modified: gnucash/trunk/src/app-utils/gnc-ui-util.h
===================================================================
--- gnucash/trunk/src/app-utils/gnc-ui-util.h	2007-03-13 01:18:42 UTC (rev 15708)
+++ gnucash/trunk/src/app-utils/gnc-ui-util.h	2007-03-13 03:43:24 UTC (rev 15709)
@@ -275,6 +275,9 @@
 const char * xaccPrintAmount (gnc_numeric val, GNCPrintAmountInfo info);
 int xaccSPrintAmount (char *buf, gnc_numeric val, GNCPrintAmountInfo info);
 
+const gchar *printable_value(gdouble val, gint denom);
+gchar *number_to_words(gdouble val, gint64 denom);
+gchar *numeric_to_words(gnc_numeric val);
 
 /* xaccParseAmount parses in_str to obtain a numeric result. The
  *   routine will parse as much of in_str as it can to obtain a single

Modified: gnucash/trunk/src/gnome/dialog-print-check.c
===================================================================
--- gnucash/trunk/src/gnome/dialog-print-check.c	2007-03-13 01:18:42 UTC (rev 15708)
+++ gnucash/trunk/src/gnome/dialog-print-check.c	2007-03-13 03:43:24 UTC (rev 15709)
@@ -27,7 +27,9 @@
 #include <glib/gi18n.h>
 #include <stdio.h>
 #include <libguile.h>
+#include <locale.h>
 
+#include "qof.h"
 #include "gnc-date.h"
 #include "gnc-gconf-utils.h"
 #include "gnc-numeric.h"
@@ -37,11 +39,16 @@
 #include "print-session.h"
 #include "gnc-ui.h"
 #include "gnc-date-format.h"
+#include "gnc-ui-util.h"
+#include "gnc-path.h"
+#include "gnc-filepath-utils.h"
+#include "gnc-gkeyfile-utils.h"
 
-#define CHECK_PRINT_NUM_FORMATS 4
-#define CHECK_PRINT_NUM_POSITIONS 4
-#define CHECK_PRINT_NUM_UNITS 4
+#define USE_GTKPRINT HAVE_GTK_2_10
 
+#undef G_LOG_DOMAIN
+#define G_LOG_DOMAIN "gnc.printing.checks"
+
 #define GCONF_SECTION 	       "dialogs/print_checks"
 #define KEY_CHECK_FORMAT       "check_format"
 #define KEY_CHECK_POSITION     "check_position"
@@ -54,17 +61,134 @@
 #define KEY_CUSTOM_TRANSLATION "custom_translation"
 #define KEY_CUSTOM_ROTATION    "custom_rotation"
 #define KEY_CUSTOM_UNITS       "custom_units"
+#define KEY_SHOW_DATE_FMT      "show_date_format"
 
+
+#define DEFAULT_FONT "sans 12"
+#define CHECK_FMT_DIR "checks"
+#define DEGREES_TO_RADIANS (G_PI / 180.0)
+
+#define KF_GROUP_TOP       "Top"
+#define KF_GROUP_POS       "Check Positions"
+#define KF_GROUP_ITEMS     "Check Items"
+#define KF_KEY_TITLE       "Title"
+#define KF_KEY_ROTATION    "Rotation"
+#define KF_KEY_TRANSLATION "Translation"
+#define KF_KEY_FONT        "Font"
+#define KF_KEY_ALIGN       "Align"
+#define KF_KEY_SHOW_GRID   "Show_Grid"
+#define KF_KEY_SHOW_BOXES  "Show_Boxes"
+#define KF_KEY_NAME        "Name"
+#define KF_KEY_HEIGHT      "Height"
+#define KF_KEY_TYPE        "Type"
+#define KF_KEY_COORDS      "Coords"
+#define KF_KEY_TEXT        "Text"
+#define KF_KEY_FILENAME    "Filename"
+
+#if USE_GTKPRINT
+#    define GncPrintContext GtkPrintContext
+static GtkPrintSettings *settings = NULL;
+#else
+#    define GncPrintContext GnomePrintContext
+#endif
+
+
 /* Used by glade_xml_signal_autoconnect_full */
 void gnc_ui_print_check_response_cb(GtkDialog * dialog, gint response, PrintCheckDialog * pcd);
-void gnc_print_check_combobox_changed(GtkComboBox *widget, PrintCheckDialog * pcd);
+void gnc_print_check_format_changed(GtkComboBox *widget, PrintCheckDialog * pcd);
+void gnc_print_check_position_changed(GtkComboBox *widget, PrintCheckDialog * pcd);
 static void gnc_ui_print_save_dialog(PrintCheckDialog * pcd);
 static void gnc_ui_print_restore_dialog(PrintCheckDialog * pcd);
 void gnc_ui_print_restore_dialog(PrintCheckDialog * pcd);
 
+
+/** This enum defines the types of items that gnucash knows how to
+ *  print on checks.  Most refer to specific fields from a gnucash
+ *  transaction and split, but some are generic items unrelated to
+ *  gnucash. */
+#define ENUM_CHECK_ITEM_TYPE(_) \
+        _(NONE,) \
+        _(PAYEE,) \
+        _(DATE,) \
+        _(MEMO,) \
+        _(AMOUNT_NUMBER,) \
+        _(AMOUNT_WORDS,) \
+        _(TEXT,) \
+        _(PICTURE,)
+
+DEFINE_ENUM(CheckItemType, ENUM_CHECK_ITEM_TYPE)
+FROM_STRING_DEC(CheckItemType, ENUM_CHECK_ITEM_TYPE)
+FROM_STRING_FUNC(CheckItemType, ENUM_CHECK_ITEM_TYPE)
+
+/** This data structure describes a single item printed on a check.
+ *  It is build from a description in a text file. */
+typedef struct _check_item {
+
+    CheckItemType type;         /**< What type of item is this?  */
+
+    gdouble x, y;               /**< The x/y coordinates where this item
+                                 *   should be printed.  The origin for this
+                                 *   coordinate is determined by the print
+                                 *   system used.  */
+
+    gdouble w, h;               /**< Optional. The width and height of this
+                                 *   item.  Text will be clipped to this
+                                 *   size. Pictures will be shrunk if
+                                 *   necessary to fit.  */
+
+    gchar *filename;            /**< The filename for picture items. Otherwise
+                                 *   unused. */
+
+    gchar *text;                /**< The text to be displayed (for text based
+                                 *   items.) Otherwise unused.  */
+
+    gchar *font;                /**< The font to use for text based item. This
+                                 *   overrides any font in the check format.
+                                 *   Unused for non-text items. */
+
+    PangoAlignment align;       /**< The alignment of a text based item. Only
+                                 *   used for text based items when a width is
+                                 *   specified.  */
+} check_item_t;
+
+/** This data structure describes an entire page of checks.  Depending
+ *  upon the check format, the page may contain multiple checks or
+ *  only a single check.  The data structure is build from a
+ *  description in a text file. */
+typedef struct _check_format {
+
+    gchar *title;               /**< Title of this check format. Displayed to
+                                 *   user in the dialog box. */
+
+    gboolean show_grid;         /**< Print a grid pattern on the page */
+
+    gboolean show_boxes;        /**< Print boxes when width and height are
+                                 *   known. */
+
+    gdouble rotation;           /**< Rotate entire page by this amount  */
+
+    gdouble trans_x;            /**< Move entire page by this X amount  */
+
+    gdouble trans_y;            /**< Move entire page by this Y amount  */
+
+    gchar *font;                /**< Default font for this page of checks */
+
+    gdouble height;             /**< Height of one check on a page */
+
+    GSList *positions;          /**< Names of the checks on the page. */
+
+    GSList *items;              /**< List of items printed on each check  */
+} check_format_t;
+
+/** This data structure is used to manage the print check dialog, and
+ *  the overall check printing process.  It contains pointers to many
+ *  of the widgets in the dialog, pointers to the check descriptions
+ *  that have been read, and also contains the data from the gnucash
+ *  transaction/split that is to be printed.  */
 struct _print_check_dialog {
   GladeXML * xml;
   GtkWidget * dialog;
+  GtkWindow * caller_window;
 
   GncPluginPageRegister *plugin_page;
   const char    *payee;
@@ -73,7 +197,9 @@
   const char    *memo;
 
   GtkWidget * format_combobox;
+  gint format_max;
   GtkWidget * position_combobox;
+  gint position_max;
   GtkWidget * custom_table;
   GtkSpinButton * payee_x,  * payee_y;
   GtkSpinButton * date_x,   * date_y;
@@ -90,6 +216,8 @@
 
   gchar *format_string;
 
+  GSList *formats_list;
+  check_format_t *selected_format;
 };
 
 
@@ -216,6 +344,490 @@
 }
 
 
+static gdouble
+pcd_get_custom_multip(PrintCheckDialog * pcd)
+{
+    gint selected;
+
+    selected = gtk_combo_box_get_active(GTK_COMBO_BOX(pcd->units_combobox));
+    switch (selected) {
+        default:
+            return 72.0;        /* inches */
+        case 1:
+            return 28.346;      /* cm */
+        case 2:
+            return 2.8346;      /* mm */
+        case 3:
+            return 1.0;         /* points */
+    }
+}
+
+
+/** This is an auxiliary debugging function for converting an array of doubles
+ *  into a printable string. */
+static gchar *
+doubles_to_string(gdouble * dd, gint len)
+{
+    GString *str;
+    gint i;
+
+    str = g_string_new_len(NULL, 50);
+    for (i = 0; i < len; i++)
+        g_string_append_printf(str, "%f ", dd[i]);
+    return g_string_free(str, FALSE);
+}
+
+
+/** Read the information describing the placement for each item to be printed
+ *  on the check.  This information is all relative to the upper left hand
+ *  corner of a "check".  See the format_read_multicheck_info() function for
+ *  determining if there are multiple checks on a single page of paper. This
+ *  data is build into a linked list and saved as part of the check format
+ *  information.  These items will be printed in the same order they are read,
+ *  meaning that items listed later in the date file can be printed over top
+ *  of items that appear earlier in the file. */
+static GSList *
+format_read_item_placement(const gchar * file,
+                           GKeyFile * key_file, check_format_t * format)
+{
+    check_item_t *data = NULL;
+    GError *error = NULL;
+    GSList *list = NULL;
+    gchar *key, *value, *name;
+    int item_num;
+    gdouble *dd;
+    gsize dd_len;
+
+    /* Read until failure. */
+    for (item_num = 1;; item_num++) {
+
+        /* Create the per-item data structure */
+        data = g_new0(check_item_t, 1);
+        if (NULL == data)
+            return list;
+
+        /* Get the item type */
+        key = g_strdup_printf("%s_%d", KF_KEY_TYPE, item_num);
+        value = g_key_file_get_string(key_file, KF_GROUP_ITEMS, key, &error);
+        if (error) {
+            if ((error->domain == G_KEY_FILE_ERROR)
+                && (error->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND)) {
+                /* This is the expected exit from this function. */
+                goto cleanup;
+            }
+            goto failed;
+        }
+        g_debug("Check file %s, group %s, key %s, value: %s",
+                file, KF_GROUP_ITEMS, key, value);
+        g_free(key);
+
+        /* Convert the type from a string to an enum, ignoring case. */
+        name = g_utf8_strup(value, -1);
+        data->type = CheckItemTypefromString(name);
+        g_free(name);
+        g_free(value);
+
+
+        /* Get the item location */
+        key = g_strdup_printf("%s_%d", KF_KEY_COORDS, item_num);
+        dd = g_key_file_get_double_list(key_file, KF_GROUP_ITEMS,
+                                        key, &dd_len, &error);
+        if (error)
+            goto failed;
+        value = doubles_to_string(dd, dd_len);
+        g_debug("Check file %s, group %s, key %s, length %d; values: %s",
+                file, KF_GROUP_ITEMS, key, dd_len, value);
+        g_free(value);
+
+        /* Must have "x;y" or "x;y;w;h". */
+        switch (dd_len) {
+            case 4:
+                data->w = dd[2];
+                data->h = dd[3];
+                /* fall through */
+            case 2:
+                data->x = dd[0];
+                data->y = dd[1];
+                break;
+            default:
+                g_warning
+                    ("Check file %s, group %s, key %s, error: 2 or 4 values only",
+                     file, KF_GROUP_ITEMS, key);
+                goto cleanup;
+        }
+        g_free(dd);
+        g_free(key);
+
+        /* Any text item can specify a font, and can also an alignment if a
+         * width was provided for the item. These values are optional and do
+         * not cause a failure if they are missing. */
+        if (data->type != PICTURE) {
+            key = g_strdup_printf("%s_%d", KF_KEY_FONT, item_num);
+            data->font =
+                g_key_file_get_string(key_file, KF_GROUP_ITEMS, key, &error);
+            if (!error) {
+                g_debug("Check file %s, group %s, key %s, value: %s",
+                        file, KF_GROUP_ITEMS, key, data->font);
+            } else {
+                if (!((error->domain == G_KEY_FILE_ERROR)
+                      && (error->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND)))
+                    g_warning("Check file %s, group %s, key %s, error: %s",
+                              file, KF_GROUP_ITEMS, key, error->message);
+                g_clear_error(&error);
+            }
+            g_free(key);
+
+            value =
+                g_key_file_get_string(key_file, KF_GROUP_ITEMS, KF_KEY_ALIGN,
+                                      &error);
+            if (!error) {
+                g_debug("Check file %s, group %s, key %s, value: %s",
+                        file, KF_GROUP_ITEMS, key, value);
+                name = g_utf8_strdown(value, -1);
+                if (strcmp(name, "right") == 0)
+                    data->align = PANGO_ALIGN_RIGHT;
+                else if (strcmp(name, "center") == 0)
+                    data->align = PANGO_ALIGN_CENTER;
+                else
+                    data->align = PANGO_ALIGN_LEFT;
+                g_free(name);
+                g_free(value);
+            } else {
+                if (!((error->domain == G_KEY_FILE_ERROR)
+                      && (error->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND)))
+                    g_warning("Check file %s, group %s, key %s, error: %s",
+                              file, KF_GROUP_ITEMS, key, error->message);
+                data->align = PANGO_ALIGN_LEFT;
+                g_clear_error(&error);
+            }
+        }
+        /* Get any extra data for specific items. */
+        switch (data->type) {
+            case PICTURE:
+                key = g_strdup_printf("%s_%d", KF_KEY_FILENAME, item_num);
+                data->filename =
+                    g_key_file_get_string(key_file, KF_GROUP_ITEMS, key,
+                                          &error);
+                if (error)
+                    goto failed;
+                g_debug("Check file %s, group %s, key %s, value: %s",
+                        file, KF_GROUP_ITEMS, key, data->filename);
+                g_free(key);
+                break;
+            case TEXT:
+                key = g_strdup_printf("%s_%d", KF_KEY_TEXT, item_num);
+                data->text =
+                    g_key_file_get_string(key_file, KF_GROUP_ITEMS, key,
+                                          &error);
+                if (error)
+                    goto failed;
+                g_debug("Check file %s, group %s, key %s, value: %s",
+                        file, KF_GROUP_ITEMS, key, data->text);
+                g_free(key);
+                break;
+            default:
+                break;
+        }
+
+        list = g_slist_append(list, data);
+        data = NULL;
+    }
+
+    /* Should never be reached. */
+    return list;
+
+  failed:
+    g_warning("Check file %s, group %s, key %s, error: %s",
+              file, KF_GROUP_ITEMS, key, error->message);
+  cleanup:
+    if (error)
+        g_error_free(error);
+    if (data)
+        g_free(data);
+    if (key)
+        g_free(key);
+    return list;
+}
+
+
+/** Free the data describing the placement of a single item on a check. */
+static void
+format_free_item_placement(check_item_t * data)
+{
+    if (data->font)
+        g_free(data->font);
+    if (data->text)
+        g_free(data->text);
+    if (data->filename)
+        g_free(data->filename);
+    g_free(data);
+}
+
+
+/** Read the information describing whether a page contains multiple checks or
+ *  a single check.  If there are multiple checks on a page, this functions
+ *  builds a linked list of the position names and their offsets (from the
+ *  upper left corner of the page). */
+static GSList *
+format_read_multicheck_info(const gchar * file,
+                            GKeyFile * key_file, check_format_t * format)
+{
+    GError *error = NULL;
+    GSList *list = NULL;
+    gchar *key, *name;
+    int i;
+
+    key = g_strdup_printf("%s", KF_KEY_HEIGHT);
+    format->height = g_key_file_get_double(key_file, KF_GROUP_POS, key, &error);
+    if (error) {
+        if ((error->domain == G_KEY_FILE_ERROR)
+            && ((error->code == G_KEY_FILE_ERROR_GROUP_NOT_FOUND)
+                || (error->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND))) {
+            g_clear_error(&error);
+            format->height = 0.0;
+        } else {
+            g_warning("Check file %s, error reading group %s, key %s: %s",
+                      file, KF_GROUP_POS, key, error->message);
+            g_free(key);
+            return list;
+        }
+    }
+
+    for (i = 1;; i++) {
+        key = g_strdup_printf("%s_%d", KF_KEY_NAME, i);
+        name = g_key_file_get_string(key_file, KF_GROUP_POS, key, &error);
+        if (error) {
+            if ((error->domain == G_KEY_FILE_ERROR)
+                && ((error->code == G_KEY_FILE_ERROR_GROUP_NOT_FOUND)
+                    || (error->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND))) {
+                /* This is the expected exit from this function. */
+                g_free(key);
+                return list;
+            }
+            g_warning("Check file %s, error reading group %s, key %s: %s",
+                      file, KF_GROUP_POS, key, error->message);
+            g_free(key);
+            return list;
+        }
+        g_free(key);
+
+        list = g_slist_append(list, name);
+    }
+
+    /* Should never be reached. */
+    return list;
+}
+
+
+/** Free the data describing the placement of multiple checks on a page. */
+static void
+free_check_position(gchar * name)
+{
+    g_free(name);
+}
+
+
+/** Read the information describing the general layout of a page of checks.
+ *  All items in this section are optional except or the name of the check
+ *  style. */
+static gboolean
+format_read_general_info(const gchar * file,
+                         GKeyFile * key_file, check_format_t * format)
+{
+    GError *error = NULL;
+    gchar *value;
+    double *dd;
+    gsize dd_len;
+
+    format->title =
+        g_key_file_get_string(key_file, KF_GROUP_TOP, KF_KEY_TITLE, &error);
+    if (!error) {
+        g_debug("Check file %s, group %s, key %s, value: %s",
+                file, KF_GROUP_TOP, KF_KEY_TITLE, format->title);
+    } else {
+        g_warning("Check file %s, group %s, key %s, error: %s",
+                  file, KF_GROUP_TOP, KF_KEY_TITLE, error->message);
+        return FALSE;
+    }
+
+    format->show_grid =
+        g_key_file_get_boolean(key_file, KF_GROUP_TOP, KF_KEY_SHOW_GRID,
+                               &error);
+    if (!error) {
+        g_debug("Check file %s, group %s, key %s, value: %d",
+                file, KF_GROUP_TOP, KF_KEY_SHOW_GRID, format->show_grid);
+    } else {
+        if (!((error->domain == G_KEY_FILE_ERROR)
+              && (error->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND)))
+            g_warning("Check file %s, group %s, key %s, error: %s",
+                      file, KF_GROUP_TOP, KF_KEY_SHOW_GRID, error->message);
+        format->show_grid = FALSE;
+        g_clear_error(&error);
+    }
+
+    format->show_boxes =
+        g_key_file_get_boolean(key_file, KF_GROUP_TOP, KF_KEY_SHOW_BOXES,
+                               &error);
+    if (!error) {
+        g_debug("Check file %s, group %s, key %s, value: %d",
+                file, KF_GROUP_TOP, KF_KEY_SHOW_BOXES, format->show_boxes);
+    } else {
+        if (!((error->domain == G_KEY_FILE_ERROR)
+              && (error->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND)))
+            g_warning("Check file %s, group %s, key %s, error: %s",
+                      file, KF_GROUP_TOP, KF_KEY_SHOW_BOXES, error->message);
+        format->show_boxes = FALSE;
+        g_clear_error(&error);
+    }
+
+    format->font =
+        g_key_file_get_string(key_file, KF_GROUP_TOP, KF_KEY_FONT, &error);
+    if (!error) {
+        g_debug("Check file %s, group %s, key %s, value: %s",
+                file, KF_GROUP_TOP, KF_KEY_FONT, format->font);
+    } else {
+        if (!((error->domain == G_KEY_FILE_ERROR)
+              && (error->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND)))
+            g_warning("Check file %s, group %s, key %s, error: %s",
+                      file, KF_GROUP_TOP, KF_KEY_FONT, error->message);
+        format->font = g_strdup(DEFAULT_FONT);
+        g_clear_error(&error);
+    }
+
+    format->rotation =
+        g_key_file_get_double(key_file, KF_GROUP_TOP, KF_KEY_ROTATION, &error);
+    if (!error) {
+        g_debug("Check file %s, group %s, key %s, value: %f",
+                file, KF_GROUP_TOP, KF_KEY_ROTATION, format->rotation);
+    } else {
+        if (!((error->domain == G_KEY_FILE_ERROR)
+              && (error->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND)))
+            g_warning("Check file %s, group %s, key %s, error: %s",
+                      file, KF_GROUP_TOP, KF_KEY_ROTATION, error->message);
+        format->rotation = 0.0;
+        g_clear_error(&error);
+    }
+
+    dd = g_key_file_get_double_list(key_file, KF_GROUP_TOP, KF_KEY_TRANSLATION,
+                                    &dd_len, &error);
+    if (!error) {
+        value = doubles_to_string(dd, dd_len);
+        g_debug("Check file %s, group %s, key %s, length %d; values: %s",
+                file, KF_GROUP_TOP, KF_KEY_TRANSLATION, dd_len, value);
+        g_free(value);
+
+        if (dd_len == 2) {
+            format->trans_x = dd[0];
+            format->trans_y = dd[1];
+        } else {
+            g_warning("Check file %s, error top %s, key %s: 2 values only",
+                      file, KF_GROUP_TOP, KF_KEY_TRANSLATION);
+        }
+        g_free(dd);
+    } else {
+        if (!((error->domain == G_KEY_FILE_ERROR)
+              && (error->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND)))
+            g_warning("Check file %s, group top %s, key %s: %s",
+                      file, KF_GROUP_ITEMS, KF_KEY_TRANSLATION, error->message);
+        g_clear_error(&error);
+    }
+
+    return TRUE;
+}
+
+
+/** Free all of the information describing a page of checks. */
+static void
+free_check_format(check_format_t * data)
+{
+    g_free(data->title);
+    g_free(data->font);
+    g_slist_foreach(data->positions, (GFunc) free_check_position, NULL);
+    g_slist_free(data->positions);
+    g_slist_foreach(data->items, (GFunc) format_free_item_placement, NULL);
+    g_slist_free(data->items);
+    g_free(data);
+}
+
+
+/** Read a single check format file and append the resulting format to the
+ *  list of all known formats.  This function calls other functions to read
+ *  each section of the data file. */
+static void
+read_one_check_format(PrintCheckDialog * pcd,
+                      const gchar * dirname, const gchar * file)
+{
+    gchar *pathname;
+    GKeyFile *key_file;
+    check_format_t *format;
+
+    pathname = g_build_filename(dirname, file, (char *)NULL);
+    key_file = gnc_key_file_load_from_file(pathname, FALSE, FALSE);
+    g_free(pathname);
+    if (!key_file) {
+        g_warning("Check file %s, cannot load file", file);
+        return;
+    }
+
+    format = g_new0(check_format_t, 1);
+    if (format_read_general_info(file, key_file, format)) {
+        format->positions = format_read_multicheck_info(file, key_file, format);
+        format->items = format_read_item_placement(file, key_file, format);
+    }
+
+    g_key_file_free(key_file);
+    if ((NULL == format->title) || (NULL == format->items)) {
+        g_warning("Check file %s, no items read. Dropping file.", file);
+        free_check_format(format);
+        return;
+    }
+
+    pcd->formats_list = g_slist_append(pcd->formats_list, format);
+}
+
+
+/** Iterate over a single check directory, throwing out any backup files and
+ *  then calling a helper function to read and parse the check format withing
+ *  the file. */
+static void
+read_one_check_directory(PrintCheckDialog * pcd, const gchar * dirname)
+{
+    GDir *dir;
+    const gchar *filename;
+
+    dir = g_dir_open(dirname, 0, NULL);
+    if (dir) {
+        while ((filename = g_dir_read_name(dir)) != NULL) {
+            if (g_str_has_prefix(filename, "#"))
+                continue;
+            if (g_str_has_suffix(filename, ".chk"))
+                read_one_check_format(pcd, dirname, filename);
+        }
+        g_dir_close(dir);
+    }
+}
+
+
+/** Read all check formats.  This function first looks in the system directory
+ *  for check files, and then looks in the user's .gnucash directory for any
+ *  custom check files. */
+static void
+read_formats(PrintCheckDialog * pcd)
+{
+    gchar *dirname, *pkgdatadir;
+
+    pkgdatadir = gnc_path_get_pkgdatadir();
+    dirname = g_build_filename(pkgdatadir, CHECK_FMT_DIR, (char *)NULL);
+    read_one_check_directory(pcd, dirname);
+    g_free(dirname);
+    g_free(pkgdatadir);
+
+    dirname = gnc_build_dotgnucash_path(CHECK_FMT_DIR);
+    read_one_check_directory(pcd, dirname);
+    g_free(dirname);
+}
+
+
 /********************************************************************\
  * gnc_ui_print_check_dialog_create
  * make a new print check dialog and wait for it.
@@ -232,6 +844,8 @@
   GladeXML *xml;
   GtkWidget *table;
   GtkWindow *window;
+  GSList *elem;
+  GtkListStore *store;
 
   pcd = g_new0(PrintCheckDialog, 1);
   pcd->plugin_page = plugin_page;
@@ -246,6 +860,8 @@
   pcd->xml = xml;
   pcd->dialog = glade_xml_get_widget (xml, "Print Check Dialog");
 
+  read_formats(pcd);
+
   /* now pick out the relevant child widgets */
   pcd->format_combobox = glade_xml_get_widget (xml, "check_format_combobox");
   pcd->position_combobox = glade_xml_get_widget (xml, "check_position_combobox");
@@ -274,99 +890,699 @@
 
   window = GTK_WINDOW(GNC_PLUGIN_PAGE(plugin_page)->window);
   gtk_window_set_transient_for(GTK_WINDOW(pcd->dialog), window);
+  pcd->caller_window = GTK_WINDOW(window);
 
   /* Create and attach the date-format chooser */
   table = glade_xml_get_widget (xml, "options_table");
   pcd->date_format = gnc_date_format_new_without_label();
   gtk_table_attach_defaults(GTK_TABLE(table), pcd->date_format, 1, 3, 2, 7);
 
+  /* Update the combo boxes bases on the available check formats */
+  store = gtk_list_store_new (1, G_TYPE_STRING);
+  gtk_combo_box_set_model(GTK_COMBO_BOX(pcd->format_combobox),
+                          GTK_TREE_MODEL(store));
+  for (elem = pcd->formats_list; elem; elem = g_slist_next(elem)) {
+    gtk_combo_box_append_text(GTK_COMBO_BOX(pcd->format_combobox),
+                              ((check_format_t*)elem->data)->title);
+  }
+  gtk_combo_box_append_text(GTK_COMBO_BOX(pcd->format_combobox), _("Custom"));
+  pcd->format_max = g_slist_length(pcd->formats_list); /* -1 for 0 base, +1 for custom entry*/
+
+#if USE_GTKPRINT
+  gtk_widget_destroy(glade_xml_get_widget (xml, "lower_left"));
+#else
+  gtk_widget_destroy(glade_xml_get_widget (xml, "upper_left"));
+#endif
+
   gnc_ui_print_restore_dialog(pcd);
   gnc_restore_window_size(GCONF_SECTION, GTK_WINDOW(pcd->dialog));
   gtk_widget_show_all(pcd->dialog);
 }
 
 /********************************************************************\
+ * Print check contents to the page.
+\********************************************************************/
+
+
+/** Draw a grid pattern on the page to be printed.  This grid is helpful when
+ *  figuring out the offsets for where to print various items on the page. */
+static void
+draw_grid(GncPrintContext * context, gint width, gint height)
+{
+    const double dash_pattern[2] = { 1.0, 5.0 };
+#if USE_GTKPRINT
+    PangoFontDescription *desc;
+    PangoLayout *layout;
+    cairo_t *cr;
+#endif
+    gchar *text;
+    gint i;
+
+#if USE_GTKPRINT
+    /* Initialize for printing text */
+    layout = gtk_print_context_create_pango_layout(context);
+    desc = pango_font_description_from_string("sans 12");
+    pango_layout_set_font_description(layout, desc);
+    pango_font_description_free(desc);
+    pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT);
+    pango_layout_set_width(layout, -1);
+#endif
+
+    /* Set up the line to draw with. */
+#if USE_GTKPRINT
+    cr = gtk_print_context_get_cairo_context(context);
+    cairo_save(cr);
+    cairo_set_line_width(cr, 1.0);
+    cairo_set_line_cap(cr, CAIRO_LINE_JOIN_ROUND);
+    cairo_set_dash(cr, dash_pattern, 2, 0);
+#else
+    gnome_print_gsave(context);
+    gnome_print_setlinewidth(context, 1.0);
+    gnome_print_setlinecap(context, 2);
+    gnome_print_setdash(context, 2, dash_pattern, 0);
+#endif
+
+    /* Draw horizontal lines */
+    for (i = -200; i < (height + 200); i += 50) {
+        text = g_strdup_printf("%d", (int)i);
+#if USE_GTKPRINT
+        cairo_move_to(cr, -200, i);
+        cairo_line_to(cr, width + 200, i);
+        cairo_stroke(cr);
+        pango_layout_set_text(layout, text, -1);
+        cairo_move_to(cr, 0, i);
+        pango_cairo_show_layout(cr, layout);
+#else
+        gnome_print_line_stroked(context, -200, i, width + 200, i);
+        gnome_print_moveto(context, 0, i);
+        gnome_print_show(context, text);
+#endif
+        g_free(text);
+    }
+
+    /* Draw vertical lines */
+    for (i = -200; i < (width + 200); i += 50) {
+        text = g_strdup_printf("%d", (int)i);
+#if USE_GTKPRINT
+        cairo_move_to(cr, i, -200);
+        cairo_line_to(cr, i, height + 200);
+        cairo_stroke(cr);
+        pango_layout_set_text(layout, text, -1);
+        cairo_move_to(cr, i, 0);
+        pango_cairo_show_layout(cr, layout);
+#else
+        gnome_print_line_stroked(context, i, -200, i, height + 200);
+        gnome_print_moveto(context, i, 0);
+        gnome_print_show(context, text);
+#endif
+        g_free(text);
+    }
+
+    /* Clean up after ourselves */
+#if USE_GTKPRINT
+    cairo_restore(cr);
+    g_object_unref(layout);
+#else
+    gnome_print_gsave(context);
+#endif
+}
+
+
+/** Print a single line of text to the printed page.  If a width and height
+ *  are specified, the line will be wrapped at the specified width, and the
+ *  resulting text will be clipped if it does not fit in the space
+ *  available. */
+static gdouble
+draw_text(GncPrintContext * context, const gchar * text, check_item_t * data,
+          PangoFontDescription *default_desc)
+{
+#if USE_GTKPRINT
+    PangoFontDescription *desc;
+    PangoLayout *layout;
+    cairo_t *cr;
+    gint layout_height, layout_width;
+    gdouble width, height;
+
+    /* Initialize for printing text */
+    layout = gtk_print_context_create_pango_layout(context);
+    if (data->font) {
+      desc = pango_font_description_from_string(data->font);
+      pango_layout_set_font_description(layout, desc);
+      pango_font_description_free(desc);
+    } else {
+      pango_layout_set_font_description(layout, default_desc);
+    }
+    pango_layout_set_alignment(layout,
+                               data->w ? data->align : PANGO_ALIGN_LEFT);
+    pango_layout_set_width(layout, data->w ? data->w * PANGO_SCALE : -1);
+    pango_layout_set_text(layout, text, -1);
+    pango_layout_get_size(layout, &layout_width, &layout_height);
+    width = (gdouble) layout_width / PANGO_SCALE;
+    height = (gdouble) layout_height / PANGO_SCALE;
+
+    cr = gtk_print_context_get_cairo_context(context);
+    cairo_save(cr);
+
+    /* Clip text to the enclosing rectangle */
+    if (data->w && data->h) {
+        g_debug("Text clip rectangle, coords %f,%f, size %f,%f",
+                data->x, data->y - data->h, data->w, data->h);
+        cairo_rectangle(cr, data->x, data->y - data->h, data->w, data->h);
+        cairo_clip_preserve(cr);
+    }
+
+    /* Draw the text */
+    g_debug("Text move to %f,%f, print '%s'", data->x, data->y, text);
+    cairo_move_to(cr, data->x, data->y - height);
+    pango_cairo_show_layout(cr, layout);
+
+    /* Clean up after ourselves */
+    cairo_restore(cr);
+    g_object_unref(layout);
+    return width;
+#else
+    g_debug("Text move to %f,%f, print '%s'", data->x, data->y, text);
+    gnome_print_moveto(context, data->x, data->y);
+    gnome_print_show(context, text);
+    return 0.0;
+#endif
+}
+
+
+/** Print a single image to the printed page.  This picture will be scaled
+ *  down to fit in the specified size rectangle.  Scaling is done with the
+ *  proportions locked 1:1 so as not to distort the image. */
+#if USE_GTKPRINT
+static void
+draw_picture(GtkPrintContext * context, check_item_t * data)
+{
+    cairo_t *cr;
+    GdkPixbuf *pixbuf, *scaled_pixbuf;
+    GtkImage *image;
+    gint pix_w, pix_h;
+    gdouble scale_w, scale_h, scale;
+
+    cr = gtk_print_context_get_cairo_context(context);
+    cairo_save(cr);
+
+    /* Get the picture. */
+    image = GTK_IMAGE(gtk_image_new_from_file(data->filename));
+    pixbuf = gtk_image_get_pixbuf(image);
+    pix_w = gdk_pixbuf_get_width(pixbuf);
+    pix_h = gdk_pixbuf_get_height(pixbuf);
+
+    /* Draw the enclosing rectangle */
+    if (data->w && data->h) {
+        cairo_rectangle(cr, data->x, data->y - data->h, data->w, data->h);
+        g_debug("Picture clip rectangle, user coords %f,%f, user size %f,%f",
+                data->x, data->y - data->h, data->w, data->h);
+    } else {
+        cairo_rectangle(cr, data->x, data->y - pix_h, pix_w, pix_h);
+        g_debug("Picture clip rectangle, user coords %f,%f, pic size %d,%d",
+                data->x, data->y - data->h, pix_w, pix_h);
+    }
+    cairo_clip_preserve(cr);
+
+    /* Scale down to fit.  Never scale up. */
+    scale_w = scale_h = 1;
+    if (data->w && (pix_w > data->w))
+        scale_w = data->w / pix_w;
+    if (data->h && (pix_h > data->h))
+        scale_h = data->h / pix_h;
+    scale = MIN(scale_w, scale_h);
+
+    if (scale != 1) {
+        scaled_pixbuf = gdk_pixbuf_scale_simple(pixbuf, pix_w * scale,
+                                                pix_h * scale,
+                                                GDK_INTERP_BILINEAR);
+        pix_h = gdk_pixbuf_get_height(scaled_pixbuf);
+        gdk_cairo_set_source_pixbuf(cr, scaled_pixbuf, data->x,
+                                    data->y - pix_h);
+        g_object_unref(scaled_pixbuf);
+    } else {
+        gdk_cairo_set_source_pixbuf(cr, pixbuf, data->x, data->y - pix_h);
+    }
+    cairo_paint(cr);
+
+    /* Clean up after ourselves */
+    cairo_restore(cr);
+    gtk_widget_destroy(GTK_WIDGET(image));
+}
+#endif
+
+
+#define DATE_FMT_HEIGHT 8
+#define DATE_FMT_SLOP   2
+
+/* There is a new Canadian requirement that all software that prints the date
+ * on a check must also print the format of that date underneath using a 6-8
+ * point font.  This function implements that requirement.  It requires the
+ * font description used in printing the date so that it can print in the same
+ * font using a smaller point size.  It also requires width of the printed
+ * date as an argument, allowing it to center the format string under the
+ * date.
+ *
+ * Note: This code only prints a date if the user has explicitly requested it
+ * via a preference (gconf) setting.  This is because gnucash has no way of
+ * knowing if the user's checks already have a date format printed on them.
+ */
+static void
+draw_date_format(GncPrintContext * context, const gchar *date_format,
+                 check_item_t * data, PangoFontDescription *default_desc,
+                 gdouble width)
+{
+#if USE_GTKPRINT
+    PangoFontDescription *date_desc;
+    check_item_t date_item;
+    gchar *text = NULL, *expanded = NULL;
+    const gchar *thislocale, *c;
+    GString *cdn_fmt;
+
+    thislocale = setlocale(LC_ALL, NULL);
+    if (!gnc_gconf_get_bool(GCONF_SECTION, KEY_SHOW_DATE_FMT, NULL))
+        return;
+
+    date_desc = pango_font_description_copy_static(default_desc);
+    pango_font_description_set_size(date_desc, DATE_FMT_HEIGHT * PANGO_SCALE);
+    date_item = *data;
+    date_item.y += (DATE_FMT_HEIGHT + DATE_FMT_SLOP);
+    date_item.w = width;
+    date_item.h = DATE_FMT_HEIGHT + DATE_FMT_SLOP;
+    date_item.align = PANGO_ALIGN_CENTER;
+
+    /* This is a date format string. It should only contain ascii. */
+    cdn_fmt = g_string_new_len(NULL, 50);
+    for (c = date_format; c && *c; ) {
+        if ((c[0] != '%') || (c[1] == '\0')) {
+            c += 1;
+            continue;
+        }
+        switch (c[1]) {
+            case 'F':
+                cdn_fmt = g_string_append(cdn_fmt, "YYYYMMDD");
+                break;
+            case 'Y':
+                cdn_fmt = g_string_append(cdn_fmt, "YYYY");
+                break;
+            case 'y':
+                cdn_fmt = g_string_append(cdn_fmt, "YY");
+                break;
+            case 'm':
+                cdn_fmt = g_string_append(cdn_fmt, "MM");
+                break;
+            case 'd':
+            case 'e':
+                cdn_fmt = g_string_append(cdn_fmt, "DD");
+                break;
+            case 'x':
+                expanded = g_strdup_printf("%s%s",
+                                           qof_date_format_get_string(QOF_DATE_FORMAT_LOCALE),
+                                           c + 2);
+                c = expanded;
+                continue;
+            default:
+                break;
+        }
+        c += 2;
+    }
+
+    text = g_string_free(cdn_fmt, FALSE);
+    draw_text(context, text, &date_item, date_desc);
+    g_free(text);     
+    if (expanded)
+        g_free(expanded);
+    pango_font_description_free(date_desc);
+#endif
+}
+
+
+/** Print each of the items that in the description of a single check.  This
+ *  function uses helper functions to print text based and picture based
+ *  items. */
+static void
+draw_page_items(GncPrintContext * context,
+                gint page_nr, check_format_t * format, gpointer user_data)
+{
+    PrintCheckDialog *pcd = (PrintCheckDialog *) user_data;
+    PangoFontDescription *default_desc, *date_desc;
+    GNCPrintAmountInfo info;
+    const gchar *date_format;
+    gchar *text = NULL, buf[100];
+    GSList *elem;
+    check_item_t *item, date_item;
+    gdouble width;
+    GDate *date;
+
+    default_desc = pango_font_description_from_string(format->font);
+
+    /* Now put the actual data onto the page. */
+    for (elem = format->items; elem; elem = g_slist_next(elem)) {
+        item = elem->data;
+
+        switch (item->type) {
+            case DATE:
+                date = g_date_new();
+                g_date_set_time(date, pcd->date);
+                date_format =
+                    gnc_date_format_get_custom(GNC_DATE_FORMAT
+                                               (pcd->date_format));
+                g_date_strftime(buf, 100, date_format, date);
+                width = draw_text(context, buf, item, default_desc);
+		draw_date_format(context, date_format, item, default_desc, width);
+                g_date_free(date);
+                break;
+
+            case PAYEE:
+                draw_text(context, pcd->payee, item, default_desc);
+                break;
+
+            case MEMO:
+                draw_text(context, pcd->memo, item, default_desc);
+                break;
+
+            case AMOUNT_NUMBER:
+                info = gnc_default_print_info(FALSE);
+                draw_text(context, xaccPrintAmount(pcd->amount, info),
+                          item, default_desc);
+                break;
+
+            case AMOUNT_WORDS:
+                text = numeric_to_words(pcd->amount);
+                draw_text(context, text, item, default_desc);
+                g_free(text);
+                break;
+
+            case TEXT:
+                draw_text(context, item->text, item, default_desc);
+                break;
+
+#if USE_GTKPRINT
+            case PICTURE:
+                draw_picture(context, item);
+                break;
+#endif
+
+            default:
+                text = g_strdup_printf("(unknown check field %d)", item->type);
+                draw_text(context, text, item, default_desc);
+                g_free(text);
+        }
+    }
+
+    pango_font_description_free(default_desc);
+}
+
+
+#if USE_GTKPRINT
+/** Print each of the items that in the description of a single check.  This
+ *  function uses helper functions to print text based and picture based
+ *  items. */
+static void
+draw_page_boxes(GncPrintContext * context,
+                gint page_nr, check_format_t * format, gpointer user_data)
+{
+    cairo_t *cr;
+    GSList *elem;
+    check_item_t *item;
+
+    cr = gtk_print_context_get_cairo_context(context);
+
+    /* Now put the actual data onto the page. */
+    for (elem = format->items; elem; elem = g_slist_next(elem)) {
+        item = elem->data;
+        if (!item->w || !item->h)
+            continue;
+        cairo_rectangle(cr, item->x, item->y - item->h, item->w, item->h);
+        cairo_stroke(cr);
+    }
+}
+
+
+/** Print an entire page based upon the layout in a check description file.
+ *  This function takes care of translating/rotating the page, calling the function to print the grid
+ *  pattern (if requested), an
+
+each of the items that in the description of a single check.  This
+ *  function uses helper functions to print text based and picture based
+ *  items. */
+static void
+draw_page_format(GncPrintContext * context,
+                 gint page_nr, check_format_t * format, gpointer user_data)
+{
+    PrintCheckDialog *pcd = (PrintCheckDialog *) user_data;
+    cairo_t *cr;
+    gint i;
+    gdouble x, y, multip;
+
+    cr = gtk_print_context_get_cairo_context(context);
+    cairo_translate(cr, format->trans_x, format->trans_y);
+    g_debug("Page translated by %f,%f", format->trans_x, format->trans_y);
+    cairo_rotate(cr, format->rotation * DEGREES_TO_RADIANS);
+    g_debug("Page rotated by %f degrees", format->rotation);
+
+    /* The grid is useful when determining check layouts */
+    if (format->show_grid) {
+        draw_grid(context,
+                  gtk_print_context_get_width(context),
+                  gtk_print_context_get_height(context));
+    }
+
+    /* Translate all subsequent check items if requested. */
+    i = gtk_combo_box_get_active(GTK_COMBO_BOX(pcd->position_combobox));
+    if ((i >= 0) && (i < pcd->position_max)) {
+        y = format->height * i;
+        cairo_translate(cr, 0, y);
+        g_debug("Position translated by %f (pre-defined)", y);
+    } else {
+        multip = pcd_get_custom_multip(pcd);
+        x = multip * gtk_spin_button_get_value(pcd->translation_x);
+        y = multip * gtk_spin_button_get_value(pcd->translation_y);
+        cairo_translate(cr, x, y);
+        g_debug("Position translated by %f (custom)", y);
+    }
+
+    /* Draw layout boxes if requested. Also useful when determining check
+     * layouts. */
+    if (format->show_boxes)
+      draw_page_boxes(context, page_nr, format, user_data);
+
+    /* Draw the actual check data. */
+    draw_page_items(context, page_nr, format, user_data);
+}
+
+#else
+
+static void
+draw_page_format(PrintSession * ps, check_format_t * format, gpointer user_data)
+{
+    PrintCheckDialog *pcd = (PrintCheckDialog *) user_data;
+    GnomePrintConfig *config;
+    gint i;
+    GSList *elem;
+    check_item_t *item;
+    gdouble width, height, x, y, multip;
+
+    config = gnome_print_job_get_config(ps->job);
+    gnome_print_job_get_page_size_from_config(config, &width, &height);
+
+    gnome_print_gsave(ps->context);
+    gnome_print_translate(ps->context, format->trans_x, format->trans_y);
+    g_debug("Page translated by %f,%f", format->trans_x, format->trans_y);
+    gnome_print_rotate(ps->context, format->rotation);
+    g_debug("Page rotated by %f degrees", format->rotation);
+
+    /* The grid is useful when determining check layouts */
+    if (format->show_grid) {
+        draw_grid(ps->context, width, height);
+    }
+
+    /* Translate all subsequent check items if requested. */
+    i = gtk_combo_box_get_active(GTK_COMBO_BOX(pcd->position_combobox));
+    if ((i >= 0) && (i < pcd->position_max)) {
+        y = height - (format->height * (i + 1));
+        gnome_print_translate(ps->context, 0, y);
+        g_debug("Check translated by %f (pre-defined)", y);
+    } else {
+        multip = pcd_get_custom_multip(pcd);
+        x = multip * gtk_spin_button_get_value(pcd->translation_x);
+        y = multip * gtk_spin_button_get_value(pcd->translation_y);
+        gnome_print_translate(ps->context, x, y);
+        g_debug("Check translated by %f (custom)", y);
+    }
+
+    /* Draw layout boxes if requested. Also useful when determining check
+     * layouts. */
+    if (format->show_boxes) {
+        for (elem = format->items; elem; elem = g_slist_next(elem)) {
+            item = elem->data;
+            if (!item->w || !item->h)
+                continue;
+            gnome_print_rect_stroked(ps->context, item->x, item->y, item->w,
+                                     item->h);
+        }
+    }
+
+    draw_page_items(ps->context, 1, format, user_data);
+}
+#endif
+
+static void
+draw_page_custom(GncPrintContext * context, gint page_nr, gpointer user_data)
+{
+    PrintCheckDialog *pcd = (PrintCheckDialog *) user_data;
+    GNCPrintAmountInfo info;
+    PangoFontDescription *desc;
+#if USE_GTKPRINT
+    cairo_t *cr;
+#endif
+    const gchar *date_format;
+    gchar *text = NULL, buf[100];
+    check_item_t item = { 0 };
+    gdouble x, y, multip, degrees;
+    GDate *date;
+
+    desc = pango_font_description_from_string("sans 12");
+
+    multip = pcd_get_custom_multip(pcd);
+    degrees = gtk_spin_button_get_value(pcd->check_rotation);
+#if USE_GTKPRINT
+    cr = gtk_print_context_get_cairo_context(context);
+    cairo_rotate(cr, degrees * DEGREES_TO_RADIANS);
+#else
+    gnome_print_rotate(context, degrees);
+#endif
+    g_debug("Page rotated by %f degrees", degrees);
+
+    x = multip * gtk_spin_button_get_value(pcd->translation_x);
+    y = multip * gtk_spin_button_get_value(pcd->translation_y);
+#if USE_GTKPRINT
+    cairo_translate(cr, x, y);
+#else
+    gnome_print_translate(context, x, y);
+#endif
+    g_debug("Page translated by %f,%f", x, y);
+
+    item.x = multip * gtk_spin_button_get_value(pcd->payee_x);
+    item.y = multip * gtk_spin_button_get_value(pcd->payee_y);
+    draw_text(context, pcd->payee, &item, desc);
+
+    item.x = multip * gtk_spin_button_get_value(pcd->date_x);
+    item.y = multip * gtk_spin_button_get_value(pcd->date_y);
+    date = g_date_new();
+    g_date_set_time(date, pcd->date);
+    date_format = gnc_date_format_get_custom(GNC_DATE_FORMAT(pcd->date_format));
+    g_date_strftime(buf, 100, date_format, date);
+    draw_text(context, buf, &item, desc);
+    g_date_free(date);
+
+    item.x = multip * gtk_spin_button_get_value(pcd->words_x);
+    item.y = multip * gtk_spin_button_get_value(pcd->words_y);
+    info = gnc_default_print_info(FALSE);
+    draw_text(context, xaccPrintAmount(pcd->amount, info), &item, desc);
+
+    item.x = multip * gtk_spin_button_get_value(pcd->number_x);
+    item.y = multip * gtk_spin_button_get_value(pcd->number_y);
+    text = numeric_to_words(pcd->amount);
+    draw_text(context, text, &item, desc);
+    g_free(text);
+
+    item.x = multip * gtk_spin_button_get_value(pcd->memo_x);
+    item.y = multip * gtk_spin_button_get_value(pcd->memo_y);
+    draw_text(context, pcd->memo, &item, desc);
+
+    pango_font_description_free(desc);
+}
+
+#if USE_GTKPRINT
+/* Print a page of checks. Today, check printing only prints one check at a
+ * time.  When its extended to print multiple checks, this will need to take
+ * into account the number of checks to print, the number of checks on a page,
+ * and the starting check position on the page. This function is called once
+ * by the GtkPrint code once for each page to be printed. */
+static void
+draw_page(GtkPrintOperation * operation,
+          GtkPrintContext * context, gint page_nr, gpointer user_data)
+{
+    PrintCheckDialog *pcd = (PrintCheckDialog *) user_data;
+    check_format_t *format;
+
+    format = pcd->selected_format;
+    if (format)
+        draw_page_format(context, page_nr, format, user_data);
+    else
+        draw_page_custom(context, page_nr, user_data);
+}
+
+
+/* Compute the number of pages required to complete this print operation.
+ * Today, check printing only prints one check at a time.  When its extended to 
+ * print multiple checks, this will need to take into account the number of
+ * checks to print, the number of checks on a page, and the starting check
+ * position on the page. This function is called once by the GtkPrint code to
+ * determine the number of pages required to complete the print operation. */
+static void
+begin_print(GtkPrintOperation * operation,
+            GtkPrintContext * context, gpointer user_data)
+{
+    gtk_print_operation_set_n_pages(operation, 1);
+}
+
+/********************************************************************\
  * gnc_ui_print_check_dialog_ok_cb
 \********************************************************************/
 
 static void
 gnc_ui_print_check_dialog_ok_cb(PrintCheckDialog * pcd)
 {
-  SCM        make_check_format = scm_c_eval_string("make-print-check-format");
-  SCM        print_check = scm_c_eval_string("gnc:print-check");
-  SCM        format_data;
-  SCM        fmt, posn, cust_format, date_format;
-  int        sel_option;
-  double     multip = 72.0;
+    GtkPrintOperation *print;
+    GtkPrintOperationResult res;
 
-  char       * formats[]   = { "quicken", "deluxe", "wallet", "custom" };
-  char       * positions[] = { "top", "middle", "bottom", "custom" };
+    print = gtk_print_operation_new();
 
-  sel_option = gtk_combo_box_get_active(GTK_COMBO_BOX(pcd->format_combobox));
-  if (-1 == sel_option)
-    return;
-  fmt = scm_str2symbol(formats[sel_option]);
+    if (settings != NULL)
+        gtk_print_operation_set_print_settings(print, settings);
+    gtk_print_operation_set_unit(print, GTK_UNIT_POINTS);
+    gtk_print_operation_set_use_full_page(print, TRUE);
+    g_signal_connect(print, "begin_print", G_CALLBACK(begin_print), NULL);
+    g_signal_connect(print, "draw_page", G_CALLBACK(draw_page), pcd);
 
-  sel_option = gtk_combo_box_get_active(GTK_COMBO_BOX(pcd->position_combobox));
-  if (-1 == sel_option)
-    return;
-  posn = scm_str2symbol(positions[sel_option]);
+    res = gtk_print_operation_run(print,
+                                  GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
+                                  pcd->caller_window, NULL);
 
-  sel_option = gtk_combo_box_get_active(GTK_COMBO_BOX(pcd->units_combobox));
-  switch(sel_option) {
-  case -1: return;
-  case 0:  multip = 72.0; break;   /* inches */
-  case 1:  multip = 28.346; break; /* cm */
-  case 2:  multip = 2.8346; break; /* mm */
-  case 3:  multip = 1.0; break;    /* points */
-  }
-    
-  date_format = scm_makfrom0str
-    (gnc_date_format_get_custom(GNC_DATE_FORMAT(pcd->date_format)));
-  
-  cust_format = 
-    SCM_LIST7
-    (scm_cons(scm_str2symbol("payee"),
-	      SCM_LIST2(scm_make_real(multip*gtk_spin_button_get_value(pcd->payee_x)),
-			scm_make_real(multip*gtk_spin_button_get_value(pcd->payee_y)))),
-     scm_cons(scm_str2symbol("date"),
-	      SCM_LIST2(scm_make_real(multip*gtk_spin_button_get_value(pcd->date_x)),
-			scm_make_real(multip*gtk_spin_button_get_value(pcd->date_y)))),
-     scm_cons(scm_str2symbol("amount-words"),
-	      SCM_LIST2(scm_make_real(multip*gtk_spin_button_get_value(pcd->words_x)),
-			scm_make_real(multip*gtk_spin_button_get_value(pcd->words_y)))),
-     scm_cons(scm_str2symbol("amount-number"),
-	      SCM_LIST2(scm_make_real(multip*gtk_spin_button_get_value(pcd->number_x)),
-			scm_make_real(multip*gtk_spin_button_get_value(pcd->number_y)))),
-     scm_cons(scm_str2symbol("memo"),
-	      SCM_LIST2(scm_make_real(multip*gtk_spin_button_get_value(pcd->memo_x)),
-			scm_make_real(multip*gtk_spin_button_get_value(pcd->memo_y)))),
-     scm_cons(scm_str2symbol("translate"),
-	      SCM_LIST2(scm_make_real(multip*gtk_spin_button_get_value(pcd->translation_x)),
-			scm_make_real(multip*gtk_spin_button_get_value(pcd->translation_y)))),
-     scm_cons(scm_str2symbol("rotate"),
-	      scm_make_real(gtk_spin_button_get_value(pcd->check_rotation))));
+    if (res == GTK_PRINT_OPERATION_RESULT_APPLY) {
+        if (settings != NULL)
+            g_object_unref(settings);
+        settings = g_object_ref(gtk_print_operation_get_print_settings(print));
+    }
 
-  /* hide the window */
-  gtk_widget_hide(pcd->dialog);
+    g_object_unref(print);
+}
 
-  /* now call the callback passed in from the scheme side with 
-     the format as an arg */
-  format_data = scm_apply(make_check_format,
-			  SCM_LIST4(fmt, posn, date_format, cust_format),
-			  SCM_EOL);
+#else
 
-  scm_apply(print_check,
-	    SCM_LIST5(format_data,
-		      scm_makfrom0str(pcd->payee),
-		      scm_make_real(gnc_numeric_to_double (pcd->amount)),
-		      scm_ulong2num(pcd->date),
-		      scm_makfrom0str(pcd->memo)),
-	    SCM_EOL);
-  
+static void
+gnc_ui_print_check_dialog_ok_cb(PrintCheckDialog * pcd)
+{
+  PrintSession *ps;
+  check_format_t *format;
+
+  ps = gnc_print_session_create(TRUE);
+
+  format = pcd->selected_format;
+  if (format) {
+    draw_page_format(ps, format, pcd);
+  } else {
+    draw_page_custom(ps->context, 1, pcd);
+  }
+
+  gnc_print_session_done(ps);
+  gnc_print_session_destroy(ps);
 }
+#endif
 
 
+
 static void
 gnc_print_check_set_sensitive (GtkWidget *widget, gpointer data)
 {
@@ -376,29 +1592,71 @@
 
 
 void
-gnc_print_check_combobox_changed (GtkComboBox *widget,
+gnc_print_check_position_changed (GtkComboBox *widget,
 				  PrintCheckDialog * pcd)
 {
   gboolean sensitive;
   gint value;
 
-  value = gtk_combo_box_get_active(GTK_COMBO_BOX(pcd->format_combobox));
+  value = gtk_combo_box_get_active(GTK_COMBO_BOX(pcd->position_combobox));
   if (-1 == value)
     return;
-  sensitive = (value == (CHECK_PRINT_NUM_FORMATS - 1));
+  sensitive = (value == pcd->position_max);
+  gtk_widget_set_sensitive(GTK_WIDGET(pcd->translation_label), sensitive);
+  gtk_widget_set_sensitive(GTK_WIDGET(pcd->translation_x), sensitive);
+  gtk_widget_set_sensitive(GTK_WIDGET(pcd->translation_y), sensitive);
+}
+
+void
+gnc_print_check_format_changed (GtkComboBox *widget,
+                                PrintCheckDialog * pcd)
+{
+  GtkListStore *store;
+  gboolean sensitive;
+  gint fnum, pnum;
+  check_format_t *format;
+  GSList *elem;
+
+  fnum = gtk_combo_box_get_active(GTK_COMBO_BOX(pcd->format_combobox));
+  if (-1 == fnum)
+    return;
+  pnum = gtk_combo_box_get_active(GTK_COMBO_BOX(pcd->position_combobox));
+
+  /* Update the positions combobox */
+  format = g_slist_nth_data(pcd->formats_list, fnum);
+  pcd->selected_format = format;
+  g_signal_handlers_block_by_func(pcd->position_combobox,
+                                  gnc_print_check_position_changed, pcd);
+  store = gtk_list_store_new (1, G_TYPE_STRING);
+  gtk_combo_box_set_model(GTK_COMBO_BOX(pcd->position_combobox),
+                          GTK_TREE_MODEL(store));
+  if (format) {
+    pcd->position_max = g_slist_length(format->positions); /* -1 for 0 base, +1 for custom entry */
+    for (elem = format->positions; elem; elem = g_slist_next(elem)) {
+      gtk_combo_box_append_text(GTK_COMBO_BOX(pcd->position_combobox), elem->data);
+    }
+  } else {
+    pcd->position_max = 0;
+  }
+  gtk_combo_box_append_text(GTK_COMBO_BOX(pcd->position_combobox), _("Custom"));
+  pnum = MIN(pnum, pcd->position_max);
+  gtk_combo_box_set_active(GTK_COMBO_BOX(pcd->position_combobox), pnum);
+  g_signal_handlers_unblock_by_func(pcd->position_combobox,
+                                    gnc_print_check_position_changed, pcd);
+
+  /* If there's only one thing in the position combobox, make it insensitive */
+  sensitive = (pcd->position_max > 0);
+  gtk_widget_set_sensitive(GTK_WIDGET(pcd->position_combobox), sensitive);
+  
+  /* Update the custom page */
+  sensitive = (fnum == pcd->format_max);
   gtk_container_foreach(GTK_CONTAINER(pcd->custom_table),
 			gnc_print_check_set_sensitive,
 			GINT_TO_POINTER(sensitive));
   if (sensitive == TRUE)
     return;
   
-  value = gtk_combo_box_get_active(GTK_COMBO_BOX(pcd->position_combobox));
-  if (-1 == value)
-    return;
-  sensitive = (value == (CHECK_PRINT_NUM_POSITIONS - 1));
-  gtk_widget_set_sensitive(GTK_WIDGET(pcd->translation_label), sensitive);
-  gtk_widget_set_sensitive(GTK_WIDGET(pcd->translation_x), sensitive);
-  gtk_widget_set_sensitive(GTK_WIDGET(pcd->translation_y), sensitive);
+  gnc_print_check_position_changed(widget, pcd);
 }
 
 void
@@ -414,7 +1672,8 @@
     case GTK_RESPONSE_OK:
       gnc_ui_print_check_dialog_ok_cb(pcd);
       gnc_ui_print_save_dialog(pcd);
-      /* fall through */
+      gnc_save_window_size(GCONF_SECTION, GTK_WINDOW(dialog));
+      break;
 
     case GTK_RESPONSE_CANCEL:
       gnc_save_window_size(GCONF_SECTION, GTK_WINDOW(dialog));
@@ -423,5 +1682,7 @@
 
   gtk_widget_destroy(pcd->dialog);
   g_object_unref(pcd->xml);
+  g_slist_foreach(pcd->formats_list, (GFunc)free_check_format, NULL);
+  g_slist_free(pcd->formats_list);
   g_free(pcd);
 }

Modified: gnucash/trunk/src/gnome/glade/print.glade
===================================================================
--- gnucash/trunk/src/gnome/glade/print.glade	2007-03-13 01:18:42 UTC (rev 15708)
+++ gnucash/trunk/src/gnome/glade/print.glade	2007-03-13 03:43:24 UTC (rev 15709)
@@ -193,7 +193,7 @@
 Custom</property>
 		  <property name="add_tearoffs">False</property>
 		  <property name="focus_on_click">True</property>
-		  <signal name="changed" handler="gnc_print_check_combobox_changed" last_modification_time="Sat, 28 Jan 2006 04:19:16 GMT"/>
+		  <signal name="changed" handler="gnc_print_check_format_changed" last_modification_time="Sat, 03 Mar 2007 22:06:00 GMT"/>
 		</widget>
 		<packing>
 		  <property name="left_attach">1</property>
@@ -213,7 +213,7 @@
 Custom</property>
 		  <property name="add_tearoffs">False</property>
 		  <property name="focus_on_click">True</property>
-		  <signal name="changed" handler="gnc_print_check_combobox_changed" last_modification_time="Sat, 28 Jan 2006 04:19:41 GMT"/>
+		  <signal name="changed" handler="gnc_print_check_position_changed" last_modification_time="Sat, 03 Mar 2007 22:06:12 GMT"/>
 		</widget>
 		<packing>
 		  <property name="left_attach">1</property>
@@ -257,7 +257,7 @@
 	  <child>
 	    <widget class="GtkTable" id="custom_table">
 	      <property name="visible">True</property>
-	      <property name="n_rows">9</property>
+	      <property name="n_rows">11</property>
 	      <property name="n_columns">3</property>
 	      <property name="homogeneous">False</property>
 	      <property name="row_spacing">0</property>
@@ -853,6 +853,91 @@
 		  <property name="y_options"></property>
 		</packing>
 	      </child>
+
+	      <child>
+		<widget class="GtkLabel" id="upper_left">
+		  <property name="visible">True</property>
+		  <property name="label" translatable="yes">The origin point is the upper left-hand corner of the page.</property>
+		  <property name="use_underline">False</property>
+		  <property name="use_markup">False</property>
+		  <property name="justify">GTK_JUSTIFY_LEFT</property>
+		  <property name="wrap">False</property>
+		  <property name="selectable">False</property>
+		  <property name="xalign">0</property>
+		  <property name="yalign">0.5</property>
+		  <property name="xpad">0</property>
+		  <property name="ypad">0</property>
+		  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		  <property name="width_chars">-1</property>
+		  <property name="single_line_mode">False</property>
+		  <property name="angle">0</property>
+		</widget>
+		<packing>
+		  <property name="left_attach">0</property>
+		  <property name="right_attach">3</property>
+		  <property name="top_attach">9</property>
+		  <property name="bottom_attach">10</property>
+		  <property name="x_options">fill</property>
+		  <property name="y_options"></property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkLabel" id="lower_left">
+		  <property name="visible">True</property>
+		  <property name="label" translatable="yes">The origin point is the lower left-hand corner of the page.</property>
+		  <property name="use_underline">False</property>
+		  <property name="use_markup">False</property>
+		  <property name="justify">GTK_JUSTIFY_LEFT</property>
+		  <property name="wrap">False</property>
+		  <property name="selectable">False</property>
+		  <property name="xalign">0</property>
+		  <property name="yalign">0.5</property>
+		  <property name="xpad">0</property>
+		  <property name="ypad">0</property>
+		  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		  <property name="width_chars">-1</property>
+		  <property name="single_line_mode">False</property>
+		  <property name="angle">0</property>
+		</widget>
+		<packing>
+		  <property name="left_attach">0</property>
+		  <property name="right_attach">3</property>
+		  <property name="top_attach">10</property>
+		  <property name="bottom_attach">11</property>
+		  <property name="x_options">fill</property>
+		  <property name="y_options"></property>
+		</packing>
+	      </child>
+
+	      <child>
+		<widget class="GtkLabel" id="rotation_units">
+		  <property name="visible">True</property>
+		  <property name="label" translatable="yes">Degrees</property>
+		  <property name="use_underline">False</property>
+		  <property name="use_markup">False</property>
+		  <property name="justify">GTK_JUSTIFY_LEFT</property>
+		  <property name="wrap">False</property>
+		  <property name="selectable">False</property>
+		  <property name="xalign">0</property>
+		  <property name="yalign">0.5</property>
+		  <property name="xpad">0</property>
+		  <property name="ypad">0</property>
+		  <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		  <property name="width_chars">-1</property>
+		  <property name="single_line_mode">False</property>
+		  <property name="angle">0</property>
+		</widget>
+		<packing>
+		  <property name="left_attach">2</property>
+		  <property name="right_attach">3</property>
+		  <property name="top_attach">7</property>
+		  <property name="bottom_attach">8</property>
+		  <property name="x_padding">6</property>
+		  <property name="x_options">fill</property>
+		  <property name="y_options"></property>
+		</packing>
+	      </child>
 	    </widget>
 	    <packing>
 	      <property name="tab_expand">False</property>

Modified: gnucash/trunk/src/scm/Makefile.am
===================================================================
--- gnucash/trunk/src/scm/Makefile.am	2007-03-13 01:18:42 UTC (rev 15708)
+++ gnucash/trunk/src/scm/Makefile.am	2007-03-13 03:43:24 UTC (rev 15709)
@@ -1,5 +1,5 @@
 
-SUBDIRS = gnumeric printing
+SUBDIRS = gnumeric
 
 gncscmdir = ${GNC_SCM_INSTALL_DIR}
 gncscmmoddir = ${GNC_SHAREDIR}/guile-modules/gnucash

Modified: gnucash/trunk/src/scm/main.scm
===================================================================
--- gnucash/trunk/src/scm/main.scm	2007-03-13 01:18:42 UTC (rev 15708)
+++ gnucash/trunk/src/scm/main.scm	2007-03-13 03:43:24 UTC (rev 15709)
@@ -67,10 +67,6 @@
 ;; from main-window.scm
 (export gnc:main-window-properties-cb)
 
-;; from printing/print-check.scm
-(export make-print-check-format)
-(export gnc:print-check)
-
 ;; Get the Makefile.am/configure.in generated variables.
 (load-from-path "build-config.scm")
 
@@ -220,7 +216,6 @@
 
   ;; Now we can load a bunch of files.
   (load-from-path "command-line.scm") ;; depends on app-utils (N_, etc.)...
-  (load-from-path "printing/print-check.scm") ;; depends on simple-obj...
 
   (gnc:initialize-config-vars) ;; in command-line.scm
   ;; handle unrecognized command line args



More information about the gnucash-changes mailing list