GnuCash  5.6-150-g038405b370+
dialog-ab-trans.c
1 /*
2  * dialog-ab-trans.c --
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of
7  * the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, contact:
16  *
17  * Free Software Foundation Voice: +1-617-542-5942
18  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
19  * Boston, MA 02110-1301, USA gnu@gnu.org
20  */
21 
32 #include <config.h>
33 
34 #include <glib/gi18n.h>
35 #include "gnc-ab-utils.h"
36 #if (AQBANKING_VERSION_INT >= 60400)
37 #include <aqbanking/types/transaction.h>
38 
39 #include <gnc-aqbanking-templates.h>
40 #endif
41 #include "dialog-ab-trans.h"
42 #include "dialog-transfer.h"
43 #include "dialog-utils.h"
44 #include "gnc-amount-edit.h"
45 #include "gnc-ui.h"
46 
47 /* This static indicates the debugging module that this .o belongs to. */
48 static QofLogModule log_module = G_LOG_DOMAIN;
49 
50 #if (AQBANKING_VERSION_INT >= 60400)
51 /* Template handling */
52 static void gnc_ab_trans_dialog_fill_templ_helper(gpointer data, gpointer user_data);
53 static gboolean gnc_ab_trans_dialog_clear_templ_helper(GtkTreeModel *model,
54  GtkTreePath *path,
55  GtkTreeIter *iter,
56  gpointer user_data);
57 static gboolean gnc_ab_trans_dialog_get_templ_helper(GtkTreeModel *model,
58  GtkTreePath *path,
59  GtkTreeIter *iter,
60  gpointer data);
61 #endif
62 static AB_TRANSACTION *gnc_ab_trans_dialog_fill_values(GncABTransDialog *td);
63 static GNC_AB_JOB *gnc_ab_trans_dialog_get_available_empty_job(GNC_AB_ACCOUNT_SPEC *ab_acc,
64  GncABTransType trans_type);
65 
66 static void gnc_ab_trans_dialog_check_iban(const GncABTransDialog *td,
67  const AB_TRANSACTION *trans);
68 
69 /* Callbacks - connected with GtkBuilder - so should not be static */
70 void gnc_ab_trans_dialog_add_templ_cb(GtkButton *button, gpointer user_data);
71 void gnc_ab_trans_dialog_moveup_templ_cb(GtkButton *button, gpointer user_data);
72 void gnc_ab_trans_dialog_movedown_templ_cb(GtkButton *button, gpointer user_data);
73 void gnc_ab_trans_dialog_sort_templ_cb(GtkButton *button, gpointer user_data);
74 void gnc_ab_trans_dialog_del_templ_cb(GtkButton *button, gpointer user_data);
75 void gnc_ab_trans_dialog_ibanentry_filter_cb (GtkEditable *editable,
76  const gchar *text,
77  gint length,
78  gint *position,
79  gpointer user_data);
80 void gnc_ab_trans_dialog_bicentry_filter_cb (GtkEditable *editable,
81  const gchar *text,
82  gint length,
83  gint *position,
84  gpointer user_data);
85 void gnc_ab_trans_dialog_templ_list_row_activated_cb(GtkTreeView *view,
86  GtkTreePath *path,
87  GtkTreeViewColumn *column,
88  gpointer user_data);
89 
90 static void gnc_ab_trans_dialog_verify_values(GncABTransDialog *td);
91 
92 
93 enum
94 {
95  TEMPLATE_NAME,
96  TEMPLATE_POINTER,
97  TEMPLATE_NUM_COLUMNS
98 };
99 
101 {
102  /* The dialog itself */
103  GtkWidget *dialog;
104  GtkWidget *parent;
105  GNC_AB_ACCOUNT_SPEC *ab_acc;
106 
107  /* Whether this is a transfer or a direct debit */
108  GncABTransType trans_type;
109 
110  /* Recipient */
111  GtkWidget *recp_name_entry;
112  GtkWidget *recp_account_entry;
113  GtkWidget *recp_bankcode_entry;
114 
115  /* Amount */
116  GtkWidget *amount_edit;
117 
118  /* Purpose, description */
119  GtkWidget *purpose_entry;
120  GtkWidget *purpose_cont_entry;
121  GtkWidget *purpose_cont2_entry;
122  GtkWidget *purpose_cont3_entry;
123 
124  /* Recipient's bank name (may be filled in automatically sometime later) */
125  GtkWidget *recp_bankname_label;
126 
127  /* Originator's name (might have to be edited by the user) */
128  GtkWidget *orig_name_entry;
129 
130  /* The template choosing GtkTreeView/GtkListStore */
131  GtkTreeView *template_gtktreeview;
132  GtkListStore *template_list_store;
133 
134  /* Exec button */
135  GtkWidget *exec_button;
136 
137  /* Flag, if template list has been changed */
138  gboolean templ_changed;
139 
140  /* The aqbanking transaction that got created here */
141  AB_TRANSACTION *ab_trans;
142 
143  /* The gnucash transaction that got created here */
144  Transaction *gnc_trans;
145 };
146 
147 gboolean gnc_ab_trans_isSEPA(GncABTransType t)
148 {
149  switch (t)
150  {
151  case SEPA_TRANSFER:
152 #if (AQBANKING_VERSION_INT >= 60400)
153  case SEPA_INTERNAL_TRANSFER:
154 #endif
155  case SEPA_DEBITNOTE:
156  return TRUE;
157  default:
158  return FALSE;
159  }
160 }
161 
162 #if (AQBANKING_VERSION_INT >= 60400)
163 static void
164 gnc_ab_trans_dialog_fill_templ_helper(gpointer data, gpointer user_data)
165 {
166  GncABTransTempl *templ = data;
167  GtkListStore *store = user_data;
168  GtkTreeIter iter;
169 
170  g_return_if_fail(templ && store);
171  gtk_list_store_append(store, &iter);
172  gtk_list_store_set(store, &iter,
173  TEMPLATE_NAME, gnc_ab_trans_templ_get_name(templ),
174  TEMPLATE_POINTER, templ,
175  -1);
176 }
177 #endif
178 
182 static AB_TRANSACTION *
183 gnc_ab_trans_dialog_fill_values(GncABTransDialog *td)
184 {
185  /* Fill in the user-entered values */
186  AB_TRANSACTION *trans = AB_Transaction_new();
187  AB_VALUE *value;
188 
189  AB_Banking_FillTransactionFromAccountSpec(trans, td->ab_acc);
190 
191  if (gnc_ab_trans_isSEPA(td->trans_type))
192  {
193  AB_Transaction_SetRemoteBic(
194  trans, gtk_entry_get_text(GTK_ENTRY(td->recp_bankcode_entry)));
195  AB_Transaction_SetRemoteIban(
196  trans, gtk_entry_get_text(GTK_ENTRY(td->recp_account_entry)));
197  AB_Transaction_SetLocalName(
198  trans, gtk_entry_get_text(GTK_ENTRY(td->orig_name_entry)));
199  }
200  else
201  {
202  AB_Transaction_SetRemoteBankCode(
203  trans, gtk_entry_get_text(GTK_ENTRY(td->recp_bankcode_entry)));
204  AB_Transaction_SetRemoteAccountNumber(
205  trans, gtk_entry_get_text(GTK_ENTRY(td->recp_account_entry)));
206  }
207  AB_Transaction_SetRemoteCountry(trans, "DE");
208  AB_Transaction_SetRemoteName(
209  trans, gtk_entry_get_text(GTK_ENTRY(td->recp_name_entry)));
210 
211  AB_Transaction_AddPurposeLine(
212  trans, gtk_entry_get_text(GTK_ENTRY(td->purpose_entry)));
213  AB_Transaction_AddPurposeLine(
214  trans, gtk_entry_get_text(GTK_ENTRY(td->purpose_cont_entry)));
215  AB_Transaction_AddPurposeLine(
216  trans, gtk_entry_get_text(GTK_ENTRY(td->purpose_cont2_entry)));
217  value = AB_Value_fromDouble(gnc_amount_edit_get_damount(
218  GNC_AMOUNT_EDIT(td->amount_edit)));
219  /* FIXME: Replace "EUR" by account-dependent string here. */
220  AB_Value_SetCurrency(value, "EUR");
221  AB_Transaction_SetValue(trans, value);
222  AB_Value_free(value);
223 
224  /* If this is a direct debit, a textkey/ "Textschluessel"/transactionCode
225  * different from the default has to be set. */
226  switch (td->trans_type)
227  {
228  case SINGLE_DEBITNOTE:
229  /* AB_Transaction_SetTransactionCode (trans, 05); */
230  AB_Transaction_SetTextKey(trans, 05);
231  break;
232  default:
233  /* AB_Transaction_SetTransactionCode (trans, 51); */
234  AB_Transaction_SetTextKey (trans, 51);
235  break;
236  }
237 
238  return trans;
239 }
240 
241 GncABTransDialog *
242 gnc_ab_trans_dialog_new(GtkWidget *parent, GNC_AB_ACCOUNT_SPEC *ab_acc,
243  gint commodity_scu, GncABTransType trans_type,
244  GList *templates)
245 {
246  GncABTransDialog *td;
247  GtkBuilder *builder;
248  const gchar *ab_ownername;
249  const gchar *ab_accountnumber;
250  const gchar *ab_bankname;
251  const gchar *ab_bankcode;
252  G_GNUC_UNUSED GtkWidget *trans_vbox;
253  GtkWidget *heading_label;
254  GtkWidget *recp_name_heading;
255  GtkWidget *recp_account_heading;
256  GtkWidget *recp_bankcode_heading;
257  GtkWidget *amount_hbox, *amount_label;
258  GtkWidget *orig_name_heading;
259  GtkWidget *orig_account_heading;
260  GtkWidget *orig_account_label;
261  G_GNUC_UNUSED GtkWidget *orig_bankname_heading;
262  GtkWidget *orig_bankname_label;
263  GtkWidget *orig_bankcode_heading;
264  GtkWidget *orig_bankcode_label;
265  GtkCellRenderer *renderer;
266  GtkTreeViewColumn *column;
267 #if (AQBANKING_VERSION_INT >= 60400)
268  GtkExpander *template_expander;
269  GtkWidget *template_label;
270  GtkWidget *add_templ_button;
271  GtkWidget *del_templ_button;
272 #endif
273 
274  g_return_val_if_fail(ab_acc, NULL);
275 
276  ab_ownername = AB_AccountSpec_GetOwnerName(ab_acc);
277  if (!ab_ownername)
278  ab_ownername = "";
279  ab_accountnumber = AB_AccountSpec_GetAccountNumber(ab_acc);
280  ab_bankcode = AB_AccountSpec_GetBankCode(ab_acc);
281  ab_bankname = _("(unknown)");
282 
283  td = g_new0(GncABTransDialog, 1);
284  td->parent = parent;
285  td->ab_acc = ab_acc;
286  td->trans_type = trans_type;
287 
288  builder = gtk_builder_new();
289  gnc_builder_add_from_file (builder, "dialog-ab.glade", "aqbanking_transaction_dialog");
290  td->dialog = GTK_WIDGET(gtk_builder_get_object (builder, "aqbanking_transaction_dialog"));
291 
292  if (parent)
293  gtk_window_set_transient_for(GTK_WINDOW(td->dialog), GTK_WINDOW(parent));
294 
295  /* Extract widgets */
296  trans_vbox = GTK_WIDGET(gtk_builder_get_object (builder, "trans_vbox"));
297  heading_label = GTK_WIDGET(gtk_builder_get_object (builder, "heading_label"));
298  recp_name_heading = GTK_WIDGET(gtk_builder_get_object (builder, "recp_name_heading"));
299  td->recp_name_entry = GTK_WIDGET(gtk_builder_get_object (builder, "recp_name_entry"));
300  recp_account_heading = GTK_WIDGET(gtk_builder_get_object (builder, "recp_account_heading"));
301  td->recp_account_entry = GTK_WIDGET(gtk_builder_get_object (builder, "recp_account_entry"));
302  recp_bankcode_heading = GTK_WIDGET(gtk_builder_get_object (builder, "recp_bankcode_heading"));
303  td->recp_bankcode_entry = GTK_WIDGET(gtk_builder_get_object (builder, "recp_bankcode_entry"));
304  td->recp_bankname_label = GTK_WIDGET(gtk_builder_get_object (builder, "recp_bankname_label"));
305  amount_hbox = GTK_WIDGET(gtk_builder_get_object (builder, "amount_hbox"));
306  amount_label = GTK_WIDGET(gtk_builder_get_object (builder, "amount_label"));
307  td->purpose_entry = GTK_WIDGET(gtk_builder_get_object (builder, "purpose_entry"));
308  td->purpose_cont_entry = GTK_WIDGET(gtk_builder_get_object (builder, "purpose_cont_entry"));
309  td->purpose_cont2_entry = GTK_WIDGET(gtk_builder_get_object (builder, "purpose_cont2_entry"));
310  td->purpose_cont3_entry = GTK_WIDGET(gtk_builder_get_object (builder, "purpose_cont3_entry"));
311  td->exec_button = GTK_WIDGET(gtk_builder_get_object(builder, "exec_now_button"));
312  orig_name_heading = GTK_WIDGET(gtk_builder_get_object (builder, "orig_name_heading"));
313  td->orig_name_entry = GTK_WIDGET(gtk_builder_get_object (builder, "orig_name_label"));
314  orig_account_heading = GTK_WIDGET(gtk_builder_get_object (builder, "orig_account_heading"));
315  orig_account_label = GTK_WIDGET(gtk_builder_get_object (builder, "orig_account_label"));
316  orig_bankname_heading = GTK_WIDGET(gtk_builder_get_object (builder, "orig_bankname_heading"));
317  orig_bankname_label = GTK_WIDGET(gtk_builder_get_object (builder, "orig_bankname_label"));
318  orig_bankcode_heading = GTK_WIDGET(gtk_builder_get_object (builder, "orig_bankcode_heading"));
319  orig_bankcode_label = GTK_WIDGET(gtk_builder_get_object (builder, "orig_bankcode_label"));
320  td->template_gtktreeview =
321  GTK_TREE_VIEW(gtk_builder_get_object (builder, "template_list"));
322 #if (AQBANKING_VERSION_INT >= 60400)
323  template_expander = GTK_EXPANDER(gtk_builder_get_object (builder, "expander1"));
324  template_label = GTK_WIDGET(gtk_builder_get_object (builder, "label1"));
325  add_templ_button= GTK_WIDGET(gtk_builder_get_object(builder, "add_templ_button"));
326  del_templ_button= GTK_WIDGET(gtk_builder_get_object(builder, "del_templ_button"));
327 #endif
328 
329  /* Amount edit */
330  td->amount_edit = gnc_amount_edit_new();
331  gtk_box_pack_start(GTK_BOX(amount_hbox), td->amount_edit, TRUE, TRUE, 0);
332  gnc_amount_edit_make_mnemonic_target(GNC_AMOUNT_EDIT(td->amount_edit), amount_label);
333  gnc_amount_edit_set_evaluate_on_enter(GNC_AMOUNT_EDIT(td->amount_edit),
334  TRUE);
335  gnc_amount_edit_set_fraction(GNC_AMOUNT_EDIT(td->amount_edit),
336  commodity_scu);
337 
338  /* Use "focus-out" signal because "amount-changed" is only sent when ENTER is pressed */
339  g_signal_connect_swapped (gnc_amount_edit_gtk_entry(GNC_AMOUNT_EDIT(td->amount_edit)), "focus-out-event",
340  G_CALLBACK(gnc_ab_trans_dialog_verify_values), td);
341 
342  /* Check for what kind of transaction this should be, and change the
343  * labels accordingly */
344  switch (trans_type)
345  {
346  case SINGLE_TRANSFER:
347  case SINGLE_INTERNAL_TRANSFER:
348  /* all labels are already set */
349  break;
350  case SEPA_TRANSFER:
351  gtk_label_set_text(GTK_LABEL (heading_label),
352  /* Translators: Strings from this file are
353  needed only in countries that have one of
354  aqbanking's Online Banking techniques
355  available. This is 'OFX DirectConnect'
356  (U.S. and others), 'HBCI' (Germany),
357  or 'YellowNet' (Switzerland). If none of
358  these techniques are available in your
359  country, you may safely ignore strings
360  from the import-export/hbci
361  subdirectory. */
362  _("Enter a SEPA Online Transfer"));
363  gtk_label_set_text(GTK_LABEL(recp_account_heading),
364  _("Recipient IBAN (International Account Number)"));
365  gtk_label_set_text(GTK_LABEL(recp_bankcode_heading),
366  _("Recipient BIC (Bank Code)"));
367 
368  gtk_label_set_text(GTK_LABEL(orig_account_heading),
369  _("Originator IBAN (International Account Number)"));
370  gtk_label_set_text(GTK_LABEL(orig_bankcode_heading),
371  _("Originator BIC (Bank Code)"));
372  break;
373 
374 #if (AQBANKING_VERSION_INT >= 60400)
375  case SEPA_INTERNAL_TRANSFER:
376  gtk_label_set_text(GTK_LABEL (heading_label),
377  _("Enter a SEPA Internal Transfer"));
378  gtk_label_set_text(GTK_LABEL(recp_account_heading),
379  _("Recipient IBAN (International Account Number)"));
380  gtk_label_set_text(GTK_LABEL(recp_bankcode_heading),
381  _("Recipient BIC (Bank Code)"));
382 
383  gtk_label_set_text(GTK_LABEL(orig_account_heading),
384  _("Originator IBAN (International Account Number)"));
385  gtk_label_set_text(GTK_LABEL(orig_bankcode_heading),
386  _("Originator BIC (Bank Code)"));
387  /* Disable target account entry for SEPA internal transfers, but only let choose from templates */
388  gtk_widget_set_sensitive(td->recp_name_entry, FALSE);
389  gtk_widget_set_sensitive(td->recp_account_entry, FALSE);
390  gtk_widget_set_sensitive(td->recp_bankcode_entry, FALSE);
391  gtk_widget_set_sensitive(add_templ_button, FALSE);
392  gtk_widget_set_visible(add_templ_button, FALSE);
393  gtk_widget_set_can_focus(add_templ_button, FALSE);
394  gtk_widget_set_sensitive(del_templ_button, FALSE);
395  gtk_widget_set_visible(del_templ_button, FALSE);
396  gtk_widget_set_can_focus(del_templ_button, FALSE);
397  gtk_label_set_text(GTK_LABEL(template_label),
398  _("Target Accounts"));
399  gtk_expander_set_expanded(template_expander, TRUE);
400  break;
401 #endif
402 
403  case SINGLE_DEBITNOTE:
404  /* this case is no longer in use; don't introduce extra strings */
405  break;
406 
407  case SEPA_DEBITNOTE:
408  gtk_label_set_text(GTK_LABEL (heading_label),
409  _("Enter a SEPA Online Direct Debit Note"));
410 
411  gtk_label_set_text(GTK_LABEL(recp_name_heading),
412  _("Debited Account Owner"));
413  gtk_label_set_text(GTK_LABEL(recp_account_heading),
414  _("Debited IBAN (International Account Number)"));
415  gtk_label_set_text(GTK_LABEL(recp_bankcode_heading),
416  _("Debited BIC (Bank Code)"));
417 
418  gtk_label_set_text(GTK_LABEL(orig_name_heading),
419  _("Credited Account Owner"));
420  gtk_label_set_text(GTK_LABEL(orig_account_heading),
421  _("Credited IBAN (International Account Number)"));
422  gtk_label_set_text(GTK_LABEL(orig_bankcode_heading),
423  _("Credited BIC (Bank Code)"));
424  break;
425 
426  default:
427  g_critical("gnc_ab_trans_dialog_new: Oops, unknown GncABTransType %d",
428  trans_type);
429  break;
430  }
431 
432  /* Additionally change the labels for the European (SEPA) transactions */
433  if (gnc_ab_trans_isSEPA(trans_type))
434  {
435  // Also, SEPA might have much longer IBAN (up to 34 chars) and BIC (11)
436  gtk_entry_set_max_length(GTK_ENTRY(td->recp_bankcode_entry), 11);
437  gtk_entry_set_max_length(GTK_ENTRY(td->recp_account_entry), 34);
438  }
439 
440  gtk_entry_set_text(GTK_ENTRY(td->orig_name_entry), ab_ownername);
441  gtk_label_set_text(GTK_LABEL(orig_bankname_label), ab_bankname);
442  if (gnc_ab_trans_isSEPA(trans_type))
443  {
444  gtk_widget_set_sensitive(GTK_WIDGET(td->orig_name_entry), TRUE);
445  ab_accountnumber = AB_AccountSpec_GetIban(ab_acc);
446  ab_bankcode = AB_AccountSpec_GetBic(ab_acc);
447  gtk_label_set_text(GTK_LABEL(orig_account_label), ab_accountnumber);
448  gtk_label_set_text (GTK_LABEL (orig_bankcode_label), ab_bankcode);
449  }
450  else
451  {
452  gtk_widget_set_sensitive(GTK_WIDGET(td->orig_name_entry), FALSE);
453  gtk_label_set_text(GTK_LABEL(orig_account_label), ab_accountnumber);
454  gtk_label_set_text (GTK_LABEL (orig_bankcode_label), ab_bankcode);
455  }
456 
457 #if (AQBANKING_VERSION_INT >= 60400)
458  /* Fill list for choosing a transaction template */
459  td->template_list_store = gtk_list_store_new(TEMPLATE_NUM_COLUMNS,
460  G_TYPE_STRING, G_TYPE_POINTER);
461  g_list_foreach(templates, gnc_ab_trans_dialog_fill_templ_helper, td->template_list_store);
462  gtk_tree_view_set_model(td->template_gtktreeview,
463  GTK_TREE_MODEL(td->template_list_store));
464  td->templ_changed = FALSE;
465  /* Keep a reference to the store */
466 #endif
467  /* Show this list */
468  renderer = gtk_cell_renderer_text_new();
469  column = gtk_tree_view_column_new_with_attributes(
470  "Template Name", renderer, "text", TEMPLATE_NAME, NULL);
471  gtk_tree_view_append_column(td->template_gtktreeview, column);
472 
473  /* Connect the Signals */
474  gtk_builder_connect_signals_full(builder, gnc_builder_connect_full_func, td);
475 
476  g_object_unref(G_OBJECT(builder));
477 
478  /* Disabled OK button until suitable values are filled */
479  gnc_ab_trans_dialog_verify_values(td);
480 
481  return td;
482 }
483 
484 static void
485 gnc_ab_trans_dialog_entry_set (GtkWidget* entry,
486  const gchar* message,
487  const gchar* icon_name)
488 {
489  g_object_set (entry,
490  "secondary-icon-name", icon_name,
491  "secondary-icon-tooltip-text", message,
492  NULL);
493 }
494 
495 static void
496 gnc_ab_trans_dialog_check_iban(const GncABTransDialog *td,
497  const AB_TRANSACTION *trans)
498 {
499  if (gnc_ab_trans_isSEPA(td->trans_type))
500  {
501  /* Verify the correct IBAN bank code */
502  int rv = AB_Banking_CheckIban(AB_Transaction_GetRemoteIban(trans));
503  if (rv != 0) {
504  gchar *message = g_strdup_printf(_("The internal check of the destination IBAN '%s' "
505  "failed. This means "
506  "the account number might contain an error."),
507  AB_Transaction_GetRemoteIban(trans));
508  gnc_ab_trans_dialog_entry_set (td->recp_account_entry, message,
509  "dialog-warning");
510  }
511  else
512  {
513  gnc_ab_trans_dialog_entry_set (td->recp_account_entry, "",
514  NULL);
515  gnc_ab_trans_dialog_entry_set (td->recp_bankcode_entry, "",
516  NULL);
517  }
518  }
519  else
520  {
521  /* this case is no longer in use */
522  return;
523  }
524 }
525 
526 static void
527 gnc_ab_trans_dialog_clear_transaction(GncABTransDialog *td)
528 {
529  AB_Transaction_free(td->ab_trans);
530  td->ab_trans = NULL;
531 }
532 
533 void
534 gnc_ab_trans_dialog_verify_values(GncABTransDialog *td)
535 {
536  gchar* purpose;
537  gchar* othername;
538  const gchar* account;
539  const gchar* bankcode;
540 
541  gboolean values_ok = TRUE;
542 
543  GtkWidget *amount_entry = gnc_amount_edit_gtk_entry(GNC_AMOUNT_EDIT(td->amount_edit));
544 
545  /* Fill in the values from the entry fields into a new
546  * AB_TRANSACTION */
547  td->ab_trans = gnc_ab_trans_dialog_fill_values(td);
548 
549  // Verify that we have a local IBAN and BIC
550  if (gnc_ab_trans_isSEPA(td->trans_type))
551  {
552  const char* localIBAN = AB_Transaction_GetLocalIban(td->ab_trans);
553  if (!localIBAN || (strlen(localIBAN) == 0))
554  {
555  const char* localBankCode = AB_Transaction_GetLocalBankCode(td->ab_trans);
556  const char* localAccountCode = AB_Transaction_GetLocalAccountNumber(td->ab_trans);
557  values_ok = FALSE;
558  gnc_error_dialog(GTK_WINDOW (td->dialog),
559  _("Your local bank account does not yet have the SEPA account information stored."
560  " We are sorry, but in this development version one additional step is necessary "
561  "which has not yet been implemented directly in gnucash. "
562  "Please execute the command line program \"aqhbci-tool\" for your account, as follows: "
563  "aqhbci-tool4 getaccsepa -b %s -a %s"),
564  (localBankCode ? localBankCode : ""),
565  (localAccountCode ? localAccountCode : ""));
566  }
567  }
568 
569  /* Check recipient / remote name */
570  othername = gnc_ab_get_remote_name(td->ab_trans);
571  if (!othername || !strlen(othername))
572  {
573  gnc_ab_trans_dialog_entry_set (td->recp_name_entry,
574  _("You did not enter a recipient name. A recipient name is "
575  "required for an online transfer.\n"),
576  "process-stop");
577 
578  g_free (othername);
579  values_ok = FALSE;
580  }
581  else
582  {
583  gnc_ab_trans_dialog_entry_set (td->recp_name_entry, "", NULL);
584  g_free(othername);
585  }
586 
587  /* Check account */
588  account = gnc_ab_trans_isSEPA(td->trans_type)
589  ? AB_Transaction_GetRemoteIban(td->ab_trans)
590  : AB_Transaction_GetRemoteAccountNumber(td->ab_trans);
591  if (!account || !strlen(account))
592  {
593  gnc_ab_trans_dialog_entry_set (td->recp_account_entry,
594  _("You did not enter a recipient account. A recipient account is "
595  "required for an online transfer.\n"),
596  "process-stop");
597  values_ok = FALSE;
598  }
599  else
600  {
601  gnc_ab_trans_dialog_entry_set (td->recp_account_entry, "", NULL);
602  }
603  /* Check bank */
604  bankcode = gnc_ab_trans_isSEPA(td->trans_type)
605  ? AB_Transaction_GetRemoteBic(td->ab_trans)
606  : AB_Transaction_GetRemoteBankCode(td->ab_trans);
607  if (!gnc_ab_trans_isSEPA(td->trans_type) && (!bankcode || !strlen(bankcode)))
608  {
609  gnc_ab_trans_dialog_entry_set (td->recp_bankcode_entry,
610  _("You did not enter a recipient bank. A recipient bank is "
611  "required for an online transfer.\n"),
612  "process-stop");
613  values_ok = FALSE;
614  }
615  else
616  {
617  gnc_ab_trans_dialog_entry_set (td->recp_bankcode_entry, "", NULL);
618  }
619  /* Check if account details are correct - gives warning only */
620  if (values_ok)
621  gnc_ab_trans_dialog_check_iban(td, td->ab_trans);
622 
623  /* Check transaction value */
624  if (AB_Value_GetValueAsDouble(AB_Transaction_GetValue(td->ab_trans))
625  == 0.0)
626  {
627  gnc_ab_trans_dialog_entry_set (amount_entry,
628  _("The amount is zero or the amount field could not be "
629  "interpreted correctly. You might have mixed up decimal "
630  "point and comma, compared to your locale settings. "
631  "This does not result in a valid online transfer job."),
632  "process-stop");
633  values_ok = FALSE;
634  }
635  else
636  {
637  gnc_ab_trans_dialog_entry_set (amount_entry, "", NULL);
638  }
639 
640  /* Check transaction purpose. OFX doesn't do transfers. */
641  purpose = gnc_ab_get_purpose(td->ab_trans, FALSE);
642  if (!purpose || !strlen(purpose))
643  {
644  gnc_ab_trans_dialog_entry_set (td->purpose_entry,
645  _("You did not enter any transaction purpose. A purpose is "
646  "required for an online transfer.\n"),
647  "process-stop");
648  g_free (purpose);
649  values_ok = FALSE;
650  }
651  else
652  {
653  gnc_ab_trans_dialog_entry_set (td->purpose_entry, "", NULL);
654  g_free(purpose);
655  }
656 
657  gtk_widget_set_sensitive(td->exec_button, values_ok);
658  gnc_ab_trans_dialog_clear_transaction(td);
659 }
660 
661 gint
662 gnc_ab_trans_dialog_run_until_ok(GncABTransDialog *td)
663 {
664  gint result;
665  GNC_AB_JOB *job;
666  const AB_TRANSACTION_LIMITS *joblimits;
667  guint8 max_purpose_lines;
668 
669  /* Check whether the account supports this job */
670  job = gnc_ab_trans_dialog_get_available_empty_job(td->ab_acc, td->trans_type);
671  if (!job)
672  {
673  g_warning("gnc_ab_trans_dialog_run_until_ok: Oops, job not available");
674  return GTK_RESPONSE_CANCEL;
675  }
676 
677  /* Activate as many purpose entries as available for the job */
678  joblimits = AB_AccountSpec_GetTransactionLimitsForCommand(td->ab_acc, AB_Transaction_GetCommand(job));
679  max_purpose_lines = joblimits ?
680  AB_TransactionLimits_GetMaxLinesPurpose(joblimits) : 2;
681  gtk_widget_set_sensitive(td->purpose_cont_entry, max_purpose_lines > 1);
682  gtk_widget_set_sensitive(td->purpose_cont2_entry, max_purpose_lines > 2);
683  gtk_widget_set_sensitive(td->purpose_cont3_entry, max_purpose_lines > 3);
684  if (joblimits)
685  {
686  gtk_entry_set_max_length(GTK_ENTRY(td->purpose_entry),
687  AB_TransactionLimits_GetMaxLenPurpose(joblimits));
688  gtk_entry_set_max_length(GTK_ENTRY(td->purpose_cont_entry),
689  AB_TransactionLimits_GetMaxLenPurpose(joblimits));
690  gtk_entry_set_max_length(GTK_ENTRY(td->purpose_cont2_entry),
691  AB_TransactionLimits_GetMaxLenPurpose(joblimits));
692  gtk_entry_set_max_length(GTK_ENTRY(td->purpose_cont3_entry),
693  AB_TransactionLimits_GetMaxLenPurpose(joblimits));
694  gtk_entry_set_max_length(GTK_ENTRY(td->recp_name_entry),
695  AB_TransactionLimits_GetMaxLenRemoteName(joblimits));
696  }
697 
698  /* Show the dialog */
699  gtk_widget_show(td->dialog);
700 
701  /* Now run the dialog until it gets closed by a button press */
702  result = gtk_dialog_run (GTK_DIALOG (td->dialog));
703 
704  /* Was cancel pressed or dialog closed?
705  * GNC_RESPONSE_NOW == execute now
706  * GNC_RESPONSE_LATER == scheduled for later execution (unimplemented)
707  * GTK_RESPONSE_CANCEL == cancel
708  * GTK_RESPONSE_DELETE_EVENT == window destroyed */
709  if (result != GNC_RESPONSE_NOW && result != GNC_RESPONSE_LATER)
710  {
711  gtk_widget_destroy(td->dialog);
712  td->dialog = NULL;
713  return result;
714  }
715 
716  /* Get the transaction details - have been checked beforehand */
717  td->ab_trans = gnc_ab_trans_dialog_fill_values(td);
718 
719  /* FIXME: If this is a direct debit, set the textkey/ "Textschluessel"/
720  * transactionCode according to some GUI selection here!! */
721  /*if (td->trans_type == SINGLE_DEBITNOTE)
722  AB_TRANSACTION_setTextKey (td->hbci_trans, 05); */
723 
724 
725  /* Hide the dialog */
726  if (td->dialog)
727  gtk_widget_hide(td->dialog);
728 
729  return result;
730 }
731 
732 #if (AQBANKING_VERSION_INT >= 60400)
733 static gboolean
734 gnc_ab_trans_dialog_clear_templ_helper(GtkTreeModel *model,
735  GtkTreePath *path,
736  GtkTreeIter *iter,
737  gpointer user_data)
738 {
739  GncABTransTempl *templ;
740 
741  g_return_val_if_fail(model && iter, TRUE);
742 
743  gtk_tree_model_get(model, iter, TEMPLATE_POINTER, &templ, -1);
745  return FALSE;
746 }
747 #endif
748 void
749 gnc_ab_trans_dialog_free(GncABTransDialog *td)
750 {
751  if (!td) return;
752  if (td->ab_trans)
753  AB_Transaction_free(td->ab_trans);
754  if (td->dialog)
755  gtk_widget_destroy(td->dialog);
756 
757 #if (AQBANKING_VERSION_INT >= 60400)
758  if (td->template_list_store)
759  {
760  gtk_tree_model_foreach(GTK_TREE_MODEL(td->template_list_store),
761  gnc_ab_trans_dialog_clear_templ_helper, NULL);
762  g_object_unref(td->template_list_store);
763  }
764 #endif
765  g_free(td);
766 }
767 
768 #if (AQBANKING_VERSION_INT >= 60400)
769 static gboolean
770 gnc_ab_trans_dialog_get_templ_helper(GtkTreeModel *model,
771  GtkTreePath *path,
772  GtkTreeIter *iter,
773  gpointer data)
774 {
775  GList **list = data;
776  GncABTransTempl *templ;
777 
778  g_return_val_if_fail(model && iter, TRUE);
779 
780  gtk_tree_model_get(model, iter, TEMPLATE_POINTER, &templ, -1);
781  *list = g_list_prepend(*list, templ);
782  return FALSE;
783 }
784 
785 GList *
786 gnc_ab_trans_dialog_get_templ(const GncABTransDialog *td, gboolean *changed)
787 {
788  GList *list = NULL;
789 
790  g_return_val_if_fail(td, NULL);
791 
792  if (changed)
793  {
794  *changed = td->templ_changed;
795  if (!*changed)
796  return NULL;
797  }
798 
799  gtk_tree_model_foreach(GTK_TREE_MODEL(td->template_list_store),
800  gnc_ab_trans_dialog_get_templ_helper, &list);
801  list = g_list_reverse(list);
802  return list;
803 }
804 #endif
805 
806 GtkWidget *
807 gnc_ab_trans_dialog_get_parent(const GncABTransDialog *td)
808 {
809  g_return_val_if_fail(td, NULL);
810  return td->parent;
811 }
812 
813 const AB_TRANSACTION *
814 gnc_ab_trans_dialog_get_ab_trans(const GncABTransDialog *td)
815 {
816  g_return_val_if_fail(td, NULL);
817  return td->ab_trans;
818 }
819 
820 static GNC_AB_JOB *
821 gnc_ab_trans_dialog_get_available_empty_job(GNC_AB_ACCOUNT_SPEC *ab_acc, GncABTransType trans_type)
822 {
823  GNC_AB_JOB *job;
824  AB_TRANSACTION_COMMAND cmd = AB_Transaction_CommandUnknown;
825 
826  switch (trans_type)
827  {
828  case SINGLE_DEBITNOTE: /* no longer in use */
829  cmd=AB_Transaction_CommandDebitNote;
830  break;
831  case SINGLE_INTERNAL_TRANSFER:
832  cmd=AB_Transaction_CommandInternalTransfer;
833  break;
834  case SEPA_TRANSFER:
835  cmd=AB_Transaction_CommandSepaTransfer;
836  break;
837 #if (AQBANKING_VERSION_INT >= 60400)
838  case SEPA_INTERNAL_TRANSFER:
839  cmd=AB_Transaction_CommandSepaInternalTransfer;
840  break;
841 #endif
842  case SEPA_DEBITNOTE:
843  cmd=AB_Transaction_CommandSepaDebitNote;
844  break;
845  default:
846  cmd=AB_Transaction_CommandTransfer; /* no longer in use */
847  break;
848  };
849  if (!AB_AccountSpec_GetTransactionLimitsForCommand(ab_acc, cmd))
850  return NULL;
851 
852  job = AB_Transaction_new();
853  AB_Transaction_SetCommand(job, cmd);
854  AB_Transaction_SetUniqueAccountId(job, AB_AccountSpec_GetUniqueId(ab_acc));
855  return job;
856 }
857 
858 GNC_AB_JOB *
859 gnc_ab_trans_dialog_get_job(const GncABTransDialog *td)
860 {
861  g_return_val_if_fail(td, NULL);
862  return gnc_ab_get_trans_job(td->ab_acc, td->ab_trans, td->trans_type);
863 }
864 
865 GNC_AB_JOB *
866 gnc_ab_get_trans_job(GNC_AB_ACCOUNT_SPEC *ab_acc,
867  const AB_TRANSACTION *ab_trans,
868  GncABTransType trans_type)
869 {
870  GNC_AB_JOB *job;
871 
872  g_return_val_if_fail(ab_acc && ab_trans, NULL);
873 
874  job = gnc_ab_trans_dialog_get_available_empty_job(ab_acc, trans_type);
875  if (job)
876  {
877  AB_TRANSACTION *new_job;
878 
879  /* merge transactions */
880  new_job=AB_Transaction_dup(ab_trans);
881  AB_Transaction_SetCommand(new_job, AB_Transaction_GetCommand(job));
882  AB_Transaction_SetUniqueAccountId(new_job,
883  AB_Transaction_GetUniqueAccountId(job));
884 
885  AB_Transaction_free(job);
886  return new_job;
887  }
888  return NULL;
889 
890 }
891 
892 #if (AQBANKING_VERSION_INT >= 60400)
893 void
894 gnc_ab_trans_dialog_templ_list_row_activated_cb(GtkTreeView *view,
895  GtkTreePath *path,
896  GtkTreeViewColumn *column,
897  gpointer user_data)
898 {
899  GncABTransDialog *td = user_data;
900  GtkTreeIter iter;
901  GncABTransTempl *templ;
902  const gchar *new_name;
903  const gchar *new_account;
904  const gchar *new_bankcode;
905  const gchar *new_purpose;
906  const gchar *new_purpose_cont;
907  gnc_numeric new_amount;
908 
909  g_return_if_fail(td);
910 
911  ENTER("td=%p", td);
912  if (!gtk_tree_model_get_iter(GTK_TREE_MODEL(td->template_list_store), &iter,
913  path))
914  {
915  LEAVE("Could not get iter");
916  return;
917  }
918  gtk_tree_model_get(GTK_TREE_MODEL(td->template_list_store), &iter,
919  TEMPLATE_POINTER, &templ, -1);
920 
921  /* Get new values */
922  new_name = gnc_ab_trans_templ_get_recp_name(templ);
923  new_account = gnc_ab_trans_templ_get_recp_account(templ);
924  new_bankcode = gnc_ab_trans_templ_get_recp_bankcode(templ);
925  new_purpose = gnc_ab_trans_templ_get_purpose(templ);
926  new_purpose_cont = gnc_ab_trans_templ_get_purpose_cont(templ);
927  new_amount = gnc_ab_trans_templ_get_amount(templ);
928  if (!new_name) new_name = "";
929  if (!new_account) new_account = "";
930  if (!new_bankcode) new_bankcode = "";
931  if (!new_purpose) new_purpose = "";
932  if (!new_purpose_cont) new_purpose_cont = "";
933 
934  /* Fill in */
935  gtk_entry_set_text(GTK_ENTRY(td->recp_name_entry), new_name);
936  gtk_entry_set_text(GTK_ENTRY(td->recp_account_entry), new_account);
937  gtk_entry_set_text(GTK_ENTRY(td->recp_bankcode_entry), new_bankcode);
938  gtk_entry_set_text(GTK_ENTRY(td->purpose_entry), new_purpose);
939  gtk_entry_set_text(GTK_ENTRY(td->purpose_cont_entry), new_purpose_cont);
940  gnc_amount_edit_set_amount(GNC_AMOUNT_EDIT(td->amount_edit), new_amount);
941  LEAVE(" ");
942 }
943 
944 
945 struct _FindTemplData
946 {
947  const gchar *name;
948  const GncABTransTempl *pointer;
949 };
950 
951 static gboolean
952 find_templ_helper(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter,
953  gpointer user_data)
954 {
955  struct _FindTemplData *data = user_data;
956  gchar *name;
957  GncABTransTempl *templ;
958  gboolean match;
959 
960  g_return_val_if_fail(model && data, TRUE);
961  gtk_tree_model_get(model, iter,
962  TEMPLATE_NAME, &name,
963  TEMPLATE_POINTER, &templ,
964  -1);
965  if (data->name)
966  {
967  /* Search for the template by name */
968  g_return_val_if_fail(!data->pointer, TRUE);
969  match = strcmp(name, data->name) == 0;
970  if (match) data->pointer = templ;
971  }
972  else
973  {
974  /* Search for the template by template pointer */
975  g_return_val_if_fail(!data->name, TRUE);
976  match = templ == data->pointer;
977  if (match) data->name = g_strdup(name);
978  }
979  g_free(name);
980  return match;
981 }
982 
983 void
984 gnc_ab_trans_dialog_add_templ_cb(GtkButton *button, gpointer user_data)
985 {
986  GncABTransDialog *td = user_data;
987  GtkBuilder *builder;
988  GtkWidget *dialog;
989  GtkWidget *entry;
990  gint retval;
991  const gchar *name;
992  GncABTransTempl *templ;
993  struct _FindTemplData data;
994  GtkTreeSelection *selection;
995  GtkTreeIter cur_iter;
996  GtkTreeIter new_iter;
997 
998  g_return_if_fail(td);
999 
1000  ENTER("td=%p", td);
1001  builder = gtk_builder_new();
1002  gnc_builder_add_from_file (builder, "dialog-ab.glade", "aqbanking_template_name_dialog");
1003  dialog = GTK_WIDGET(gtk_builder_get_object (builder, "aqbanking_template_name_dialog"));
1004 
1005  entry = GTK_WIDGET(gtk_builder_get_object (builder, "template_name"));
1006 
1007  /* Suggest recipient name as name of the template */
1008  gtk_entry_set_text(GTK_ENTRY(entry),
1009  gtk_entry_get_text(GTK_ENTRY(td->recp_name_entry)));
1010 
1011  do
1012  {
1013  retval = gtk_dialog_run(GTK_DIALOG(dialog));
1014  if (retval != GTK_RESPONSE_OK)
1015  break;
1016 
1017  name = gtk_entry_get_text(GTK_ENTRY(entry));
1018  if (!*name)
1019  break;
1020 
1021  data.name = name;
1022  data.pointer = NULL;
1023  gtk_tree_model_foreach(GTK_TREE_MODEL(td->template_list_store),
1024  find_templ_helper, &data);
1025  if (data.pointer)
1026  {
1027  gnc_error_dialog(GTK_WINDOW (dialog), "%s",
1028  _("A template with the given name already exists. "
1029  "Please enter another name."));
1030  continue;
1031  }
1032 
1033  /* Create a new template */
1035  name,
1036  gtk_entry_get_text(GTK_ENTRY(td->recp_name_entry)),
1037  gtk_entry_get_text(GTK_ENTRY(td->recp_account_entry)),
1038  gtk_entry_get_text(GTK_ENTRY(td->recp_bankcode_entry)),
1039  gnc_amount_edit_get_amount(GNC_AMOUNT_EDIT(td->amount_edit)),
1040  gtk_entry_get_text(GTK_ENTRY(td->purpose_entry)),
1041  gtk_entry_get_text (GTK_ENTRY(td->purpose_cont_entry)));
1042 
1043  /* Insert it, either after the selected one or at the end */
1044  selection = gtk_tree_view_get_selection(td->template_gtktreeview);
1045  if (gtk_tree_selection_get_selected(selection, NULL, &cur_iter))
1046  {
1047  gtk_list_store_insert_after(td->template_list_store,
1048  &new_iter, &cur_iter);
1049  }
1050  else
1051  {
1052  gtk_list_store_append(td->template_list_store, &new_iter);
1053  }
1054  gtk_list_store_set(td->template_list_store, &new_iter,
1055  TEMPLATE_NAME, name,
1056  TEMPLATE_POINTER, templ,
1057  -1);
1058  td->templ_changed = TRUE;
1059  DEBUG("Added template with name %s", name);
1060  break;
1061  }
1062  while (TRUE);
1063 
1064  g_object_unref(G_OBJECT(builder));
1065 
1066  gtk_widget_destroy(dialog);
1067 
1068  LEAVE(" ");
1069 }
1070 #endif
1071 
1072 void
1073 gnc_ab_trans_dialog_moveup_templ_cb(GtkButton *button, gpointer user_data)
1074 {
1075  GncABTransDialog *td = user_data;
1076  GtkTreeSelection *selection;
1077  GtkTreeModel *model;
1078  GtkTreeIter iter;
1079  GtkTreePath *prev_path;
1080  GtkTreeIter prev_iter;
1081 
1082  g_return_if_fail(td);
1083 
1084  selection = gtk_tree_view_get_selection(td->template_gtktreeview);
1085  if (!gtk_tree_selection_get_selected(selection, &model, &iter))
1086  return;
1087 
1088  prev_path = gtk_tree_model_get_path(model, &iter);
1089  if (gtk_tree_path_prev(prev_path))
1090  {
1091  if (gtk_tree_model_get_iter(model, &prev_iter, prev_path))
1092  {
1093  gtk_list_store_move_before(GTK_LIST_STORE(model), &iter, &prev_iter);
1094  td->templ_changed = TRUE;
1095  }
1096  }
1097  gtk_tree_path_free(prev_path);
1098 }
1099 
1100 void
1101 gnc_ab_trans_dialog_movedown_templ_cb(GtkButton *button, gpointer user_data)
1102 {
1103  GncABTransDialog *td = user_data;
1104  GtkTreeSelection *selection;
1105  GtkTreeModel *model;
1106  GtkTreeIter iter;
1107  GtkTreeIter next_iter;
1108 
1109  g_return_if_fail(td);
1110 
1111  selection = gtk_tree_view_get_selection(td->template_gtktreeview);
1112  if (!gtk_tree_selection_get_selected (selection, &model, &iter))
1113  return;
1114 
1115  next_iter = iter;
1116  if (gtk_tree_model_iter_next(model, &next_iter))
1117  {
1118  gtk_list_store_move_after(GTK_LIST_STORE(model), &iter, &next_iter);
1119  td->templ_changed = TRUE;
1120  }
1121 }
1122 
1123 void
1124 gnc_ab_trans_dialog_sort_templ_cb(GtkButton *button, gpointer user_data)
1125 {
1126  GncABTransDialog *td = user_data;
1127 
1128  g_return_if_fail(td);
1129 
1130  ENTER("td=%p", td);
1131  gtk_tree_sortable_set_sort_column_id(
1132  GTK_TREE_SORTABLE(td->template_list_store),
1133  TEMPLATE_NAME, GTK_SORT_ASCENDING);
1134  gtk_tree_sortable_set_sort_column_id(
1135  GTK_TREE_SORTABLE(td->template_list_store),
1136  GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID,
1137  GTK_SORT_ASCENDING);
1138  td->templ_changed = TRUE;
1139  LEAVE(" ");
1140 }
1141 
1142 void
1143 gnc_ab_trans_dialog_del_templ_cb(GtkButton *button, gpointer user_data)
1144 {
1145  GncABTransDialog *td = user_data;
1146  GtkTreeSelection *selection;
1147  GtkTreeModel *model;
1148  GtkTreeIter iter;
1149  gchar *name;
1150 
1151  g_return_if_fail(td);
1152 
1153  ENTER("td=%p", td);
1154  selection = gtk_tree_view_get_selection(td->template_gtktreeview);
1155  if (!gtk_tree_selection_get_selected (selection, &model, &iter))
1156  {
1157  LEAVE("None selected");
1158  return;
1159  }
1160 
1161  gtk_tree_model_get(model, &iter, TEMPLATE_NAME, &name, -1);
1162  if (gnc_verify_dialog (
1163  GTK_WINDOW (td->parent), FALSE,
1164  _("Do you really want to delete the template with the name \"%s\"?"),
1165  name))
1166  {
1167  gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
1168  td->templ_changed = TRUE;
1169  DEBUG("Deleted template with name %s", name);
1170  }
1171  g_free(name);
1172  LEAVE(" ");
1173 }
1174 
1175 void
1176 gnc_ab_trans_dialog_ibanentry_filter_cb (GtkEditable *editable,
1177  const gchar *text,
1178  gint length,
1179  gint *position,
1180  gpointer data)
1181 {
1182  GString* result = g_string_new(NULL);
1183  gint i;
1184  GncABTransDialog *td = data;
1185 
1186  if (length == -1)
1187  length = strlen(text);
1188  g_assert(position);
1189 
1190  /* Filter digits / non digits as needed */
1191  for (i = 0; i < length; i++)
1192  {
1193  gchar c = text[i];
1194 
1195  if (gnc_ab_trans_isSEPA(td->trans_type))
1196  {
1197  enum {
1198  ALPHA
1199  , ALNUM
1200  , NUMERIC
1201  } allowed_characterclass;
1202 
1203  // SEPA: Only alphas in the first two places (at index 0, 1)
1204  if (*position + i < 2)
1205  {
1206  allowed_characterclass = ALPHA;
1207  }
1208  // SEPA: Next two places are digits only (index 2, 3)
1209  else if (*position + i < 4)
1210  {
1211  allowed_characterclass = NUMERIC;
1212  }
1213  // SEPA: The rest depends on the country code: Either Alpha-numeric or numeric only
1214  else
1215  {
1216  const gchar* acct_text = gtk_entry_get_text(GTK_ENTRY(td->recp_account_entry));
1217  // Special case for German ("DE") IBAN: Numeric only. Otherwise allow alpha-numeric
1218  if (acct_text[0] == 'D' && acct_text[1] == 'E')
1219  {
1220  allowed_characterclass = NUMERIC;
1221  }
1222  else
1223  {
1224  allowed_characterclass = ALNUM;
1225  }
1226  }
1227 
1228  // Do the actual character class check. Alphas are only allowed in
1229  // uppercase, though.
1230  switch (allowed_characterclass)
1231  {
1232  case ALPHA:
1233  if (g_ascii_isalpha(c))
1234  g_string_append_c(result, g_ascii_toupper(c));
1235  break;
1236  case ALNUM:
1237  if (g_ascii_isalnum(c))
1238  g_string_append_c(result, g_ascii_toupper(c));
1239  break;
1240  case NUMERIC:
1241  if (g_ascii_isdigit(c))
1242  g_string_append_c(result, c);
1243  break;
1244  }
1245  }
1246  else
1247  {
1248  // Non-SEPA: Only accept digits.
1249  if (g_ascii_isdigit(c))
1250  {
1251  g_string_append_c(result, c);
1252  }
1253  }
1254  }
1255 
1256  g_signal_handlers_block_by_func (editable,
1257  (gpointer) gnc_ab_trans_dialog_ibanentry_filter_cb, data);
1258  gtk_editable_insert_text (editable, result->str, result->len, position);
1259  g_signal_handlers_unblock_by_func (editable,
1260  (gpointer) gnc_ab_trans_dialog_ibanentry_filter_cb, data);
1261  g_signal_stop_emission_by_name (editable, "insert_text");
1262  g_string_free (result, TRUE);
1263 }
1264 
1265 void
1266 gnc_ab_trans_dialog_bicentry_filter_cb (GtkEditable *editable,
1267  const gchar *text,
1268  gint length,
1269  gint *position,
1270  gpointer data)
1271 {
1272  GString* result = g_string_new(NULL);
1273  gint i;
1274  GncABTransDialog *td = data;
1275 
1276  if (length == -1)
1277  length = strlen(text);
1278  g_assert(position);
1279 
1280  /* Filter non digits */
1281  for (i = 0; i < length; i++)
1282  {
1283  gchar c = text[i];
1284 
1285  if (gnc_ab_trans_isSEPA(td->trans_type))
1286  {
1287  // SEPA: Only alphas in the first 6 places (only upper case, though), then both upper-case alphas and digits
1288  if (*position + i < 6)
1289  {
1290  if (g_ascii_isalpha(c))
1291  g_string_append_c(result, g_ascii_toupper(c));
1292  }
1293  else
1294  {
1295  if (g_ascii_isalnum(c))
1296  g_string_append_c(result, g_ascii_toupper(c));
1297  }
1298  }
1299  else
1300  {
1301  // Non-SEPA: Only digits accepted.
1302  if (g_ascii_isdigit(c))
1303  {
1304  g_string_append_c(result, c);
1305  }
1306  }
1307  }
1308 
1309  g_signal_handlers_block_by_func (editable,
1310  (gpointer) gnc_ab_trans_dialog_bicentry_filter_cb, data);
1311  gtk_editable_insert_text (editable, result->str, result->len, position);
1312  g_signal_handlers_unblock_by_func (editable,
1313  (gpointer) gnc_ab_trans_dialog_bicentry_filter_cb, data);
1314  g_signal_stop_emission_by_name (editable, "insert_text");
1315  g_string_free (result, TRUE);
1316 }
Dialog for AqBanking transaction data.
const gchar * gnc_ab_trans_templ_get_purpose(const GncABTransTempl *t)
void gnc_ab_trans_templ_free(GncABTransTempl *t)
Free the memory used by a template.
gchar * gnc_ab_get_remote_name(const AB_TRANSACTION *ab_trans)
Retrieve the merged "remote name" fields from a transaction.
Definition: gnc-ab-utils.c:347
gboolean gnc_ab_trans_isSEPA(GncABTransType t)
Returns true if the given GncABTransType is an European (SEPA) transaction (transfer or debit note)...
#define G_LOG_DOMAIN
Functions providing the SX List as a plugin page.
gchar * gnc_ab_get_purpose(const AB_TRANSACTION *ab_trans, gboolean is_ofx)
Retrieve the merged purpose fields from a transaction.
Definition: gnc-ab-utils.c:367
#define DEBUG(format, args...)
Print a debugging message.
Definition: qoflog.h:264
GncABTransDialog * gnc_ab_trans_dialog_new(GtkWidget *parent, GNC_AB_ACCOUNT_SPEC *ab_acc, gint commodity_scu, GncABTransType trans_type, GList *templates)
Create a new AqBanking transfer dialog.
GNC_AB_JOB * gnc_ab_trans_dialog_get_job(const GncABTransDialog *td)
Receive the Aqbanking job filled by the dialog.
const gchar * gnc_ab_trans_templ_get_recp_account(const GncABTransTempl *t)
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
const gchar * gnc_ab_trans_templ_get_name(const GncABTransTempl *t)
gnc_numeric gnc_ab_trans_templ_get_amount(const GncABTransTempl *t)
const gchar * gnc_ab_trans_templ_get_recp_bankcode(const GncABTransTempl *t)
const gchar * gnc_ab_trans_templ_get_recp_name(const GncABTransTempl *t)
GNC_AB_JOB * gnc_ab_get_trans_job(GNC_AB_ACCOUNT_SPEC *ab_acc, const AB_TRANSACTION *ab_trans, GncABTransType trans_type)
Return the AqBanking job associated with the transaction.
GncABTransTempl * gnc_ab_trans_templ_new_full(const gchar *name, const gchar *recp_name, const gchar *recp_account, const gchar *recp_bankcode, gnc_numeric amount, const gchar *purpose, const gchar *purpose_cont)
Create a template with given contents.
const gchar * gnc_ab_trans_templ_get_purpose_cont(const GncABTransTempl *t)
void gnc_ab_trans_dialog_free(GncABTransDialog *td)
Free a Aqbanking transfer dialog.
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
const AB_TRANSACTION * gnc_ab_trans_dialog_get_ab_trans(const GncABTransDialog *td)
Receive the Aqbanking Transaction filled by the dialog.
GtkWidget * gnc_ab_trans_dialog_get_parent(const GncABTransDialog *td)
Retrieve the widget used as parent.
gint gnc_ab_trans_dialog_run_until_ok(GncABTransDialog *td)
Run the Aqbanking transfer dialog until correct values where entered or the user cancelled the dialog...
AqBanking utility functions.