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  *                                                                  *
8  * This program is free software; you can redistribute it and/or    *
9  * modify it under the terms of the GNU General Public License as   *
10  * published by the Free Software Foundation; either version 2 of   *
11  * the License, or (at your option) any later version.              *
12  *                                                                  *
13  * This program is distributed in the hope that it will be useful,  *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
16  * GNU General Public License for more details.                     *
17  *                                                                  *
18  * You should have received a copy of the GNU General Public License*
19  * along with this program; if not, write to the Free Software      *
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.        *
21  *                                                                  *
22 \********************************************************************/
23 
24 #include <config.h>
25 
26 #include <time.h>
27 
28 #include "Account.h"
29 #include "Query.h"
30 #include "qof.h"
31 #include "SX-book.h"
32 #include "Transaction.h"
33 #include "gnc-component-manager.h"
34 #include "gnc-date.h"
35 #include "gnc-engine.h"
36 #include "gnc-event.h"
37 #include "gnc-ledger-display.h"
38 #include "gnc-prefs.h"
39 #include "gnc-ui-util.h"
40 #include <gnc-glib-utils.h>
41 #include "split-register-control.h"
42 #include "split-register-model.h"
43 
44 
45 #define REGISTER_SINGLE_CM_CLASS     "register-single"
46 #define REGISTER_SUBACCOUNT_CM_CLASS "register-subaccount"
47 #define REGISTER_GL_CM_CLASS         "register-gl"
48 #define REGISTER_TEMPLATE_CM_CLASS   "register-template"
49 
50 #define GNC_PREF_DOUBLE_LINE_MODE         "double-line-mode"
51 #define GNC_PREF_MAX_TRANS                "max-transactions"
52 #define GNC_PREF_DEFAULT_STYLE_LEDGER     "default-style-ledger"
53 #define GNC_PREF_DEFAULT_STYLE_AUTOLEDGER "default-style-autoledger"
54 #define GNC_PREF_DEFAULT_STYLE_JOURNAL    "default-style-journal"
55 
56 
57 struct gnc_ledger_display
58 {
59     GncGUID leader;
60 
61     Query* query;
62 
63     GNCLedgerDisplayType ld_type;
64 
65     SplitRegister* reg;
66 
67     gboolean loading;
68     gboolean use_double_line_default;
69 
70     GNCLedgerDisplayDestroy destroy;
71     GNCLedgerDisplayGetParent get_parent;
72 
73     gpointer user_data;
74 
75     gint number_of_subaccounts;
76 
77     gint component_id;
78 };
79 
80 
81 /** GLOBALS *********************************************************/
82 static QofLogModule log_module = GNC_MOD_LEDGER;
83 
84 
85 /** Declarations ****************************************************/
86 static GNCLedgerDisplay*
87 gnc_ledger_display_internal (Account* lead_account, Query* q,
88                              GNCLedgerDisplayType ld_type,
89                              SplitRegisterType reg_type,
90                              SplitRegisterStyle style,
91                              gboolean use_double_line,
92                              gboolean is_template,
93                              gboolean mismatched_commodities);
94 
95 static void gnc_ledger_display_refresh_internal (GNCLedgerDisplay* ld,
96                                                  GList* splits);
97 
98 static void gnc_ledger_display_make_query (GNCLedgerDisplay* ld,
99                                            gint limit,
100                                            SplitRegisterType type);
101 
102 /** Implementations *************************************************/
103 
104 Account*
gnc_ledger_display_leader(GNCLedgerDisplay * ld)105 gnc_ledger_display_leader (GNCLedgerDisplay* ld)
106 {
107     if (!ld)
108         return NULL;
109 
110     return xaccAccountLookup (&ld->leader, gnc_get_current_book());
111 }
112 
113 GNCLedgerDisplayType
gnc_ledger_display_type(GNCLedgerDisplay * ld)114 gnc_ledger_display_type (GNCLedgerDisplay* ld)
115 {
116     if (!ld)
117         return -1;
118 
119     return ld->ld_type;
120 }
121 
122 void
gnc_ledger_display_set_user_data(GNCLedgerDisplay * ld,gpointer user_data)123 gnc_ledger_display_set_user_data (GNCLedgerDisplay* ld, gpointer user_data)
124 {
125     if (!ld)
126         return;
127 
128     ld->user_data = user_data;
129 }
130 
131 gpointer
gnc_ledger_display_get_user_data(GNCLedgerDisplay * ld)132 gnc_ledger_display_get_user_data (GNCLedgerDisplay* ld)
133 {
134     if (!ld)
135         return NULL;
136 
137     return ld->user_data;
138 }
139 
140 void
gnc_ledger_display_set_handlers(GNCLedgerDisplay * ld,GNCLedgerDisplayDestroy destroy,GNCLedgerDisplayGetParent get_parent)141 gnc_ledger_display_set_handlers (GNCLedgerDisplay* ld,
142                                  GNCLedgerDisplayDestroy destroy,
143                                  GNCLedgerDisplayGetParent get_parent)
144 {
145     if (!ld)
146         return;
147 
148     ld->destroy = destroy;
149     ld->get_parent = get_parent;
150 }
151 
152 SplitRegister*
gnc_ledger_display_get_split_register(GNCLedgerDisplay * ld)153 gnc_ledger_display_get_split_register (GNCLedgerDisplay* ld)
154 {
155     if (!ld)
156         return NULL;
157 
158     return ld->reg;
159 }
160 
161 Query*
gnc_ledger_display_get_query(GNCLedgerDisplay * ld)162 gnc_ledger_display_get_query (GNCLedgerDisplay* ld)
163 {
164     if (!ld)
165         return NULL;
166 
167     return ld->query;
168 }
169 
170 static gboolean
find_by_leader(gpointer find_data,gpointer user_data)171 find_by_leader (gpointer find_data, gpointer user_data)
172 {
173     Account* account = find_data;
174     GNCLedgerDisplay* ld = user_data;
175 
176     if (!account || !ld)
177         return FALSE;
178 
179     return (account == gnc_ledger_display_leader (ld));
180 }
181 
182 static gboolean
find_by_query(gpointer find_data,gpointer user_data)183 find_by_query (gpointer find_data, gpointer user_data)
184 {
185     Query* q = find_data;
186     GNCLedgerDisplay* ld = user_data;
187 
188     if (ld->reg->type != SEARCH_LEDGER)
189         return FALSE;
190 
191     if (!q || !ld)
192         return FALSE;
193 
194     return ld->query == q;
195 }
196 
197 static gboolean
find_by_reg(gpointer find_data,gpointer user_data)198 find_by_reg (gpointer find_data, gpointer user_data)
199 {
200     SplitRegister* reg = find_data;
201     GNCLedgerDisplay* ld = user_data;
202 
203     if (!reg || !ld)
204         return FALSE;
205 
206     return ld->reg == reg;
207 }
208 
209 static SplitRegisterStyle
gnc_get_default_register_style(GNCAccountType type)210 gnc_get_default_register_style (GNCAccountType type)
211 {
212     SplitRegisterStyle new_style = REG_STYLE_LEDGER;
213 
214     if (gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER,
215                             GNC_PREF_DEFAULT_STYLE_JOURNAL))
216         new_style = REG_STYLE_JOURNAL;
217     else if (gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER,
218                                  GNC_PREF_DEFAULT_STYLE_AUTOLEDGER))
219         new_style = REG_STYLE_AUTO_LEDGER;
220 
221     return new_style;
222 }
223 
224 static gpointer
look_for_portfolio_cb(Account * account,gpointer data)225 look_for_portfolio_cb (Account* account, gpointer data)
226 {
227     return xaccAccountIsPriced (account) ? (gpointer) PORTFOLIO_LEDGER : NULL;
228 }
229 
230 static SplitRegisterType
gnc_get_reg_type(Account * leader,GNCLedgerDisplayType ld_type)231 gnc_get_reg_type (Account* leader, GNCLedgerDisplayType ld_type)
232 {
233     GNCAccountType account_type;
234     SplitRegisterType reg_type;
235 
236     if (ld_type == LD_GL)
237         return GENERAL_JOURNAL;
238 
239     account_type = xaccAccountGetType (leader);
240 
241     if (ld_type == LD_SINGLE)
242     {
243         switch (account_type)
244         {
245         case ACCT_TYPE_BANK:
246             return BANK_REGISTER;
247 
248         case ACCT_TYPE_CASH:
249             return CASH_REGISTER;
250 
251         case ACCT_TYPE_ASSET:
252             return ASSET_REGISTER;
253 
254         case ACCT_TYPE_CREDIT:
255             return CREDIT_REGISTER;
256 
257         case ACCT_TYPE_LIABILITY:
258             return LIABILITY_REGISTER;
259 
260         case ACCT_TYPE_PAYABLE:
261             return PAYABLE_REGISTER;
262 
263         case ACCT_TYPE_RECEIVABLE:
264             return RECEIVABLE_REGISTER;
265 
266         case ACCT_TYPE_STOCK:
267         case ACCT_TYPE_MUTUAL:
268             return STOCK_REGISTER;
269 
270         case ACCT_TYPE_INCOME:
271             return INCOME_REGISTER;
272 
273         case ACCT_TYPE_EXPENSE:
274             return EXPENSE_REGISTER;
275 
276         case ACCT_TYPE_EQUITY:
277             return EQUITY_REGISTER;
278 
279         case ACCT_TYPE_CURRENCY:
280             return CURRENCY_REGISTER;
281 
282         case ACCT_TYPE_TRADING:
283             return TRADING_REGISTER;
284 
285         default:
286             PERR ("unknown account type %d\n", account_type);
287             return BANK_REGISTER;
288         }
289     }
290 
291     if (ld_type != LD_SUBACCOUNT)
292     {
293         PERR ("unknown ledger type %d\n", ld_type);
294         return BANK_REGISTER;
295     }
296 
297     switch (account_type)
298     {
299     case ACCT_TYPE_BANK:
300     case ACCT_TYPE_CASH:
301     case ACCT_TYPE_ASSET:
302     case ACCT_TYPE_CREDIT:
303     case ACCT_TYPE_LIABILITY:
304     case ACCT_TYPE_RECEIVABLE:
305     case ACCT_TYPE_PAYABLE:
306     {
307         /* If any of the sub-accounts have ACCT_TYPE_STOCK or
308          * ACCT_TYPE_MUTUAL types, then we must use the PORTFOLIO_LEDGER
309          * ledger. Otherwise, a plain old GENERAL_JOURNAL will do. */
310         gpointer ret;
311         reg_type = GENERAL_JOURNAL;
312 
313         ret = gnc_account_foreach_descendant_until (leader, look_for_portfolio_cb,
314                                                     NULL);
315         if (ret) reg_type = PORTFOLIO_LEDGER;
316         break;
317     }
318 
319     case ACCT_TYPE_STOCK:
320     case ACCT_TYPE_MUTUAL:
321     case ACCT_TYPE_CURRENCY:
322         reg_type = PORTFOLIO_LEDGER;
323         break;
324 
325     case ACCT_TYPE_INCOME:
326     case ACCT_TYPE_EXPENSE:
327         reg_type = INCOME_LEDGER;
328         break;
329 
330     case ACCT_TYPE_EQUITY:
331     case ACCT_TYPE_TRADING:
332         reg_type = GENERAL_JOURNAL;
333         break;
334 
335     default:
336         PERR ("unknown account type:%d", account_type);
337         reg_type = GENERAL_JOURNAL;
338         break;
339     }
340 
341     return reg_type;
342 }
343 
344 /* Returns a boolean of whether this display should be single or double lined
345  * mode by default */
346 gboolean
gnc_ledger_display_default_double_line(GNCLedgerDisplay * gld)347 gnc_ledger_display_default_double_line (GNCLedgerDisplay* gld)
348 {
349     return (gld->use_double_line_default ||
350             gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER,
351                                 GNC_PREF_DOUBLE_LINE_MODE));
352 }
353 
354 /* Opens up a register window to display a single account */
355 GNCLedgerDisplay*
gnc_ledger_display_simple(Account * account)356 gnc_ledger_display_simple (Account* account)
357 {
358     SplitRegisterType reg_type;
359     GNCAccountType acc_type = xaccAccountGetType (account);
360     gboolean use_double_line;
361     GNCLedgerDisplay* ld;
362 
363     ENTER ("account=%p", account);
364 
365     switch (acc_type)
366     {
367     case ACCT_TYPE_PAYABLE:
368     case ACCT_TYPE_RECEIVABLE:
369         use_double_line = TRUE;
370         break;
371     default:
372         use_double_line = FALSE;
373         break;
374     }
375 
376     reg_type = gnc_get_reg_type (account, LD_SINGLE);
377 
378     ld = gnc_ledger_display_internal (account, NULL, LD_SINGLE, reg_type,
379                                       gnc_get_default_register_style (acc_type),
380                                       use_double_line, FALSE, FALSE);
381     LEAVE ("%p", ld);
382     return ld;
383 }
384 
385 /* Opens up a register window to display an account, and all of its
386  *   children, in the same window */
387 GNCLedgerDisplay*
gnc_ledger_display_subaccounts(Account * account,gboolean mismatched_commodities)388 gnc_ledger_display_subaccounts (Account* account,
389                                 gboolean mismatched_commodities)
390 {
391     SplitRegisterType reg_type;
392     GNCLedgerDisplay* ld;
393 
394     ENTER ("account=%p", account);
395 
396     reg_type = gnc_get_reg_type (account, LD_SUBACCOUNT);
397 
398     ld = gnc_ledger_display_internal (account, NULL, LD_SUBACCOUNT,
399                                       reg_type, REG_STYLE_JOURNAL, FALSE,
400                                       FALSE, mismatched_commodities);
401     LEAVE ("%p", ld);
402     return ld;
403 }
404 
405 /* Opens up a general journal window. */
406 GNCLedgerDisplay*
gnc_ledger_display_gl(void)407 gnc_ledger_display_gl (void)
408 {
409     Query* query;
410     time64 start;
411     struct tm tm;
412     GNCLedgerDisplay* ld;
413 
414     ENTER (" ");
415 
416     query = qof_query_create_for (GNC_ID_SPLIT);
417 
418     qof_query_set_book (query, gnc_get_current_book());
419 
420     /* In lieu of not "mis-using" some portion of the infrastructure by writing
421      * a bunch of new code, we just filter out the accounts of the template
422      * transactions.  While these are in a separate Account trees just for this
423      * reason, the query engine makes no distinction between Account trees.
424      * See Gnome Bug 86302.
425      *         -- jsled */
426     {
427         Account* tRoot;
428         GList* al;
429 
430         tRoot = gnc_book_get_template_root (gnc_get_current_book());
431         al = gnc_account_get_descendants (tRoot);
432 
433         if (gnc_list_length_cmp (al, 0))
434             xaccQueryAddAccountMatch (query, al, QOF_GUID_MATCH_NONE, QOF_QUERY_AND);
435 
436         g_list_free (al);
437         al = NULL;
438         tRoot = NULL;
439     }
440 
441     gnc_tm_get_today_start (&tm);
442     tm.tm_mon--; /* Default the register to the last month's worth of transactions. */
443     start = gnc_mktime (&tm);
444     xaccQueryAddDateMatchTT (query,
445                              TRUE, start,
446                              FALSE, 0,
447                              QOF_QUERY_AND);
448 
449     ld = gnc_ledger_display_internal (NULL, query, LD_GL, GENERAL_JOURNAL,
450                                       REG_STYLE_JOURNAL, FALSE, FALSE, FALSE);
451     LEAVE ("%p", ld);
452 
453     qof_query_destroy (query);
454     return ld;
455 }
456 
457 /**
458  * @param id: The string version of the GncGUID of the context of template
459  * transaction being edited in this template GL.  As used by scheduled
460  * transactions, this is the GncGUID of the SX itself which is magically the
461  * *name* of the (template) account which contains the transactions for this
462  * scheduled transaction.  That's right.  The stringified GncGUID of the SX is
463  * the name of the SX'es template account.
464  **/
465 GNCLedgerDisplay*
gnc_ledger_display_template_gl(char * id)466 gnc_ledger_display_template_gl (char* id)
467 {
468     QofBook* book;
469     Query* q;
470     GNCLedgerDisplay* ld;
471     SplitRegister* sr;
472     Account* root, *acct;
473     gboolean isTemplateModeTrue;
474 
475     ENTER ("id=%s", id ? id : "(null)");
476 
477     acct = NULL;
478     isTemplateModeTrue = TRUE;
479 
480     q = qof_query_create_for (GNC_ID_SPLIT);
481 
482     book = gnc_get_current_book();
483     qof_query_set_book (q, book);
484 
485     if (id != NULL)
486     {
487         root = gnc_book_get_template_root (book);
488         acct = gnc_account_lookup_by_name (root, id);
489         g_assert (acct);
490         xaccQueryAddSingleAccountMatch (q, acct, QOF_QUERY_AND);
491     }
492 
493     ld = gnc_ledger_display_internal (NULL, q, LD_GL,
494                                       SEARCH_LEDGER,
495                                       REG_STYLE_JOURNAL,
496                                       FALSE,
497                                       isTemplateModeTrue,
498                                       FALSE);
499 
500     sr = gnc_ledger_display_get_split_register (ld);
501     if (acct)
502     {
503         gnc_split_register_set_template_account (sr, acct);
504     }
505 
506     LEAVE ("%p", ld);
507     return ld;
508 }
509 
510 GtkWidget*
gnc_ledger_display_get_parent(GNCLedgerDisplay * ld)511 gnc_ledger_display_get_parent (GNCLedgerDisplay* ld)
512 {
513     if (ld == NULL)
514         return NULL;
515 
516     if (ld->get_parent == NULL)
517         return NULL;
518 
519     return ld->get_parent (ld);
520 }
521 
522 static GtkWidget*
gnc_ledger_display_parent(void * user_data)523 gnc_ledger_display_parent (void* user_data)
524 {
525     GNCLedgerDisplay* ld = user_data;
526     return gnc_ledger_display_get_parent (ld);
527 }
528 
529 static void
gnc_ledger_display_set_watches(GNCLedgerDisplay * ld,GList * splits)530 gnc_ledger_display_set_watches (GNCLedgerDisplay* ld, GList* splits)
531 {
532     GList* node;
533 
534     gnc_gui_component_clear_watches (ld->component_id);
535 
536     gnc_gui_component_watch_entity_type (ld->component_id,
537                                          GNC_ID_ACCOUNT,
538                                          QOF_EVENT_MODIFY | QOF_EVENT_DESTROY
539                                          | GNC_EVENT_ITEM_CHANGED);
540 
541     for (node = splits; node; node = node->next)
542     {
543         Split* split = node->data;
544         Transaction* trans = xaccSplitGetParent (split);
545 
546         gnc_gui_component_watch_entity (ld->component_id,
547                                         xaccTransGetGUID (trans),
548                                         QOF_EVENT_MODIFY);
549     }
550 }
551 
552 static void
refresh_handler(GHashTable * changes,gpointer user_data)553 refresh_handler (GHashTable* changes, gpointer user_data)
554 {
555     GNCLedgerDisplay* ld = user_data;
556     const EventInfo* info;
557     gboolean has_leader;
558     GList* splits;
559 
560     ENTER ("changes=%p, user_data=%p", changes, user_data);
561 
562     if (ld->loading)
563     {
564         LEAVE ("already loading");
565         return;
566     }
567 
568     has_leader = (ld->ld_type == LD_SINGLE || ld->ld_type == LD_SUBACCOUNT);
569 
570     if (has_leader)
571     {
572         Account* leader = gnc_ledger_display_leader (ld);
573         if (!leader)
574         {
575             gnc_close_gui_component (ld->component_id);
576             LEAVE ("no leader");
577             return;
578         }
579     }
580 
581     if (changes && has_leader)
582     {
583         info = gnc_gui_get_entity_events (changes, &ld->leader);
584         if (info && (info->event_mask & QOF_EVENT_DESTROY))
585         {
586             gnc_close_gui_component (ld->component_id);
587             LEAVE ("destroy");
588             return;
589         }
590     }
591 
592     /* if subaccount ledger, check to see if still the same number
593      *  of subaccounts, if not recreate the query. */
594     if (ld->ld_type == LD_SUBACCOUNT)
595     {
596         Account* leader = gnc_ledger_display_leader (ld);
597         GList* accounts = gnc_account_get_descendants (leader);
598 
599         if (g_list_length (accounts) != ld->number_of_subaccounts)
600             gnc_ledger_display_make_query (ld,
601                                            gnc_prefs_get_float (GNC_PREFS_GROUP_GENERAL_REGISTER, GNC_PREF_MAX_TRANS),
602                                            gnc_get_reg_type (leader, ld->ld_type));
603 
604         g_list_free (accounts);
605     }
606 
607     /* Its not clear if we should re-run the query, or if we should
608      * just use qof_query_last_run().  Its possible that the dates
609      * changed, requiring a full new query.  Similar considerations
610      * needed for multi-user mode.
611      */
612     splits = qof_query_run (ld->query);
613 
614     gnc_ledger_display_set_watches (ld, splits);
615 
616     gnc_ledger_display_refresh_internal (ld, splits);
617     LEAVE (" ");
618 }
619 
620 static void
close_handler(gpointer user_data)621 close_handler (gpointer user_data)
622 {
623     GNCLedgerDisplay* ld = user_data;
624 
625     if (!ld)
626         return;
627 
628     gnc_unregister_gui_component (ld->component_id);
629     ld->component_id = NO_COMPONENT;
630 
631     if (ld->destroy)
632         ld->destroy (ld);
633 
634     gnc_split_register_destroy (ld->reg);
635     ld->reg = NULL;
636 
637     qof_query_destroy (ld->query);
638     ld->query = NULL;
639 
640     g_free (ld);
641 }
642 
643 static void
gnc_ledger_display_make_query(GNCLedgerDisplay * ld,gint limit,SplitRegisterType type)644 gnc_ledger_display_make_query (GNCLedgerDisplay* ld,
645                                gint limit,
646                                SplitRegisterType type)
647 {
648     Account* leader;
649     GList* accounts;
650 
651     if (!ld)
652         return;
653 
654     switch (ld->ld_type)
655     {
656     case LD_SINGLE:
657     case LD_SUBACCOUNT:
658         break;
659 
660     case LD_GL:
661         return;
662 
663     default:
664         PERR ("unknown ledger type: %d", ld->ld_type);
665         return;
666     }
667 
668     qof_query_destroy (ld->query);
669     ld->query = qof_query_create_for (GNC_ID_SPLIT);
670 
671     /* This is a bit of a hack. The number of splits should be
672      * configurable, or maybe we should go back a time range instead
673      * of picking a number, or maybe we should be able to exclude
674      * based on reconciled status. Anyway, this works for now. */
675     if ((limit != 0) && (type != SEARCH_LEDGER))
676         qof_query_set_max_results (ld->query, limit);
677 
678     qof_query_set_book (ld->query, gnc_get_current_book());
679 
680     leader = gnc_ledger_display_leader (ld);
681 
682     /* if this is a subaccount ledger, record the number of
683      * subaccounts so we can determine if the query needs
684      * recreating on a refresh. */
685     if (ld->ld_type == LD_SUBACCOUNT)
686     {
687         accounts = gnc_account_get_descendants (leader);
688         ld->number_of_subaccounts = g_list_length (accounts);
689     }
690     else
691         accounts = NULL;
692 
693     accounts = g_list_prepend (accounts, leader);
694 
695     xaccQueryAddAccountMatch (ld->query, accounts,
696                               QOF_GUID_MATCH_ANY, QOF_QUERY_AND);
697 
698     g_list_free (accounts);
699 }
700 
701 /* Opens up a ledger window for an arbitrary query. */
702 GNCLedgerDisplay*
gnc_ledger_display_query(Query * query,SplitRegisterType type,SplitRegisterStyle style)703 gnc_ledger_display_query (Query* query, SplitRegisterType type,
704                           SplitRegisterStyle style)
705 {
706     GNCLedgerDisplay* ld;
707 
708     ENTER ("query=%p", query);
709 
710     ld = gnc_ledger_display_internal (NULL, query, LD_GL, type, style,
711                                       FALSE, FALSE, FALSE);
712     LEAVE ("%p", ld);
713     return ld;
714 }
715 
716 static GNCLedgerDisplay*
gnc_ledger_display_internal(Account * lead_account,Query * q,GNCLedgerDisplayType ld_type,SplitRegisterType reg_type,SplitRegisterStyle style,gboolean use_double_line,gboolean is_template,gboolean mismatched_commodities)717 gnc_ledger_display_internal (Account* lead_account, Query* q,
718                              GNCLedgerDisplayType ld_type,
719                              SplitRegisterType reg_type,
720                              SplitRegisterStyle style,
721                              gboolean use_double_line,
722                              gboolean is_template,
723                              gboolean mismatched_commodities)
724 {
725     GNCLedgerDisplay* ld;
726     gint limit;
727     const char* klass;
728     GList* splits;
729 
730     switch (ld_type)
731     {
732     case LD_SINGLE:
733         klass = REGISTER_SINGLE_CM_CLASS;
734 
735         if (reg_type >= NUM_SINGLE_REGISTER_TYPES)
736         {
737             PERR ("single-account register with wrong split register type");
738             return NULL;
739         }
740 
741         if (!lead_account)
742         {
743             PERR ("single-account register with no account specified");
744             return NULL;
745         }
746 
747         if (q)
748         {
749             PWARN ("single-account register with external query");
750             q = NULL;
751         }
752 
753         ld = gnc_find_first_gui_component (klass, find_by_leader, lead_account);
754         if (ld)
755             return ld;
756 
757         break;
758 
759     case LD_SUBACCOUNT:
760         klass = REGISTER_SUBACCOUNT_CM_CLASS;
761 
762         if (!lead_account)
763         {
764             PERR ("sub-account register with no lead account");
765             return NULL;
766         }
767 
768         if (q)
769         {
770             PWARN ("account register with external query");
771             q = NULL;
772         }
773 
774         ld = gnc_find_first_gui_component (klass, find_by_leader, lead_account);
775         if (ld)
776             return ld;
777 
778         break;
779 
780     case LD_GL:
781         klass = REGISTER_GL_CM_CLASS;
782 
783         if (!q)
784         {
785             PWARN ("general journal with no query");
786         }
787 
788         break;
789 
790     default:
791         PERR ("bad ledger type: %d", ld_type);
792         return NULL;
793 
794     }
795 
796     ld = g_new (GNCLedgerDisplay, 1);
797 
798     ld->leader = *xaccAccountGetGUID (lead_account);
799     ld->query = NULL;
800     ld->ld_type = ld_type;
801     ld->loading = FALSE;
802     ld->destroy = NULL;
803     ld->get_parent = NULL;
804     ld->user_data = NULL;
805 
806     limit = gnc_prefs_get_float (GNC_PREFS_GROUP_GENERAL_REGISTER,
807                                  GNC_PREF_MAX_TRANS);
808 
809     /* set up the query filter */
810     if (q)
811         ld->query = qof_query_copy (q);
812     else
813         gnc_ledger_display_make_query (ld, limit, reg_type);
814 
815     ld->component_id = gnc_register_gui_component (klass,
816                                                    refresh_handler,
817                                                    close_handler, ld);
818 
819     /******************************************************************\
820      * The main register window itself                                *
821     \******************************************************************/
822 
823     ld->use_double_line_default = use_double_line;
824 
825     ld->reg = gnc_split_register_new (reg_type, style, use_double_line,
826                                       is_template, mismatched_commodities);
827 
828     gnc_split_register_set_data (ld->reg, ld, gnc_ledger_display_parent);
829 
830     splits = qof_query_run (ld->query);
831 
832     gnc_ledger_display_set_watches (ld, splits);
833 
834     gnc_ledger_display_refresh_internal (ld, splits);
835 
836     return ld;
837 }
838 
839 void
gnc_ledger_display_set_query(GNCLedgerDisplay * ledger_display,Query * q)840 gnc_ledger_display_set_query (GNCLedgerDisplay* ledger_display, Query* q)
841 {
842     if (!ledger_display || !q)
843         return;
844 
845     g_return_if_fail (ledger_display->ld_type == LD_GL);
846 
847     qof_query_destroy (ledger_display->query);
848     ledger_display->query = qof_query_copy (q);
849 }
850 
851 GNCLedgerDisplay*
gnc_ledger_display_find_by_query(Query * q)852 gnc_ledger_display_find_by_query (Query* q)
853 {
854     if (!q)
855         return NULL;
856 
857     return gnc_find_first_gui_component (REGISTER_GL_CM_CLASS, find_by_query, q);
858 }
859 
860 /********************************************************************\
861  * refresh only the indicated register window                       *
862 \********************************************************************/
863 
864 static void
gnc_ledger_display_refresh_internal(GNCLedgerDisplay * ld,GList * splits)865 gnc_ledger_display_refresh_internal (GNCLedgerDisplay* ld, GList* splits)
866 {
867     if (!ld || ld->loading)
868         return;
869 
870     if (!gnc_split_register_full_refresh_ok (ld->reg))
871         return;
872 
873     ld->loading = TRUE;
874 
875     gnc_split_register_load (ld->reg, splits,
876                              gnc_ledger_display_leader (ld));
877 
878     ld->loading = FALSE;
879 }
880 
881 void
gnc_ledger_display_refresh(GNCLedgerDisplay * ld)882 gnc_ledger_display_refresh (GNCLedgerDisplay* ld)
883 {
884     ENTER ("ld=%p", ld);
885 
886     if (!ld)
887     {
888         LEAVE ("no display");
889         return;
890     }
891 
892     if (ld->loading)
893     {
894         LEAVE ("already loading");
895         return;
896     }
897 
898     gnc_ledger_display_refresh_internal (ld, qof_query_run (ld->query));
899     LEAVE (" ");
900 }
901 
902 void
gnc_ledger_display_refresh_by_split_register(SplitRegister * reg)903 gnc_ledger_display_refresh_by_split_register (SplitRegister* reg)
904 {
905     GNCLedgerDisplay* ld;
906 
907     if (!reg)
908         return;
909 
910     ld = gnc_find_first_gui_component (REGISTER_SINGLE_CM_CLASS,
911                                        find_by_reg, reg);
912     if (ld)
913     {
914         gnc_ledger_display_refresh (ld);
915         return;
916     }
917 
918     ld = gnc_find_first_gui_component (REGISTER_SUBACCOUNT_CM_CLASS,
919                                        find_by_reg, reg);
920     if (ld)
921     {
922         gnc_ledger_display_refresh (ld);
923         return;
924     }
925 
926     ld = gnc_find_first_gui_component (REGISTER_GL_CM_CLASS,
927                                        find_by_reg, reg);
928     if (ld)
929     {
930         gnc_ledger_display_refresh (ld);
931         return;
932     }
933 
934     ld = gnc_find_first_gui_component (REGISTER_TEMPLATE_CM_CLASS,
935                                        find_by_reg, reg);
936     if (ld)
937     {
938         gnc_ledger_display_refresh (ld);
939     }
940 }
941 
942 void
gnc_ledger_display_close(GNCLedgerDisplay * ld)943 gnc_ledger_display_close (GNCLedgerDisplay* ld)
944 {
945     if (!ld)
946         return;
947 
948     gnc_close_gui_component (ld->component_id);
949 }
950