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