GnuCash c935c2f+
Loading...
Searching...
No Matches
dialog-imap-editor.c
1/********************************************************************\
2 * dialog-imap-editor.c -- Import Map Editor dialog *
3 * Copyright (C) 2015 Robert Fewell *
4 * *
5 * This program is free software; you can redistribute it and/or *
6 * modify it under the terms of the GNU General Public License as *
7 * published by the Free Software Foundation; either version 2 of *
8 * the License, or (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License*
16 * along with this program; if not, contact: *
17 * *
18 * Free Software Foundation Voice: +1-617-542-5942 *
19 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
20 * Boston, MA 02110-1301, USA gnu@gnu.org *
21\********************************************************************/
22
23#include <config.h>
24
25#include <gtk/gtk.h>
26#include <glib/gi18n.h>
27
28#include "dialog-imap-editor.h"
29
30#include "dialog-utils.h"
31#include "gnc-component-manager.h"
32#include "gnc-session.h"
33
34#include "gnc-ui.h"
35#include "gnc-ui-util.h"
36#include <gnc-glib-utils.h>
37#include "Account.h"
38
39#define DIALOG_IMAP_CM_CLASS "dialog-imap-edit"
40#define GNC_PREFS_GROUP "dialogs.imap-editor"
41
42#define IMAP_FRAME_BAYES "import-map-bayes"
43#define IMAP_FRAME "import-map"
44
45#define IMAP_FRAME_DESC "desc"
46#define IMAP_FRAME_MEMO "memo"
47#define IMAP_FRAME_CSV "csv-account-map"
48
50enum GncImapColumn {SOURCE_FULL_ACC, SOURCE_ACCOUNT, BASED_ON, MATCH_STRING,
51 MAP_FULL_ACC, MAP_ACCOUNT, HEAD, CATEGORY, COUNT, FILTER};
52
53typedef enum
54{
55 BAYES,
56 NBAYES,
57 ONLINE
58}GncListType;
59
60typedef struct
61{
62 guint inv_dialog_shown_bayes : 1;
63 guint inv_dialog_shown_nbayes : 1;
64 guint inv_dialog_shown_online : 1;
66
67typedef struct
68{
69 GtkWidget *dialog;
70 QofSession *session;
71 GtkWidget *view;
72 GtkTreeModel *model;
73 GncListType type;
74
75 GtkWidget *radio_bayes;
76 GtkWidget *radio_nbayes;
77 GtkWidget *radio_online;
78
79 GtkWidget *filter_button;
80 GtkWidget *filter_text_entry;
81 GtkWidget *filter_label;
82 gboolean apply_selection_filter;
83
84 GtkWidget *total_entries_label;
85 gint tot_entries;
86 gint tot_invalid_maps;
87
88 GtkWidget *expand_button;
89 GtkWidget *collapse_button;
90 GtkWidget *remove_button;
91 GncInvFlags inv_dialog_shown;
93
94
95/* This static indicates the debugging module that this .o belongs to. */
96static QofLogModule log_module = GNC_MOD_GUI;
97
98void gnc_imap_dialog_window_destroy_cb (GtkWidget *object, gpointer user_data);
99void gnc_imap_dialog_close_cb (GtkDialog *dialog, gpointer user_data);
100void gnc_imap_dialog_response_cb (GtkDialog *dialog, gint response_id, gpointer user_data);
101
102static void get_account_info (ImapDialog *imap_dialog);
103
104void
105gnc_imap_dialog_window_destroy_cb (GtkWidget *object, gpointer user_data)
106{
107 ImapDialog *imap_dialog = user_data;
108
109 ENTER(" ");
110 gnc_unregister_gui_component_by_data (DIALOG_IMAP_CM_CLASS, imap_dialog);
111
112 if (imap_dialog->dialog)
113 {
114 gtk_widget_destroy (imap_dialog->dialog);
115 imap_dialog->dialog = NULL;
116 }
117 g_free (imap_dialog);
118 LEAVE(" ");
119}
120
121void
122gnc_imap_dialog_close_cb (GtkDialog *dialog, gpointer user_data)
123{
124 ImapDialog *imap_dialog = user_data;
125
126 ENTER(" ");
127 gnc_close_gui_component_by_data (DIALOG_IMAP_CM_CLASS, imap_dialog);
128 LEAVE(" ");
129}
130
131static void
132delete_info_bayes (Account *source_account, gchar *head, gint depth)
133{
134 if (depth != 1) // below top level
135 gnc_account_delete_map_entry (source_account, head, NULL, NULL, FALSE);
136 else
137 gnc_account_delete_all_bayes_maps (source_account);
138}
139
140static void
141delete_info_nbayes (Account *source_account, gchar *head,
142 gchar *category, gchar *match_string, gint depth)
143{
144 if (depth != 1) // below top level
145 {
146 gnc_account_delete_map_entry (source_account, head, category, match_string, FALSE);
147 gnc_account_delete_map_entry (source_account, head, category, NULL, TRUE);
148 }
149 else
150 gnc_account_delete_map_entry (source_account, head, category, NULL, FALSE);
151
152 gnc_account_delete_map_entry (source_account, head, NULL, NULL, TRUE);
153}
154
155static void
156delete_selected_row (ImapDialog *imap_dialog, GtkTreeIter *iter)
157{
158 Account *source_account = NULL;
159 gchar *full_source_account;
160 gchar *head;
161 gchar *category;
162 gchar *match_string;
163 gint num = 0;
164 GtkTreeIter parent;
165
166 // get the parent iter and see how many children it has, if 1 we will remove
167 if (gtk_tree_model_iter_parent (imap_dialog->model, &parent, iter))
168 num = gtk_tree_model_iter_n_children (imap_dialog->model, &parent);
169
170 gtk_tree_model_get (imap_dialog->model, iter, SOURCE_ACCOUNT, &source_account,
171 SOURCE_FULL_ACC, &full_source_account,
172 HEAD, &head,
173 CATEGORY, &category,
174 MATCH_STRING, &match_string, -1);
175
176 PINFO("Account is '%s', Head is '%s', Category is '%s', Match String is '%s'",
177 full_source_account, head, category, match_string);
178
179 if (source_account != NULL)
180 {
181 GtkTreePath *tree_path;
182 gint depth;
183
184 // Get the level we are at in the tree-model
185 tree_path = gtk_tree_model_get_path (imap_dialog->model, iter);
186 depth = gtk_tree_path_get_depth (tree_path);
187 gtk_tree_path_free (tree_path);
188
189 if (imap_dialog->type == ONLINE)
190 gnc_account_delete_map_entry (source_account, head, NULL, NULL, FALSE);
191
192 if (imap_dialog->type == BAYES)
193 delete_info_bayes (source_account, head, depth);
194
195 if (imap_dialog->type == NBAYES)
196 delete_info_nbayes (source_account, head, category, match_string, depth);
197
198 gtk_tree_store_remove (GTK_TREE_STORE(imap_dialog->model), iter);
199
200 if (num == 1 && (imap_dialog->type != ONLINE))
201 gtk_tree_store_remove (GTK_TREE_STORE(imap_dialog->model), &parent);
202 }
203 // Clear the total
204 gtk_label_set_text (GTK_LABEL(imap_dialog->total_entries_label), " ");
205
206 if (head)
207 g_free (head);
208 if (category)
209 g_free (category);
210 if (match_string)
211 g_free (match_string);
212 if (full_source_account)
213 g_free (full_source_account);
214}
215
216static gboolean
217find_invalid_mappings_total (GtkTreeModel *model, GtkTreePath *path,
218 GtkTreeIter *iter, ImapDialog *imap_dialog)
219{
220 Account *source_account = NULL;
221 Account *map_account = NULL;
222 gchar *head;
223 gint depth;
224
225 gtk_tree_model_get (model, iter, SOURCE_ACCOUNT, &source_account,
226 MAP_ACCOUNT, &map_account,
227 HEAD, &head, -1);
228
229 depth = gtk_tree_path_get_depth (path);
230
231 if ((source_account != NULL) && (map_account == NULL))
232 {
233 if (((g_strcmp0 (head, "online_id") == 0) && (depth == 1)) || (depth == 2))
234 imap_dialog->tot_invalid_maps ++;
235 }
236 g_free (head);
237 return FALSE;
238}
239
240static void
241gnc_imap_dialog_delete (ImapDialog *imap_dialog)
242{
243 GList *list, *row;
244 GtkTreeModel *fmodel;
245 GtkTreeIter fiter;
246 GtkTreeIter iter;
247 GtkTreeSelection *selection;
248
249 fmodel = gtk_tree_view_get_model (GTK_TREE_VIEW(imap_dialog->view));
250 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(imap_dialog->view));
251
252 list = gtk_tree_selection_get_selected_rows (selection, &fmodel);
253
254 // Make sure we have some rows selected
255 if (!gnc_list_length_cmp (list, 0))
256 return;
257
258 // reset the invalid map total
259 imap_dialog->tot_invalid_maps = 0;
260
261 // reverse list
262 list = g_list_reverse (list);
263
264 // Suspend GUI refreshing
265 gnc_suspend_gui_refresh();
266
267 // Walk the list
268 for (row = g_list_first (list); row; row = g_list_next (row))
269 {
270 if (gtk_tree_model_get_iter (fmodel, &fiter, row->data))
271 {
272 gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER(fmodel), &iter, &fiter);
273 delete_selected_row (imap_dialog, &iter);
274 }
275 }
276 g_list_foreach (list, (GFunc) gtk_tree_path_free, NULL);
277 g_list_free (list);
278
279 // Enable GUI refresh again
280 gnc_resume_gui_refresh();
281
282 // recount the number of invalid maps
283 gtk_tree_model_foreach (imap_dialog->model,
284 (GtkTreeModelForeachFunc)find_invalid_mappings_total,
285 imap_dialog);
286
287 if (imap_dialog->tot_invalid_maps == 0)
288 gtk_widget_hide (imap_dialog->remove_button);
289
290}
291
292static gboolean
293find_invalid_mappings (GtkTreeModel *model, GtkTreePath *path,
294 GtkTreeIter *iter, GList **rowref_list)
295{
296 Account *source_account = NULL;
297 Account *map_account = NULL;
298 gchar *head;
299 gint depth;
300
301 gtk_tree_model_get (model, iter, SOURCE_ACCOUNT, &source_account,
302 MAP_ACCOUNT, &map_account,
303 HEAD, &head, -1);
304
305 depth = gtk_tree_path_get_depth (path);
306
307 if ((source_account != NULL) && (map_account == NULL))
308 {
309 if (((g_strcmp0 (head, "online_id") == 0) && (depth == 1)) || (depth == 2))
310 {
311 GtkTreeRowReference *rowref = gtk_tree_row_reference_new (model, path);
312 *rowref_list = g_list_prepend (*rowref_list, rowref);
313 }
314 }
315 g_free (head);
316 return FALSE;
317}
318
319static void
320gnc_imap_remove_invalid_maps (ImapDialog *imap_dialog)
321{
322 GList *rr_list = NULL;
323 GList *node;
324
325 gtk_tree_model_foreach (imap_dialog->model,
326 (GtkTreeModelForeachFunc)find_invalid_mappings,
327 &rr_list);
328
329 // Suspend GUI refreshing
330 gnc_suspend_gui_refresh();
331
332 // Walk the list
333 for (node = rr_list; node != NULL; node = node->next)
334 {
335 GtkTreePath *path = gtk_tree_row_reference_get_path ((GtkTreeRowReference*)node->data);
336
337 if (path)
338 {
339 GtkTreeIter iter;
340
341 if (gtk_tree_model_get_iter (GTK_TREE_MODEL(imap_dialog->model), &iter, path))
342 delete_selected_row (imap_dialog, &iter);
343
344 gtk_tree_path_free (path);
345 }
346 }
347
348 // Enable GUI refresh again
349 gnc_resume_gui_refresh();
350
351 g_list_foreach (rr_list, (GFunc)gtk_tree_row_reference_free, NULL);
352 g_list_free (rr_list);
353}
354
355static void
356gnc_imap_invalid_maps_dialog (ImapDialog *imap_dialog)
357{
358 gtk_widget_hide (imap_dialog->remove_button);
359
360 if (imap_dialog->tot_invalid_maps > 0)
361 {
362 /* Translators: This is a ngettext(3) message, %d is the number of maps missing */
363 gchar *message = g_strdup_printf (ngettext ("There is %d invalid mapping,\n\nWould you like to remove it now?",
364 "There are %d invalid mappings,\n\nWould you like to remove them now?",
365 imap_dialog->tot_invalid_maps),
366 imap_dialog->tot_invalid_maps);
367
368 gchar *message2 = g_strdup_printf (gettext ("To see the invalid mappings, use a filter of '%s'"), _("Map Account NOT found"));
369
370 gchar *text = g_strdup_printf ("%s\n\n%s\n\n%s", message, message2, _("(Note, if there is a large number, it may take a while)"));
371
372 if (gnc_verify_dialog (GTK_WINDOW (imap_dialog->dialog), FALSE, "%s", text))
373 {
374 gnc_imap_remove_invalid_maps (imap_dialog);
375 gtk_widget_hide (imap_dialog->remove_button);
376 }
377 else
378 {
379 gtk_widget_show (imap_dialog->remove_button);
380
381 if (imap_dialog->type == BAYES)
382 imap_dialog->inv_dialog_shown.inv_dialog_shown_bayes = TRUE;
383 if (imap_dialog->type == NBAYES)
384 imap_dialog->inv_dialog_shown.inv_dialog_shown_nbayes = TRUE;
385 if (imap_dialog->type == ONLINE)
386 imap_dialog->inv_dialog_shown.inv_dialog_shown_online = TRUE;
387 }
388 g_free (message);
389 g_free (message2);
390 g_free (text);
391 }
392}
393
394void
395gnc_imap_dialog_response_cb (GtkDialog *dialog, gint response_id, gpointer user_data)
396{
397 ImapDialog *imap_dialog = user_data;
398
399 switch (response_id)
400 {
401 case GTK_RESPONSE_APPLY:
402 gnc_imap_dialog_delete (imap_dialog);
403 return;
404
405 case GTK_RESPONSE_REJECT:
406 gnc_imap_invalid_maps_dialog (imap_dialog);
407 return;
408
409 case GTK_RESPONSE_CLOSE:
410 default:
411 gnc_close_gui_component_by_data (DIALOG_IMAP_CM_CLASS, imap_dialog);
412 return;
413 }
414}
415
416static gboolean
417filter_test_and_move_next (ImapDialog *imap_dialog, GtkTreeIter *iter,
418 const gchar *filter_text)
419{
420 GtkTreePath *tree_path;
421 gint depth;
422 gboolean valid;
423 gchar *match_string;
424 gchar *map_full_acc;
425
426 // Read the row
427 gtk_tree_model_get (imap_dialog->model, iter, MATCH_STRING, &match_string, MAP_FULL_ACC, &map_full_acc, -1);
428
429 // Get the level we are at in the tree-model
430 tree_path = gtk_tree_model_get_path (imap_dialog->model, iter);
431 depth = gtk_tree_path_get_depth (tree_path);
432
433 // Reset filter to TRUE
434 gtk_tree_store_set (GTK_TREE_STORE(imap_dialog->model), iter, FILTER, TRUE, -1);
435
436 // Check for a filter_text entry
437 if (filter_text && *filter_text != '\0')
438 {
439 if (match_string != NULL) // Check for match_string is not NULL, valid line
440 {
441 if ((g_strrstr (match_string, filter_text) == NULL) &&
442 (g_strrstr (map_full_acc, filter_text) == NULL ))
443 gtk_tree_store_set (GTK_TREE_STORE(imap_dialog->model), iter, FILTER, FALSE, -1);
444 else
445 gtk_tree_view_expand_to_path (GTK_TREE_VIEW(imap_dialog->view), tree_path);
446 }
447 }
448 // Select next entry based on path
449 if (depth == 1)
450 gtk_tree_path_down (tree_path);
451 else
452 {
453 gtk_tree_path_next (tree_path);
454 if (!gtk_tree_model_get_iter (imap_dialog->model, iter, tree_path))
455 {
456 gtk_tree_path_prev (tree_path);
457 gtk_tree_path_up (tree_path);
458 gtk_tree_path_next (tree_path);
459 }
460 }
461 valid = gtk_tree_model_get_iter (imap_dialog->model, iter, tree_path);
462
463 gtk_tree_path_free (tree_path);
464 g_free (match_string);
465 g_free (map_full_acc);
466
467 return valid;
468}
469
470static void
471filter_button_cb (GtkButton *button, ImapDialog *imap_dialog)
472{
473 GtkTreeIter iter;
474 gboolean valid;
475 const gchar *filter_text;
476
477 filter_text = gtk_entry_get_text (GTK_ENTRY(imap_dialog->filter_text_entry));
478
479 // Collapse all nodes
480 gtk_tree_view_collapse_all (GTK_TREE_VIEW(imap_dialog->view));
481 imap_dialog->apply_selection_filter = FALSE;
482
483 // clear any selection
484 gtk_tree_selection_unselect_all (gtk_tree_view_get_selection
485 (GTK_TREE_VIEW(imap_dialog->view)));
486
487 // do we have a filter, apply selection filter
488 if (filter_text && *filter_text != '\0')
489 imap_dialog->apply_selection_filter = TRUE;
490
491 valid = gtk_tree_model_get_iter_first (imap_dialog->model, &iter);
492
493 while (valid)
494 {
495 valid = filter_test_and_move_next (imap_dialog, &iter, filter_text);
496 }
497 gtk_widget_grab_focus (GTK_WIDGET(imap_dialog->view));
498}
499
500static void
501expand_button_cb (GtkButton *button, ImapDialog *imap_dialog)
502{
503 // Clear the filter
504 gtk_entry_set_text (GTK_ENTRY(imap_dialog->filter_text_entry), "");
505
506 filter_button_cb (button, imap_dialog);
507
508 gtk_tree_view_expand_all (GTK_TREE_VIEW(imap_dialog->view));
509}
510
511static void
512collapse_button_cb (GtkButton *button, ImapDialog *imap_dialog)
513{
514 // Clear the filter
515 gtk_entry_set_text (GTK_ENTRY(imap_dialog->filter_text_entry), "");
516
517 filter_button_cb (button, imap_dialog);
518
519 gtk_tree_view_collapse_all (GTK_TREE_VIEW(imap_dialog->view));
520}
521
522static void
523list_type_selected_cb (GtkToggleButton* button, ImapDialog *imap_dialog)
524{
525 GncListType type;
526
527 if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(imap_dialog->radio_bayes)))
528 type = BAYES;
529 else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(imap_dialog->radio_nbayes)))
530 type = NBAYES;
531 else
532 type = ONLINE;
533
534 if (type != ONLINE)
535 gtk_widget_grab_focus (GTK_WIDGET(imap_dialog->filter_text_entry));
536
537 // Lets do this only on change of list type
538 if (type != imap_dialog->type)
539 {
540 gboolean inv_dialog_shown = FALSE;
541
542 imap_dialog->type = type;
543 get_account_info (imap_dialog);
544
545 if ((imap_dialog->type == BAYES) && (imap_dialog->inv_dialog_shown.inv_dialog_shown_bayes))
546 inv_dialog_shown = TRUE;
547
548 if ((imap_dialog->type == NBAYES) && (imap_dialog->inv_dialog_shown.inv_dialog_shown_nbayes))
549 inv_dialog_shown = TRUE;
550
551 if ((imap_dialog->type == ONLINE) && (imap_dialog->inv_dialog_shown.inv_dialog_shown_online))
552 inv_dialog_shown = TRUE;
553
554 if (!inv_dialog_shown)
555 gnc_imap_invalid_maps_dialog (imap_dialog);
556 }
557}
558
559static void
560show_count_column (ImapDialog *imap_dialog, gboolean show)
561{
562 GtkTreeViewColumn *tree_column;
563
564 // Show Count Column
565 tree_column = gtk_tree_view_get_column (GTK_TREE_VIEW(imap_dialog->view), 4);
566 gtk_tree_view_column_set_visible (tree_column, show);
567
568 // Hide Based on Column
569 tree_column = gtk_tree_view_get_column (GTK_TREE_VIEW(imap_dialog->view), 1);
570 gtk_tree_view_column_set_visible (tree_column, !show);
571
572 gtk_tree_view_columns_autosize (GTK_TREE_VIEW(imap_dialog->view));
573}
574
575static void
576add_to_store (ImapDialog *imap_dialog, GtkTreeIter *iter, const gchar *text, GncImapInfo *imapInfo)
577{
578 gchar *fullname = NULL;
579 gchar *map_fullname = NULL;
580
581 fullname = gnc_account_get_full_name (imapInfo->source_account);
582
583 // Do we have a valid map account
584 if (imapInfo->map_account == NULL)
585 {
586 // count the total invalid maps
587 imap_dialog->tot_invalid_maps ++;
588
589 map_fullname = g_strdup (_("Map Account NOT found"));
590 }
591 else
592 map_fullname = gnc_account_get_full_name (imapInfo->map_account);
593
594 // count the total entries
595 imap_dialog->tot_entries ++;
596
597 PINFO("Add to Store: Source Acc '%s', Head is '%s', Category is '%s', Match '%s', Map Acc '%s', Count is %s",
598 fullname, imapInfo->head, imapInfo->category, imapInfo->match_string, map_fullname, imapInfo->count);
599
600 gtk_tree_store_set (GTK_TREE_STORE(imap_dialog->model), iter,
601 SOURCE_FULL_ACC, fullname, SOURCE_ACCOUNT, imapInfo->source_account,
602 BASED_ON, text,
603 MATCH_STRING, imapInfo->match_string,
604 MAP_FULL_ACC, map_fullname, MAP_ACCOUNT, imapInfo->map_account,
605 HEAD, imapInfo->head, CATEGORY, imapInfo->category, COUNT, imapInfo->count,
606 FILTER, TRUE, -1);
607
608 g_free (fullname);
609 g_free (map_fullname);
610}
611
612static void
613get_imap_info (ImapDialog *imap_dialog, Account *acc, const gchar *category, const gchar *text)
614{
615 GtkTreeIter toplevel, child;
616 GList *imap_list, *node;
617 gchar *acc_name = NULL;
618 gchar *head = NULL;
619
620 acc_name = gnc_account_get_full_name (acc);
621 PINFO("Source Acc '%s', Based on '%s', Path Head '%s'", acc_name, text, category);
622
623 if (category == NULL) // For Bayesian, category is NULL
624 imap_list = gnc_account_imap_get_info_bayes (acc);
625 else
626 imap_list = gnc_account_imap_get_info (acc, category);
627
628 if (category == NULL)
629 head = IMAP_FRAME_BAYES;
630 else
631 head = IMAP_FRAME;
632
633 if (gnc_list_length_cmp (imap_list, 0))
634 {
635 PINFO("List length is %d", g_list_length (imap_list));
636
637 // Add top level entry of Source full Account and Based on.
638 gtk_tree_store_append (GTK_TREE_STORE(imap_dialog->model), &toplevel, NULL);
639 gtk_tree_store_set (GTK_TREE_STORE(imap_dialog->model), &toplevel,
640 SOURCE_ACCOUNT, acc, SOURCE_FULL_ACC, acc_name,
641 HEAD, head, CATEGORY, category, BASED_ON, text, FILTER, TRUE, -1);
642
643 for (node = imap_list; node; node = g_list_next (node))
644 {
645 GncImapInfo *imapInfo = node->data;
646
647 // First add a child entry and pass iter to add_to_store
648 gtk_tree_store_append (GTK_TREE_STORE(imap_dialog->model), &child, &toplevel);
649 add_to_store (imap_dialog, &child, text, imapInfo);
650 }
651 }
652 g_free (acc_name);
653 g_list_free_full (imap_list, (GDestroyNotify)gnc_account_imap_info_destroy); // Free the List
654}
655
656static void
657show_first_row (ImapDialog *imap_dialog)
658{
659 GtkTreeIter iter;
660
661 // See if there are any entries
662 if (gtk_tree_model_get_iter_first (imap_dialog->model, &iter))
663 {
664 GtkTreePath *path;
665 path = gtk_tree_path_new_first (); // Set Path to first entry
666 gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW(imap_dialog->view), path, NULL, TRUE, 0.0, 0.0);
667 gtk_tree_path_free (path);
668 }
669}
670
671static void
672get_account_info_bayes (ImapDialog *imap_dialog, GList *accts)
673{
674 GList *ptr;
675
676 /* Go through list of accounts */
677 for (ptr = accts; ptr; ptr = g_list_next (ptr))
678 {
679 Account *acc = ptr->data;
680
681 get_imap_info (imap_dialog, acc, NULL, _("Bayesian"));
682 }
683}
684
685static void
686get_account_info_nbayes (ImapDialog *imap_dialog, GList *accts)
687{
688 GList *ptr;
689
690 /* Go through list of accounts */
691 for (ptr = accts; ptr; ptr = g_list_next (ptr))
692 {
693 Account *acc = ptr->data;
694
695 // Description
696 get_imap_info (imap_dialog, acc, IMAP_FRAME_DESC, _("Description Field"));
697
698 // Memo
699 get_imap_info (imap_dialog, acc, IMAP_FRAME_MEMO, _("Memo Field"));
700
701 // CSV Account Map
702 get_imap_info (imap_dialog, acc, IMAP_FRAME_CSV, _("CSV Account Map"));
703 }
704}
705
706static void
707add_online_entry_to_store (ImapDialog *imap_dialog, GtkTreeIter *toplevel,
708 const gchar *based_on, GncImapInfo *imapInfo)
709{
710 // Add top level entry and pass iter to add_to_store
711 gtk_tree_store_append (GTK_TREE_STORE(imap_dialog->model), toplevel, NULL);
712 add_to_store (imap_dialog, toplevel, based_on, imapInfo);
713
714 imapInfo->map_account = NULL;
715}
716
717static void
718check_online_id (ImapDialog *imap_dialog, GtkTreeIter *toplevel, Account *acc, GncImapInfo *imapInfo)
719{
720 // Check for online_id
721 gchar *head = "online_id";
722 gchar *text = gnc_account_get_map_entry (acc, head, NULL);
723
724 if (!text)
725 return;
726
727 // Save source account
728 imapInfo->source_account = acc;
729 imapInfo->head = head;
730
731 if (text && *text)
732 imapInfo->map_account = imapInfo->source_account;
733
734 imapInfo->match_string = text;
735
736 add_online_entry_to_store (imap_dialog, toplevel, _("Online Id"), imapInfo);
737
738 g_free (text);
739}
740
741static void
742check_hbci (ImapDialog *imap_dialog, GtkTreeIter *toplevel, Account *acc, GncImapInfo *imapInfo)
743{
744 // Check for aqbanking hbci
745 gchar *head = "hbci";
746 gchar *hbci_account_id = gnc_account_get_map_entry (acc, head, "account-id");
747 gchar *hbci_bank_code = gnc_account_get_map_entry (acc, head, "bank-code");
748
749 if (!hbci_account_id || !hbci_bank_code)
750 return;
751
752 gchar *text = g_strconcat (hbci_bank_code, ",", hbci_account_id, NULL);
753
754 // Save source account
755 imapInfo->source_account = acc;
756 imapInfo->head = head;
757
758 if (text && *text)
759 imapInfo->map_account = imapInfo->source_account;
760
761 imapInfo->match_string = text;
762
763 add_online_entry_to_store (imap_dialog, toplevel, _("Online HBCI"), imapInfo);
764
765 g_free (hbci_account_id);
766 g_free (hbci_bank_code);
767 g_free (text);
768}
769
770static void
771check_ofx_account (ImapDialog *imap_dialog, GtkTreeIter *toplevel, Account *acc, GncImapInfo *imapInfo)
772{
773 // Check for ofx income account
774 gchar *head = "ofx/associated-income-account";
775 GncGUID *acct_guid = gnc_account_get_map_guid_entry (acc, head, NULL);
776
777 if (!acct_guid)
778 return;
779
780 gchar *text = guid_to_string (acct_guid);
781
782 // Save source account
783 imapInfo->source_account = acc;
784 imapInfo->head = head;
785
786 if (text && *text)
787 imapInfo->map_account = xaccAccountLookup (acct_guid, gnc_get_current_book ());
788
789 imapInfo->match_string = text;
790
791 add_online_entry_to_store (imap_dialog, toplevel, _("OFX Income Account"), imapInfo);
792
793 guid_free (acct_guid);
794 g_free (text);
795}
796
797static void
798get_account_info_online (ImapDialog *imap_dialog, GList *accts)
799{
800 GList *ptr;
801 GtkTreeIter toplevel;
802
803 GncImapInfo imapInfo;
804
805 imapInfo.map_account = NULL;
806 imapInfo.source_account = NULL;
807 imapInfo.category = " ";
808 imapInfo.count = " ";
809
810 /* Go through list of accounts */
811 for (ptr = accts; ptr; ptr = g_list_next (ptr))
812 {
813 Account *acc = ptr->data;
814
815 // Check for online_id
816 check_online_id (imap_dialog, &toplevel, acc, &imapInfo);
817
818 // Check for aqbanking hbci
819 check_hbci (imap_dialog, &toplevel, acc, &imapInfo);
820
821 // Check for ofx income account
822 check_ofx_account (imap_dialog, &toplevel, acc, &imapInfo);
823 }
824}
825
826static void
827show_filter_option (ImapDialog *imap_dialog, gboolean show)
828{
829 if (show)
830 {
831 gtk_widget_show (imap_dialog->filter_text_entry);
832 gtk_widget_show (imap_dialog->filter_button);
833 gtk_widget_show (imap_dialog->filter_label);
834 gtk_widget_show (imap_dialog->expand_button);
835 gtk_widget_show (imap_dialog->collapse_button);
836 }
837 else
838 {
839 gtk_widget_hide (imap_dialog->filter_text_entry);
840 gtk_widget_hide (imap_dialog->filter_button);
841 gtk_widget_hide (imap_dialog->filter_label);
842 gtk_widget_hide (imap_dialog->expand_button);
843 gtk_widget_hide (imap_dialog->collapse_button);
844 }
845}
846
847static void
848get_account_info (ImapDialog *imap_dialog)
849{
850 Account *root;
851 GList *accts;
852 GtkTreeModel *fmodel;
853 gchar *total;
854
855 /* Get list of Accounts */
856 root = gnc_book_get_root_account (gnc_get_current_book());
858
859 imap_dialog->tot_entries = 0;
860 imap_dialog->tot_invalid_maps = 0;
861
862 fmodel = gtk_tree_view_get_model (GTK_TREE_VIEW(imap_dialog->view));
863
864 imap_dialog->model = gtk_tree_model_filter_get_model (GTK_TREE_MODEL_FILTER(fmodel));
865
866 // Disconnect the filter model from the treeview
867 g_object_ref (G_OBJECT(imap_dialog->model));
868 gtk_tree_view_set_model (GTK_TREE_VIEW(imap_dialog->view), NULL);
869
870 // Clear the tree store
871 gtk_tree_store_clear (GTK_TREE_STORE(imap_dialog->model));
872
873 // Clear the filter
874 gtk_entry_set_text (GTK_ENTRY(imap_dialog->filter_text_entry), "");
875 imap_dialog->apply_selection_filter = FALSE;
876
877 // Hide Count Column
878 show_count_column (imap_dialog, FALSE);
879
880 // Show Filter Option
881 show_filter_option (imap_dialog, TRUE);
882
883 if (imap_dialog->type == BAYES)
884 {
885 get_account_info_bayes (imap_dialog, accts);
886
887 // Show Count Column
888 show_count_column (imap_dialog, TRUE);
889 }
890 else if (imap_dialog->type == NBAYES)
891 get_account_info_nbayes (imap_dialog, accts);
892 else if (imap_dialog->type == ONLINE)
893 {
894 // Hide Filter Option
895 show_filter_option (imap_dialog, FALSE);
896 get_account_info_online (imap_dialog, accts);
897 }
898 // create a new filter model and reconnect to treeview
899 fmodel = gtk_tree_model_filter_new (GTK_TREE_MODEL(imap_dialog->model), NULL);
900 gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER(fmodel), FILTER);
901 g_object_unref (G_OBJECT(imap_dialog->model));
902
903 gtk_tree_view_set_model (GTK_TREE_VIEW(imap_dialog->view), fmodel);
904 g_object_unref (G_OBJECT(fmodel));
905
906 // if there are any entries, show first row
907 show_first_row (imap_dialog);
908
909 // add the totals
910 total = g_strdup_printf ("%s %d", _("Total Entries"), imap_dialog->tot_entries);
911 gtk_label_set_text (GTK_LABEL(imap_dialog->total_entries_label), total);
912 gtk_widget_show (imap_dialog->total_entries_label);
913 g_free (total);
914
915 if (imap_dialog->tot_invalid_maps > 0)
916 gtk_widget_show (imap_dialog->remove_button);
917 else
918 gtk_widget_hide (imap_dialog->remove_button);
919
920 g_list_free (accts);
921}
922
923static gboolean
924view_selection_function (GtkTreeSelection *selection,
925 GtkTreeModel *model,
926 GtkTreePath *path,
927 gboolean path_currently_selected,
928 gpointer user_data)
929{
930 ImapDialog *imap_dialog = user_data;
931 GtkTreeIter iter;
932
933 if (!imap_dialog->apply_selection_filter)
934 return TRUE;
935
936 // do we have a valid row
937 if (gtk_tree_model_get_iter (model, &iter, path))
938 {
939 gchar *match_string;
940
941 // read the row
942 gtk_tree_model_get (model, &iter, MATCH_STRING, &match_string, -1);
943
944 // match_string NULL, top level can not be selected with a filter
945 if (match_string == NULL)
946 return FALSE;
947 g_free (match_string);
948 }
949 return TRUE;
950}
951
952static void
953gnc_imap_dialog_create (GtkWidget *parent, ImapDialog *imap_dialog)
954{
955 GtkWidget *dialog;
956 GtkBuilder *builder;
957 GtkTreeModel *filter;
958 GtkTreeSelection *selection;
959
960 ENTER(" ");
961 builder = gtk_builder_new();
962 gnc_builder_add_from_file (builder, "dialog-imap-editor.glade", "tree-store");
963 gnc_builder_add_from_file (builder, "dialog-imap-editor.glade", "treemodelfilter");
964 gnc_builder_add_from_file (builder, "dialog-imap-editor.glade", "import_map_dialog");
965
966 dialog = GTK_WIDGET(gtk_builder_get_object (builder, "import_map_dialog"));
967 imap_dialog->dialog = dialog;
968
969 // Set the name for this dialog so it can be easily manipulated with css
970 gtk_widget_set_name (GTK_WIDGET(dialog), "gnc-id-import-map");
971
972 imap_dialog->session = gnc_get_current_session();
973 imap_dialog->type = BAYES;
974
975 /* parent */
976 if (parent != NULL)
977 gtk_window_set_transient_for (GTK_WINDOW(dialog), GTK_WINDOW(parent));
978
979 /* Connect the radio buttons...*/
980 imap_dialog->radio_bayes = GTK_WIDGET(gtk_builder_get_object (builder, "radio-bayes"));
981 imap_dialog->radio_nbayes = GTK_WIDGET(gtk_builder_get_object (builder, "radio-nbayes"));
982 imap_dialog->radio_online = GTK_WIDGET(gtk_builder_get_object (builder, "radio-online"));
983 g_signal_connect (imap_dialog->radio_bayes, "toggled",
984 G_CALLBACK(list_type_selected_cb), (gpointer)imap_dialog);
985 g_signal_connect (imap_dialog->radio_nbayes, "toggled",
986 G_CALLBACK(list_type_selected_cb), (gpointer)imap_dialog);
987
988 imap_dialog->total_entries_label = GTK_WIDGET(gtk_builder_get_object (builder, "total_entries_label"));
989 imap_dialog->filter_text_entry = GTK_WIDGET(gtk_builder_get_object (builder, "filter-text-entry"));
990 imap_dialog->filter_label = GTK_WIDGET(gtk_builder_get_object (builder, "filter-label"));
991 imap_dialog->filter_button = GTK_WIDGET(gtk_builder_get_object (builder, "filter-button"));
992 g_signal_connect (imap_dialog->filter_button, "clicked",
993 G_CALLBACK(filter_button_cb), (gpointer)imap_dialog);
994
995 imap_dialog->expand_button = GTK_WIDGET(gtk_builder_get_object (builder, "expand-button"));
996 g_signal_connect (imap_dialog->expand_button, "clicked",
997 G_CALLBACK(expand_button_cb), (gpointer)imap_dialog);
998
999 imap_dialog->collapse_button = GTK_WIDGET(gtk_builder_get_object (builder, "collapse-button"));
1000 g_signal_connect (imap_dialog->collapse_button, "clicked",
1001 G_CALLBACK(collapse_button_cb), (gpointer)imap_dialog);
1002
1003 imap_dialog->view = GTK_WIDGET(gtk_builder_get_object (builder, "treeview"));
1004
1005 imap_dialog->remove_button = GTK_WIDGET(gtk_builder_get_object (builder, "remove_button"));
1006
1007 // Set filter column
1008 filter = gtk_tree_view_get_model (GTK_TREE_VIEW(imap_dialog->view));
1009 gtk_tree_model_filter_set_visible_column (GTK_TREE_MODEL_FILTER(filter), FILTER);
1010
1011 // Set grid lines option to preference
1012 gtk_tree_view_set_grid_lines (GTK_TREE_VIEW(imap_dialog->view), gnc_tree_view_get_grid_lines_pref ());
1013
1014 /* default to 'close' button */
1015 gtk_dialog_set_default_response (GTK_DIALOG(dialog), GTK_RESPONSE_CLOSE);
1016
1017 selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(imap_dialog->view));
1018 gtk_tree_selection_set_mode (selection, GTK_SELECTION_MULTIPLE);
1019
1020 /* add a select function */
1021 gtk_tree_selection_set_select_function (selection,
1022 view_selection_function,
1023 imap_dialog,
1024 NULL);
1025
1026 gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, imap_dialog);
1027
1028 g_object_unref (G_OBJECT(builder));
1029
1030 gnc_restore_window_size (GNC_PREFS_GROUP, GTK_WINDOW(imap_dialog->dialog), GTK_WINDOW(parent));
1031 get_account_info (imap_dialog);
1032
1033 LEAVE(" ");
1034}
1035
1036static void
1037close_handler (gpointer user_data)
1038{
1039 ImapDialog *imap_dialog = user_data;
1040
1041 ENTER(" ");
1042 gnc_save_window_size (GNC_PREFS_GROUP, GTK_WINDOW(imap_dialog->dialog));
1043 gtk_widget_destroy (GTK_WIDGET(imap_dialog->dialog));
1044 LEAVE(" ");
1045}
1046
1047static void
1048refresh_handler (GHashTable *changes, gpointer user_data)
1049{
1050 ENTER(" ");
1051 LEAVE(" ");
1052}
1053
1054static gboolean
1055show_handler (const char *klass, gint component_id,
1056 gpointer user_data, gpointer iter_data)
1057{
1058 ImapDialog *imap_dialog = user_data;
1059
1060 ENTER(" ");
1061 if (!imap_dialog)
1062 {
1063 LEAVE("No data structure");
1064 return(FALSE);
1065 }
1066 gtk_window_present (GTK_WINDOW(imap_dialog->dialog));
1067 LEAVE(" ");
1068 return(TRUE);
1069}
1070
1071/********************************************************************\
1072 * gnc_imap_dialog *
1073 * opens a window showing Bayesian and Non-Bayesian information *
1074 * *
1075 * Args: parent - the parent of the window to be created *
1076 * Return: nothing *
1077\********************************************************************/
1078void
1079gnc_imap_dialog (GtkWidget *parent)
1080{
1081 ImapDialog *imap_dialog;
1082 gint component_id;
1083
1084 ENTER(" ");
1085 if (gnc_forall_gui_components (DIALOG_IMAP_CM_CLASS, show_handler, NULL))
1086 {
1087 LEAVE("Existing dialog raised");
1088 return;
1089 }
1090 imap_dialog = g_new0 (ImapDialog, 1);
1091
1092 gnc_imap_dialog_create (parent, imap_dialog);
1093
1094 component_id = gnc_register_gui_component (DIALOG_IMAP_CM_CLASS,
1095 refresh_handler, close_handler,
1096 imap_dialog);
1097
1098 gnc_gui_component_set_session (component_id, imap_dialog->session);
1099
1100 gtk_widget_show (imap_dialog->dialog);
1101 gtk_widget_hide (imap_dialog->remove_button);
1102 gnc_imap_invalid_maps_dialog (imap_dialog);
1103 LEAVE(" ");
1104}
Account handling public routines.
GLib helper routines.
utility functions for the GnuCash UI
GList * gnc_account_get_descendants_sorted(const Account *account)
This function returns a GList containing all the descendants of the specified account,...
Definition Account.cpp:3052
gchar * gnc_account_get_full_name(const Account *account)
The gnc_account_get_full_name routine returns the fully qualified name of the account using the given...
Definition Account.cpp:3305
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
The xaccAccountLookup() subroutine will return the account associated with the given id,...
Definition Account.cpp:2050
gchar * gnc_account_get_map_entry(Account *acc, const char *head, const char *category)
Returns the text string pointed to by head and category for the Account, free the returned text.
Definition Account.cpp:5732
void gnc_account_delete_all_bayes_maps(Account *acc)
Delete all bayes entries for Account.
Definition Account.cpp:5775
GList * gnc_account_imap_get_info(Account *acc, const char *category)
Returns a GList of structure imap_info of all Non Bayesian mappings for required Account.
Definition Account.cpp:5703
void gnc_account_imap_info_destroy(GncImapInfo *imapInfo)
Clean destructor for the imap_info structure of Bayesian mappings.
Definition Account.cpp:5682
void gnc_account_delete_map_entry(Account *acc, char *head, char *category, char *match_string, gboolean empty)
Delete the entry for Account pointed to by head,category and match_string, if empty is TRUE then use ...
Definition Account.cpp:5748
GList * gnc_account_imap_get_info_bayes(Account *acc)
Returns a GList of structure imap_info of all Bayesian mappings for required Account.
Definition Account.cpp:5692
GncGUID * gnc_account_get_map_guid_entry(Account *acc, const char *head, const char *category)
Returns the guid pointed to by head and category for the Account, free the returned guid.
Definition Account.cpp:5740
gchar * guid_to_string(const GncGUID *guid)
The guid_to_string() routine returns a null-terminated string encoding of the id.
Definition guid.cpp:199
gint gnc_list_length_cmp(const GList *list, size_t len)
Scans the GList elements the minimum number of iterations required to test it against a specified siz...
#define PINFO(format, args...)
Print an informational note.
Definition qoflog.h:256
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition qoflog.h:282
#define ENTER(format, args...)
Print a function entry debugging message.
Definition qoflog.h:272
STRUCTS.
The type used to store guids in C.
Definition guid.h:75