GnuCash c935c2f+
Loading...
Searching...
No Matches
gnc-ledger-display.c
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>
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
58{
59 GncGUID leader;
60
61 Query* query;
62 Query* pre_filter_query;
63
64 GNCLedgerDisplayType ld_type;
65
66 SplitRegister* reg;
67
68 gboolean loading;
69 gboolean use_double_line_default;
70 gboolean visible; /* focus */
71 gboolean needs_refresh;
72
73 GNCLedgerDisplayDestroy destroy;
74 GNCLedgerDisplayGetParent get_parent;
75
76 GHashTable *excluded_template_acc_hash;
77
78 gpointer user_data;
79
80 gint number_of_subaccounts;
81
82 gint component_id;
83};
84
85
87static QofLogModule log_module = GNC_MOD_LEDGER;
88
89
91static GNCLedgerDisplay*
92gnc_ledger_display_internal (Account* lead_account, Query* q,
93 GNCLedgerDisplayType ld_type,
94 SplitRegisterType reg_type,
96 gboolean use_double_line,
97 gboolean is_template,
98 gboolean mismatched_commodities);
99
100static void
101gnc_ledger_display_refresh_internal (GNCLedgerDisplay* ld);
102
103static void gnc_ledger_display_make_query (GNCLedgerDisplay* ld,
104 gint limit,
105 SplitRegisterType type);
106
109Account*
110gnc_ledger_display_leader (GNCLedgerDisplay* ld)
111{
112 if (!ld)
113 return NULL;
114
115 return xaccAccountLookup (&ld->leader, gnc_get_current_book());
116}
117
118GNCLedgerDisplayType
119gnc_ledger_display_type (GNCLedgerDisplay* ld)
120{
121 if (!ld)
122 return -1;
123
124 return ld->ld_type;
125}
126
127void
128gnc_ledger_display_set_user_data (GNCLedgerDisplay* ld, gpointer user_data)
129{
130 if (!ld)
131 return;
132
133 ld->user_data = user_data;
134}
135
136gpointer
137gnc_ledger_display_get_user_data (GNCLedgerDisplay* ld)
138{
139 if (!ld)
140 return NULL;
141
142 return ld->user_data;
143}
144
145void
147 GNCLedgerDisplayDestroy destroy,
148 GNCLedgerDisplayGetParent get_parent)
149{
150 if (!ld)
151 return;
152
153 ld->destroy = destroy;
154 ld->get_parent = get_parent;
155}
156
157SplitRegister*
159{
160 if (!ld)
161 return NULL;
162
163 return ld->reg;
164}
165
166Query*
167gnc_ledger_display_get_query (GNCLedgerDisplay* ld)
168{
169 if (!ld)
170 return NULL;
171
172 return ld->query;
173}
174
175static void
176exclude_template_accounts (Query* q, GHashTable *excluded_template_acc_hash)
177{
178 Account* tRoot;
179 GList* al;
180
181 tRoot = gnc_book_get_template_root (gnc_get_current_book());
182 al = gnc_account_get_descendants (tRoot);
183
184 if (gnc_list_length_cmp (al, 0) && excluded_template_acc_hash)
185 {
186 GList *node, *next;
187
188 for (node = al; node; node = next)
189 {
190 Account *acc = node->data;
191 next = g_list_next (node);
192
193 if (g_hash_table_lookup (excluded_template_acc_hash, acc) != NULL)
194 al = g_list_delete_link (al, node);
195 else
196 g_hash_table_insert (excluded_template_acc_hash, acc, acc);
197 }
198 }
199 if (gnc_list_length_cmp (al, 0))
200 xaccQueryAddAccountMatch (q, al, QOF_GUID_MATCH_NONE, QOF_QUERY_AND);
201
202 g_list_free (al);
203 al = NULL;
204 tRoot = NULL;
205}
206
207static gboolean
208find_by_leader (gpointer find_data, gpointer user_data)
209{
210 Account* account = find_data;
211 GNCLedgerDisplay* ld = user_data;
212
213 if (!account || !ld)
214 return FALSE;
215
216 return (account == gnc_ledger_display_leader (ld));
217}
218
219static gboolean
220find_by_query (gpointer find_data, gpointer user_data)
221{
222 Query* q = find_data;
223 GNCLedgerDisplay* ld = user_data;
224
225 if (ld->reg->type != SEARCH_LEDGER)
226 return FALSE;
227
228 if (!q || !ld)
229 return FALSE;
230
231 return ld->query == q;
232}
233
234static gboolean
235find_by_reg (gpointer find_data, gpointer user_data)
236{
237 SplitRegister* reg = find_data;
238 GNCLedgerDisplay* ld = user_data;
239
240 if (!reg || !ld)
241 return FALSE;
242
243 return ld->reg == reg;
244}
245
247gnc_get_default_register_style (GNCAccountType type)
248{
249 SplitRegisterStyle new_style = REG_STYLE_LEDGER;
250
251 if (gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER,
252 GNC_PREF_DEFAULT_STYLE_JOURNAL))
253 new_style = REG_STYLE_JOURNAL;
254 else if (gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER,
255 GNC_PREF_DEFAULT_STYLE_AUTOLEDGER))
256 new_style = REG_STYLE_AUTO_LEDGER;
257
258 return new_style;
259}
260
261static gpointer
262look_for_portfolio_cb (Account* account, gpointer data)
263{
264 return xaccAccountIsPriced (account) ? (gpointer) PORTFOLIO_LEDGER : NULL;
265}
266
268gnc_get_reg_type (Account* leader, GNCLedgerDisplayType ld_type)
269{
270 GNCAccountType account_type;
271 SplitRegisterType reg_type;
272
273 if (ld_type == LD_GL)
274 return GENERAL_JOURNAL;
275
276 account_type = xaccAccountGetType (leader);
277
278 if (ld_type == LD_SINGLE)
279 {
280 switch (account_type)
281 {
282 case ACCT_TYPE_BANK:
283 return BANK_REGISTER;
284
285 case ACCT_TYPE_CASH:
286 return CASH_REGISTER;
287
288 case ACCT_TYPE_ASSET:
289 return ASSET_REGISTER;
290
291 case ACCT_TYPE_CREDIT:
292 return CREDIT_REGISTER;
293
295 return LIABILITY_REGISTER;
296
298 return PAYABLE_REGISTER;
299
301 return RECEIVABLE_REGISTER;
302
303 case ACCT_TYPE_STOCK:
304 case ACCT_TYPE_MUTUAL:
305 return STOCK_REGISTER;
306
307 case ACCT_TYPE_INCOME:
308 return INCOME_REGISTER;
309
311 return EXPENSE_REGISTER;
312
313 case ACCT_TYPE_EQUITY:
314 return EQUITY_REGISTER;
315
317 return CURRENCY_REGISTER;
318
320 return TRADING_REGISTER;
321
322 default:
323 PERR ("unknown account type %d\n", account_type);
324 return BANK_REGISTER;
325 }
326 }
327
328 if (ld_type != LD_SUBACCOUNT)
329 {
330 PERR ("unknown ledger type %d\n", ld_type);
331 return BANK_REGISTER;
332 }
333
334 switch (account_type)
335 {
336 case ACCT_TYPE_BANK:
337 case ACCT_TYPE_CASH:
338 case ACCT_TYPE_ASSET:
339 case ACCT_TYPE_CREDIT:
343 {
344 /* If any of the sub-accounts have ACCT_TYPE_STOCK or
345 * ACCT_TYPE_MUTUAL types, then we must use the PORTFOLIO_LEDGER
346 * ledger. Otherwise, a plain old GENERAL_JOURNAL will do. */
347 gpointer ret;
348 reg_type = GENERAL_JOURNAL;
349
350 ret = gnc_account_foreach_descendant_until (leader, look_for_portfolio_cb,
351 NULL);
352 if (ret) reg_type = PORTFOLIO_LEDGER;
353 break;
354 }
355
356 case ACCT_TYPE_STOCK:
357 case ACCT_TYPE_MUTUAL:
359 reg_type = PORTFOLIO_LEDGER;
360 break;
361
362 case ACCT_TYPE_INCOME:
364 reg_type = INCOME_LEDGER;
365 break;
366
367 case ACCT_TYPE_EQUITY:
369 reg_type = GENERAL_JOURNAL;
370 break;
371
372 default:
373 PERR ("unknown account type:%d", account_type);
374 reg_type = GENERAL_JOURNAL;
375 break;
376 }
377
378 return reg_type;
379}
380
381/* Returns a boolean of whether this display should be single or double lined
382 * mode by default */
383gboolean
385{
386 return (gld->use_double_line_default ||
387 gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER,
388 GNC_PREF_DOUBLE_LINE_MODE));
389}
390
391/* Opens up a register window to display a single account */
392GNCLedgerDisplay*
394{
395 SplitRegisterType reg_type;
396 GNCAccountType acc_type = xaccAccountGetType (account);
397 gboolean use_double_line;
398 GNCLedgerDisplay* ld;
399
400 ENTER ("account=%p", account);
401
402 switch (acc_type)
403 {
406 use_double_line = TRUE;
407 break;
408 default:
409 use_double_line = FALSE;
410 break;
411 }
412
413 reg_type = gnc_get_reg_type (account, LD_SINGLE);
414
415 ld = gnc_ledger_display_internal (account, NULL, LD_SINGLE, reg_type,
416 gnc_get_default_register_style (acc_type),
417 use_double_line, FALSE, FALSE);
418 LEAVE ("%p", ld);
419 return ld;
420}
421
422/* Opens up a register window to display an account, and all of its
423 * children, in the same window */
424GNCLedgerDisplay*
426 gboolean mismatched_commodities)
427{
428 SplitRegisterType reg_type;
429 GNCLedgerDisplay* ld;
430
431 ENTER ("account=%p", account);
432
433 reg_type = gnc_get_reg_type (account, LD_SUBACCOUNT);
434
435 ld = gnc_ledger_display_internal (account, NULL, LD_SUBACCOUNT,
436 reg_type, REG_STYLE_JOURNAL, FALSE,
437 FALSE, mismatched_commodities);
438 LEAVE ("%p", ld);
439 return ld;
440}
441
442/* Opens up a general journal window. */
443GNCLedgerDisplay*
445{
446 Query* query;
447 time64 start;
448 GNCLedgerDisplay* ld;
449 GHashTable *exclude_template_accounts_hash;
450
451 ENTER (" ");
452
453 query = qof_query_create_for (GNC_ID_SPLIT);
454
455 qof_query_set_book (query, gnc_get_current_book());
456
457 exclude_template_accounts_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
458
459 /* In lieu of not "mis-using" some portion of the infrastructure by writing
460 * a bunch of new code, we just filter out the accounts of the template
461 * transactions. While these are in a separate Account trees just for this
462 * reason, the query engine makes no distinction between Account trees.
463 * See Gnome Bug 86302.
464 * -- jsled */
465 // Exclude any template accounts for search register and gl
466 exclude_template_accounts (query, exclude_template_accounts_hash);
467
468 // the default is to show last 30 days
469 static const time64 secs_per_thirty_days = 2592000;
470 start = gnc_time64_get_today_start () - secs_per_thirty_days;
471
472 xaccQueryAddDateMatchTT (query,
473 TRUE, start,
474 FALSE, 0,
475 QOF_QUERY_AND);
476
477 ld = gnc_ledger_display_internal (NULL, query, LD_GL, GENERAL_JOURNAL,
478 REG_STYLE_JOURNAL, FALSE, FALSE, FALSE);
479
480 ld->excluded_template_acc_hash = exclude_template_accounts_hash;
481 LEAVE ("%p", ld);
482
483 qof_query_destroy (query);
484 return ld;
485}
486
495GNCLedgerDisplay*
497{
498 QofBook* book;
499 Query* q;
500 GNCLedgerDisplay* ld;
501 SplitRegister* sr;
502 Account* root, *acct;
503 gboolean isTemplateModeTrue;
504
505 ENTER ("id=%s", id ? id : "(null)");
506
507 acct = NULL;
508 isTemplateModeTrue = TRUE;
509
510 q = qof_query_create_for (GNC_ID_SPLIT);
511
512 book = gnc_get_current_book();
513 qof_query_set_book (q, book);
514
515 if (id != NULL)
516 {
517 root = gnc_book_get_template_root (book);
518 acct = gnc_account_lookup_by_name (root, id);
519 g_assert (acct);
520 xaccQueryAddSingleAccountMatch (q, acct, QOF_QUERY_AND);
521 }
522
523 ld = gnc_ledger_display_internal (NULL, q, LD_GL,
524 SEARCH_LEDGER,
525 REG_STYLE_JOURNAL,
526 FALSE,
527 isTemplateModeTrue,
528 FALSE);
529
531 if (acct)
532 {
534 }
535
537
538 LEAVE ("%p", ld);
539 return ld;
540}
541
542GtkWidget*
543gnc_ledger_display_get_parent (GNCLedgerDisplay* ld)
544{
545 if (ld == NULL)
546 return NULL;
547
548 if (ld->get_parent == NULL)
549 return NULL;
550
551 return ld->get_parent (ld);
552}
553
554static GtkWidget*
555gnc_ledger_display_parent (void* user_data)
556{
557 GNCLedgerDisplay* ld = user_data;
559}
560
561static void
562gnc_ledger_display_set_watches (GNCLedgerDisplay* ld, GList* splits)
563{
564 GList* node;
565
566 gnc_gui_component_clear_watches (ld->component_id);
567
568 gnc_gui_component_watch_entity_type (ld->component_id,
569 GNC_ID_ACCOUNT,
570 QOF_EVENT_MODIFY | QOF_EVENT_DESTROY
571 | GNC_EVENT_ITEM_CHANGED);
572
573 for (node = splits; node; node = node->next)
574 {
575 Split* split = node->data;
576 Transaction* trans = xaccSplitGetParent (split);
577
578 gnc_gui_component_watch_entity (ld->component_id,
579 xaccTransGetGUID (trans),
580 QOF_EVENT_MODIFY);
581 }
582}
583
584static void
585refresh_handler (GHashTable* changes, gpointer user_data)
586{
587 GNCLedgerDisplay* ld = user_data;
588 const EventInfo* info;
589 gboolean has_leader;
590
591 ENTER ("changes=%p, user_data=%p", changes, user_data);
592
593 if (ld->loading)
594 {
595 LEAVE ("already loading");
596 return;
597 }
598
599 has_leader = (ld->ld_type == LD_SINGLE || ld->ld_type == LD_SUBACCOUNT);
600
601 if (has_leader)
602 {
603 Account* leader = gnc_ledger_display_leader (ld);
604 if (!leader)
605 {
606 gnc_close_gui_component (ld->component_id);
607 LEAVE ("no leader");
608 return;
609 }
610 }
611
612 if (changes && has_leader)
613 {
614 info = gnc_gui_get_entity_events (changes, &ld->leader);
615 if (info && (info->event_mask & QOF_EVENT_DESTROY))
616 {
617 gnc_close_gui_component (ld->component_id);
618 LEAVE ("destroy");
619 return;
620 }
621 }
622
623 if (ld->visible)
624 {
625 DEBUG ("immediate refresh because ledger is visible");
627 }
628 else
629 {
630 ld->needs_refresh = TRUE;
631 }
632 LEAVE (" ");
633}
634
635static void
636close_handler (gpointer user_data)
637{
638 GNCLedgerDisplay* ld = user_data;
639
640 if (!ld)
641 return;
642
643 gnc_unregister_gui_component (ld->component_id);
644 ld->component_id = NO_COMPONENT;
645
646 if (ld->destroy)
647 ld->destroy (ld);
648
650 ld->reg = NULL;
651
652 // Destroy the excluded template account hash
653 if (ld->excluded_template_acc_hash)
654 g_hash_table_destroy (ld->excluded_template_acc_hash);
655
656 qof_query_destroy (ld->query);
657 ld->query = NULL;
658
659 qof_query_destroy (ld->pre_filter_query);
660 ld->pre_filter_query = NULL;
661
662 g_free (ld);
663}
664
665static void
666gnc_ledger_display_make_query (GNCLedgerDisplay* ld,
667 gint limit,
669{
670 Account* leader;
671 GList* accounts;
672
673 if (!ld)
674 return;
675
676 switch (ld->ld_type)
677 {
678 case LD_SINGLE:
679 case LD_SUBACCOUNT:
680 break;
681
682 case LD_GL:
683 return;
684
685 default:
686 PERR ("unknown ledger type: %d", ld->ld_type);
687 return;
688 }
689
690 qof_query_destroy (ld->query);
691 ld->query = qof_query_create_for (GNC_ID_SPLIT);
692
693 /* This is a bit of a hack. The number of splits should be
694 * configurable, or maybe we should go back a time range instead
695 * of picking a number, or maybe we should be able to exclude
696 * based on reconciled status. Anyway, this works for now. */
697 if ((limit != 0) && (type != SEARCH_LEDGER))
698 qof_query_set_max_results (ld->query, limit);
699
700 qof_query_set_book (ld->query, gnc_get_current_book());
701
702 leader = gnc_ledger_display_leader (ld);
703
704 /* if this is a subaccount ledger, record the number of
705 * subaccounts so we can determine if the query needs
706 * recreating on a refresh. */
707 if (ld->ld_type == LD_SUBACCOUNT)
708 {
709 accounts = gnc_account_get_descendants (leader);
710 ld->number_of_subaccounts = g_list_length (accounts);
711 }
712 else
713 accounts = NULL;
714
715 accounts = g_list_prepend (accounts, leader);
716
717 xaccQueryAddAccountMatch (ld->query, accounts,
718 QOF_GUID_MATCH_ANY, QOF_QUERY_AND);
719
720 g_list_free (accounts);
721}
722
723/* Opens up a ledger window for an arbitrary query. */
724GNCLedgerDisplay*
726 SplitRegisterStyle style)
727{
728 GNCLedgerDisplay* ld;
729
730 ENTER ("query=%p", query);
731
732 ld = gnc_ledger_display_internal (NULL, query, LD_GL, type, style,
733 FALSE, FALSE, FALSE);
734
735 ld->excluded_template_acc_hash = g_hash_table_new (g_direct_hash, g_direct_equal);
736 LEAVE ("%p", ld);
737 return ld;
738}
739
740static GNCLedgerDisplay*
741gnc_ledger_display_internal (Account* lead_account, Query* q,
742 GNCLedgerDisplayType ld_type,
743 SplitRegisterType reg_type,
744 SplitRegisterStyle style,
745 gboolean use_double_line,
746 gboolean is_template,
747 gboolean mismatched_commodities)
748{
749 GNCLedgerDisplay* ld;
750 gint limit;
751 const char* klass;
752
753 switch (ld_type)
754 {
755 case LD_SINGLE:
756 klass = REGISTER_SINGLE_CM_CLASS;
757
758 if (reg_type >= NUM_SINGLE_REGISTER_TYPES)
759 {
760 PERR ("single-account register with wrong split register type");
761 return NULL;
762 }
763
764 if (!lead_account)
765 {
766 PERR ("single-account register with no account specified");
767 return NULL;
768 }
769
770 if (q)
771 {
772 PWARN ("single-account register with external query");
773 q = NULL;
774 }
775
776 ld = gnc_find_first_gui_component (klass, find_by_leader, lead_account);
777 if (ld)
778 return ld;
779
780 break;
781
782 case LD_SUBACCOUNT:
783 klass = REGISTER_SUBACCOUNT_CM_CLASS;
784
785 if (!lead_account)
786 {
787 PERR ("sub-account register with no lead account");
788 return NULL;
789 }
790
791 if (q)
792 {
793 PWARN ("account register with external query");
794 q = NULL;
795 }
796
797 ld = gnc_find_first_gui_component (klass, find_by_leader, lead_account);
798 if (ld)
799 return ld;
800
801 break;
802
803 case LD_GL:
804 klass = REGISTER_GL_CM_CLASS;
805
806 if (!q)
807 {
808 PWARN ("general journal with no query");
809 }
810
811 break;
812
813 default:
814 PERR ("bad ledger type: %d", ld_type);
815 return NULL;
816
817 }
818
819 ld = g_new (GNCLedgerDisplay, 1);
820
821 ld->leader = *xaccAccountGetGUID (lead_account);
822 ld->query = NULL;
823 ld->ld_type = ld_type;
824 ld->loading = FALSE;
825 ld->visible = FALSE;
826 ld->needs_refresh = TRUE;
827 ld->destroy = NULL;
828 ld->get_parent = NULL;
829 ld->user_data = NULL;
830 ld->excluded_template_acc_hash = NULL;
831
832 limit = gnc_prefs_get_float (GNC_PREFS_GROUP_GENERAL_REGISTER,
833 GNC_PREF_MAX_TRANS);
834
835 /* set up the query filter */
836 if (q)
837 ld->query = qof_query_copy (q);
838 else
839 gnc_ledger_display_make_query (ld, limit, reg_type);
840
841 ld->pre_filter_query = qof_query_copy (ld->query);
842
843 ld->component_id = gnc_register_gui_component (klass,
844 refresh_handler,
845 close_handler, ld);
846
847 /******************************************************************\
848 * The main register window itself *
849 \******************************************************************/
850
851 ld->use_double_line_default = use_double_line;
852
853 ld->reg = gnc_split_register_new (reg_type, style, use_double_line,
854 is_template, mismatched_commodities);
855
856 gnc_split_register_set_data (ld->reg, ld, gnc_ledger_display_parent);
857
858 /* Must call this before gnc_table_realize_gui() gets called or all the
859 * combo boxes will be empty. Use an empty list of splits instad of running
860 * the query when we're not in focus yet.
861 */
862 ld->loading = TRUE;
863 gnc_split_register_load (ld->reg, NULL, NULL, gnc_ledger_display_leader (ld));
864 ld->loading = FALSE;
865 return ld;
866}
867
868void
869gnc_ledger_display_set_query (GNCLedgerDisplay* ledger_display, Query* q)
870{
871 if (!ledger_display || !q)
872 return;
873
874 g_return_if_fail (ledger_display->ld_type == LD_GL);
875
876 qof_query_destroy (ledger_display->query);
877 ledger_display->query = qof_query_copy (q);
878}
879
880GNCLedgerDisplay*
882{
883 if (!q)
884 return NULL;
885
886 return gnc_find_first_gui_component (REGISTER_GL_CM_CLASS, find_by_query, q);
887}
888
889/********************************************************************\
890 * refresh only the indicated register window *
891\********************************************************************/
892
893static void
894gnc_ledger_display_refresh_internal (GNCLedgerDisplay* ld)
895{
896 GList* splits;
897 GList* pre_filter_splits = NULL;
898
899 if (ld->loading)
900 return;
901
902 /* It's not clear if we should re-run the query, or if we should
903 * just use qof_query_last_run(). It's possible that the dates
904 * changed, requiring a full new query. Similar considerations
905 * needed for multi-user mode.
906 */
907 splits = qof_query_run (ld->query);
908
909 if (!qof_query_equal (ld->query, ld->pre_filter_query))
910 pre_filter_splits = qof_query_run (ld->pre_filter_query);
911
912 gnc_ledger_display_set_watches (ld, splits);
913
914 if (!gnc_split_register_full_refresh_ok (ld->reg))
915 return;
916
917 ld->loading = TRUE;
918
919 gnc_split_register_load (ld->reg, splits, pre_filter_splits,
921
922 ld->needs_refresh = FALSE;
923 ld->loading = FALSE;
924}
925
926void
927gnc_ledger_display_refresh (GNCLedgerDisplay* ld)
928{
929 ENTER ("ld=%p", ld);
930
931 if (!ld)
932 {
933 LEAVE ("no display");
934 return;
935 }
936
937 if (ld->loading)
938 {
939 LEAVE ("already loading");
940 return;
941 }
942
943 /* if subaccount ledger, check to see if still the same number
944 * of subaccounts, if not recreate the query. */
945 if (ld->ld_type == LD_SUBACCOUNT)
946 {
947 Account* leader = gnc_ledger_display_leader (ld);
948 GList* accounts = gnc_account_get_descendants (leader);
949
950 if (g_list_length (accounts) != ld->number_of_subaccounts)
951 {
952 time64 start_time, end_time;
953 xaccQueryGetDateMatchTT (ld->query, &start_time, &end_time);
954
955 cleared_match_t cleared_match = xaccQueryGetClearedMatch (ld->query);
956
957 gnc_ledger_display_make_query (ld,
958 gnc_prefs_get_float (GNC_PREFS_GROUP_GENERAL_REGISTER, GNC_PREF_MAX_TRANS),
959 gnc_get_reg_type (leader, ld->ld_type));
960
961 qof_query_destroy (ld->pre_filter_query);
962 ld->pre_filter_query = qof_query_copy (ld->query);
963
964 if (cleared_match != CLEARED_ALL)
965 xaccQueryAddClearedMatch (ld->query, cleared_match, QOF_QUERY_AND);
966
967 if (start_time || end_time)
968 {
969 xaccQueryAddDateMatchTT (ld->query,
970 start_time != 0, start_time,
971 end_time != 0, end_time,
972 QOF_QUERY_AND);
973 }
974 }
975 g_list_free (accounts);
976 }
977
978 /* In lieu of not "mis-using" some portion of the infrastructure by writing
979 * a bunch of new code, we just filter out the accounts of the template
980 * transactions. While these are in a separate Account trees just for this
981 * reason, the query engine makes no distinction between Account trees.
982 * See Gnome Bug 86302.
983 * -- jsled */
984 // Exclude any template accounts for search register and gl
985 if (!ld->reg->is_template && (ld->reg->type == SEARCH_LEDGER || ld->ld_type == LD_GL))
986 {
987 exclude_template_accounts (ld->query, ld->excluded_template_acc_hash);
988
989 qof_query_destroy (ld->pre_filter_query);
990 ld->pre_filter_query = qof_query_copy (ld->query);
991 }
992 gnc_ledger_display_refresh_internal (ld);
993 LEAVE (" ");
994}
995
996void gnc_ledger_display_set_focus (GNCLedgerDisplay* ld, gboolean focus)
997{
998 if (!ld)
999 return;
1000
1001 ld->visible = focus;
1002
1003 if (ld->visible && ld->needs_refresh)
1004 {
1005 DEBUG ("deferred refresh because ledger is now visible");
1007 }
1008}
1009
1010void
1011gnc_ledger_display_refresh_by_split_register (SplitRegister* reg)
1012{
1013 GNCLedgerDisplay* ld;
1014
1015 if (!reg)
1016 return;
1017
1018 ld = gnc_find_first_gui_component (REGISTER_SINGLE_CM_CLASS,
1019 find_by_reg, reg);
1020 if (ld)
1021 {
1023 return;
1024 }
1025
1026 ld = gnc_find_first_gui_component (REGISTER_SUBACCOUNT_CM_CLASS,
1027 find_by_reg, reg);
1028 if (ld)
1029 {
1031 return;
1032 }
1033
1034 ld = gnc_find_first_gui_component (REGISTER_GL_CM_CLASS,
1035 find_by_reg, reg);
1036 if (ld)
1037 {
1039 return;
1040 }
1041
1042 ld = gnc_find_first_gui_component (REGISTER_TEMPLATE_CM_CLASS,
1043 find_by_reg, reg);
1044 if (ld)
1045 {
1047 }
1048}
1049
1050void
1051gnc_ledger_display_close (GNCLedgerDisplay* ld)
1052{
1053 if (!ld)
1054 return;
1055
1056 gnc_close_gui_component (ld->component_id);
1057}
Account handling public routines.
Anchor Scheduled Transaction info in a book.
API for Transactions and Splits (journal entries)
Date and Time handling routines.
All type declarations for the whole Gnucash engine.
Additional event handling code.
GLib helper routines.
Public declarations for GncLedgerDisplay class.
Generic api to store and retrieve preferences.
utility functions for the GnuCash UI
GNCAccountType
The account types are used to determine how the transaction data in the account is displayed.
Definition Account.h:103
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account's account type.
Definition Account.cpp:3267
GList * gnc_account_get_descendants(const Account *account)
This routine returns a flat list of all of the accounts that are descendants of the specified account...
Definition Account.cpp:3044
#define xaccAccountGetGUID(X)
Definition Account.h:252
gboolean xaccAccountIsPriced(const Account *acc)
Returns true if the account is a stock, mutual fund or currency, otherwise false.
Definition Account.cpp:4551
gpointer gnc_account_foreach_descendant_until(const Account *acc, AccountCb2 thunk, gpointer user_data)
This method will traverse all children of this accounts and their descendants, calling 'func' on each...
Definition Account.cpp:3244
Account * xaccAccountLookup(const GncGUID *guid, QofBook *book)
The xaccAccountLookup() subroutine will return the account associated with the given id,...
Definition Account.cpp:2050
@ ACCT_TYPE_INCOME
Income accounts are used to denote income.
Definition Account.h:140
@ ACCT_TYPE_MUTUAL
Mutual Fund accounts will typically be shown in registers which show three columns: price,...
Definition Account.h:125
@ ACCT_TYPE_TRADING
Account used to record multiple commodity transactions.
Definition Account.h:155
@ ACCT_TYPE_EXPENSE
Expense accounts are used to denote expenses.
Definition Account.h:143
@ ACCT_TYPE_BANK
The bank account type denotes a savings or checking account held at a bank.
Definition Account.h:107
@ ACCT_TYPE_PAYABLE
A/P account type.
Definition Account.h:151
@ ACCT_TYPE_ASSET
asset (and liability) accounts indicate generic, generalized accounts that are none of the above.
Definition Account.h:116
@ ACCT_TYPE_CURRENCY
The currency account type indicates that the account is a currency trading account.
Definition Account.h:129
@ ACCT_TYPE_RECEIVABLE
A/R account type.
Definition Account.h:149
@ ACCT_TYPE_CASH
The cash account type is used to denote a shoe-box or pillowcase stuffed with * cash.
Definition Account.h:110
@ ACCT_TYPE_LIABILITY
liability (and asset) accounts indicate generic, generalized accounts that are none of the above.
Definition Account.h:119
@ ACCT_TYPE_EQUITY
Equity account is used to balance the balance sheet.
Definition Account.h:146
@ ACCT_TYPE_CREDIT
The Credit card account is used to denote credit (e.g.
Definition Account.h:113
@ ACCT_TYPE_STOCK
Stock accounts will typically be shown in registers which show three columns: price,...
Definition Account.h:122
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition gnc-date.h:87
time64 gnc_time64_get_today_start(void)
The gnc_time64_get_today_start() routine returns a time64 value corresponding to the first second of ...
Account * gnc_account_lookup_by_name(const Account *parent, const char *name)
The gnc_account_lookup_by_name() subroutine fetches the account by name from the descendants of the s...
Definition Account.cpp:3093
#define xaccTransGetGUID(X)
void gnc_ledger_display_set_handlers(GNCLedgerDisplay *ld, GNCLedgerDisplayDestroy destroy, GNCLedgerDisplayGetParent get_parent)
set the handlers used by the ledger display
GNCLedgerDisplay * gnc_ledger_display_gl(void)
opens up a general ledger window
GNCLedgerDisplay * gnc_ledger_display_template_gl(char *id)
Displays a template ledger.
gboolean gnc_ledger_display_default_double_line(GNCLedgerDisplay *gld)
Returns a boolean of whether this display should be single or double lined mode by default.
Query * gnc_ledger_display_get_query(GNCLedgerDisplay *ld)
return the query associated with a ledger
GNCLedgerDisplay * gnc_ledger_display_simple(Account *account)
opens up a register window to display a single account
void gnc_ledger_display_refresh(GNCLedgerDisplay *ld)
redisplay/redraw only the indicated window.
GNCLedgerDisplay * gnc_ledger_display_query(Query *query, SplitRegisterType type, SplitRegisterStyle style)
display a general ledger for an arbitrary query
GtkWidget * gnc_ledger_display_get_parent(GNCLedgerDisplay *ld)
Returns the parent of a given ledger display.
void gnc_ledger_display_close(GNCLedgerDisplay *ld)
close the window
void gnc_ledger_display_set_query(GNCLedgerDisplay *ledger_display, Query *q)
Set the query used for a register.
Account * gnc_ledger_display_leader(GNCLedgerDisplay *ld)
Implementations.
void gnc_ledger_display_set_user_data(GNCLedgerDisplay *ld, gpointer user_data)
get and set the user data associated with the ledger
GNCLedgerDisplay * gnc_ledger_display_find_by_query(Query *q)
If the given ledger display still exists, return it.
GNCLedgerDisplay * gnc_ledger_display_subaccounts(Account *account, gboolean mismatched_commodities)
opens up a register window to display the parent account and all of its children.
SplitRegister * gnc_ledger_display_get_split_register(GNCLedgerDisplay *ld)
return the split register associated with a ledger display
void gnc_ledger_display_set_focus(GNCLedgerDisplay *ld, gboolean focus)
Mark the ledger as being in focus (refresh immediately) or not.
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 DEBUG(format, args...)
Print a debugging message.
Definition qoflog.h:264
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition qoflog.h:282
#define PERR(format, args...)
Log a serious error.
Definition qoflog.h:244
#define PWARN(format, args...)
Log a warning.
Definition qoflog.h:250
#define ENTER(format, args...)
Print a function entry debugging message.
Definition qoflog.h:272
gdouble gnc_prefs_get_float(const gchar *group, const gchar *pref_name)
Get an float value from the preferences backend.
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Get a boolean value from the preferences backend.
gboolean qof_query_equal(const QofQuery *q1, const QofQuery *q2)
Compare two queries for equality.
QofQuery * qof_query_copy(QofQuery *q)
Make a copy of the indicated query.
void qof_query_set_book(QofQuery *query, QofBook *book)
Set the book to be searched.
void qof_query_destroy(QofQuery *query)
Frees the resources associate with a Query object.
GList * qof_query_run(QofQuery *query)
Perform the query, return the results.
void qof_query_set_max_results(QofQuery *q, int n)
Set the maximum number of results that should be returned.
Account * gnc_book_get_template_root(const QofBook *book)
Returns the template group from the book.
Definition SX-book.cpp:65
SplitRegisterStyle
Register styles.
SplitRegisterType
Register types.
void gnc_split_register_load(SplitRegister *reg, GList *slist, GList *pre_filter_slist, Account *default_account)
Populates the rows of a register.
void gnc_split_register_set_template_account(SplitRegister *reg, Account *template_account)
Set the template account for use in a template register.
SplitRegister * gnc_split_register_new(SplitRegisterType type, SplitRegisterStyle style, gboolean use_double_line, gboolean is_template, gboolean mismatched_commodities)
Creates a new split register.
void gnc_split_register_destroy(SplitRegister *reg)
Destroys a split register.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
TableControl specialized for the SplitRegister.
TableModels specialized for SplitRegister and template SplitRegister.
STRUCTS.
The type used to store guids in C.
Definition guid.h:75
QofBook reference.
Definition qofbook-p.hpp:47
A Query.
Definition qofquery.cpp:75
The GNCLedgerDisplay struct describes a single register/ledger instance.