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