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