GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
dialog-print-check2.c
Go to the documentation of this file.
1 /********************************************************************\
2  * dialog-print-check2.c : dialog to control check printing. *
3  * Copyright (C) 2000 Bill Gribble <[email protected]> *
4  * Copyright (C) 2006,2007 David Hampton <[email protected]> *
5  * *
6  * This program is free software; you can redistribute it and/or *
7  * modify it under the terms of the GNU General Public License as *
8  * published by the Free Software Foundation; either version 2 of *
9  * the License, or (at your option) any later version. *
10  * *
11  * This program is distributed in the hope that it will be useful, *
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14  * GNU General Public License for more details. *
15  * *
16  * You should have received a copy of the GNU General Public License*
17  * along with this program; if not, contact: *
18  * *
19  * Free Software Foundation Voice: +1-617-542-5942 *
20  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
21  * Boston, MA 02110-1301, USA [email protected] *
22 \********************************************************************/
23 
31 #include "config.h"
32 
33 #include <gtk/gtk.h>
34 #include <glib/gi18n.h>
35 #include <stdio.h>
36 #include <locale.h>
37 #include <math.h>
38 
39 #include <gnc-gdate-utils.h>
40 #include "qof.h"
41 #include "gnc-date.h"
42 #include "gnc-prefs.h"
43 #include "gnc-numeric.h"
44 #include "gnc-plugin-page-register2.h"
45 #include "dialog-print-check2.h"
46 #include "dialog-utils.h"
47 #include "print-session.h"
48 #include "gnc-ui.h"
49 #include "gnc-date-format.h"
50 #include "gnc-ui-util.h"
51 #include "gnc-path.h"
52 #include "gnc-filepath-utils.h"
53 #include "gnc-gkeyfile-utils.h"
54 
55 #include "gnc-engine.h"
56 #include "engine-helpers.h"
57 #include "Split.h"
58 #include "Transaction.h"
59 
60 #undef G_LOG_DOMAIN
61 #define G_LOG_DOMAIN "gnc.printing.checks"
62 
63 /* This static indicates the debugging module that this .o belongs to.
64  */
65 G_GNUC_UNUSED static QofLogModule log_module = "gnc.printing.checks";
66 
67 #define GNC_PREFS_GROUP "dialogs.checkprinting"
68 #define GNC_PREF_CHECK_FORMAT_GUID "check-format-guid"
69 #define GNC_PREF_CHECK_POSITION "check-position"
70 #define GNC_PREF_FIRST_PAGE_COUNT "first-page-count"
71 #define GNC_PREF_DATE_FORMAT_USER "date-format-custom"
72 #define GNC_PREF_CUSTOM_PAYEE "custom-payee"
73 #define GNC_PREF_CUSTOM_DATE "custom-date"
74 #define GNC_PREF_CUSTOM_WORDS "custom-amount-words"
75 #define GNC_PREF_CUSTOM_NUMBER "custom-amount-number"
76 #define GNC_PREF_CUSTOM_ADDRESS "custom-address"
77 #define GNC_PREF_CUSTOM_NOTES "custom-notes"
78 #define GNC_PREF_CUSTOM_MEMO "custom-memo"
79 #define GNC_PREF_CUSTOM_TRANSLATION "custom-translation"
80 #define GNC_PREF_CUSTOM_ROTATION "custom-rotation"
81 #define GNC_PREF_CUSTOM_UNITS "custom-units"
82 #define GNC_PREF_PRINT_DATE_FMT "print-date-format"
83 #define GNC_PREF_DEFAULT_FONT "default-font"
84 #define GNC_PREF_BLOCKING_CHARS "blocking-chars"
85 #define GNC_PREF_SPLITS_AMOUNT "splits-amount"
86 #define GNC_PREF_SPLITS_MEMO "splits-memo"
87 #define GNC_PREF_SPLITS_ACCOUNT "splits-account"
88 
89 
90 #define DEFAULT_FONT "sans 12"
91 #define CHECK_FMT_DIR "checks"
92 #define CHECK_NAME_EXTENSION ".chk"
93 #define DEGREES_TO_RADIANS (G_PI / 180.0)
94 
95 #define BLOCKING_CHAR_OFF 0
96 #define BLOCKING_CHAR_ON 1
97 
98 #define KF_GROUP_TOP "Top"
99 #define KF_GROUP_POS "Check Positions"
100 #define KF_GROUP_ITEMS "Check Items"
101 #define KF_KEY_GUID "Guid"
102 #define KF_KEY_TITLE "Title"
103 #define KF_KEY_ROTATION "Rotation"
104 #define KF_KEY_TRANSLATION "Translation"
105 #define KF_KEY_FONT "Font"
106 #define KF_KEY_ALIGN "Align"
107 #define KF_KEY_BLOCKING "Blocking_Chars"
108 #define KF_KEY_SHOW_GRID "Show_Grid"
109 #define KF_KEY_SHOW_BOXES "Show_Boxes"
110 #define KF_KEY_NAMES "Names"
111 #define KF_KEY_HEIGHT "Height"
112 #define KF_KEY_TYPE "Type"
113 #define KF_KEY_COORDS "Coords"
114 #define KF_KEY_TEXT "Text"
115 #define KF_KEY_FILENAME "Filename"
116 #define KF_KEY_DATE_FORMAT "DateFormat"
117 #define KF_KEY_SPLITS_AMOUNT "SplitsAmount"
118 #define KF_KEY_SPLITS_MEMO "SplitsMemo"
119 #define KF_KEY_SPLITS_ACCOUNT "SplitsAccount"
120 
121 /* This enum specifies the columns used in the check format combobox.
122  */
123 typedef enum format_combo_col_t
124 {
125  COL_NAME = 0,
135 } format_combo_col;
136 
137 void gnc_ui_print_check_response_cb2 (GtkDialog *dialog, gint response, PrintCheckDialog *pcd);
138 void gnc_print_check_format_changed2 (GtkComboBox *widget, PrintCheckDialog *pcd);
139 void gnc_print_check_position_changed2 (GtkComboBox *widget, PrintCheckDialog *pcd);
140 void gnc_print_check_save_button_clicked2 (GtkButton *button, PrintCheckDialog *pcd);
141 void gnc_check_format_title_changed2 (GtkEditable *editable, GtkWidget *ok_button);
142 
143 static void initialize_format_combobox (PrintCheckDialog *pcd);
144 gchar* get_check_address2 (PrintCheckDialog *pcd);
145 static gboolean check_format_has_address (PrintCheckDialog *pcd);
146 gchar* get_check_splits_amount2 (PrintCheckDialog *pcd);
147 gchar* get_check_splits_memo2 (PrintCheckDialog *pcd);
148 gchar* get_check_splits_account2 (PrintCheckDialog *pcd);
149 
150 /* This enum defines the types of items that gnucash knows how to
151  * print on checks. Most refer to specific fields from a gnucash
152  * transaction and split, but some are generic items unrelated to
153  * gnucash.
154  */
155 #define ENUM_CHECK_ITEM_TYPE(_) \
156  _(NONE,) \
157  _(PAYEE,) \
158  _(DATE,) \
159  _(NOTES,) \
160  _(CHECK_NUMBER,) \
161  \
162  _(MEMO,) \
163  _(ACTION,) \
164  _(AMOUNT_NUMBER,) \
165  _(AMOUNT_WORDS,) \
166  \
167  _(TEXT,) \
168  _(ADDRESS,) \
169  _(DATE_FORMAT,) \
170  _(SPLITS_AMOUNT,) \
171  _(SPLITS_MEMO,) \
172  _(SPLITS_ACCOUNT,) \
173  _(PICTURE,)
174 
175 DEFINE_ENUM(CheckItemType2, ENUM_CHECK_ITEM_TYPE)
176 FROM_STRING_DEC(CheckItemType2, ENUM_CHECK_ITEM_TYPE)
177 FROM_STRING_FUNC(CheckItemType2, ENUM_CHECK_ITEM_TYPE)
178 AS_STRING_DEC(CheckItemType2, ENUM_CHECK_ITEM_TYPE)
179 AS_STRING_FUNC(CheckItemType2, ENUM_CHECK_ITEM_TYPE)
180 
181 /* This data structure describes a single item printed on a check.
182  * It is built from a description in a text file.
183  */
184 typedef struct _check_item
185 {
186 
187  CheckItemType2 type;
189  gdouble x, y;
194  gdouble w, h;
199  gchar *filename;
202  gchar *text;
205  gchar *font;
209  gboolean blocking;
214  gboolean print_date_format;
218  PangoAlignment align;
221 } check_item_t;
222 
223 /* This data structure describes an entire page of checks. Depending
224  * upon the check format, the page may contain multiple checks or
225  * only a single check. The data structure is built from a
226  * description in a text file.
227  */
228 typedef struct _check_format
229 {
230 
231  gchar *guid;
233  const gchar *group;
235  gchar *filename;
238  gchar *title;
241  gboolean blocking;
244  gboolean print_date_format;
247  gboolean show_grid;
249  gboolean show_boxes;
252  gdouble rotation;
254  gdouble trans_x;
256  gdouble trans_y;
258  gchar *font;
260  gdouble height;
262  GSList *positions;
264  GSList *items;
266 
267 
268 /* This data structure is used to manage the print check dialog, and
269  * the overall check printing process. It contains pointers to many
270  * of the widgets in the dialog, pointers to the check descriptions
271  * that have been read, and also contains the data from the gnucash
272  * transaction/split that is to be printed.
273  */
274 struct _print_check_dialog
275 {
276  GtkBuilder *builder;
277  GtkWidget *dialog;
278  GtkWindow *caller_window;
279 
280  GncPluginPageRegister2 *plugin_page;
281  Split *split;
282  GList *splits;
283 
284  GtkWidget *format_combobox;
285  gint format_max;
286  GtkWidget *position_combobox;
287  gint position_max;
288  GtkSpinButton *first_page_count;
289  GtkWidget *custom_table;
290  GtkSpinButton *payee_x, *payee_y;
291  GtkSpinButton *date_x, *date_y;
292  GtkSpinButton *words_x, *words_y;
293  GtkSpinButton *number_x, *number_y;
294  GtkSpinButton *address_x, *address_y;
295  GtkSpinButton *notes_x, *notes_y;
296  GtkSpinButton *memo_x, *memo_y;
297  GtkSpinButton *splits_amount_x, *splits_amount_y;
298  GtkSpinButton *splits_memo_x, *splits_memo_y;
299  GtkSpinButton *splits_account_x, *splits_account_y;
300  GtkSpinButton *translation_x, *translation_y;
301  GtkSpinButton *check_rotation;
302  GtkWidget *translation_label;
303 
304  GtkWidget *units_combobox;
305 
306  GtkWidget *date_format;
307 
308  GtkWidget *check_address_name;
309  GtkWidget *check_address_1;
310  GtkWidget *check_address_2;
311  GtkWidget *check_address_3;
312  GtkWidget *check_address_4;
313 
314  gchar *default_font;
315 
316  check_format_t *selected_format;
317 };
318 
319 
320 /* This function walks ths list of available check formats looking for a
321  * specific format as specified by guid number. If found, a pointer to it is
322  * returned to the caller. Additionally, if the caller passed a pointer to a
323  * GtkTreeIter, then the iter for that entry will also be returned.
324  */
325 static check_format_t *
326 find_existing_format (GtkListStore *store, gchar *guid, GtkTreeIter *iter_out)
327 {
328  GtkTreeIter iter;
329  check_format_t *format;
330 
331  g_return_val_if_fail(store, NULL);
332  g_return_val_if_fail(guid, NULL);
333 
334  if (!gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), &iter))
335  return NULL;
336 
337  do
338  {
339  gtk_tree_model_get(GTK_TREE_MODEL(store), &iter,
340  COL_DATA, &format, -1);
341  if (format == NULL)
342  continue;
343  if (strcmp(format->guid, guid) != 0)
344  continue;
345 
346  if (iter_out)
347  *iter_out = iter;
348  return format;
349  }
350  while (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter));
351 
352  return NULL;
353 }
354 
355 
356 /* This function returns a string containing the check address in a five-line
357  * format.
358  *
359  * Note that the string needs to be freed with g_free.
360  */
361 gchar *
362 get_check_address2( PrintCheckDialog *pcd)
363 {
364  gchar *address;
365  address = g_strconcat(gtk_entry_get_text(GTK_ENTRY(pcd->check_address_name)), "\n",
366  gtk_entry_get_text(GTK_ENTRY(pcd->check_address_1)), "\n",
367  gtk_entry_get_text(GTK_ENTRY(pcd->check_address_2)), "\n",
368  gtk_entry_get_text(GTK_ENTRY(pcd->check_address_3)), "\n",
369  gtk_entry_get_text(GTK_ENTRY(pcd->check_address_4)),
370  NULL);
371  return address;
372 }
373 
374 
376 
378 /* This function formats the splits amounts for printing.
379  */
380 gchar *
381 get_check_splits_amount2(PrintCheckDialog *pcd)
382 {
383  gchar* amount = NULL;
384  Transaction *trans;
385  GList *node;
386  SplitList* s_list;
387 
388  trans = xaccSplitGetParent(pcd->split);
389  s_list = xaccTransGetSplitList(trans);
390  if ( !s_list ) return NULL;
391 
392  amount = g_strconcat("", NULL);
393  node = s_list;
394  while ( node )
395  {
396  Split *split = node->data;
397  /* Include all splits except the main split for the check */
398  if (split != pcd->split)
399  {
400  const gchar* split_amount;
401  gchar* amt_temp;
402  split_amount = xaccPrintAmount(xaccSplitGetAmount(split), gnc_split_amount_print_info(split, TRUE));
403  amt_temp = amount;
404  if (amount && *amount)
405  amount = g_strconcat(amt_temp, "\n", split_amount, NULL);
406  else
407  amount = g_strconcat(amt_temp, split_amount, NULL);
408  g_free(amt_temp);
409  }
410  node = node->next;
411  }
412  return amount;
413 }
414 
415 
416 /* This function formats the splits memo fields for printing.
417  */
418 gchar *
419 get_check_splits_memo2(PrintCheckDialog *pcd)
420 {
421  gchar* memo = NULL;
422  const gchar* split_memo;
423  Transaction *trans;
424  GList *node;
425  SplitList* s_list;
426 
427  trans = xaccSplitGetParent(pcd->split);
428  s_list = xaccTransGetSplitList(trans);
429  if ( !s_list ) return NULL;
430 
431  memo = g_strconcat("", NULL);
432  node = s_list;
433  while ( node )
434  {
435  Split *split = node->data;
436  /* Include all splits except the main split for the check */
437  if (split != pcd->split)
438  {
439  gchar* memo_temp;
440  split_memo = xaccSplitGetMemo(split);
441  memo_temp = memo;
442  if (memo && *memo)
443  memo = g_strconcat(memo_temp, "\n", split_memo, NULL);
444  else
445  memo = g_strconcat(memo_temp, split_memo, NULL);
446  g_free(memo_temp);
447  }
448  node = node->next;
449  }
450  return memo;
451 }
452 
453 
454 /* This function formats the splits accounts for printing.
455  */
456 gchar *
457 get_check_splits_account2(PrintCheckDialog *pcd)
458 {
459  gchar* account = NULL;
460  Transaction *trans;
461  GList *node;
462  SplitList* s_list;
463 
464  trans = xaccSplitGetParent(pcd->split);
465  s_list = xaccTransGetSplitList(trans);
466  if ( !s_list ) return NULL;
467 
468  account = g_strconcat("", NULL);
469  node = s_list;
470  while ( node )
471  {
472  Split *split = node->data;
473  /* Include all splits except the main split for the check */
474  if (split != pcd->split)
475  {
476  gchar* account_temp;
477  const gchar* aName = NULL;
478  Account *pAccount;
479  pAccount = xaccSplitGetAccount(split);
480  aName = gnc_get_account_name_for_register(pAccount);
481  account_temp = account;
482  if (account && *account)
483  account = g_strconcat(account_temp, "\n", aName, NULL);
484  else
485  account = g_strconcat(account_temp, aName, NULL);
486  g_free(account_temp);
487  }
488  node = node->next;
489  }
490  return account;
491 }
493 
494 
495 /* This function determines if an address item is present in the check format.
496  */
497 static gboolean
498 check_format_has_address ( PrintCheckDialog *pcd )
499 {
500  /* check format for an ADDRESS item */
501  check_item_t *item = NULL;
502  GSList *elem;
503  check_format_t *format = NULL;
504 
505  if ( !pcd ) return FALSE;
506 
507  /* If we're printing more than one check no addresses are allowed */
508  if (g_list_length(pcd->splits) != 1)
509  return FALSE;
510 
511  /* if format is NULL, then the custom format is being used
512  * which has an ADDRESS item by definition */
513  format = pcd->selected_format;
514  if ( !format ) return TRUE;
515 
516  for (elem = pcd->selected_format->items; elem; elem = g_slist_next(elem))
517  {
518  item = elem->data;
519  if ( item->type == ADDRESS ) return TRUE;
520  }
521  return FALSE;
522 }
523 
524 
525 static void
526 gnc_ui_print_save_dialog(PrintCheckDialog *pcd)
527 {
528  GtkTreeModel *model;
529  GtkTreeIter iter;
530  check_format_t *check;
531  const gchar *format;
532  gint active;
533 
534  /* Options page */
535  if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(pcd->format_combobox),
536  &iter))
537  {
538  model = gtk_combo_box_get_model(GTK_COMBO_BOX(pcd->format_combobox));
539  gtk_tree_model_get(model, &iter, COL_DATA, &check, -1);
540  gnc_prefs_set_string (GNC_PREFS_GROUP, GNC_PREF_CHECK_FORMAT_GUID,
541  check ? check->guid : "custom");
542  }
543  active = gtk_combo_box_get_active(GTK_COMBO_BOX(pcd->position_combobox));
544  gnc_prefs_set_int(GNC_PREFS_GROUP, GNC_PREF_CHECK_POSITION, active);
545  active = gtk_spin_button_get_value_as_int(pcd->first_page_count);
546  gnc_prefs_set_int(GNC_PREFS_GROUP, GNC_PREF_FIRST_PAGE_COUNT, active);
547  active = gnc_date_format_get_format (GNC_DATE_FORMAT(pcd->date_format));
548  gnc_prefs_set_int(GNC_PREFS_GROUP, GNC_PREF_DATE_FORMAT, active);
549  if (active == QOF_DATE_FORMAT_CUSTOM)
550  {
551  format = gnc_date_format_get_custom (GNC_DATE_FORMAT(pcd->date_format));
552  gnc_prefs_set_string (GNC_PREFS_GROUP, GNC_PREF_DATE_FORMAT_USER, format);
553  }
554  else
555  {
556  gnc_prefs_reset (GNC_PREFS_GROUP, GNC_PREF_DATE_FORMAT_USER);
557  }
558 
559  /* Custom format page */
560  gnc_prefs_set_coords(GNC_PREFS_GROUP, GNC_PREF_CUSTOM_PAYEE,
561  gtk_spin_button_get_value(pcd->payee_x),
562  gtk_spin_button_get_value(pcd->payee_y));
563  gnc_prefs_set_coords(GNC_PREFS_GROUP, GNC_PREF_CUSTOM_DATE,
564  gtk_spin_button_get_value(pcd->date_x),
565  gtk_spin_button_get_value(pcd->date_y));
566  gnc_prefs_set_coords(GNC_PREFS_GROUP, GNC_PREF_CUSTOM_WORDS,
567  gtk_spin_button_get_value(pcd->words_x),
568  gtk_spin_button_get_value(pcd->words_y));
569  gnc_prefs_set_coords(GNC_PREFS_GROUP, GNC_PREF_CUSTOM_NUMBER,
570  gtk_spin_button_get_value(pcd->number_x),
571  gtk_spin_button_get_value(pcd->number_y));
572  gnc_prefs_set_coords(GNC_PREFS_GROUP, GNC_PREF_CUSTOM_NOTES,
573  gtk_spin_button_get_value(pcd->notes_x),
574  gtk_spin_button_get_value(pcd->notes_y));
575  gnc_prefs_set_coords(GNC_PREFS_GROUP, GNC_PREF_CUSTOM_MEMO,
576  gtk_spin_button_get_value(pcd->memo_x),
577  gtk_spin_button_get_value(pcd->memo_y));
578  gnc_prefs_set_coords(GNC_PREFS_GROUP, GNC_PREF_CUSTOM_ADDRESS,
579  gtk_spin_button_get_value(pcd->address_x),
580  gtk_spin_button_get_value(pcd->address_y));
581  gnc_prefs_set_coords(GNC_PREFS_GROUP, GNC_PREF_SPLITS_AMOUNT,
582  gtk_spin_button_get_value(pcd->splits_amount_x),
583  gtk_spin_button_get_value(pcd->splits_amount_y));
584  gnc_prefs_set_coords(GNC_PREFS_GROUP, GNC_PREF_SPLITS_MEMO,
585  gtk_spin_button_get_value(pcd->splits_memo_x),
586  gtk_spin_button_get_value(pcd->splits_memo_y));
587  gnc_prefs_set_coords(GNC_PREFS_GROUP, GNC_PREF_SPLITS_ACCOUNT,
588  gtk_spin_button_get_value(pcd->splits_account_x),
589  gtk_spin_button_get_value(pcd->splits_account_y));
590  gnc_prefs_set_coords(GNC_PREFS_GROUP, GNC_PREF_CUSTOM_TRANSLATION,
591  gtk_spin_button_get_value(pcd->translation_x),
592  gtk_spin_button_get_value(pcd->translation_y));
593  gnc_prefs_set_float(GNC_PREFS_GROUP, GNC_PREF_CUSTOM_ROTATION,
594  gtk_spin_button_get_value(pcd->check_rotation));
595  active = gtk_combo_box_get_active(GTK_COMBO_BOX(pcd->units_combobox));
596  gnc_prefs_set_int(GNC_PREFS_GROUP, GNC_PREF_CUSTOM_UNITS, active);
597 }
598 
599 
600 static void
601 gnc_ui_print_restore_dialog(PrintCheckDialog *pcd)
602 {
603  GtkTreeModel *model;
604  GtkTreeIter iter;
605  gchar *format, *guid;
606  gdouble x, y;
607  gint active;
608 
609  /* Options page */
610  guid = gnc_prefs_get_string (GNC_PREFS_GROUP, GNC_PREF_CHECK_FORMAT_GUID);
611  if (guid == NULL)
612  gtk_combo_box_set_active(GTK_COMBO_BOX(pcd->format_combobox), 0);
613  else if (strcmp(guid, "custom") == 0)
614  gtk_combo_box_set_active(GTK_COMBO_BOX(pcd->format_combobox),
615  pcd->format_max - 1);
616  else
617  {
618  model = gtk_combo_box_get_model(GTK_COMBO_BOX(pcd->format_combobox));
619  if (find_existing_format(GTK_LIST_STORE(model), guid, &iter))
620  {
621  gtk_combo_box_set_active_iter(GTK_COMBO_BOX(pcd->format_combobox), &iter);
622  }
623  else
624  {
625  gtk_combo_box_set_active(GTK_COMBO_BOX(pcd->format_combobox), 0);
626  }
627  }
628  active = gnc_prefs_get_int(GNC_PREFS_GROUP, GNC_PREF_CHECK_POSITION);
629 
630  /* If the check format used last time no longer exists, then the saved check
631  position may be invalid. If so set it to the first position. */
632  if (active < 0 || active > pcd->position_max)
633  active = 0;
634  gtk_combo_box_set_active(GTK_COMBO_BOX(pcd->position_combobox), active);
635  active = gnc_prefs_get_int(GNC_PREFS_GROUP, GNC_PREF_FIRST_PAGE_COUNT);
636  gtk_spin_button_set_value(pcd->first_page_count, (gdouble) active);
637  active = gnc_prefs_get_int(GNC_PREFS_GROUP, GNC_PREF_DATE_FORMAT);
638  gnc_date_format_set_format(GNC_DATE_FORMAT(pcd->date_format), active);
639  if (active == QOF_DATE_FORMAT_CUSTOM)
640  {
641  format = gnc_prefs_get_string (GNC_PREFS_GROUP, GNC_PREF_DATE_FORMAT_USER);
642  if (format)
643  {
644  gnc_date_format_set_custom(GNC_DATE_FORMAT(pcd->date_format), format);
645  g_free(format);
646  }
647  }
648 
649  /* Custom format page */
650  gnc_prefs_get_coords(GNC_PREFS_GROUP, GNC_PREF_CUSTOM_PAYEE, &x, &y);
651  gtk_spin_button_set_value(pcd->payee_x, x);
652  gtk_spin_button_set_value(pcd->payee_y, y);
653 
654  gnc_prefs_get_coords(GNC_PREFS_GROUP, GNC_PREF_CUSTOM_DATE, &x, &y);
655  gtk_spin_button_set_value(pcd->date_x, x);
656  gtk_spin_button_set_value(pcd->date_y, y);
657  gnc_prefs_get_coords(GNC_PREFS_GROUP, GNC_PREF_CUSTOM_WORDS, &x, &y);
658  gtk_spin_button_set_value(pcd->words_x, x);
659  gtk_spin_button_set_value(pcd->words_y, y);
660  gnc_prefs_get_coords(GNC_PREFS_GROUP, GNC_PREF_CUSTOM_NUMBER, &x, &y);
661  gtk_spin_button_set_value(pcd->number_x, x);
662  gtk_spin_button_set_value(pcd->number_y, y);
663  gnc_prefs_get_coords(GNC_PREFS_GROUP, GNC_PREF_CUSTOM_ADDRESS, &x, &y);
664  gtk_spin_button_set_value(pcd->address_x, x);
665  gtk_spin_button_set_value(pcd->address_y, y);
666  gnc_prefs_get_coords(GNC_PREFS_GROUP, GNC_PREF_CUSTOM_NOTES, &x, &y);
667  gtk_spin_button_set_value(pcd->notes_x, x);
668  gtk_spin_button_set_value(pcd->notes_y, y);
669  gnc_prefs_get_coords(GNC_PREFS_GROUP, GNC_PREF_CUSTOM_MEMO, &x, &y);
670  gtk_spin_button_set_value(pcd->memo_x, x);
671  gtk_spin_button_set_value(pcd->memo_y, y);
672  gnc_prefs_get_coords(GNC_PREFS_GROUP, GNC_PREF_SPLITS_AMOUNT, &x, &y);
673  gtk_spin_button_set_value(pcd->splits_amount_x, x);
674  gtk_spin_button_set_value(pcd->splits_amount_y, y);
675  gnc_prefs_get_coords(GNC_PREFS_GROUP, GNC_PREF_SPLITS_MEMO, &x, &y);
676  gtk_spin_button_set_value(pcd->splits_memo_x, x);
677  gtk_spin_button_set_value(pcd->splits_memo_y, y);
678  gnc_prefs_get_coords(GNC_PREFS_GROUP, GNC_PREF_SPLITS_ACCOUNT, &x, &y);
679  gtk_spin_button_set_value(pcd->splits_account_x, x);
680  gtk_spin_button_set_value(pcd->splits_account_y, y);
681  gnc_prefs_get_coords(GNC_PREFS_GROUP, GNC_PREF_CUSTOM_TRANSLATION, &x, &y);
682  gtk_spin_button_set_value(pcd->translation_x, x);
683  gtk_spin_button_set_value(pcd->translation_y, y);
684  x = gnc_prefs_get_float(GNC_PREFS_GROUP, GNC_PREF_CUSTOM_ROTATION);
685  gtk_spin_button_set_value(pcd->check_rotation, x);
686  active = gnc_prefs_get_int(GNC_PREFS_GROUP, GNC_PREF_CUSTOM_UNITS);
687  gtk_combo_box_set_active(GTK_COMBO_BOX(pcd->units_combobox), active);
688 }
689 
690 
691 static gdouble
692 pcd_get_custom_multip(PrintCheckDialog *pcd)
693 {
694  gint selected;
695 
696  selected = gtk_combo_box_get_active(GTK_COMBO_BOX(pcd->units_combobox));
697  switch (selected)
698  {
699  default:
700  return 72.0; /* inches */
701  case 1:
702  return 28.346; /* cm */
703  case 2:
704  return 2.8346; /* mm */
705  case 3:
706  return 1.0; /* points */
707  }
708 }
709 
710 
711 /* This function saves a coordinate pair into a check description file. It
712  * extracts the values from the spin buttons, adjusts them according to the
713  * unit multiplier (inches, pixels, etc), then adds them to the gKeyFile.
714  */
715 static void
716 pcd_key_file_save_xy (GKeyFile *key_file, const gchar *group_name,
717  const gchar *key_name, gdouble multip,
718  GtkSpinButton *spin0, GtkSpinButton *spin1)
719 {
720  gdouble dd[2];
721 
722  dd[0] = multip * gtk_spin_button_get_value(spin0);
723  dd[1] = multip * gtk_spin_button_get_value(spin1);
724 
725  /* Clip the numbers to three decimal places. */
726  dd[0] = round(dd[0] * 1000) / 1000;
727  dd[1] = round(dd[1] * 1000) / 1000;
728  g_key_file_set_double_list(key_file, group_name, key_name, dd, 2);
729 }
730 
731 
732 /* This function saves the information about a single printed item into a
733  * check description file. It uses a helper function to extracts and save the
734  * item coordinates.
735  */
736 static void
737 pcd_key_file_save_item_xy (GKeyFile *key_file, int index,
738  CheckItemType2 type, gdouble multip,
739  GtkSpinButton *spin0, GtkSpinButton *spin1)
740 {
741  gchar *key;
742  key = g_strdup_printf("Type_%d", index);
743  g_key_file_set_string(key_file, KF_GROUP_ITEMS, key,
744  CheckItemType2asString(type));
745  g_free(key);
746  key = g_strdup_printf("Coords_%d", index);
747  pcd_key_file_save_xy(key_file, KF_GROUP_ITEMS, key, multip, spin0, spin1);
748  g_free(key);
749 }
750 
751 
752 /* This function saves all of the information from the custom check dialog
753  * into a check description file.
754  */
755 static void
756 pcd_save_custom_data(PrintCheckDialog *pcd, const gchar *title)
757 {
758  GKeyFile *key_file;
759  GError *error = NULL;
760  GtkWidget *dialog;
761  gdouble multip;
762  gint i = 1;
763  GncGUID guid;
764  char buf[GUID_ENCODING_LENGTH+1];
765  gchar *filename, *pathname;
766 
767  multip = pcd_get_custom_multip(pcd);
768 
769  key_file = g_key_file_new();
770  guid_replace(&guid);
771  guid_to_string_buff(&guid, buf);
772  g_key_file_set_string(key_file, KF_GROUP_TOP, KF_KEY_GUID, buf);
773  g_key_file_set_string(key_file, KF_GROUP_TOP, KF_KEY_TITLE, title);
774  g_key_file_set_boolean(key_file, KF_GROUP_TOP, KF_KEY_SHOW_GRID, FALSE);
775  g_key_file_set_boolean(key_file, KF_GROUP_TOP, KF_KEY_SHOW_BOXES, FALSE);
776  g_key_file_set_double(key_file, KF_GROUP_TOP, KF_KEY_ROTATION,
777  gtk_spin_button_get_value(pcd->check_rotation));
778  pcd_key_file_save_xy(key_file, KF_GROUP_TOP, KF_KEY_TRANSLATION, multip,
779  pcd->translation_x, pcd->translation_y);
780 
781  pcd_key_file_save_item_xy(key_file, i++, PAYEE, multip,
782  pcd->payee_x, pcd->payee_y);
783  pcd_key_file_save_item_xy(key_file, i++, DATE, multip,
784  pcd->date_x, pcd->date_y);
785  pcd_key_file_save_item_xy(key_file, i++, AMOUNT_WORDS, multip,
786  pcd->words_x, pcd->words_y);
787  pcd_key_file_save_item_xy(key_file, i++, AMOUNT_NUMBER, multip,
788  pcd->number_x, pcd->number_y);
789  pcd_key_file_save_item_xy(key_file, i++, ADDRESS, multip,
790  pcd->address_x, pcd->address_y);
791  pcd_key_file_save_item_xy(key_file, i++, NOTES, multip,
792  pcd->notes_x, pcd->notes_y);
793  pcd_key_file_save_item_xy(key_file, i++, MEMO, multip,
794  pcd->memo_x, pcd->memo_y);
795  pcd_key_file_save_item_xy(key_file, i++, SPLITS_AMOUNT, multip,
796  pcd->splits_amount_x, pcd->splits_amount_y);
797  pcd_key_file_save_item_xy(key_file, i++, SPLITS_MEMO, multip,
798  pcd->splits_memo_x, pcd->splits_memo_y);
799  pcd_key_file_save_item_xy(key_file, i++, SPLITS_ACCOUNT, multip,
800  pcd->splits_account_x, pcd->splits_account_y);
801 
802  filename = g_strconcat(title, CHECK_NAME_EXTENSION, NULL);
803  pathname = g_build_filename(gnc_dotgnucash_dir(), CHECK_FMT_DIR,
804  filename, NULL);
805 
806  if (gnc_key_file_save_to_file(pathname, key_file, &error))
807  {
808  if (!gnc_prefs_get_bool(GNC_PREFS_GROUP, GNC_PREF_PRINT_DATE_FMT))
809  /* Reload the format combo box and reselect the "custom" entry */
810  initialize_format_combobox(pcd);
811 
812  gtk_combo_box_set_active(GTK_COMBO_BOX(pcd->format_combobox),
813  pcd->format_max - 1);
814  }
815  else
816  {
817  dialog = gtk_message_dialog_new(GTK_WINDOW(pcd->dialog),
818  GTK_DIALOG_DESTROY_WITH_PARENT,
819  GTK_MESSAGE_ERROR,
820  GTK_BUTTONS_CLOSE, "%s",
821  _("Cannot save check format file."));
822  gtk_message_dialog_format_secondary_text(GTK_MESSAGE_DIALOG(dialog),
823  "%s", error->message);
824  gtk_dialog_run(GTK_DIALOG(dialog));
825  gtk_widget_destroy(dialog);
826  g_error_free(error);
827  }
828  g_free(pathname);
829  g_free(filename);
830 }
831 
832 
833 /* This function makes the OK button active iff a title has been entered.
834  */
835 void
836 gnc_check_format_title_changed2 (GtkEditable *editable, GtkWidget *ok_button)
837 {
838  const gchar *text;
839  gboolean sensitive;
840 
841  text = gtk_entry_get_text(GTK_ENTRY(editable));
842  sensitive = text && *text;
843  gtk_widget_set_sensitive(ok_button, sensitive);
844 }
845 
846 
847 /* This function is called when the user clicks the "save format" button in
848  * the check printing dialog. It presents another dialog to the user to get
849  * the filename for saving the data.
850  */
851 void
852 gnc_print_check_save_button_clicked2(GtkButton *unused, PrintCheckDialog *pcd)
853 {
854  GtkWidget *dialog, *entry, *button;
855  GtkBuilder *builder;
856  gchar *title;
857 
858  builder = gtk_builder_new();
859  gnc_builder_add_from_file (builder, "dialog-print-check.glade", "Format Title Dialog");
860 
861  /* Get a title for the new check format. */
862  dialog = GTK_WIDGET(gtk_builder_get_object (builder, "Format Title Dialog"));
863  entry = GTK_WIDGET(gtk_builder_get_object (builder, "format_title"));
864  button = GTK_WIDGET(gtk_builder_get_object (builder, "ok_button"));
865  gnc_check_format_title_changed2(GTK_EDITABLE(entry), button);
866  gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, pcd);
867 
868  gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(pcd->dialog));
869  if (gtk_dialog_run (GTK_DIALOG (dialog)) != GTK_RESPONSE_OK)
870  {
871  gtk_widget_destroy(dialog);
872  g_object_unref(G_OBJECT(builder));
873  return;
874  }
875 
876  title = g_strdup(gtk_entry_get_text(GTK_ENTRY(entry)));
877  gtk_widget_destroy (dialog);
878 
879  g_object_unref(G_OBJECT(builder));
880 
881  pcd_save_custom_data(pcd, title);
882  g_free(title);
883 }
884 
885 
886 /* This function is an auxiliary debugging function for converting an array of
887  * doubles into a printable string.
888  */
889 static gchar *
890 doubles_to_string(gdouble *dd, gint len)
891 {
892  GString *str;
893  gint i;
894 
895  str = g_string_new_len(NULL, 50);
896  for (i = 0; i < len; i++)
897  g_string_append_printf(str, "%f ", dd[i]);
898  return g_string_free(str, FALSE);
899 }
900 
901 
902 /* This function reads in the information describing the placement for each
903  * item to be printed on a check. This information is all relative to the
904  * upper left hand corner of a "check". See the format_read_multicheck_info()
905  * function for determining if there are multiple checks on a single page of
906  * paper. This data is build into a linked list and saved as part of the check
907  * format information. These items will be printed in the same order they are
908  * read, meaning that items listed later in the date file can be printed over
909  * top of items that appear earlier in the file.
910  */
911 static GSList *
912 format_read_item_placement(const gchar *file,
913  GKeyFile *key_file, check_format_t *format)
914 {
915  check_item_t *data = NULL;
916  GError *error = NULL;
917  GSList *list = NULL;
918  gchar *key, *value, *name;
919  int item_num;
920  gboolean bval;
921  gdouble *dd;
922  gsize dd_len;
923 
924  /* Read until failure. */
925  for (item_num = 1;; item_num++)
926  {
927 
928  /* Create the per-item data structure */
929  data = g_new0(check_item_t, 1);
930  if (NULL == data)
931  return list;
932 
933  /* Get the item type */
934  key = g_strdup_printf("%s_%d", KF_KEY_TYPE, item_num);
935  value = g_key_file_get_string(key_file, KF_GROUP_ITEMS, key, &error);
936  if (error)
937  {
938  if ((error->domain == G_KEY_FILE_ERROR)
939  && (error->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND))
940  {
941  /* This is the expected exit from this function. */
942  goto cleanup;
943  }
944  goto failed;
945  }
946  g_debug("Check file %s, group %s, key %s, value: %s",
947  file, KF_GROUP_ITEMS, key, value);
948  g_free(key);
949 
950  /* Convert the type from a string to an enum, ignoring case. */
951  name = g_utf8_strup(value, -1);
952  data->type = CheckItemType2fromString(name);
953  g_free(name);
954  g_free(value);
955 
956 
957  /* Get the item location */
958  key = g_strdup_printf("%s_%d", KF_KEY_COORDS, item_num);
959  dd = g_key_file_get_double_list(key_file, KF_GROUP_ITEMS,
960  key, &dd_len, &error);
961  if (error)
962  goto failed;
963  value = doubles_to_string(dd, dd_len);
964  g_debug("Check file %s, group %s, key %s, length %"G_GSIZE_FORMAT"; values: %s",
965  file, KF_GROUP_ITEMS, key, dd_len, value);
966  g_free(value);
967 
968  /* Must have "x;y" or "x;y;w;h". */
969  switch (dd_len)
970  {
971  case 4:
972  data->w = dd[2];
973  data->h = dd[3];
974  /* fall through */
975  case 2:
976  data->x = dd[0];
977  data->y = dd[1];
978  break;
979  default:
980  g_warning
981  ("Check file %s, group %s, key %s, error: 2 or 4 values only",
982  file, KF_GROUP_ITEMS, key);
983  goto cleanup;
984  }
985  g_free(dd);
986  g_free(key);
987 
988  /* Any text item can specify:
989  * a font FONT_n
990  * an alignment if a width was provided for the item ALIGN_n
991  * blocking chars flag BLOCKING_CHARS_n
992  * These values are optional and do not cause a failure if they are missing. */
993 
994  if (data->type != PICTURE)
995  {
996  key = g_strdup_printf("%s_%d", KF_KEY_FONT, item_num);
997  data->font =
998  g_key_file_get_string(key_file, KF_GROUP_ITEMS, key, &error);
999  if (!error)
1000  {
1001  g_debug("Check file %s, group %s, key %s, value: %s",
1002  file, KF_GROUP_ITEMS, key, data->font);
1003  }
1004  else
1005  {
1006  if (!((error->domain == G_KEY_FILE_ERROR)
1007  && (error->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND)))
1008  g_warning("Check file %s, group %s, key %s, error: %s",
1009  file, KF_GROUP_ITEMS, key, error->message);
1010  g_clear_error(&error);
1011  }
1012  g_free(key);
1013 
1014  key = g_strdup_printf("%s_%d", KF_KEY_ALIGN, item_num);
1015  value =
1016  g_key_file_get_string(key_file, KF_GROUP_ITEMS, key, &error);
1017  if (!error)
1018  {
1019  g_debug("Check file %s, group %s, key %s, value: %s",
1020  file, KF_GROUP_ITEMS, key, value);
1021  name = g_utf8_strdown(value, -1);
1022  if (strcmp(name, "right") == 0)
1023  data->align = PANGO_ALIGN_RIGHT;
1024  else if (strcmp(name, "center") == 0)
1025  data->align = PANGO_ALIGN_CENTER;
1026  else
1027  data->align = PANGO_ALIGN_LEFT;
1028  g_free(name);
1029  g_free(value);
1030  }
1031  else
1032  {
1033  if (!((error->domain == G_KEY_FILE_ERROR)
1034  && (error->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND)))
1035  g_warning("Check file %s, group %s, key %s, error: %s",
1036  file, KF_GROUP_ITEMS, key, error->message);
1037  data->align = PANGO_ALIGN_LEFT;
1038  g_clear_error(&error);
1039  }
1040  g_free(key);
1041 
1042  key = g_strdup_printf("%s_%d", KF_KEY_BLOCKING, item_num);
1043  bval =
1044  g_key_file_get_boolean(key_file, KF_GROUP_ITEMS, key, &error);
1045  if (!error)
1046  {
1047  g_debug("Check file %s, group %s, key %s, value: %d",
1048  file, KF_GROUP_ITEMS, key, bval);
1049  data->blocking = bval;
1050  }
1051  else
1052  {
1053  if (!((error->domain == G_KEY_FILE_ERROR)
1054  && (error->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND)))
1055  g_warning("Check file %s, group %s, key %s, error: %s",
1056  file, KF_GROUP_ITEMS, key, error->message);
1057  data->blocking = format->blocking;
1058  g_clear_error(&error);
1059  }
1060  g_free(key);
1061  }
1062  /* Get any extra data for specific items. */
1063  switch (data->type)
1064  {
1065  case PICTURE:
1066  key = g_strdup_printf("%s_%d", KF_KEY_FILENAME, item_num);
1067  data->filename =
1068  g_key_file_get_string(key_file, KF_GROUP_ITEMS, key,
1069  &error);
1070  if (error)
1071  goto failed;
1072  g_debug("Check file %s, group %s, key %s, value: %s",
1073  file, KF_GROUP_ITEMS, key, data->filename);
1074  g_free(key);
1075  break;
1076  case TEXT:
1077  key = g_strdup_printf("%s_%d", KF_KEY_TEXT, item_num);
1078  data->text =
1079  g_key_file_get_string(key_file, KF_GROUP_ITEMS, key,
1080  &error);
1081  if (error)
1082  goto failed;
1083  g_debug("Check file %s, group %s, key %s, value: %s",
1084  file, KF_GROUP_ITEMS, key, data->text);
1085  g_free(key);
1086  break;
1087  case DATE:
1088  /* no error if the date_format is not present */
1089  key = g_strdup_printf("%s_%d", KF_KEY_DATE_FORMAT, item_num);
1090  bval = g_key_file_get_boolean(key_file, KF_GROUP_ITEMS, key, &error);
1091  if (!error)
1092  {
1093  g_debug("Check file %s, group %s, key %s, value: %d",
1094  file, KF_GROUP_ITEMS, key, bval);
1095  data->print_date_format = bval;
1096  }
1097  else
1098  {
1099  if (!((error->domain == G_KEY_FILE_ERROR)
1100  && (error->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND)))
1101  g_warning("Check file %s, group %s, key %s, error: %s",
1102  file, KF_GROUP_ITEMS, key, error->message);
1103  data->print_date_format = format->print_date_format;
1104  g_clear_error(&error);
1105  }
1106  g_free(key);
1107  break;
1108  default:
1109  break;
1110  }
1111 
1112  list = g_slist_append(list, data);
1113  data = NULL;
1114  }
1115 
1116  /* Should never be reached. */
1117  return list;
1118 
1119 failed:
1120  g_warning("Check file %s, group %s, key %s, error: %s",
1121  file, KF_GROUP_ITEMS, key, error->message);
1122 cleanup:
1123  if (error)
1124  g_error_free(error);
1125  if (data)
1126  g_free(data);
1127  if (key)
1128  g_free(key);
1129  return list;
1130 }
1131 
1132 
1133 /* Free the data describing the placement of a single item on a check.
1134  */
1135 static void
1136 format_free_item_placement(check_item_t *data)
1137 {
1138  if (data->font)
1139  g_free(data->font);
1140  if (data->text)
1141  g_free(data->text);
1142  if (data->filename)
1143  g_free(data->filename);
1144  g_free(data);
1145 }
1146 
1147 
1148 /* Read the information describing whether a page contains multiple checks or
1149  * a single check. If there are multiple checks on a page, this functions
1150  * builds a linked list of the position names and their offsets (from the
1151  * upper left corner of the page).
1152  */
1153 static GSList *
1154 format_read_multicheck_info(const gchar *file,
1155  GKeyFile *key_file, check_format_t *format)
1156 {
1157  GError *error = NULL;
1158  GSList *list = NULL;
1159  gchar *key, **names;
1160  gsize length;
1161  gint i;
1162 
1163  key = g_strdup_printf("%s", KF_KEY_HEIGHT);
1164  format->height = g_key_file_get_double(key_file, KF_GROUP_POS, key, &error);
1165  if (error)
1166  {
1167  if ((error->domain == G_KEY_FILE_ERROR)
1168  && ((error->code == G_KEY_FILE_ERROR_GROUP_NOT_FOUND)
1169  || (error->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND)))
1170  {
1171  g_clear_error(&error);
1172  format->height = 0.0;
1173  }
1174  else
1175  {
1176  g_warning("Check file %s, error reading group %s, key %s: %s",
1177  file, KF_GROUP_POS, key, error->message);
1178  g_free(key);
1179  return NULL;
1180  }
1181  }
1182 
1183  names = g_key_file_get_string_list(key_file, KF_GROUP_POS, KF_KEY_NAMES,
1184  &length, &error);
1185  if (error)
1186  {
1187  if ((error->domain == G_KEY_FILE_ERROR)
1188  && ((error->code == G_KEY_FILE_ERROR_GROUP_NOT_FOUND)
1189  || (error->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND)))
1190  {
1191  /* This is the expected exit from this function. */
1192  g_free(key);
1193  return NULL;
1194  }
1195  g_warning("Check file %s, error reading group %s, key %s: %s",
1196  file, KF_GROUP_POS, key, error->message);
1197  g_free(key);
1198  return list;
1199  }
1200 
1201  for (i = 0; i < length; i++)
1202  list = g_slist_append(list, g_strdup(names[i]));
1203 
1204  g_strfreev(names);
1205  return list;
1206 }
1207 
1208 
1209 /* Free the data describing the placement of multiple checks on a page.
1210  */
1211 static void
1212 free_check_position(gchar *name)
1213 {
1214  g_free(name);
1215 }
1216 
1217 
1218 /* Read the information describing the general layout of a page of checks.
1219  * All items in this section are optional except or the name of the check
1220  * style.
1221  */
1222 static gboolean
1223 format_read_general_info(const gchar *file,
1224  GKeyFile *key_file, check_format_t *format)
1225 {
1226  GError *error = NULL;
1227  gchar **parts;
1228  gchar *value;
1229  double *dd;
1230  gsize dd_len;
1231 
1232  value = g_key_file_get_string(key_file, KF_GROUP_TOP, KF_KEY_GUID, &error);
1233  if (error)
1234  {
1235  g_warning("Check file %s, group %s, key %s, error: %s",
1236  file, KF_GROUP_TOP, KF_KEY_GUID, error->message);
1237  g_error_free(error);
1238  return FALSE;
1239  }
1240  parts = g_strsplit(value, "-", -1);
1241  format->guid = g_strjoinv("", parts);
1242  g_strfreev(parts);
1243  g_debug("Check file %s, group %s, key %s, value: %s",
1244  file, KF_GROUP_TOP, KF_KEY_GUID, format->guid);
1245 
1246  format->title =
1247  g_key_file_get_string(key_file, KF_GROUP_TOP, KF_KEY_TITLE, &error);
1248  if (!error)
1249  {
1250  g_debug("Check file %s, group %s, key %s, value: %s",
1251  file, KF_GROUP_TOP, KF_KEY_TITLE, format->title);
1252  }
1253  else
1254  {
1255  g_warning("Check file %s, group %s, key %s, error: %s",
1256  file, KF_GROUP_TOP, KF_KEY_TITLE, error->message);
1257  return FALSE;
1258  }
1259 
1260  format->blocking =
1261  g_key_file_get_boolean(key_file, KF_GROUP_TOP, KF_KEY_BLOCKING,
1262  &error);
1263  if (!error)
1264  {
1265  g_debug("Check file %s, group %s, key %s, value: %d",
1266  file, KF_GROUP_TOP, KF_KEY_BLOCKING, format->blocking);
1267  }
1268  else
1269  {
1270  if (!((error->domain == G_KEY_FILE_ERROR)
1271  && (error->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND)))
1272  g_warning("Check file %s, group %s, key %s, error: %s",
1273  file, KF_GROUP_TOP, KF_KEY_BLOCKING, error->message);
1274  if ( gnc_prefs_get_bool(GNC_PREFS_GROUP, GNC_PREF_BLOCKING_CHARS) )
1275  {
1276  format->blocking = TRUE;
1277  }
1278  else
1279  {
1280  format->blocking = FALSE;
1281  }
1282  g_clear_error(&error);
1283  }
1284 
1285  format->print_date_format =
1286  g_key_file_get_boolean(key_file, KF_GROUP_TOP, KF_KEY_DATE_FORMAT,
1287  &error);
1288  if (!error)
1289  {
1290  g_debug("Check file %s, group %s, key %s, value: %d",
1291  file, KF_GROUP_TOP, KF_KEY_DATE_FORMAT, format->print_date_format);
1292  }
1293  else
1294  {
1295  if (!((error->domain == G_KEY_FILE_ERROR)
1296  && (error->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND)))
1297  g_warning("Check file %s, group %s, key %s, error: %s",
1298  file, KF_GROUP_TOP, KF_KEY_DATE_FORMAT, error->message);
1299  if ( gnc_prefs_get_bool(GNC_PREFS_GROUP, GNC_PREF_PRINT_DATE_FMT) )
1300  {
1301  format->print_date_format = TRUE;
1302  }
1303  else
1304  {
1305  format->print_date_format = FALSE;
1306  }
1307  g_clear_error(&error);
1308  }
1309 
1310  format->show_grid =
1311  g_key_file_get_boolean(key_file, KF_GROUP_TOP, KF_KEY_SHOW_GRID,
1312  &error);
1313  if (!error)
1314  {
1315  g_debug("Check file %s, group %s, key %s, value: %d",
1316  file, KF_GROUP_TOP, KF_KEY_SHOW_GRID, format->show_grid);
1317  }
1318  else
1319  {
1320  if (!((error->domain == G_KEY_FILE_ERROR)
1321  && (error->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND)))
1322  g_warning("Check file %s, group %s, key %s, error: %s",
1323  file, KF_GROUP_TOP, KF_KEY_SHOW_GRID, error->message);
1324  format->show_grid = FALSE;
1325  g_clear_error(&error);
1326  }
1327 
1328  format->show_boxes =
1329  g_key_file_get_boolean(key_file, KF_GROUP_TOP, KF_KEY_SHOW_BOXES,
1330  &error);
1331  if (!error)
1332  {
1333  g_debug("Check file %s, group %s, key %s, value: %d",
1334  file, KF_GROUP_TOP, KF_KEY_SHOW_BOXES, format->show_boxes);
1335  }
1336  else
1337  {
1338  if (!((error->domain == G_KEY_FILE_ERROR)
1339  && (error->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND)))
1340  g_warning("Check file %s, group %s, key %s, error: %s",
1341  file, KF_GROUP_TOP, KF_KEY_SHOW_BOXES, error->message);
1342  format->show_boxes = FALSE;
1343  g_clear_error(&error);
1344  }
1345 
1346  format->font =
1347  g_key_file_get_string(key_file, KF_GROUP_TOP, KF_KEY_FONT, &error);
1348  if (!error)
1349  {
1350  g_debug("Check file %s, group %s, key %s, value: %s",
1351  file, KF_GROUP_TOP, KF_KEY_FONT, format->font);
1352  }
1353  else
1354  {
1355  if (!((error->domain == G_KEY_FILE_ERROR)
1356  && (error->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND)))
1357  g_warning("Check file %s, group %s, key %s, error: %s",
1358  file, KF_GROUP_TOP, KF_KEY_FONT, error->message);
1359  g_clear_error(&error);
1360  }
1361 
1362  format->rotation =
1363  g_key_file_get_double(key_file, KF_GROUP_TOP, KF_KEY_ROTATION, &error);
1364  if (!error)
1365  {
1366  g_debug("Check file %s, group %s, key %s, value: %f",
1367  file, KF_GROUP_TOP, KF_KEY_ROTATION, format->rotation);
1368  }
1369  else
1370  {
1371  if (!((error->domain == G_KEY_FILE_ERROR)
1372  && (error->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND)))
1373  g_warning("Check file %s, group %s, key %s, error: %s",
1374  file, KF_GROUP_TOP, KF_KEY_ROTATION, error->message);
1375  format->rotation = 0.0;
1376  g_clear_error(&error);
1377  }
1378 
1379  dd = g_key_file_get_double_list(key_file, KF_GROUP_TOP, KF_KEY_TRANSLATION,
1380  &dd_len, &error);
1381  if (!error)
1382  {
1383  value = doubles_to_string(dd, dd_len);
1384  g_debug("Check file %s, group %s, key %s, length %"G_GSIZE_FORMAT"; values: %s",
1385  file, KF_GROUP_TOP, KF_KEY_TRANSLATION, dd_len, value);
1386  g_free(value);
1387 
1388  if (dd_len == 2)
1389  {
1390  format->trans_x = dd[0];
1391  format->trans_y = dd[1];
1392  }
1393  else
1394  {
1395  g_warning("Check file %s, error top %s, key %s: 2 values only",
1396  file, KF_GROUP_TOP, KF_KEY_TRANSLATION);
1397  }
1398  g_free(dd);
1399  }
1400  else
1401  {
1402  if (!((error->domain == G_KEY_FILE_ERROR)
1403  && (error->code == G_KEY_FILE_ERROR_KEY_NOT_FOUND)))
1404  g_warning("Check file %s, group top %s, key %s: %s",
1405  file, KF_GROUP_ITEMS, KF_KEY_TRANSLATION, error->message);
1406  g_clear_error(&error);
1407  }
1408 
1409  return TRUE;
1410 }
1411 
1412 
1413 /* Free all of the information describing a page of checks.
1414  */
1415 static void
1416 free_check_format(check_format_t *data)
1417 {
1418  g_free(data->guid);
1419  g_free(data->filename);
1420  g_free(data->title);
1421  g_free(data->font);
1422  g_slist_foreach(data->positions, (GFunc) free_check_position, NULL);
1423  g_slist_free(data->positions);
1424  g_slist_foreach(data->items, (GFunc) format_free_item_placement, NULL);
1425  g_slist_free(data->items);
1426  g_free(data);
1427 }
1428 
1429 
1430 /* Read a single check format file and append the resulting format to the
1431  * list of all known formats. This function calls other functions to read
1432  * each section of the data file.
1433  */
1434 static check_format_t *
1435 read_one_check_format(PrintCheckDialog *pcd, const gchar *groupname,
1436  const gchar *dirname, const gchar *file)
1437 {
1438  gchar *pathname;
1439  GKeyFile *key_file;
1440  check_format_t *format;
1441 
1442  pathname = g_build_filename(dirname, file, (char *)NULL);
1443  key_file = gnc_key_file_load_from_file(pathname, FALSE, FALSE, NULL);
1444  g_free(pathname);
1445  if (!key_file)
1446  {
1447  g_warning("Check file %s, cannot load file", file);
1448  return NULL;
1449  }
1450 
1451  format = g_new0(check_format_t, 1);
1452  format->group = groupname;
1453  format->filename = g_strdup(file);
1454  if (format_read_general_info(file, key_file, format))
1455  {
1456  format->positions = format_read_multicheck_info(file, key_file, format);
1457  format->items = format_read_item_placement(file, key_file, format);
1458  }
1459 
1460  g_key_file_free(key_file);
1461  if ((NULL == format->title) || (NULL == format->items))
1462  {
1463  g_warning("Check file %s, no items read. Dropping file.", file);
1464  free_check_format(format);
1465  return NULL;
1466  }
1467 
1468  return format;
1469 }
1470 
1471 
1472 /* Iterate over a single check directory, throwing out any backup files and
1473  * then calling a helper function to read and parse the check format withing
1474  * the file.
1475  */
1476 static void
1477 read_one_check_directory(PrintCheckDialog *pcd, GtkListStore *store,
1478  const gchar *groupname, const gchar *dirname)
1479 {
1480  check_format_t *format, *existing;
1481  GDir *dir;
1482  const gchar *filename;
1483  GtkTreeIter iter;
1484  GtkWidget *dialog;
1485  gboolean found = FALSE;
1486 
1487  dir = g_dir_open(dirname, 0, NULL);
1488  if (dir == NULL)
1489  return;
1490 
1491  while ((filename = g_dir_read_name(dir)) != NULL)
1492  {
1493  if (g_str_has_prefix(filename, "#"))
1494  continue;
1495  if (!g_str_has_suffix(filename, ".chk"))
1496  continue;
1497 
1498  format = read_one_check_format(pcd, groupname, dirname, filename);
1499  if (NULL == format)
1500  continue;
1501 
1502  existing = find_existing_format(store, format->guid, NULL);
1503  if (existing)
1504  {
1505  dialog = gtk_message_dialog_new
1506  (GTK_WINDOW(pcd->dialog),
1507  GTK_DIALOG_DESTROY_WITH_PARENT,
1508  GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s",
1509  _("There is a duplicate check format file."));
1510  gtk_message_dialog_format_secondary_text
1511  (GTK_MESSAGE_DIALOG(dialog),
1512  /* Translators: %1$s is the type of the first check
1513  * format (user defined or application defined); %2$s
1514  * is the filename of that format; %3$s the type of
1515  * the other check format; and %4$s the filename of
1516  * that other format. */
1517  _("The GUIDs in the %s check format file '%s' and "
1518  "the %s check format file '%s' match."),
1519  existing->group, existing->filename,
1520  format->group, format->filename);
1521  gtk_dialog_run(GTK_DIALOG(dialog));
1522  gtk_widget_destroy(dialog);
1523  }
1524  else
1525  {
1526  gtk_list_store_append(store, &iter);
1527  gtk_list_store_set(store, &iter, COL_NAME, format->title,
1528  COL_DATA, format, -1);
1529  found = TRUE;
1530  }
1531  }
1532  g_dir_close(dir);
1533 
1534  /* If any files were added to the list, add a separator between
1535  * this group and the next. */
1536  if (found)
1537  {
1538  gtk_list_store_append(store, &iter);
1539  gtk_list_store_set(store, &iter, COL_SEP, TRUE, -1);
1540  }
1541 }
1542 
1543 
1544 /* Read all check formats. This function first looks in the system directory
1545  * for check files, and then looks in the user's .gnucash directory for any
1546  * custom check files.
1547  */
1548 static void
1549 read_formats(PrintCheckDialog *pcd, GtkListStore *store)
1550 {
1551  gchar *dirname, *pkgdatadir;
1552 
1553  pkgdatadir = gnc_path_get_pkgdatadir();
1554  dirname = g_build_filename(pkgdatadir, CHECK_FMT_DIR, (char *)NULL);
1555  /* Translators: This is a directory name. It may be presented to
1556  * the user to indicate that some data file was defined by the
1557  * gnucash application. */
1558  read_one_check_directory(pcd, store, _("application"), dirname);
1559  g_free(dirname);
1560  g_free(pkgdatadir);
1561 
1562  dirname = gnc_build_dotgnucash_path(CHECK_FMT_DIR);
1563  /* Translators: This is a directory name. It may be presented to
1564  * the user to indicate that some data file was defined by a
1565  * user herself. */
1566  read_one_check_directory(pcd, store, _("user"), dirname);
1567  g_free(dirname);
1568 }
1569 
1570 
1571 static gboolean
1572 format_is_a_separator (GtkTreeModel *model, GtkTreeIter *iter, gpointer data)
1573 {
1574  gboolean separator;
1575 
1576  gtk_tree_model_get(model, iter, COL_SEP, &separator, -1);
1577  return separator;
1578 }
1579 
1580 
1581 static void
1582 initialize_format_combobox (PrintCheckDialog *pcd)
1583 {
1584  GtkListStore *store;
1585  GtkTreeIter iter;
1586 
1587  store = gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_BOOLEAN);
1588  read_formats(pcd, store);
1589  gtk_list_store_append(store, &iter);
1590  gtk_list_store_set(store, &iter, COL_NAME, _("Custom"), -1);
1591  pcd->format_max = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), NULL);
1592  gtk_combo_box_set_model(GTK_COMBO_BOX(pcd->format_combobox),
1593  GTK_TREE_MODEL(store));
1594  gtk_combo_box_set_row_separator_func(GTK_COMBO_BOX(pcd->format_combobox),
1595  format_is_a_separator, NULL, NULL);
1596 }
1597 
1598 
1599 /*****************************************************
1600  * gnc_ui_print_check_dialog_create2 *
1601  * make a new print check dialog and wait for it. *
1602  *****************************************************/
1603 void
1604 gnc_ui_print_check_dialog_create2(GncPluginPageRegister2 *plugin_page,
1605  GList *splits)
1606 {
1607  PrintCheckDialog *pcd;
1608  GtkBuilder *builder;
1609  GtkWidget *table;
1610  GtkWindow *window;
1611  gchar *font;
1612  Transaction *trans = NULL;
1613 
1614  pcd = g_new0(PrintCheckDialog, 1);
1615  pcd->plugin_page = plugin_page;
1616  pcd->splits = g_list_copy(splits);
1617 
1618  builder = gtk_builder_new();
1619  gnc_builder_add_from_file (builder, "dialog-print-check.glade", "adjustment1");
1620  gnc_builder_add_from_file (builder, "dialog-print-check.glade", "adjustment2");
1621  gnc_builder_add_from_file (builder, "dialog-print-check.glade", "adjustment3");
1622  gnc_builder_add_from_file (builder, "dialog-print-check.glade", "adjustment4");
1623  gnc_builder_add_from_file (builder, "dialog-print-check.glade", "adjustment5");
1624  gnc_builder_add_from_file (builder, "dialog-print-check.glade", "adjustment6");
1625  gnc_builder_add_from_file (builder, "dialog-print-check.glade", "adjustment7");
1626  gnc_builder_add_from_file (builder, "dialog-print-check.glade", "adjustment8");
1627  gnc_builder_add_from_file (builder, "dialog-print-check.glade", "adjustment9");
1628  gnc_builder_add_from_file (builder, "dialog-print-check.glade", "adjustment10");
1629  gnc_builder_add_from_file (builder, "dialog-print-check.glade", "adjustment11");
1630  gnc_builder_add_from_file (builder, "dialog-print-check.glade", "adjustment12");
1631  gnc_builder_add_from_file (builder, "dialog-print-check.glade", "adjustment13");
1632  gnc_builder_add_from_file (builder, "dialog-print-check.glade", "adjustment14");
1633  gnc_builder_add_from_file (builder, "dialog-print-check.glade", "adjustment15");
1634  gnc_builder_add_from_file (builder, "dialog-print-check.glade", "adjustment16");
1635  gnc_builder_add_from_file (builder, "dialog-print-check.glade", "adjustment17");
1636  gnc_builder_add_from_file (builder, "dialog-print-check.glade", "adjustment18");
1637  gnc_builder_add_from_file (builder, "dialog-print-check.glade", "adjustment19");
1638  gnc_builder_add_from_file (builder, "dialog-print-check.glade", "adjustment20");
1639  gnc_builder_add_from_file (builder, "dialog-print-check.glade", "adjustment21");
1640  gnc_builder_add_from_file (builder, "dialog-print-check.glade", "adjustment22");
1641  gnc_builder_add_from_file (builder, "dialog-print-check.glade", "adjustment23");
1642  gnc_builder_add_from_file (builder, "dialog-print-check.glade", "adjustment24");
1643  gnc_builder_add_from_file (builder, "dialog-print-check.glade", "liststore1");
1644  gnc_builder_add_from_file (builder, "dialog-print-check.glade", "liststore2");
1645  gnc_builder_add_from_file (builder, "dialog-print-check.glade", "liststore3");
1646  gnc_builder_add_from_file (builder, "dialog-print-check.glade", "Print Check Dialog");
1647 
1648  gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, pcd);
1649 
1650  pcd->builder = builder;
1651  pcd->dialog = GTK_WIDGET(gtk_builder_get_object (builder, "Print Check Dialog"));
1652 
1653  /* now pick out the relevant child widgets */
1654  pcd->format_combobox = GTK_WIDGET(gtk_builder_get_object (builder, "check_format_combobox"));
1655  pcd->position_combobox = GTK_WIDGET(gtk_builder_get_object (builder, "check_position_combobox"));
1656  pcd->first_page_count = GTK_SPIN_BUTTON(gtk_builder_get_object (builder, "first_page_count_entry"));
1657 
1658  pcd->custom_table = GTK_WIDGET(gtk_builder_get_object (builder, "custom_table"));
1659  pcd->payee_x = GTK_SPIN_BUTTON(gtk_builder_get_object (builder, "payee_x_entry"));
1660  pcd->payee_y = GTK_SPIN_BUTTON(gtk_builder_get_object (builder, "payee_y_entry"));
1661  pcd->date_x = GTK_SPIN_BUTTON(gtk_builder_get_object (builder, "date_x_entry"));
1662  pcd->date_y = GTK_SPIN_BUTTON(gtk_builder_get_object (builder, "date_y_entry"));
1663  pcd->words_x = GTK_SPIN_BUTTON(gtk_builder_get_object (builder, "amount_words_x_entry"));
1664  pcd->words_y = GTK_SPIN_BUTTON(gtk_builder_get_object (builder, "amount_words_y_entry"));
1665  pcd->number_x = GTK_SPIN_BUTTON(gtk_builder_get_object (builder, "amount_numbers_x_entry"));
1666  pcd->number_y = GTK_SPIN_BUTTON(gtk_builder_get_object (builder, "amount_numbers_y_entry"));
1667  pcd->notes_x = GTK_SPIN_BUTTON(gtk_builder_get_object (builder, "notes_x_entry"));
1668  pcd->notes_y = GTK_SPIN_BUTTON(gtk_builder_get_object (builder, "notes_y_entry"));
1669  pcd->memo_x = GTK_SPIN_BUTTON(gtk_builder_get_object (builder, "memo_x_entry"));
1670  pcd->memo_y = GTK_SPIN_BUTTON(gtk_builder_get_object (builder, "memo_y_entry"));
1671  pcd->address_x = GTK_SPIN_BUTTON(gtk_builder_get_object (builder, "address_x_entry"));
1672  pcd->address_y = GTK_SPIN_BUTTON(gtk_builder_get_object (builder, "address_y_entry"));
1673  pcd->splits_amount_x = GTK_SPIN_BUTTON(gtk_builder_get_object (builder, "splits_amount_x_entry"));
1674  pcd->splits_amount_y = GTK_SPIN_BUTTON(gtk_builder_get_object (builder, "splits_amount_y_entry"));
1675  pcd->splits_memo_x = GTK_SPIN_BUTTON(gtk_builder_get_object (builder, "splits_memo_x_entry"));
1676  pcd->splits_memo_y = GTK_SPIN_BUTTON(gtk_builder_get_object (builder, "splits_memo_y_entry"));
1677  pcd->splits_account_x = GTK_SPIN_BUTTON(gtk_builder_get_object (builder, "splits_account_x_entry"));
1678  pcd->splits_account_y = GTK_SPIN_BUTTON(gtk_builder_get_object (builder, "splits_account_y_entry"));
1679  pcd->translation_x = GTK_SPIN_BUTTON(gtk_builder_get_object (builder, "translation_x_entry"));
1680  pcd->translation_y = GTK_SPIN_BUTTON(gtk_builder_get_object (builder, "translation_y_entry"));
1681  pcd->translation_label = GTK_WIDGET(gtk_builder_get_object (builder, "translation_label"));
1682  pcd->check_rotation = GTK_SPIN_BUTTON(gtk_builder_get_object (builder, "check_rotation_entry"));
1683  pcd->units_combobox = GTK_WIDGET(gtk_builder_get_object (builder, "units_combobox"));
1684 
1685  window = GTK_WINDOW(GNC_PLUGIN_PAGE(plugin_page)->window);
1686  gtk_window_set_transient_for(GTK_WINDOW(pcd->dialog), window);
1687  pcd->caller_window = GTK_WINDOW(window);
1688 
1689  /* Create and attach the date-format chooser */
1690  table = GTK_WIDGET(gtk_builder_get_object (builder, "options_table"));
1691  pcd->date_format = gnc_date_format_new_without_label();
1692  gtk_table_attach_defaults(GTK_TABLE(table), pcd->date_format, 1, 3, 4, 7);
1693 
1694  /* Default font (set in preferences) */
1695  font = gnc_prefs_get_string(GNC_PREFS_GROUP, GNC_PREF_DEFAULT_FONT);
1696  pcd->default_font = font ? font : g_strdup(DEFAULT_FONT);
1697 
1698  /* Update the combo boxes bases on the available check formats */
1699  initialize_format_combobox(pcd);
1700 
1701  /* address */
1702  pcd->check_address_name = GTK_WIDGET(gtk_builder_get_object (builder, "check_address_name"));
1703  pcd->check_address_1 = GTK_WIDGET(gtk_builder_get_object (builder, "check_address_1"));
1704  pcd->check_address_2 = GTK_WIDGET(gtk_builder_get_object (builder, "check_address_2"));
1705  pcd->check_address_3 = GTK_WIDGET(gtk_builder_get_object (builder, "check_address_3"));
1706  pcd->check_address_4 = GTK_WIDGET(gtk_builder_get_object (builder, "check_address_4"));
1707  /* fill in any available address data */
1708  /* Can't access business objects e.g. Customer,Vendor,Employee because
1709  * it would create build problems */
1710  if (g_list_length(pcd->splits) == 1)
1711  trans = xaccSplitGetParent((Split *)(pcd->splits->data));
1712  else
1713  trans = NULL;
1714  if ( trans )
1715  {
1716  gtk_entry_set_text(GTK_ENTRY(pcd->check_address_name), xaccTransGetDescription(trans));
1717  }
1718  else
1719  {
1720  /* nothing to do - defaults to blank */
1721  }
1722 
1723  gtk_widget_destroy(GTK_WIDGET(gtk_builder_get_object (builder, "lower_left")));
1724 
1725  gnc_ui_print_restore_dialog(pcd);
1726  gnc_restore_window_size(GNC_PREFS_GROUP, GTK_WINDOW(pcd->dialog));
1727 
1728  g_object_unref(G_OBJECT(builder));
1729  gtk_widget_show_all(pcd->dialog);
1730 }
1731 
1732 
1733 /**************************************
1734  * Print check contents to the page. *
1735  **************************************/
1736 
1737 /* Draw a grid pattern on the page to be printed. This grid is helpful when
1738  * figuring out the offsets for where to print various items on the page.
1739  */
1740 static void
1741 draw_grid(GtkPrintContext *context, gint width, gint height, const gchar *font)
1742 {
1743  const double dash_pattern[2] = { 1.0, 5.0 };
1744  PangoFontDescription *desc;
1745  PangoLayout *layout;
1746  cairo_t *cr;
1747  gchar *text;
1748  gint i;
1749 
1750  /* Initialize for printing text */
1751  layout = gtk_print_context_create_pango_layout(context);
1752  desc = pango_font_description_from_string(font);
1753  pango_layout_set_font_description(layout, desc);
1754  pango_font_description_free(desc);
1755  pango_layout_set_alignment(layout, PANGO_ALIGN_LEFT);
1756  pango_layout_set_width(layout, -1);
1757 
1758  /* Set up the line to draw with. */
1759  cr = gtk_print_context_get_cairo_context(context);
1760  cairo_save(cr);
1761  cairo_set_line_width(cr, 1.0);
1762  cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
1763  cairo_set_dash(cr, dash_pattern, 2, 0);
1764 
1765  /* Draw horizontal lines */
1766  for (i = -200; i < (height + 200); i += 50)
1767  {
1768  text = g_strdup_printf("%d", (int)i);
1769  cairo_move_to(cr, -200, i);
1770  cairo_line_to(cr, width + 200, i);
1771  cairo_stroke(cr);
1772  pango_layout_set_text(layout, text, -1);
1773  cairo_move_to(cr, 0, i);
1774  pango_cairo_show_layout(cr, layout);
1775  g_free(text);
1776  }
1777 
1778  /* Draw vertical lines */
1779  for (i = -200; i < (width + 200); i += 50)
1780  {
1781  text = g_strdup_printf("%d", (int)i);
1782  cairo_move_to(cr, i, -200);
1783  cairo_line_to(cr, i, height + 200);
1784  cairo_stroke(cr);
1785  pango_layout_set_text(layout, text, -1);
1786  cairo_move_to(cr, i, 0);
1787  pango_cairo_show_layout(cr, layout);
1788  g_free(text);
1789  }
1790 
1791  /* Clean up after ourselves */
1792  cairo_restore(cr);
1793  g_object_unref(layout);
1794 }
1795 
1796 
1797 /* Print a single line of text to the printed page. If a width and height
1798  * are specified, the line will be wrapped at the specified width, and the
1799  * resulting text will be clipped if it does not fit in the space
1800  * available.
1801  */
1802 static gdouble
1803 draw_text(GtkPrintContext *context, const gchar *text, check_item_t *data,
1804  PangoFontDescription *default_desc)
1805 {
1806  PangoFontDescription *desc;
1807  PangoLayout *layout;
1808  cairo_t *cr;
1809  gint layout_height, layout_width;
1810  gdouble width, height;
1811  gchar *new_text;
1812 
1813  if ((NULL == text) || (strlen(text) == 0))
1814  return 0.0;
1815 
1816  /* Initialize for printing text */
1817  layout = gtk_print_context_create_pango_layout(context);
1818  if (data->font)
1819  {
1820  desc = pango_font_description_from_string(data->font);
1821  pango_layout_set_font_description(layout, desc);
1822  pango_font_description_free(desc);
1823  }
1824  else
1825  {
1826  pango_layout_set_font_description(layout, default_desc);
1827  }
1828  pango_layout_set_alignment(layout,
1829  data->w ? data->align : PANGO_ALIGN_LEFT);
1830  pango_layout_set_width(layout, data->w ? data->w * PANGO_SCALE : -1);
1831  pango_layout_set_ellipsize(layout, PANGO_ELLIPSIZE_END);
1832  if ( data->blocking )
1833  {
1834  new_text = g_strdup_printf("***%s***", text);
1835  pango_layout_set_text(layout, new_text, -1);
1836  g_free(new_text);
1837  }
1838  else
1839  {
1840  pango_layout_set_text(layout, text, -1);
1841  }
1842  pango_layout_get_size(layout, &layout_width, &layout_height);
1843  width = (gdouble) layout_width / PANGO_SCALE;
1844  height = (gdouble) layout_height / PANGO_SCALE;
1845 
1846  cr = gtk_print_context_get_cairo_context(context);
1847  cairo_save(cr);
1848 
1849  /* Clip text to the enclosing rectangle */
1850  if (data->w && data->h)
1851  {
1852  g_debug("Text clip rectangle, coords %f,%f, size %f,%f",
1853  data->x, data->y - data->h, data->w, data->h);
1854  cairo_rectangle(cr, data->x, data->y - data->h, data->w, data->h);
1855  cairo_clip_preserve(cr);
1856  }
1857 
1858  /* Draw the text */
1859  g_debug("Text move to %f,%f, print '%s'", data->x, data->y,
1860  text ? text : "(null)");
1861  cairo_move_to(cr, data->x, data->y - height);
1862  pango_cairo_show_layout(cr, layout);
1863 
1864  /* Clean up after ourselves */
1865  cairo_restore(cr);
1866  g_object_unref(layout);
1867  return width;
1868 
1869 }
1870 
1871 
1872 /* Find and load the specified image. If the specified filename isn't an
1873  * absolute path name, this code will also look in the gnucash system check
1874  * format directory, and then in the user's private check format
1875  * directory.
1876  *
1877  * NOTE: The gtk_image_new_from_file() function never fails. If it can't
1878  * find the specified file, it returns the "broken image" icon. This function
1879  * takes advantage of that.
1880 */
1881 static GtkWidget *
1882 read_image (const gchar *filename)
1883 {
1884  GtkWidget *image;
1885  gchar *pkgdatadir, *dirname, *tmp_name;
1886 
1887  if (g_path_is_absolute(filename))
1888  return gtk_image_new_from_file(filename);
1889 
1890  pkgdatadir = gnc_path_get_pkgdatadir();
1891  tmp_name = g_build_filename(pkgdatadir, CHECK_FMT_DIR, filename, (char *)NULL);
1892  if (!g_file_test(tmp_name, G_FILE_TEST_EXISTS))
1893  {
1894  g_free(tmp_name);
1895  dirname = gnc_build_dotgnucash_path(CHECK_FMT_DIR);
1896  tmp_name = g_build_filename(dirname, filename, (char *)NULL);
1897  g_free(dirname);
1898  }
1899  image = gtk_image_new_from_file(tmp_name);
1900  g_free(tmp_name);
1901  return image;
1902 }
1903 
1904 
1905 /* Print a single image to the printed page. This picture will be scaled
1906  * down to fit in the specified size rectangle. Scaling is done with the
1907  * proportions locked 1:1 so as not to distort the image.
1908  */
1909 static void
1910 draw_picture(GtkPrintContext *context, check_item_t *data)
1911 {
1912  cairo_t *cr;
1913  GdkPixbuf *pixbuf, *scaled_pixbuf;
1914  GtkImage *image;
1915  gint pix_w, pix_h;
1916  gdouble scale_w, scale_h, scale;
1917 
1918  cr = gtk_print_context_get_cairo_context(context);
1919  cairo_save(cr);
1920 
1921  /* Get the picture. */
1922  image = GTK_IMAGE(read_image(data->filename));
1923  pixbuf = gtk_image_get_pixbuf(image);
1924  if (pixbuf)
1925  {
1926  g_object_ref(pixbuf);
1927  }
1928  else
1929  {
1930  g_warning("Filename '%s' cannot be read or understood.",
1931  data->filename);
1932  pixbuf = gtk_widget_render_icon(GTK_WIDGET(image),
1933  GTK_STOCK_MISSING_IMAGE,
1934  -1, NULL);
1935  }
1936  pix_w = gdk_pixbuf_get_width(pixbuf);
1937  pix_h = gdk_pixbuf_get_height(pixbuf);
1938 
1939  /* Draw the enclosing rectangle */
1940  if (data->w && data->h)
1941  {
1942  cairo_rectangle(cr, data->x, data->y - data->h, data->w, data->h);
1943  g_debug("Picture clip rectangle, user coords %f,%f, user size %f,%f",
1944  data->x, data->y - data->h, data->w, data->h);
1945  }
1946  else
1947  {
1948  cairo_rectangle(cr, data->x, data->y - pix_h, pix_w, pix_h);
1949  g_debug("Picture clip rectangle, user coords %f,%f, pic size %d,%d",
1950  data->x, data->y - data->h, pix_w, pix_h);
1951  }
1952  cairo_clip_preserve(cr);
1953 
1954  /* Scale down to fit. Never scale up. */
1955  scale_w = scale_h = 1;
1956  if (data->w && (pix_w > data->w))
1957  scale_w = data->w / pix_w;
1958  if (data->h && (pix_h > data->h))
1959  scale_h = data->h / pix_h;
1960  scale = MIN(scale_w, scale_h);
1961 
1962  if (scale != 1)
1963  {
1964  scaled_pixbuf = gdk_pixbuf_scale_simple(pixbuf, pix_w * scale,
1965  pix_h * scale,
1966  GDK_INTERP_BILINEAR);
1967  pix_h = gdk_pixbuf_get_height(scaled_pixbuf);
1968  gdk_cairo_set_source_pixbuf(cr, scaled_pixbuf, data->x,
1969  data->y - pix_h);
1970 
1971  g_object_unref(scaled_pixbuf);
1972  }
1973  else
1974  {
1975  gdk_cairo_set_source_pixbuf(cr, pixbuf, data->x, data->y - pix_h);
1976  }
1977  g_object_unref(pixbuf);
1978  cairo_paint(cr);
1979 
1980  /* Clean up after ourselves */
1981  cairo_restore(cr);
1982  gtk_widget_destroy(GTK_WIDGET(image));
1983 }
1984 
1985 
1986 #define DATE_FMT_HEIGHT 8
1987 #define DATE_FMT_SLOP 2
1988 
1989 /* There is a new Canadian requirement that all software that prints the date
1990  * on a check must also print the format of that date underneath using a 6-8
1991  * point font. This function implements that requirement. It requires the
1992  * font description used in printing the date so that it can print in the same
1993  * font using a smaller point size. It also requires width of the printed
1994  * date as an argument, allowing it to center the format string under the
1995  * date.
1996  *
1997  * Note: This code only prints a date if the user has explicitly requested it
1998  * via a preference setting. This is because gnucash has no way of
1999  * knowing if the user's checks already have a date format printed on them.
2000  */
2001 static void
2002 draw_date_format(GtkPrintContext *context, const gchar *date_format,
2003  check_item_t *data, PangoFontDescription *default_desc,
2004  gdouble width)
2005 {
2006  PangoFontDescription *date_desc;
2007  check_item_t date_item;
2008  gchar *text = NULL, *expanded = NULL;
2009  const gchar *c;
2010  GString *cdn_fmt;
2011 
2012  setlocale(LC_ALL, NULL);
2013  if ( !data->print_date_format ) return;
2014 
2015  date_desc = pango_font_description_copy_static(default_desc);
2016  pango_font_description_set_size(date_desc, DATE_FMT_HEIGHT * PANGO_SCALE);
2017  date_item = *data;
2018  date_item.y += (DATE_FMT_HEIGHT + DATE_FMT_SLOP);
2019  date_item.w = width;
2020  date_item.h = DATE_FMT_HEIGHT + DATE_FMT_SLOP;
2021  date_item.align = PANGO_ALIGN_CENTER;
2022 
2023  /* This is a date format string. It should only contain ascii. */
2024  cdn_fmt = g_string_new_len(NULL, 50);
2025  for (c = date_format; c && *c; )
2026  {
2027  if ((c[0] != '%') || (c[1] == '\0'))
2028  {
2029  c += 1;
2030  continue;
2031  }
2032  switch (c[1])
2033  {
2034  case 'F':
2035  cdn_fmt = g_string_append(cdn_fmt, "YYYYMMDD");
2036  break;
2037  case 'Y':
2038  cdn_fmt = g_string_append(cdn_fmt, "YYYY");
2039  break;
2040  case 'y':
2041  cdn_fmt = g_string_append(cdn_fmt, "YY");
2042  break;
2043  case 'm':
2044  cdn_fmt = g_string_append(cdn_fmt, "MM");
2045  break;
2046  case 'd':
2047  case 'e':
2048  cdn_fmt = g_string_append(cdn_fmt, "DD");
2049  break;
2050  case 'x':
2051  expanded = g_strdup_printf("%s%s",
2053  c + 2);
2054  c = expanded;
2055  continue;
2056  default:
2057  break;
2058  }
2059  c += 2;
2060  }
2061 
2062  text = g_string_free(cdn_fmt, FALSE);
2063  draw_text(context, text, &date_item, date_desc);
2064  g_free(text);
2065  if (expanded)
2066  g_free(expanded);
2067  pango_font_description_free(date_desc);
2068 }
2069 
2070 
2071 /* Print each of the items that in the description of a single check. This
2072  * function uses helper functions to print text based and picture based items.
2073  */
2074 static void
2075 draw_page_items(GtkPrintContext *context,
2076  check_format_t *format, gpointer user_data)
2077 {
2078  PrintCheckDialog *pcd = (PrintCheckDialog *) user_data;
2079  PangoFontDescription *default_desc;
2080  Transaction *trans;
2081  gnc_numeric amount;
2082  GNCPrintAmountInfo info;
2083  const gchar *date_format;
2084  gchar *text = NULL, buf[100];
2085  GSList *elem;
2086  check_item_t *item;
2087  gdouble width;
2088  gchar *address = NULL;
2089 
2090  trans = xaccSplitGetParent(pcd->split);
2091  /* This was valid when the check printing dialog was instantiated. */
2092  g_return_if_fail(trans);
2093  amount = gnc_numeric_abs(xaccSplitGetAmount(pcd->split));
2094 
2095  if (format->font)
2096  default_desc = pango_font_description_from_string(format->font);
2097  else
2098  default_desc = pango_font_description_from_string(pcd->default_font);
2099 
2100  /* Now put the actual data onto the page. */
2101  for (elem = format->items; elem; elem = g_slist_next(elem))
2102  {
2103  item = elem->data;
2104 
2105  switch (item->type)
2106  {
2107  case DATE:
2108  {
2109  GDate date;
2110  g_date_clear (&date, 1);
2111  gnc_gdate_set_time64 (&date, xaccTransGetDate(trans));
2112  date_format =
2113  gnc_date_format_get_custom(GNC_DATE_FORMAT
2114  (pcd->date_format));
2115  g_date_strftime(buf, 100, date_format, &date);
2116  width = draw_text(context, buf, item, default_desc);
2117  draw_date_format(context, date_format, item, default_desc, width);
2118  break;
2119  }
2120 
2121  case PAYEE:
2122  draw_text(context, xaccTransGetDescription(trans), item, default_desc);
2123  break;
2124 
2125  case NOTES:
2126  draw_text(context, xaccTransGetNotes(trans), item, default_desc);
2127  break;
2128 
2129  case MEMO:
2130  draw_text(context, xaccSplitGetMemo(pcd->split), item, default_desc);
2131  break;
2132 
2133  case ACTION:
2134  draw_text(context, gnc_get_action_num(trans, pcd->split), item,
2135  default_desc);
2136  break;
2137 
2138  case CHECK_NUMBER:
2139  draw_text(context, gnc_get_num_action(trans, pcd->split), item,
2140  default_desc);
2141  break;
2142 
2143  case AMOUNT_NUMBER:
2144  info = gnc_default_print_info(FALSE);
2145  draw_text(context, xaccPrintAmount(amount, info),
2146  item, default_desc);
2147  break;
2148 
2149  case AMOUNT_WORDS:
2150  text = numeric_to_words(amount);
2151  draw_text(context, text, item, default_desc);
2152  g_free(text);
2153  break;
2154 
2155  case TEXT:
2156  draw_text(context, item->text, item, default_desc);
2157  break;
2158 
2159  case ADDRESS:
2160  address = get_check_address2(pcd);
2161  draw_text(context, address, item, default_desc);
2162  g_free(address);
2163  break;
2164 
2165  case SPLITS_AMOUNT:
2166  text = get_check_splits_amount2(pcd);
2167  draw_text(context, text, item, default_desc);
2168  g_free(text);
2169  break;
2170 
2171  case SPLITS_MEMO:
2172  text = get_check_splits_memo2(pcd);
2173  draw_text(context, text, item, default_desc);
2174  g_free(text);
2175  break;
2176 
2177  case SPLITS_ACCOUNT:
2178  text = get_check_splits_account2(pcd);
2179  draw_text(context, text, item, default_desc);
2180  g_free(text);
2181  break;
2182 
2183  case PICTURE:
2184  draw_picture(context, item);
2185  break;
2186 
2187  default:
2188  text = g_strdup_printf("(unknown check field, type %d)", item->type);
2189  draw_text(context, text, item, default_desc);
2190  g_free(text);
2191  break;
2192  }
2193  }
2194 
2195  pango_font_description_free(default_desc);
2196 }
2197 
2198 
2199 /* Print each of the items that in the description of a single check. This
2200  * function uses helper functions to print text based and picture based items.
2201  */
2202 static void
2203 draw_page_boxes(GtkPrintContext *context,
2204  check_format_t *format, gpointer user_data)
2205 {
2206  cairo_t *cr;
2207  GSList *elem;
2208  check_item_t *item;
2209 
2210  cr = gtk_print_context_get_cairo_context(context);
2211 
2212  /* Now put the actual data onto the page. */
2213  for (elem = format->items; elem; elem = g_slist_next(elem))
2214  {
2215  item = elem->data;
2216  if (!item->w || !item->h)
2217  continue;
2218  cairo_rectangle(cr, item->x, item->y - item->h, item->w, item->h);
2219  cairo_stroke(cr);
2220  }
2221 }
2222 
2223 
2224 /* Print an entire page based upon the layout in a check description file. This
2225  * function takes care of translating/rotating the page, calling the function to
2226  * print the grid pattern (if requested), and calls a helper function to print
2227  * all check items.
2228  */
2229 static void
2230 draw_check_format(GtkPrintContext *context, gint position,
2231  check_format_t *format, gpointer user_data)
2232 {
2233  PrintCheckDialog *pcd = (PrintCheckDialog *) user_data;
2234  cairo_t *cr;
2235  gdouble x, y, r, multip;
2236 
2237  cr = gtk_print_context_get_cairo_context(context);
2238  cairo_translate(cr, format->trans_x, format->trans_y);
2239  g_debug("Page translated by %f,%f", format->trans_x, format->trans_y);
2240  cairo_rotate(cr, format->rotation * DEGREES_TO_RADIANS);
2241  g_debug("Page rotated by %f degrees", format->rotation);
2242 
2243  /* The grid is useful when determining check layouts */
2244  if (format->show_grid)
2245  {
2246  draw_grid(context,
2247  gtk_print_context_get_width(context),
2248  gtk_print_context_get_height(context),
2249  pcd->default_font);
2250  }
2251 
2252  /* Translate all subsequent check items if requested.
2253  * For check position 0, no translation is needed. */
2254  if ((position > 0) && (position < pcd->position_max))
2255  {
2256  /* Standard positioning is used.
2257  * Note that the first check on the page (position 0) doesn't
2258  * need to be moved (hence the test for position > 0 above. */
2259  cairo_translate(cr, 0, format->height);
2260  g_debug("Position %d translated by %f (pre-defined)", position, format->height);
2261  }
2262  else if (position == pcd->position_max)
2263  {
2264  /* Custom positioning is used. */
2265  multip = pcd_get_custom_multip(pcd);
2266  x = multip * gtk_spin_button_get_value(pcd->translation_x);
2267  y = multip * gtk_spin_button_get_value(pcd->translation_y);
2268  cairo_translate(cr, x, y);
2269  g_debug("Position translated by %f,%f (custom)", x, y);
2270  r = gtk_spin_button_get_value(pcd->check_rotation);
2271  cairo_rotate(cr, r * DEGREES_TO_RADIANS);
2272  g_debug("Position rotated by %f degrees (custom)", r);
2273  }
2274 
2275  /* Draw layout boxes if requested. Also useful when determining check
2276  * layouts. */
2277  if (format->show_boxes)
2278  draw_page_boxes(context, format, user_data);
2279 
2280  /* Draw the actual check data. */
2281  draw_page_items(context, format, user_data);
2282 }
2283 
2284 
2285 static void
2286 draw_check_custom(GtkPrintContext *context, gpointer user_data)
2287 {
2288  PrintCheckDialog *pcd = (PrintCheckDialog *) user_data;
2289  GNCPrintAmountInfo info;
2290  PangoFontDescription *desc;
2291  Transaction *trans;
2292  gnc_numeric amount;
2293  cairo_t *cr;
2294  const gchar *date_format;
2295  gchar *text = NULL, buf[100];
2296  check_item_t item = { 0 };
2297  gdouble x, y, multip, degrees;
2298  GDate date;
2299  gchar *address;
2300 
2301  trans = xaccSplitGetParent(pcd->split);
2302  /* This was valid when the check printing dialog was instantiated. */
2303  g_return_if_fail(trans);
2304 
2305  desc = pango_font_description_from_string(pcd->default_font);
2306 
2307  multip = pcd_get_custom_multip(pcd);
2308  degrees = gtk_spin_button_get_value(pcd->check_rotation);
2309  cr = gtk_print_context_get_cairo_context(context);
2310  cairo_rotate(cr, degrees * DEGREES_TO_RADIANS);
2311  g_debug("Page rotated by %f degrees", degrees);
2312 
2313  x = multip * gtk_spin_button_get_value(pcd->translation_x);
2314  y = multip * gtk_spin_button_get_value(pcd->translation_y);
2315  cairo_translate(cr, x, y);
2316  g_debug("Page translated by %f,%f", x, y);
2317 
2318  item.x = multip * gtk_spin_button_get_value(pcd->payee_x);
2319  item.y = multip * gtk_spin_button_get_value(pcd->payee_y);
2320  draw_text(context, xaccTransGetDescription(trans), &item, desc);
2321 
2322  item.x = multip * gtk_spin_button_get_value(pcd->date_x);
2323  item.y = multip * gtk_spin_button_get_value(pcd->date_y);
2324  g_date_clear (&date, 1);
2325  gnc_gdate_set_time64 (&date, xaccTransGetDate(trans));
2326  date_format = gnc_date_format_get_custom(GNC_DATE_FORMAT(pcd->date_format));
2327  g_date_strftime(buf, 100, date_format, &date);
2328  draw_text(context, buf, &item, desc);
2329 
2330  item.x = multip * gtk_spin_button_get_value(pcd->number_x);
2331  item.y = multip * gtk_spin_button_get_value(pcd->number_y);
2332  info = gnc_default_print_info(FALSE);
2333  amount = gnc_numeric_abs(xaccSplitGetAmount(pcd->split));
2334  draw_text(context, xaccPrintAmount(amount, info), &item, desc);
2335 
2336  item.x = multip * gtk_spin_button_get_value(pcd->words_x);
2337  item.y = multip * gtk_spin_button_get_value(pcd->words_y);
2338  text = numeric_to_words(amount);
2339  draw_text(context, text, &item, desc);
2340  g_free(text);
2341 
2342  item.x = multip * gtk_spin_button_get_value(pcd->address_x);
2343  item.y = multip * gtk_spin_button_get_value(pcd->address_y);
2344  address = get_check_address2(pcd);
2345  draw_text(context, address, &item, desc);
2346  g_free(address);
2347 
2348  item.x = multip * gtk_spin_button_get_value(pcd->splits_amount_x);
2349  item.y = multip * gtk_spin_button_get_value(pcd->splits_amount_y);
2350  text = get_check_splits_amount2(pcd);
2351  draw_text(context, text, &item, desc);
2352  g_free(text);
2353 
2354  item.x = multip * gtk_spin_button_get_value(pcd->splits_memo_x);
2355  item.y = multip * gtk_spin_button_get_value(pcd->splits_memo_y);
2356  text = get_check_splits_memo2(pcd);
2357  draw_text(context, text, &item, desc);
2358  g_free(text);
2359 
2360  item.x = multip * gtk_spin_button_get_value(pcd->splits_account_x);
2361  item.y = multip * gtk_spin_button_get_value(pcd->splits_account_y);
2362  text = get_check_splits_account2(pcd);
2363  draw_text(context, text, &item, desc);
2364  g_free(text);
2365 
2366  item.x = multip * gtk_spin_button_get_value(pcd->notes_x);
2367  item.y = multip * gtk_spin_button_get_value(pcd->notes_y);
2368  draw_text(context, xaccTransGetNotes(trans), &item, desc);
2369 
2370  item.x = multip * gtk_spin_button_get_value(pcd->memo_x);
2371  item.y = multip * gtk_spin_button_get_value(pcd->memo_y);
2372  draw_text(context, xaccSplitGetMemo(pcd->split), &item, desc);
2373 
2374  pango_font_description_free(desc);
2375 }
2376 
2377 
2378 /* Print a page of checks. This takes into account the number of checks to print,
2379  * the number of checks on a page, and the starting check position on the page.
2380  * This function is called once by the GtkPrint code once for each page to be printed.
2381  */
2382 static void
2383 draw_page(GtkPrintOperation *operation,
2384  GtkPrintContext *context, gint page_nr, gpointer user_data)
2385 {
2386  PrintCheckDialog *pcd = (PrintCheckDialog *) user_data;
2387  check_format_t *format;
2388 
2389  format = pcd->selected_format;
2390  if (format)
2391  {
2392  gint first_check, last_check;
2393  gint first_page_count;
2394  guint check_count = g_list_length(pcd->splits);
2395  gint check_number;
2396  gint position = gtk_combo_box_get_active(GTK_COMBO_BOX(pcd->position_combobox));
2397  gint checks_per_page;
2398  GList *next_split;
2399 
2400  if (position == pcd->position_max)
2401  {
2402  /* Custom position, one check per page */
2403  checks_per_page = 1;
2404  first_page_count = 1;
2405  }
2406  else
2407  {
2408  checks_per_page = pcd->position_max;
2409  first_page_count = gtk_spin_button_get_value_as_int(pcd->first_page_count);
2410  }
2411 
2412  if (page_nr == 0)
2413  {
2414  first_check = 0;
2415  last_check = first_page_count - 1;
2416  next_split = pcd->splits;
2417  }
2418  else
2419  {
2420  first_check = first_page_count + (page_nr - 1) * checks_per_page;
2421  last_check = MIN(check_count - 1, first_check + checks_per_page - 1);
2422  next_split = g_list_nth(pcd->splits, first_check);
2423  /* If position is not "custom" reset it to top */
2424  if (position < pcd->position_max)
2425  position = 0;
2426  }
2427 
2428  for (check_number = first_check; check_number <= last_check;
2429  check_number++, position++)
2430  {
2431  pcd->split = (Split *) next_split->data;
2432  next_split = g_list_next(next_split);
2433  draw_check_format(context, position, format, user_data);
2434  }
2435  }
2436  else
2437  {
2438  /* Custom check format */
2439  pcd->split = (Split *) g_list_nth_data(pcd->splits, page_nr);
2440  g_return_if_fail(pcd->split);
2441  draw_check_custom(context, user_data);
2442  }
2443 }
2444 
2445 
2446 /* Compute the number of pages required to complete this print operation.
2447  * This function is called once by the GtkPrint code to determine the number
2448  * of pages required to complete the print operation.
2449  */
2450 static void
2451 begin_print(GtkPrintOperation *operation,
2452  GtkPrintContext *context, gpointer user_data)
2453 {
2454  PrintCheckDialog *pcd = (PrintCheckDialog *) user_data;
2455  guint check_count = g_list_length(pcd->splits);
2456  gint first_page_count;
2457  gint pages;
2458  gint position = gtk_combo_box_get_active(GTK_COMBO_BOX(pcd->position_combobox));
2459 
2460  if (pcd->selected_format && pcd->position_max > 1 && position < pcd->position_max)
2461  {
2462  first_page_count = gtk_spin_button_get_value_as_int(pcd->first_page_count);
2463  pages = ((check_count - first_page_count) + pcd->position_max - 1) /
2464  pcd->position_max + 1;
2465  }
2466  else
2467  pages = check_count;
2468  gtk_print_operation_set_n_pages(operation, pages);
2469 }
2470 
2471 
2472 /************************************
2473  * gnc_ui_print_check_dialog_ok_cb *
2474  ************************************/
2475 static void
2476 gnc_ui_print_check_dialog_ok_cb(PrintCheckDialog *pcd)
2477 {
2478  GtkPrintOperation *print;
2479  GtkPrintOperationResult res;
2480 
2481  print = gtk_print_operation_new();
2482 
2483  gnc_print_operation_init(print, "GnuCash-Checks");
2484  gtk_print_operation_set_unit(print, GTK_UNIT_POINTS);
2485  gtk_print_operation_set_use_full_page(print, TRUE);
2486  g_signal_connect(print, "begin_print", G_CALLBACK(begin_print), pcd);
2487  g_signal_connect(print, "draw_page", G_CALLBACK(draw_page), pcd);
2488 
2489  res = gtk_print_operation_run(print,
2490  GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG,
2491  pcd->caller_window, NULL);
2492 
2493  if (res == GTK_PRINT_OPERATION_RESULT_APPLY)
2495 
2496  g_object_unref(print);
2497 }
2498 
2499 
2500 static void
2501 gnc_print_check_set_sensitive (GtkWidget *widget, gpointer data)
2502 {
2503  gboolean sensitive;
2504  if (GTK_IS_LABEL(widget) || GTK_IS_SEPARATOR(widget))
2505  return;
2506  sensitive = GPOINTER_TO_INT(data);
2507  gtk_widget_set_sensitive(widget, sensitive);
2508 }
2509 
2510 
2511 void
2512 gnc_print_check_format_changed2 (GtkComboBox *widget,
2513  PrintCheckDialog *pcd)
2514 {
2515  GtkListStore *p_store;
2516  GtkTreeModel *f_model;
2517  GtkTreeIter f_iter, iter;
2518  gboolean sensitive;
2519  gint pnum;
2520  check_format_t *format;
2521  gboolean separator;
2522  GSList *elem;
2523 
2524  if (!gtk_combo_box_get_active_iter(GTK_COMBO_BOX(pcd->format_combobox), &f_iter))
2525  return;
2526  f_model = gtk_combo_box_get_model(GTK_COMBO_BOX(pcd->format_combobox));
2527  gtk_tree_model_get(f_model, &f_iter, COL_DATA, &format, COL_SEP, &separator, -1);
2528  if (separator)
2529  return;
2530 
2531  pnum = gtk_combo_box_get_active(GTK_COMBO_BOX(pcd->position_combobox));
2532 
2533  /* Update the positions combobox */
2534  pcd->selected_format = format;
2535  p_store = gtk_list_store_new (1, G_TYPE_STRING);
2536  gtk_combo_box_set_model(GTK_COMBO_BOX(pcd->position_combobox),
2537  GTK_TREE_MODEL(p_store));
2538  if (format)
2539  {
2540  if (format->positions)
2541  {
2542  pcd->position_max = g_slist_length(format->positions); /* -1 for 0 base, +1 for custom entry */
2543  for (elem = format->positions; elem; elem = g_slist_next(elem))
2544  {
2545  gtk_list_store_append(GTK_LIST_STORE(p_store), &iter);
2546  gtk_list_store_set (GTK_LIST_STORE(p_store), &iter, 0, elem->data, -1);
2547  }
2548  }
2549  else
2550  {
2551  /* Invent a "Top" position if format has no positions */
2552  pcd->position_max = 1;
2553  gtk_list_store_append(GTK_LIST_STORE(p_store), &iter);
2554  gtk_list_store_set (GTK_LIST_STORE(p_store), &iter, 0, _("Top"), -1);
2555  }
2556  }
2557  else
2558  {
2559  pcd->position_max = 0;
2560  }
2561  gtk_list_store_append(GTK_LIST_STORE(p_store), &iter);
2562  gtk_list_store_set (GTK_LIST_STORE(p_store), &iter, 0, _("Custom"), -1);
2563 
2564  /* If there's only one thing in the position combobox, make it insensitive */
2565  sensitive = (pcd->position_max > 0);
2566  gtk_widget_set_sensitive(GTK_WIDGET(pcd->position_combobox), sensitive);
2567 
2568  /* Update the custom page, this must be done before setting the active
2569  entry in the position combo box since gnc_print_check_position_changed2
2570  will adjust these settings in some cases. */
2571  sensitive = (!separator && !format);
2572  gtk_container_foreach(GTK_CONTAINER(pcd->custom_table),
2573  gnc_print_check_set_sensitive,
2574  GINT_TO_POINTER(sensitive));
2575 
2576  /* Set the active entry in the position combo box, this will trigger a
2577  call to gnc_print_check_position_changed2 */
2578  pnum = MAX(MIN(pnum, pcd->position_max), 0);
2579  gtk_combo_box_set_active(GTK_COMBO_BOX(pcd->position_combobox), pnum);
2580 
2581  /* Update address fields */
2582  sensitive = check_format_has_address(pcd);
2583  gtk_widget_set_sensitive(pcd->check_address_name, sensitive);
2584  gtk_widget_set_sensitive(pcd->check_address_1, sensitive);
2585  gtk_widget_set_sensitive(pcd->check_address_2, sensitive);
2586  gtk_widget_set_sensitive(pcd->check_address_3, sensitive);
2587  gtk_widget_set_sensitive(pcd->check_address_4, sensitive);
2588 }
2589 
2590 
2591 void
2592 gnc_print_check_position_changed2 (GtkComboBox *widget,
2593  PrintCheckDialog *pcd)
2594 {
2595  gboolean sensitive;
2596  gint pnum;
2597  guint check_count;
2598  gint first_page_max, first_page_min, first_page_value;
2599 
2600  pnum = gtk_combo_box_get_active(GTK_COMBO_BOX(pcd->position_combobox));
2601 
2602  /* Make the translation and rotation fields active if the position is "custom" */
2603  sensitive = pnum == pcd->position_max;
2604  gtk_widget_set_sensitive(GTK_WIDGET(pcd->translation_x), sensitive);
2605  gtk_widget_set_sensitive(GTK_WIDGET(pcd->translation_y), sensitive);
2606  gtk_widget_set_sensitive(GTK_WIDGET(pcd->check_rotation), sensitive);
2607  gtk_widget_set_sensitive(GTK_WIDGET(pcd->units_combobox), sensitive);
2608 
2609  /* Set up the first page check count spin box */
2610  check_count = g_list_length(pcd->splits);
2611  first_page_max = MAX(1, MIN(pcd->position_max - pnum, check_count));
2612  first_page_min = 1;
2613  pnum = gtk_spin_button_get_value_as_int(pcd->first_page_count);
2614  first_page_value = MAX(MIN(pnum, first_page_max), first_page_min);
2615  gtk_spin_button_set_range(pcd->first_page_count, (gdouble)first_page_min, (gdouble)first_page_max);
2616  gtk_spin_button_set_value(pcd->first_page_count, (gdouble)first_page_value);
2617  sensitive = first_page_max > 1;
2618  gtk_widget_set_sensitive(GTK_WIDGET(pcd->first_page_count), sensitive);
2619 }
2620 
2621 
2622 void
2623 gnc_ui_print_check_response_cb2(GtkDialog *dialog,
2624  gint response,
2625  PrintCheckDialog *pcd)
2626 {
2627  switch (response)
2628  {
2629  case GTK_RESPONSE_HELP:
2630  gnc_gnome_help(HF_HELP, HL_PRINTCHECK);
2631  return;
2632 
2633  case GTK_RESPONSE_OK:
2634  gnc_ui_print_check_dialog_ok_cb(pcd);
2635  gnc_ui_print_save_dialog(pcd);
2636  gnc_save_window_size(GNC_PREFS_GROUP, GTK_WINDOW(dialog));
2637  break;
2638 
2639  case GTK_RESPONSE_CANCEL:
2640  gnc_save_window_size(GNC_PREFS_GROUP, GTK_WINDOW(dialog));
2641  break;
2642  }
2643 
2644  gtk_widget_destroy(pcd->dialog);
2645  g_free(pcd->default_font);
2646  g_list_free(pcd->splits);
2647  g_free(pcd);
2648 }
void guid_replace(GncGUID *guid)
time64 xaccTransGetDate(const Transaction *trans)
Definition: Transaction.c:2215
gchar * gnc_prefs_get_string(const gchar *group, const gchar *pref_name)
Definition: gnc-prefs.c:237
Date and Time handling routines.
utility functions for the GnuCash UI
An exact-rational-number library for gnucash. (to be renamed qofnumeric.h in libqof2) ...
gboolean gnc_prefs_set_int(const gchar *group, const gchar *pref_name, gint value)
Definition: gnc-prefs.c:293
GKeyFile helper routines.
void gnc_print_operation_save_print_settings(GtkPrintOperation *op)
Definition: print-session.c:47
void gnc_prefs_reset(const gchar *group, const gchar *pref_name)
Definition: gnc-prefs.c:366
Transaction * xaccSplitGetParent(const Split *split)
Definition: Split.c:1903
API for Transactions and Splits (journal entries)
gchar * guid_to_string_buff(const GncGUID *guid, gchar *buff)
gboolean gnc_prefs_set_string(const gchar *group, const gchar *pref_name, const gchar *value)
Definition: gnc-prefs.c:324
gchar * gnc_build_dotgnucash_path(const gchar *filename)
Make a path to filename in the user's configuration directory.
CheckItemType type
gint gnc_prefs_get_int(const gchar *group, const gchar *pref_name)
Definition: gnc-prefs.c:206
Definition: guid.h:65
const char * xaccTransGetNotes(const Transaction *trans)
Definition: Transaction.c:2197
PangoAlignment align
CheckItemType2 type
gchar * gnc_get_account_name_for_register(const Account *account)
Definition: gnc-ui-util.c:282
GList SplitList
Definition: gnc-engine.h:203
void gnc_print_operation_init(GtkPrintOperation *op, const gchar *jobname)
Definition: print-session.c:59
gboolean print_date_format
gboolean gnc_key_file_save_to_file(const gchar *filename, GKeyFile *key_file, GError **error)
#define GUID_ENCODING_LENGTH
Definition: guid.h:74
const gchar * qof_date_format_get_string(QofDateFormat df)
gboolean gnc_prefs_set_float(const gchar *group, const gchar *pref_name, gdouble value)
Definition: gnc-prefs.c:313
gboolean gnc_prefs_set_coords(const gchar *group, const gchar *pref_name, gdouble x, gdouble y)
Definition: gnc-prefs.c:346
void gnc_prefs_get_coords(const gchar *group, const gchar *pref_name, gdouble *x, gdouble *y)
Definition: gnc-prefs.c:257
const char * xaccTransGetDescription(const Transaction *trans)
Definition: Transaction.c:2184
GKeyFile * gnc_key_file_load_from_file(const gchar *filename, gboolean ignore_error, gboolean return_empty_struct, GError **caller_error)
gnc_numeric gnc_numeric_abs(gnc_numeric a)
void gnc_gnome_help(const char *file_name, const char *anchor)
All type declarations for the whole Gnucash engine.
Generic api to store and retrieve preferences.
GDate helper routines.
Definition: SplitP.h:71
Account * xaccSplitGetAccount(const Split *s)
Definition: Split.c:968
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Definition: gnc-prefs.c:196
gboolean print_date_format
const gchar * gnc_dotgnucash_dir(void)
Ensure that the user's configuration directory exists and is minimally populated. ...
const gchar * group
const char * xaccSplitGetMemo(const Split *split)
Definition: Split.c:1968
format_combo_col_t
File path resolution utility functions.
API for Transactions and Splits (journal entries)
SplitList * xaccTransGetSplitList(const Transaction *trans)
Definition: Transaction.c:2164
const gchar * QofLogModule
Definition: qofid.h:89
void gnc_gdate_set_time64(GDate *gd, time64 time)
gdouble gnc_prefs_get_float(const gchar *group, const gchar *pref_name)
Definition: gnc-prefs.c:227
gnc_numeric xaccSplitGetAmount(const Split *split)
Definition: Split.c:1987