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