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