1 /********************************************************************\
2  * gnc-ledger-display.c -- utilities for dealing with multiple      *
3  *                         register/ledger windows in GnuCash       *
4  *                                                                  *
5  * Copyright (C) 1997 Robin D. Clark                                *
6  * Copyright (C) 1997, 1998 Linas Vepstas                           *
7  * Copyright (C) 2012 Robert Fewell                                 *
8  *                                                                  *
9  * This program is free software; you can redistribute it and/or    *
10  * modify it under the terms of the GNU General Public License as   *
11  * published by the Free Software Foundation; either version 2 of   *
12  * the License, or (at your option) any later version.              *
13  *                                                                  *
14  * This program is distributed in the hope that it will be useful,  *
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
17  * GNU General Public License for more details.                     *
18  *                                                                  *
19  * You should have received a copy of the GNU General Public License*
20  * along with this program; if not, write to the Free Software      *
21  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.        *
22  *                                                                  *
23 \********************************************************************/
24 
25 #include <config.h>
26 
27 #include <time.h>
28 
29 #include "Account.h"
30 #include "Query.h"
31 #include "qof.h"
32 #include "SX-book.h"
33 #include "Transaction.h"
34 #include "gnc-component-manager.h"
35 #include "gnc-date.h"
36 #include "gnc-engine.h"
37 #include "gnc-event.h"
38 #include "gnc-ledger-display2.h"
39 #include "gnc-prefs.h"
40 #include "gnc-ui-util.h"
41 
42 #include "split-register-control.h"
43 #include "split-register-model.h"
44 
45 #include "gnc-tree-model-split-reg.h"
46 
47 
48 #define REGISTER_SINGLE_CM_CLASS     "register-single"
49 #define REGISTER_SUBACCOUNT_CM_CLASS "register-subaccount"
50 #define REGISTER_GL_CM_CLASS         "register-gl"
51 #define REGISTER_TEMPLATE_CM_CLASS   "register-template"
52 
53 #define GNC_PREF_DOUBLE_LINE_MODE         "double-line-mode"
54 #define GNC_PREF_MAX_TRANS                "max-transactions"
55 #define GNC_PREF_DEFAULT_STYLE_LEDGER     "default-style-ledger"
56 #define GNC_PREF_DEFAULT_STYLE_AUTOLEDGER "default-style-autoledger"
57 #define GNC_PREF_DEFAULT_STYLE_JOURNAL    "default-style-journal"
58 
59 
60 struct gnc_ledger_display2
61 {
62     GncGUID leader;
63 
64     Query *query;
65 
66     GNCLedgerDisplay2Type ld_type;
67 
68     GncTreeModelSplitReg *model; //FIXME Might get rid of this and use function to find.
69     GncTreeViewSplitReg *view;
70 
71     gboolean refresh_ok;
72 
73     gboolean loading;
74     gboolean use_double_line_default;
75 
76     GNCLedgerDisplay2Destroy destroy;
77     GNCLedgerDisplay2GetParent get_parent;
78 
79     gpointer user_data;
80 
81     gint component_id;
82 };
83 
84 
85 /** GLOBALS *********************************************************/
86 static QofLogModule log_module = GNC_MOD_LEDGER;
87 
88 
89 /** Declarations ****************************************************/
90 static GNCLedgerDisplay2 *
91 gnc_ledger_display2_internal (Account *lead_account, Query *q,
92                              GNCLedgerDisplay2Type ld_type,
93                              SplitRegisterType2 reg_type,
94                              SplitRegisterStyle2 style,
95                              gboolean use_double_line,
96                              gboolean is_template,
97                              gboolean mismatched_commodities);
98 
99 static void gnc_ledger_display2_refresh_internal (GNCLedgerDisplay2 *ld, GList *splits);
100 
101 static void gnc_ledger_display2_refresh_cb (GncTreeModelSplitReg *model, gpointer item, gpointer user_data);
102 
103 /** Implementations *************************************************/
104 
105 Account *
gnc_ledger_display2_leader(GNCLedgerDisplay2 * ld)106 gnc_ledger_display2_leader (GNCLedgerDisplay2 *ld)
107 {
108     if (!ld)
109         return NULL;
110 
111     return xaccAccountLookup (&ld->leader, gnc_get_current_book ());
112 }
113 
114 GNCLedgerDisplay2Type
gnc_ledger_display2_type(GNCLedgerDisplay2 * ld)115 gnc_ledger_display2_type (GNCLedgerDisplay2 *ld)
116 {
117     if (!ld)
118         return -1;
119 
120     return ld->ld_type;
121 }
122 
123 void
gnc_ledger_display2_set_user_data(GNCLedgerDisplay2 * ld,gpointer user_data)124 gnc_ledger_display2_set_user_data (GNCLedgerDisplay2 *ld, gpointer user_data)
125 {
126     if (!ld)
127         return;
128 
129     ld->user_data = user_data;
130 }
131 
132 gpointer
gnc_ledger_display2_get_user_data(GNCLedgerDisplay2 * ld)133 gnc_ledger_display2_get_user_data (GNCLedgerDisplay2 *ld)
134 {
135     if (!ld)
136         return NULL;
137 
138     return ld->user_data;
139 }
140 
141 void
gnc_ledger_display2_set_handlers(GNCLedgerDisplay2 * ld,GNCLedgerDisplay2Destroy destroy,GNCLedgerDisplay2GetParent get_parent)142 gnc_ledger_display2_set_handlers (GNCLedgerDisplay2 *ld,
143                                  GNCLedgerDisplay2Destroy destroy,
144                                  GNCLedgerDisplay2GetParent get_parent)
145 {
146     if (!ld)
147         return;
148 
149     ld->destroy = destroy;
150     ld->get_parent = get_parent;
151 }
152 
153 GncTreeModelSplitReg *
gnc_ledger_display2_get_split_model_register(GNCLedgerDisplay2 * ld)154 gnc_ledger_display2_get_split_model_register (GNCLedgerDisplay2 *ld)
155 {
156     if (!ld)
157         return NULL;
158 
159     return ld->model;
160 }
161 
162 Query *
gnc_ledger_display2_get_query(GNCLedgerDisplay2 * ld)163 gnc_ledger_display2_get_query (GNCLedgerDisplay2 *ld)
164 {
165     if (!ld)
166         return NULL;
167 
168     return ld->query;
169 }
170 
171 static gboolean
find_by_leader(gpointer find_data,gpointer user_data)172 find_by_leader (gpointer find_data, gpointer user_data)
173 {
174     Account *account = find_data;
175     GNCLedgerDisplay2 *ld = user_data;
176 
177     if (!account || !ld)
178         return FALSE;
179 
180     return (account == gnc_ledger_display2_leader (ld));
181 }
182 
183 static gboolean
find_by_query(gpointer find_data,gpointer user_data)184 find_by_query (gpointer find_data, gpointer user_data)
185 {
186     Query *q = find_data;
187     GNCLedgerDisplay2 *ld = user_data;
188 
189     if (!q || !ld)
190         return FALSE;
191 
192     return ld->query == q;
193 }
194 
195 
196 static gboolean
find_by_reg(gpointer find_data,gpointer user_data)197 find_by_reg (gpointer find_data, gpointer user_data)
198 {
199     GncTreeModelSplitReg *model = find_data;
200     GNCLedgerDisplay2 *ld = user_data;
201 
202     if (!model || !ld)
203         return FALSE;
204 
205     return ld->model == model;
206 }
207 
208 static SplitRegisterStyle2
gnc_get_default_register_style(GNCAccountType type)209 gnc_get_default_register_style (GNCAccountType type)
210 {
211     SplitRegisterStyle2 new_style = REG2_STYLE_LEDGER;
212 
213     if (gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER,
214                             GNC_PREF_DEFAULT_STYLE_JOURNAL))
215         new_style = REG2_STYLE_JOURNAL;
216     else if (gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER,
217                                  GNC_PREF_DEFAULT_STYLE_AUTOLEDGER))
218         new_style = REG2_STYLE_AUTO_LEDGER;
219 
220     return new_style;
221 }
222 
223 static gpointer
look_for_portfolio_cb(Account * account,gpointer data)224 look_for_portfolio_cb (Account *account, gpointer data)
225 {
226     return xaccAccountIsPriced(account) ? (gpointer) PORTFOLIO_LEDGER2 : NULL;
227 }
228 
229 static SplitRegisterType2
gnc_get_reg_type(Account * leader,GNCLedgerDisplay2Type ld_type)230 gnc_get_reg_type (Account *leader, GNCLedgerDisplay2Type ld_type)
231 {
232     GNCAccountType account_type;
233     SplitRegisterType2 reg_type;
234 
235     if (ld_type == LD2_GL)
236         return GENERAL_JOURNAL2;
237 
238     account_type = xaccAccountGetType (leader);
239 
240     if (ld_type == LD2_SINGLE)
241     {
242         switch (account_type)
243         {
244         case ACCT_TYPE_BANK:
245             return BANK_REGISTER2;
246 
247         case ACCT_TYPE_CASH:
248             return CASH_REGISTER2;
249 
250         case ACCT_TYPE_ASSET:
251             return ASSET_REGISTER2;
252 
253         case ACCT_TYPE_CREDIT:
254             return CREDIT_REGISTER2;
255 
256         case ACCT_TYPE_LIABILITY:
257             return LIABILITY_REGISTER2;
258 
259         case ACCT_TYPE_PAYABLE:
260             return PAYABLE_REGISTER2;
261 
262         case ACCT_TYPE_RECEIVABLE:
263             return RECEIVABLE_REGISTER2;
264 
265         case ACCT_TYPE_STOCK:
266         case ACCT_TYPE_MUTUAL:
267             return STOCK_REGISTER2;
268 
269         case ACCT_TYPE_INCOME:
270             return INCOME_REGISTER2;
271 
272         case ACCT_TYPE_EXPENSE:
273             return EXPENSE_REGISTER2;
274 
275         case ACCT_TYPE_EQUITY:
276             return EQUITY_REGISTER2;
277 
278         case ACCT_TYPE_CURRENCY:
279             return CURRENCY_REGISTER2;
280 
281         case ACCT_TYPE_TRADING:
282             return TRADING_REGISTER2;
283 
284         default:
285             PERR ("unknown account type %d\n", account_type);
286             return BANK_REGISTER2;
287         }
288     }
289 
290     if (ld_type != LD2_SUBACCOUNT)
291     {
292         PERR ("unknown ledger type %d\n", ld_type);
293         return BANK_REGISTER2;
294     }
295 
296     switch (account_type)
297     {
298     case ACCT_TYPE_BANK:
299     case ACCT_TYPE_CASH:
300     case ACCT_TYPE_ASSET:
301     case ACCT_TYPE_CREDIT:
302     case ACCT_TYPE_LIABILITY:
303     case ACCT_TYPE_RECEIVABLE:
304     case ACCT_TYPE_PAYABLE:
305     {
306         /* If any of the sub-accounts have ACCT_TYPE_STOCK or
307          * ACCT_TYPE_MUTUAL types, then we must use the PORTFOLIO_LEDGER
308          * ledger. Otherwise, a plain old GENERAL_JOURNAL will do. */
309         gpointer ret;
310         reg_type = GENERAL_JOURNAL2;
311 
312         ret = gnc_account_foreach_descendant_until(leader, look_for_portfolio_cb, NULL);
313         if (ret) reg_type = PORTFOLIO_LEDGER2;
314         break;
315     }
316 
317     case ACCT_TYPE_STOCK:
318     case ACCT_TYPE_MUTUAL:
319     case ACCT_TYPE_CURRENCY:
320         reg_type = PORTFOLIO_LEDGER2;
321         break;
322 
323     case ACCT_TYPE_INCOME:
324     case ACCT_TYPE_EXPENSE:
325         reg_type = INCOME_LEDGER2;
326         break;
327 
328     case ACCT_TYPE_EQUITY:
329     case ACCT_TYPE_TRADING:
330         reg_type = GENERAL_JOURNAL2;
331         break;
332 
333     default:
334         PERR ("unknown account type:%d", account_type);
335         reg_type = GENERAL_JOURNAL2;
336         break;
337     }
338 
339     return reg_type;
340 }
341 
342 /* Returns a boolean of whether this display should be single or double lined
343  * mode by default */
344 gboolean
gnc_ledger_display2_default_double_line(GNCLedgerDisplay2 * gld)345 gnc_ledger_display2_default_double_line (GNCLedgerDisplay2 *gld)
346 {
347     return (gld->use_double_line_default ||
348             gnc_prefs_get_bool(GNC_PREFS_GROUP_GENERAL_REGISTER, GNC_PREF_DOUBLE_LINE_MODE));
349 }
350 
351 /* Opens up a register window to display a single account */
352 GNCLedgerDisplay2 *
gnc_ledger_display2_simple(Account * account)353 gnc_ledger_display2_simple (Account *account)
354 {
355     SplitRegisterType2 reg_type;
356     GNCAccountType acc_type = xaccAccountGetType (account);
357     gboolean use_double_line;
358     GNCLedgerDisplay2 *ld;
359 
360     ENTER("account=%p", account);
361 
362     switch (acc_type)
363     {
364     case ACCT_TYPE_PAYABLE:
365     case ACCT_TYPE_RECEIVABLE:
366         use_double_line = TRUE;
367         break;
368     default:
369         use_double_line = FALSE;
370         break;
371     }
372 
373     reg_type = gnc_get_reg_type (account, LD2_SINGLE);
374 
375     ld = gnc_ledger_display2_internal (account, NULL, LD2_SINGLE, reg_type,
376                                       gnc_get_default_register_style(acc_type),
377                                       use_double_line, FALSE, FALSE);
378     LEAVE("%p", ld);
379     return ld;
380 }
381 
382 /* Opens up a register window to display an account, and all of its
383  *   children, in the same window */
384 GNCLedgerDisplay2 *
gnc_ledger_display2_subaccounts(Account * account,gboolean mismatched_commodities)385 gnc_ledger_display2_subaccounts (Account *account, gboolean mismatched_commodities)
386 {
387     SplitRegisterType2 reg_type;
388     GNCLedgerDisplay2 *ld;
389 
390     ENTER("account=%p", account);
391 
392     reg_type = gnc_get_reg_type (account, LD2_SUBACCOUNT);
393 
394     ld = gnc_ledger_display2_internal (account, NULL, LD2_SUBACCOUNT,
395                                       reg_type, REG2_STYLE_JOURNAL, FALSE,
396                                       FALSE,mismatched_commodities);
397     LEAVE("%p", ld);
398     return ld;
399 }
400 
401 /* Opens up a general journal window. */
402 GNCLedgerDisplay2 *
gnc_ledger_display2_gl(void)403 gnc_ledger_display2_gl (void)
404 {
405     Query *query;
406     time64 start;
407     struct tm tm;
408     GNCLedgerDisplay2 *ld;
409 
410     ENTER(" ");
411 
412     query = qof_query_create_for (GNC_ID_SPLIT);
413 
414     qof_query_set_book (query, gnc_get_current_book());
415 
416     /* In lieu of not "mis-using" some portion of the infrastructure by writing
417      * a bunch of new code, we just filter out the accounts of the template
418      * transactions.  While these are in a separate Account trees just for this
419      * reason, the query engine makes no distinction between Account trees.
420      * See Gnome Bug 86302.
421      *         -- jsled */
422     {
423         Account *tRoot;
424         GList *al;
425 
426         tRoot = gnc_book_get_template_root( gnc_get_current_book() );
427         al = gnc_account_get_descendants( tRoot );
428 
429         if (g_list_length(al) != 0)
430             xaccQueryAddAccountMatch( query, al, QOF_GUID_MATCH_NONE, QOF_QUERY_AND );
431 
432         g_list_free (al);
433         al = NULL;
434         tRoot = NULL;
435     }
436 
437     gnc_tm_get_today_start(&tm);
438     tm.tm_mon--; /* Default the register to the last month's worth of transactions. */
439     start = gnc_mktime (&tm);
440     xaccQueryAddDateMatchTT (query,
441                              TRUE, start,
442                              FALSE, 0,
443                              QOF_QUERY_AND);
444 
445     ld = gnc_ledger_display2_internal (NULL, query, LD2_GL, GENERAL_JOURNAL2,
446                                       REG2_STYLE_JOURNAL, FALSE, FALSE, FALSE);
447     LEAVE("%p", ld);
448     return ld;
449 }
450 
451 /**
452  * @param id: The string version of the GncGUID of the context of template
453  * transaction being edited in this template GL.  As used by scheduled
454  * transactions, this is the GncGUID of the SX itself which is magically the
455  * *name* of the (template) account which contains the transactions for this
456  * scheduled transaction.  That's right.  The stringified GncGUID of the SX is
457  * the name of the SX'es template account.
458  **/
459 GNCLedgerDisplay2 *
gnc_ledger_display2_template_gl(char * id)460 gnc_ledger_display2_template_gl (char *id)
461 {
462     QofBook *book;
463     Query *q;
464     GNCLedgerDisplay2 *ld;
465     GncTreeModelSplitReg *model;
466     Account *root, *acct;
467     gboolean isTemplateModeTrue;
468 
469     ENTER("id=%s", id ? id : "(null)");
470 
471     acct = NULL;
472     isTemplateModeTrue = TRUE;
473 
474     q = qof_query_create_for(GNC_ID_SPLIT);
475 
476     book = gnc_get_current_book ();
477     qof_query_set_book (q, book);
478 
479     if ( id != NULL )
480     {
481         root = gnc_book_get_template_root (book);
482         acct = gnc_account_lookup_by_name(root, id);
483         g_assert( acct );
484         xaccQueryAddSingleAccountMatch (q, acct, QOF_QUERY_AND);
485     }
486 
487     ld = gnc_ledger_display2_internal (NULL, q, LD2_GL,
488                                       SEARCH_LEDGER2,
489                                       REG2_STYLE_JOURNAL,
490                                       FALSE,
491                                       isTemplateModeTrue,
492                                        FALSE);
493 
494 
495     model = gnc_ledger_display2_get_split_model_register (ld);
496     if ( acct )
497     {
498         gnc_tree_model_split_reg_set_template_account (model, acct);
499     }
500 
501     LEAVE("%p", ld);
502     return ld;
503 }
504 
505 GtkWidget *
gnc_ledger_display2_get_parent(GNCLedgerDisplay2 * ld)506 gnc_ledger_display2_get_parent( GNCLedgerDisplay2 *ld )
507 {
508     if ( ld == NULL )
509         return NULL;
510 
511     if ( ld->get_parent == NULL )
512         return NULL;
513 
514     return ld->get_parent( ld );
515 }
516 
517 static GtkWidget *
gnc_ledger_display2_parent(void * user_data)518 gnc_ledger_display2_parent (void *user_data)
519 {
520     GNCLedgerDisplay2 *ld = user_data;
521     return gnc_ledger_display2_get_parent( ld );
522 }
523 
524 #ifdef skip
525 //FIXME Not used ?
526 static void
gnc_ledger_display2_set_watches(GNCLedgerDisplay2 * ld,GList * splits)527 gnc_ledger_display2_set_watches (GNCLedgerDisplay2 *ld, GList *splits)
528 {
529     GList *node;
530 
531     gnc_gui_component_clear_watches (ld->component_id);
532 
533     gnc_gui_component_watch_entity_type (ld->component_id,
534                                          GNC_ID_ACCOUNT,
535                                          QOF_EVENT_MODIFY | QOF_EVENT_DESTROY
536                                          | GNC_EVENT_ITEM_CHANGED);
537 
538     for (node = splits; node; node = node->next)
539     {
540         Split *split = node->data;
541         Transaction *trans = xaccSplitGetParent (split);
542 
543         gnc_gui_component_watch_entity (ld->component_id,
544                                         xaccTransGetGUID (trans),
545                                         QOF_EVENT_MODIFY);
546     }
547 }
548 #endif
549 
550 static void
refresh_handler(GHashTable * changes,gpointer user_data)551 refresh_handler (GHashTable *changes, gpointer user_data)
552 {
553     GNCLedgerDisplay2 *ld = user_data;
554     const EventInfo *info;
555     gboolean has_leader;
556     GList *splits;
557 
558     ENTER("changes=%p, user_data=%p", changes, user_data);
559 
560     if (ld->loading)
561     {
562         LEAVE("already loading");
563         return;
564     }
565 
566     has_leader = (ld->ld_type == LD2_SINGLE || ld->ld_type == LD2_SUBACCOUNT);
567 
568     if (has_leader)
569     {
570         Account *leader = gnc_ledger_display2_leader (ld);
571         if (!leader)
572         {
573             gnc_close_gui_component (ld->component_id);
574             LEAVE("no leader");
575             return;
576         }
577     }
578 
579     if (changes && has_leader)
580     {
581         info = gnc_gui_get_entity_events (changes, &ld->leader);
582         if (info && (info->event_mask & QOF_EVENT_DESTROY))
583         {
584             gnc_close_gui_component (ld->component_id);
585             LEAVE("destroy");
586             return;
587         }
588     }
589 
590     /* Its not clear if we should re-run the query, or if we should
591      * just use qof_query_last_run().  Its possible that the dates
592      * changed, requiring a full new query.  Similar considerations
593      * needed for multi-user mode.
594      */
595     splits = qof_query_run (ld->query);
596 
597 //FIXME Not Needed ?    gnc_ledger_display2_set_watches (ld, splits);
598 //    gnc_ledger_display2_set_watches (ld, splits);
599 
600     //preference changes come this way
601     gnc_ledger_display2_refresh_internal (ld, splits);
602 
603     LEAVE(" ");
604 }
605 
606 static void
close_handler(gpointer user_data)607 close_handler (gpointer user_data)
608 {
609     GNCLedgerDisplay2 *ld = user_data;
610 
611     if (!ld)
612         return;
613 
614     ENTER(" ");
615 
616     gnc_unregister_gui_component (ld->component_id);
617 
618     if (ld->destroy)
619         ld->destroy (ld);
620 
621     gnc_tree_model_split_reg_destroy (ld->model);
622     ld->model = NULL;
623     ld->view = NULL;
624 
625     qof_query_destroy (ld->query);
626     ld->query = NULL;
627 
628     LEAVE(" ");
629     g_free (ld);
630 }
631 
632 static void
gnc_ledger_display2_make_query(GNCLedgerDisplay2 * ld,gint limit,SplitRegisterType2 type)633 gnc_ledger_display2_make_query (GNCLedgerDisplay2 *ld,
634                                gint limit,
635                                SplitRegisterType2 type)
636 {
637     Account *leader;
638     GList *accounts;
639 
640     if (!ld)
641         return;
642 
643     switch (ld->ld_type)
644     {
645     case LD2_SINGLE:
646     case LD2_SUBACCOUNT:
647         break;
648 
649     case LD2_GL:
650         return;
651 
652     default:
653         PERR ("unknown ledger type: %d", ld->ld_type);
654         return;
655     }
656 
657     qof_query_destroy (ld->query);
658     ld->query = qof_query_create_for(GNC_ID_SPLIT);
659 
660     /* This is a bit of a hack. The number of splits should be
661      * configurable, or maybe we should go back a time range instead
662      * of picking a number, or maybe we should be able to exclude
663      * based on reconciled status. Anyway, this works for now. */
664     if ((limit != 0) && (type != SEARCH_LEDGER2))
665         qof_query_set_max_results (ld->query, limit);
666 
667     qof_query_set_book (ld->query, gnc_get_current_book());
668 
669     leader = gnc_ledger_display2_leader (ld);
670 
671     if (ld->ld_type == LD2_SUBACCOUNT)
672         accounts = gnc_account_get_descendants (leader);
673     else
674         accounts = NULL;
675 
676     accounts = g_list_prepend (accounts, leader);
677 
678     xaccQueryAddAccountMatch (ld->query, accounts,
679                               QOF_GUID_MATCH_ANY, QOF_QUERY_AND);
680 
681     g_list_free (accounts);
682 }
683 
684 /* Opens up a ledger window for an arbitrary query. */
685 GNCLedgerDisplay2 *
gnc_ledger_display2_query(Query * query,SplitRegisterType2 type,SplitRegisterStyle2 style)686 gnc_ledger_display2_query (Query *query, SplitRegisterType2 type,
687                           SplitRegisterStyle2 style)
688 {
689     GNCLedgerDisplay2 *ld;
690 
691     ENTER("query=%p", query);
692 
693     ld = gnc_ledger_display2_internal (NULL, query, LD2_GL, type, style,
694                                       FALSE, FALSE, FALSE);
695     LEAVE("%p", ld);
696     return ld;
697 }
698 
699 static GNCLedgerDisplay2 *
gnc_ledger_display2_internal(Account * lead_account,Query * q,GNCLedgerDisplay2Type ld_type,SplitRegisterType2 reg_type,SplitRegisterStyle2 style,gboolean use_double_line,gboolean is_template,gboolean mismatched_commodities)700 gnc_ledger_display2_internal (Account *lead_account, Query *q,
701                              GNCLedgerDisplay2Type ld_type,
702                              SplitRegisterType2 reg_type,
703                              SplitRegisterStyle2 style,
704                              gboolean use_double_line,
705                               gboolean is_template,
706                               gboolean mismatched_commodities)
707 {
708     GNCLedgerDisplay2 *ld;
709     gint limit;
710     const char *klass;
711 //    GList *splits;
712     gboolean display_subaccounts = FALSE;
713     gboolean is_gl = FALSE;
714 
715     switch (ld_type)
716     {
717     case LD2_SINGLE:
718         klass = REGISTER_SINGLE_CM_CLASS;
719 
720         if (reg_type >= NUM_SINGLE_REGISTER_TYPES2)
721         {
722             PERR ("single-account register with wrong split register type");
723             return NULL;
724         }
725 
726         if (!lead_account)
727         {
728             PERR ("single-account register with no account specified");
729             return NULL;
730         }
731 
732         if (q)
733         {
734             PWARN ("single-account register with external query");
735             q = NULL;
736         }
737 
738         ld = gnc_find_first_gui_component (klass, find_by_leader, lead_account);
739         if (ld)
740             return ld;
741 
742         break;
743 
744     case LD2_SUBACCOUNT:
745         klass = REGISTER_SUBACCOUNT_CM_CLASS;
746 
747         if (!lead_account)
748         {
749             PERR ("sub-account register with no lead account");
750             return NULL;
751         }
752 
753         if (q)
754         {
755             PWARN ("account register with external query");
756             q = NULL;
757         }
758 
759         ld = gnc_find_first_gui_component (klass, find_by_leader, lead_account);
760         if (ld)
761             return ld;
762 
763         display_subaccounts = TRUE;
764         break;
765 
766     case LD2_GL:
767         klass = REGISTER_GL_CM_CLASS;
768 
769         if (!q)
770         {
771             PWARN ("general journal with no query");
772         }
773 
774         is_gl = TRUE;
775         break;
776 
777     default:
778         PERR ("bad ledger type: %d", ld_type);
779         return NULL;
780 
781     }
782 
783     ld = g_new (GNCLedgerDisplay2, 1);
784 
785     ld->leader = *xaccAccountGetGUID (lead_account);
786     ld->query = NULL;
787     ld->ld_type = ld_type;
788     ld->loading = FALSE;
789     ld->refresh_ok = FALSE;
790     ld->destroy = NULL;
791     ld->get_parent = NULL;
792     ld->user_data = NULL;
793 
794     limit = gnc_prefs_get_float(GNC_PREFS_GROUP_GENERAL_REGISTER, GNC_PREF_MAX_TRANS);
795 
796     /* set up the query filter */
797     if (q)
798         ld->query = qof_query_copy (q);
799     else
800         gnc_ledger_display2_make_query (ld, limit, reg_type);
801 
802     ld->component_id = gnc_register_gui_component (klass,
803                        refresh_handler,
804                        close_handler, ld);
805 
806     /******************************************************************\
807      * The main register window itself                                *
808     \******************************************************************/
809 
810     ld->use_double_line_default = use_double_line;
811 
812     ld->model = gnc_tree_model_split_reg_new (reg_type, style, use_double_line, is_template, mismatched_commodities);
813 
814     gnc_tree_model_split_reg_set_data (ld->model, ld, gnc_ledger_display2_parent);
815     gnc_tree_model_split_reg_set_display (ld->model, display_subaccounts, is_gl);
816 
817     // This sets up a call back to reload after changes
818     g_signal_connect (G_OBJECT (ld->model), "refresh_trans",
819                       G_CALLBACK (gnc_ledger_display2_refresh_cb), ld );
820 
821 //FIXME Not Needed ?    gnc_ledger_display2_set_watches (ld, splits);
822 //    gnc_ledger_display2_set_watches (ld, splits);
823 
824     // Populate the model with an empty split
825     // An empty model could cause our gui callbacks to crash
826     gnc_ledger_display2_refresh_internal (ld, NULL);
827 
828     return ld;
829 }
830 
831 void
gnc_ledger_display2_set_split_view_register(GNCLedgerDisplay2 * ledger_display,GncTreeViewSplitReg * view)832 gnc_ledger_display2_set_split_view_register (GNCLedgerDisplay2 *ledger_display, GncTreeViewSplitReg *view)
833 {
834     if (!ledger_display)
835         return;
836 
837     ledger_display->view = view;
838 }
839 
840 GncTreeViewSplitReg *
gnc_ledger_display2_get_split_view_register(GNCLedgerDisplay2 * ledger_display)841 gnc_ledger_display2_get_split_view_register (GNCLedgerDisplay2 *ledger_display)
842 {
843     if (!ledger_display)
844         return NULL;
845 
846     return ledger_display->view;
847 }
848 
849 void
gnc_ledger_display2_set_query(GNCLedgerDisplay2 * ledger_display,Query * q)850 gnc_ledger_display2_set_query (GNCLedgerDisplay2 *ledger_display, Query *q)
851 {
852     if (!ledger_display || !q)
853         return;
854 
855     g_return_if_fail (ledger_display->ld_type == LD2_GL);
856 
857     qof_query_destroy (ledger_display->query);
858     ledger_display->query = qof_query_copy (q);
859 }
860 
861 GNCLedgerDisplay2 *
gnc_ledger_display2_find_by_query(Query * q)862 gnc_ledger_display2_find_by_query (Query *q)
863 {
864     GNCLedgerDisplay2 *ledger_display;
865     GncTreeModelSplitReg *model;
866 
867     if (!q)
868         return NULL;
869 
870     ledger_display = gnc_find_first_gui_component (REGISTER_GL_CM_CLASS, find_by_query, q);
871 
872     if (ledger_display)
873     {
874         model = ledger_display->model;
875         // To get a new search page from a general journal, search register is a LD2_GL also.
876         if (model->type == GENERAL_JOURNAL2)
877             ledger_display = NULL;
878     }
879     return ledger_display;
880 }
881 
882 /********************************************************************\
883  * refresh only the indicated register window                       *
884 \********************************************************************/
885 
886 static void
gnc_ledger_display2_refresh_internal(GNCLedgerDisplay2 * ld,GList * splits)887 gnc_ledger_display2_refresh_internal (GNCLedgerDisplay2 *ld, GList *splits)
888 {
889     GtkTreeModel *s_model, *model;
890 
891     if (!ld || ld->loading)
892         return;
893 
894     if (!(ld->refresh_ok)) // We use this to test for the view available
895     {
896         ld->loading = TRUE;
897         gnc_tree_model_split_reg_load (ld->model, splits, gnc_ledger_display2_leader (ld));
898         ld->loading = FALSE;
899     }
900     else
901     {
902 	/* This is used for the reloading of registers to refresh them and to update the search_ledger */
903         ld->loading = TRUE;
904 
905 	s_model = gtk_tree_view_get_model (GTK_TREE_VIEW (ld->view)); // this is the sort model
906         model = gtk_tree_model_sort_get_model (GTK_TREE_MODEL_SORT (s_model)); // this is the model
907 
908         g_object_ref (s_model);
909         g_object_ref (model);
910 
911         gnc_tree_view_split_reg_block_selection (ld->view, TRUE); // This blocks the tree selection
912         gtk_tree_view_set_model (GTK_TREE_VIEW (ld->view), NULL); // Detach sort model from view
913         gnc_tree_model_split_reg_load (ld->model, splits, gnc_ledger_display2_leader (ld)); //reload splits
914         gtk_tree_view_set_model (GTK_TREE_VIEW (ld->view), GTK_TREE_MODEL (s_model)); // Re-attach sort model to view
915         gnc_tree_view_split_reg_block_selection (ld->view, FALSE); // This unblocks the tree selection
916 
917         g_object_unref (model);
918         g_object_unref (s_model);
919 
920         /* Set the default selection start position */
921         gnc_tree_view_split_reg_default_selection (ld->view);
922 
923         ld->loading = FALSE;
924     }
925 }
926 
927 void
gnc_ledger_display2_refilter(GNCLedgerDisplay2 * ld)928 gnc_ledger_display2_refilter (GNCLedgerDisplay2 *ld)
929 {
930     ENTER("ld=%p", ld);
931 
932     /* Set the default selection start position and refilter */
933     gnc_tree_view_split_reg_default_selection (ld->view);
934 
935     LEAVE(" ");
936 }
937 
938 void
gnc_ledger_display2_refresh_sched(GNCLedgerDisplay2 * ld,GList * splits)939 gnc_ledger_display2_refresh_sched (GNCLedgerDisplay2 *ld, GList *splits)
940 {
941     ENTER("ld=%p", ld);
942 
943     if (!ld)
944     {
945         LEAVE("no display");
946         return;
947     }
948 
949     if (ld->loading)
950     {
951         LEAVE("already loading");
952         return;
953     }
954     gnc_ledger_display2_refresh_internal (ld, splits);
955     LEAVE(" ");
956 }
957 
958 void
gnc_ledger_display2_refresh(GNCLedgerDisplay2 * ld)959 gnc_ledger_display2_refresh (GNCLedgerDisplay2 *ld)
960 {
961     ENTER("ld=%p", ld);
962 
963     if (!ld)
964     {
965         LEAVE("no display");
966         return;
967     }
968 
969     if (ld->loading)
970     {
971         LEAVE("already loading");
972         return;
973     }
974 
975     // Update the query before refresh
976     gnc_tree_model_split_reg_update_query (ld->model, ld->query);
977     gnc_ledger_display2_refresh_internal (ld, qof_query_run (ld->query));
978     LEAVE(" ");
979 }
980 
981 void
gnc_ledger_display2_refresh_by_split_register(GncTreeModelSplitReg * model)982 gnc_ledger_display2_refresh_by_split_register (GncTreeModelSplitReg *model)
983 {
984     GNCLedgerDisplay2 *ld;
985 
986     if (!model)
987         return;
988 
989     ld = gnc_find_first_gui_component (REGISTER_SINGLE_CM_CLASS,
990                                        find_by_reg, model);
991     if (ld)
992     {
993         gnc_ledger_display2_refresh (ld);
994         return;
995     }
996 
997     ld = gnc_find_first_gui_component (REGISTER_SUBACCOUNT_CM_CLASS,
998                                        find_by_reg, model);
999     if (ld)
1000     {
1001         gnc_ledger_display2_refresh (ld);
1002         return;
1003     }
1004 
1005     ld = gnc_find_first_gui_component (REGISTER_GL_CM_CLASS,
1006                                        find_by_reg, model);
1007     if (ld)
1008     {
1009         gnc_ledger_display2_refresh (ld);
1010         return;
1011     }
1012 
1013     ld = gnc_find_first_gui_component (REGISTER_TEMPLATE_CM_CLASS,
1014                                        find_by_reg, model);
1015     if (ld)
1016     {
1017         gnc_ledger_display2_refresh (ld);
1018     }
1019 }
1020 
1021 void
gnc_ledger_display2_set_split_view_refresh(GNCLedgerDisplay2 * ld,gboolean ok)1022 gnc_ledger_display2_set_split_view_refresh (GNCLedgerDisplay2 *ld, gboolean ok)
1023 {
1024     if (!ld)
1025         return;
1026 
1027     ld->refresh_ok = ok;
1028 }
1029 
1030 /* This is used to reload after any changes made */
1031 static void
gnc_ledger_display2_refresh_cb(GncTreeModelSplitReg * model,gpointer item,gpointer user_data)1032 gnc_ledger_display2_refresh_cb (GncTreeModelSplitReg *model, gpointer item, gpointer user_data)
1033 {
1034     GNCLedgerDisplay2 *ld = user_data;
1035 
1036     /* Refresh the view when idle */
1037     g_idle_add ((GSourceFunc)gnc_ledger_display2_refresh, ld);
1038 }
1039 
1040 void
gnc_ledger_display2_close(GNCLedgerDisplay2 * ld)1041 gnc_ledger_display2_close (GNCLedgerDisplay2 *ld)
1042 {
1043     if (!ld)
1044         return;
1045 
1046     gnc_close_gui_component (ld->component_id);
1047 }
1048