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