GnuCash  5.6-150-g038405b370+
split-register-load.c
1 /********************************************************************\
2  * split-register-load.c -- split register loading code *
3  * Copyright (C) 1998-2000 Linas Vepstas <linas@linas.org> *
4  * Copyright (C) 2000 Dave Peticolas *
5  * *
6  * This program is free software; you can redistribute it and/or *
7  * modify it under the terms of the GNU General Public License as *
8  * published by the Free Software Foundation; either version 2 of *
9  * the License, or (at your option) any later version. *
10  * *
11  * This program is distributed in the hope that it will be useful, *
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14  * GNU General Public License for more details. *
15  * *
16  * You should have received a copy of the GNU General Public License*
17  * along with this program; if not, contact: *
18  * *
19  * Free Software Foundation Voice: +1-617-542-5942 *
20  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
21  * Boston, MA 02110-1301, USA gnu@gnu.org *
22  * *
23 \********************************************************************/
24 
25 #include <config.h>
26 
27 #include <glib/gi18n.h>
28 #include <stdbool.h>
29 #include <stdio.h>
30 
31 #include "Account.h"
32 #include "Transaction.h"
33 #include "account-quickfill.h"
34 #include "combocell.h"
35 #include "completioncell.h"
36 #include "gnc-component-manager.h"
37 #include "qof.h"
38 #include "gnc-ui-util.h"
39 #include "gnc-gui-query.h"
40 #include "numcell.h"
41 #include "quickfillcell.h"
42 #include "doclinkcell.h"
43 #include "recncell.h"
44 #include "split-register.h"
45 #include "split-register-p.h"
46 #include "engine-helpers.h"
47 #include "gnc-prefs.h"
48 #include "pricecell.h"
49 
50 
51 /* This static indicates the debugging module that this .o belongs to. */
52 static QofLogModule log_module = GNC_MOD_LEDGER;
53 
54 
55 static void gnc_split_register_load_xfer_cells (SplitRegister* reg,
56  Account* base_account);
57 
58 static void
59 gnc_split_register_load_recn_cells (SplitRegister* reg)
60 {
61  RecnCell* cell;
62  const char* s;
63 
64  if (!reg) return;
65 
66  cell = (RecnCell*)
67  gnc_table_layout_get_cell (reg->table->layout, RECN_CELL);
68 
69  if (!cell) return;
70 
71  s = gnc_get_reconcile_valid_flags();
72  gnc_recn_cell_set_valid_flags (cell, s, *s);
73  gnc_recn_cell_set_flag_order (cell, gnc_get_reconcile_flag_order());
74  gnc_recn_cell_set_string_getter (cell, gnc_get_reconcile_str);
75 }
76 
77 static void
78 gnc_split_register_load_doclink_cells (SplitRegister* reg)
79 {
80  Doclinkcell *cell;
81  const char * s;
82 
83  if (!reg) return;
84 
85  cell = (Doclinkcell *)
86  gnc_table_layout_get_cell (reg->table->layout, DOCLINK_CELL);
87 
88  if (!cell) return;
89 
90  /* FIXME: These should get moved to an i18n function */
92  gnc_doclink_cell_set_valid_flags (cell, s, ' ');
93  gnc_doclink_cell_set_flag_order (cell, gnc_get_doclink_flag_order ());
94  gnc_doclink_cell_set_string_getter (cell, gnc_get_doclink_str);
95  gnc_doclink_cell_set_read_only (cell, TRUE);
96 }
97 
98 static void
99 gnc_split_register_load_type_cells (SplitRegister* reg)
100 {
101  RecnCell* cell;
102 
103  if (!reg) return;
104 
105  cell = (RecnCell*)
106  gnc_table_layout_get_cell (reg->table->layout, TYPE_CELL);
107 
108  if (!cell) return;
109 
110  /* FIXME: These should get moved to an i18n function */
111  gnc_recn_cell_set_valid_flags (cell, "IP?", 'I');
112  gnc_recn_cell_set_flag_order (cell, "IP");
113  gnc_recn_cell_set_read_only (cell, TRUE);
114 }
115 
116 static void
117 gnc_split_register_load_desc_cells (SplitRegister* reg)
118 {
119  CompletionCell *cell;
120 
121  if (!reg) return;
122 
123  cell = (CompletionCell *)
124  gnc_table_layout_get_cell (reg->table->layout, DESC_CELL);
125 
126  if (!cell) return;
127 
129 }
130 
193 static void
194 gnc_split_register_add_transaction (SplitRegister* reg,
195  Transaction* trans,
196  Split* split,
197  CellBlock* lead_cursor,
198  CellBlock* split_cursor,
199  gboolean visible_splits,
200  gboolean start_primary_color,
201  gboolean add_empty,
202  Transaction* find_trans,
203  Split* find_split,
204  CursorClass find_class,
205  int* new_split_row,
206  VirtualCellLocation* vcell_loc)
207 {
208  GList* node;
209 
210  g_return_if_fail (reg);
211  g_return_if_fail (vcell_loc);
212 
213  if (split == find_split)
214  *new_split_row = vcell_loc->virt_row;
215 
216  /* Set the "leading" virtual cell. */
217  gnc_table_set_vcell (reg->table, lead_cursor, xaccSplitGetGUID (split),
218  TRUE, start_primary_color, *vcell_loc);
219  vcell_loc->virt_row++;
220 
221  /* Continue setting up virtual cells in a column, using a row for each
222  * split in the transaction. */
223  for (node = xaccTransGetSplitList (trans); node; node = node->next)
224  {
225  Split* secondary = node->data;
226 
227  if (!xaccTransStillHasSplit (trans, secondary)) continue;
228  if (secondary == find_split && find_class == CURSOR_CLASS_SPLIT)
229  *new_split_row = vcell_loc->virt_row;
230 
231  gnc_table_set_vcell (reg->table, split_cursor,
232  xaccSplitGetGUID (secondary),
233  visible_splits, TRUE, *vcell_loc);
234  vcell_loc->virt_row++;
235  }
236 
237  /* If requested, add an empty split row at the end. */
238  if (add_empty)
239  {
240  if (find_trans == trans && find_split == NULL &&
241  find_class == CURSOR_CLASS_SPLIT)
242  *new_split_row = vcell_loc->virt_row;
243 
244  gnc_table_set_vcell (reg->table, split_cursor, xaccSplitGetGUID (NULL),
245  FALSE, TRUE, *vcell_loc);
246  vcell_loc->virt_row++;
247  }
248 }
249 
250 static gint
251 _find_split_with_parent_txn (gconstpointer a, gconstpointer b)
252 {
253  Split* split = (Split*)a;
254  Transaction* txn = (Transaction*)b;
255 
256  return xaccSplitGetParent (split) == txn ? 0 : 1;
257 }
258 
259 static void
260 add_quickfill_completions (TableLayout* layout, Transaction* trans,
261  Split* split, gboolean has_last_num)
262 {
263  gnc_quickfill_cell_add_completion (
264  (QuickFillCell*) gnc_table_layout_get_cell (layout, NOTES_CELL),
265  xaccTransGetNotes (trans));
266 
267  if (!has_last_num)
268  gnc_num_cell_set_last_num (
269  (NumCell*) gnc_table_layout_get_cell (layout, NUM_CELL),
270  gnc_get_num_action (trans, split));
271 
272  for (GList *n = xaccTransGetSplitList (trans); n; n = n->next)
273  {
274  Split *s = n->data;
275 
276  if (!xaccTransStillHasSplit (trans, s))
277  continue;
278 
279  gnc_quickfill_cell_add_completion (
280  (QuickFillCell*) gnc_table_layout_get_cell (layout, MEMO_CELL),
281  xaccSplitGetMemo (s));
282  }
283 }
284 
285 static Split*
286 create_blank_split (Account* default_account, SRInfo* info)
287 {
288  gboolean currency_from_account = TRUE;
289  Split* blank_split = NULL;
290  /* Determine the proper currency to use for this transaction.
291  * if default_account != NULL and default_account->commodity is
292  * a currency, then use that. Otherwise use the default currency.
293  */
294  gnc_commodity* currency = gnc_account_or_default_currency (default_account,
295  &currency_from_account);
296 
297  if (default_account != NULL && !currency_from_account)
298  {
299  /* If we don't have a currency then pop up a warning dialog */
300  gnc_info_dialog (NULL, "%s",
301  _ ("Could not determine the account currency. "
302  "Using the default currency provided by your system."));
303  }
304 
305  gnc_suspend_gui_refresh();
306  Transaction *pending_trans = xaccTransLookup (&info->pending_trans_guid,
307  gnc_get_current_book());
308 
309  if (!pending_trans)
310  {
311  pending_trans = xaccMallocTransaction (gnc_get_current_book());
312  xaccTransBeginEdit (pending_trans);
313  xaccTransSetCurrency (pending_trans, currency);
315  info->last_date_entered);
316  info->pending_trans_guid = *xaccTransGetGUID (pending_trans);
317  }
318 
319  blank_split = xaccMallocSplit (gnc_get_current_book());
320  xaccSplitSetParent (blank_split, pending_trans);
321  /* We don't want to commit this transaction yet, because the split
322  doesn't even belong to an account yet. But, we don't want to
323  set this transaction as the pending transaction either, because
324  we want to pretend that it hasn't been changed. We depend on
325  some other code (somewhere) to commit this transaction if we
326  really edit it, even though it's not marked as the pending
327  transaction. */
328 
329  info->blank_split_guid = *xaccSplitGetGUID (blank_split);
330  info->blank_split_edited = FALSE;
331  info->auto_complete = FALSE;
332  DEBUG ("created new blank_split=%p", blank_split);
333 
334  gnc_resume_gui_refresh();
335  return blank_split;
336 }
337 
338 static void
339 change_account_separator (SRInfo* info, Table* table, SplitRegister* reg)
340 {
341  info->separator_changed = FALSE;
342 
343  /* set the completion character for the xfer cells */
345  (ComboCell*) gnc_table_layout_get_cell (table->layout, MXFRM_CELL),
346  gnc_get_account_separator());
347 
349  (ComboCell*) gnc_table_layout_get_cell (table->layout, XFRM_CELL),
350  gnc_get_account_separator());
351 
352  /* set the confirmation callback for the reconcile cell */
353  gnc_recn_cell_set_confirm_cb (
354  (RecnCell*) gnc_table_layout_get_cell (table->layout, RECN_CELL),
355  gnc_split_register_recn_cell_confirm, reg);
356 }
357 
358 static void
359 update_info (SRInfo* info, SplitRegister* reg)
360 {
361  /* Set up the hint transaction, split, transaction split, and column. */
362  info->cursor_hint_trans = gnc_split_register_get_current_trans (reg);
363  info->cursor_hint_split = gnc_split_register_get_current_split (reg);
364  info->cursor_hint_trans_split =
366  info->cursor_hint_cursor_class =
368 
369  if (!info->first_pass && !info->quickfill_setup)
370  info->quickfill_setup = TRUE;
371 
372  info->hint_set_by_traverse = FALSE;
373  info->traverse_to_new = FALSE;
374  info->exact_traversal = FALSE;
375  info->first_pass = FALSE;
376  info->reg_loaded = TRUE;
377 }
378 
379 static void
380 add_completions_from_pre_filter_slist (TableLayout* layout, GList *pre_filter_slist,
381  gboolean first_pass, gboolean quickfill_setup,
382  gboolean has_last_num)
383 {
384  GList *node;
385 
386  for (node = pre_filter_slist; node; node = node->next)
387  {
388  Split *split = node->data;
389  Transaction *trans = xaccSplitGetParent (split);
390 
392  (CompletionCell*) gnc_table_layout_get_cell (layout, DESC_CELL),
393  xaccTransGetDescription (trans));
394 
395  if (!first_pass && !quickfill_setup)
396  add_quickfill_completions (layout, trans, split, has_last_num);
397  }
398 }
399 
400 void
401 gnc_split_register_load (SplitRegister* reg, GList* slist,
402  GList* pre_filter_slist, Account* default_account)
403 {
404  SRInfo* info;
405  Transaction* pending_trans;
406  CursorBuffer* cursor_buffer;
407  GHashTable* trans_table = NULL;
408  CellBlock* cursor_header;
409  CellBlock* lead_cursor;
410  CellBlock* split_cursor;
411  Transaction* blank_trans;
412  Transaction* find_trans;
413  Transaction* trans;
414  CursorClass find_class;
415  Split* find_trans_split;
416  Split* blank_split;
417  Split* find_split;
418  Split* split;
419  Table* table;
420  GList* node;
421  gnc_commodity *account_comm = NULL;
422 
423  gboolean start_primary_color = TRUE;
424  gboolean found_pending = FALSE;
425  gboolean need_divider_upper = FALSE;
426  gboolean found_divider_upper = FALSE;
427  gboolean found_divider = FALSE;
428  gboolean has_last_num = FALSE;
429  gboolean multi_line;
430  gboolean dynamic;
431  gboolean we_own_slist = FALSE;
432  gboolean use_autoreadonly = qof_book_uses_autoreadonly (
433  gnc_get_current_book());
434  gboolean future_after_blank = gnc_prefs_get_bool (
435  GNC_PREFS_GROUP_GENERAL_REGISTER,
436  GNC_PREF_FUTURE_AFTER_BLANK);
437  gboolean added_blank_trans = FALSE;
438 
439  VirtualCellLocation vcell_loc;
440  VirtualLocation save_loc;
441 
442  int new_trans_split_row = -1;
443  int new_trans_row = -1;
444  int new_split_row = -1;
445  time64 present, autoreadonly_time = 0;
446 
447  g_return_if_fail (reg);
448  table = reg->table;
449  g_return_if_fail (table);
450  info = gnc_split_register_get_info (reg);
451  g_return_if_fail (info);
452 
453  ENTER ("reg=%p, slist=%p, default_account=%p", reg, slist, default_account);
454 
455  blank_split = xaccSplitLookup (&info->blank_split_guid,
456  gnc_get_current_book());
457 
458  pending_trans = xaccTransLookup (&info->pending_trans_guid,
459  gnc_get_current_book());
460 
461  if (default_account)
462  account_comm = gnc_account_get_currency_or_parent (default_account);
463 
464  if (!account_comm)
465  account_comm = gnc_default_currency ();
466 
467  /* Bug 742089: Set the debit and credit cells' print_info to the account */
469  ((PriceCell*) gnc_table_layout_get_cell (table->layout, DEBT_CELL),
470  gnc_commodity_print_info (account_comm, FALSE));
471 
473  ((PriceCell*) gnc_table_layout_get_cell (table->layout, CRED_CELL),
474  gnc_commodity_print_info (account_comm, FALSE));
475 
477  ((PriceCell*) gnc_table_layout_get_cell (reg->table->layout, PRIC_CELL),
478  gnc_commodity_print_info (account_comm, FALSE));
479 
480  /* Only test for linked document glyths once */
481  if (info->first_pass)
482  {
483  gnc_doclink_cell_set_use_glyphs
484  ((Doclinkcell *) gnc_table_layout_get_cell (table->layout, DOCLINK_CELL));
485  }
486 
487  /* make sure we have a blank split */
488  if (blank_split == NULL)
489  blank_split = create_blank_split (default_account, info);
490 
491  blank_trans = xaccSplitGetParent (blank_split);
492 
493  DEBUG ("blank_split=%p, blank_trans=%p, pending_trans=%p",
494  blank_split, blank_trans, pending_trans);
495 
496  info->default_account = *xaccAccountGetGUID (default_account);
497 
498  // gnc_table_leave_update (table, table->current_cursor_loc);
499 
500  multi_line = (reg->style == REG_STYLE_JOURNAL);
501  dynamic = (reg->style == REG_STYLE_AUTO_LEDGER);
502 
503  lead_cursor = gnc_split_register_get_passive_cursor (reg);
504  split_cursor = gnc_table_layout_get_cursor (table->layout, CURSOR_SPLIT);
505 
506  /* figure out where we are going to. */
507  if (info->traverse_to_new)
508  {
509  find_trans = blank_trans;
510  find_split = NULL;
511  find_trans_split = blank_split;
512  find_class = CURSOR_CLASS_SPLIT;
513  }
514  else
515  {
516  find_trans = info->cursor_hint_trans;
517  find_split = info->cursor_hint_split;
518  find_trans_split = info->cursor_hint_trans_split;
519  find_class = info->cursor_hint_cursor_class;
520  }
521 
522  save_loc = table->current_cursor_loc;
523 
524  /* If the current cursor has changed we save the values for later
525  * possible restoration. */
526  if (gnc_table_current_cursor_changed (table, TRUE) &&
527  (find_split == gnc_split_register_get_current_split (reg)))
528  {
529  cursor_buffer = gnc_cursor_buffer_new();
530  gnc_table_save_current_cursor (table, cursor_buffer);
531  }
532  else
533  cursor_buffer = NULL;
534 
535  /* disable move callback -- we don't want the cascade of
536  * callbacks while we are fiddling with loading the register */
537  gnc_table_control_allow_move (table->control, FALSE);
538 
539  /* invalidate the cursor */
540  {
541  VirtualLocation virt_loc;
542 
543  gnc_virtual_location_init (&virt_loc);
544  gnc_table_move_cursor_gui (table, virt_loc);
545  }
546 
547  /* make sure that the header is loaded */
548  vcell_loc.virt_row = 0;
549  vcell_loc.virt_col = 0;
550  cursor_header = gnc_table_layout_get_cursor (table->layout, CURSOR_HEADER);
551  gnc_table_set_vcell (table, cursor_header, NULL, TRUE, TRUE, vcell_loc);
552  vcell_loc.virt_row++;
553 
554  /* get the current time and reset the dividing row */
555  present = gnc_time64_get_today_end();
556  if (use_autoreadonly)
557  {
558  GDate* d = qof_book_get_autoreadonly_gdate (gnc_get_current_book());
559  // "d" is NULL if use_autoreadonly is FALSE
560  autoreadonly_time = d ? gdate_to_time64 (*d) : 0;
561  g_date_free (d);
562  }
563 
564  if (info->first_pass)
565  {
566  if (default_account)
567  {
568  const char* last_num = xaccAccountGetLastNum (default_account);
569 
570  if (last_num)
571  {
572  NumCell* cell;
573 
574  cell = (NumCell*) gnc_table_layout_get_cell (table->layout, NUM_CELL);
575  gnc_num_cell_set_last_num (cell, last_num);
576  has_last_num = TRUE;
577  }
578  }
579 
580  /* load up account names into the transfer combobox menus */
581  gnc_split_register_load_xfer_cells (reg, default_account);
582  gnc_split_register_load_desc_cells (reg);
583  gnc_split_register_load_doclink_cells (reg);
584  gnc_split_register_load_recn_cells (reg);
585  gnc_split_register_load_type_cells (reg);
586  }
587 
588  if (info->separator_changed)
589  change_account_separator (info, table, reg);
590 
591  table->model->dividing_row_upper = -1;
592  table->model->dividing_row = -1;
593  table->model->dividing_row_lower = -1;
594 
595  // Ensure that the transaction and splits being edited are in the split
596  // list we're about to load.
597  if (pending_trans != NULL)
598  {
599  for (node = xaccTransGetSplitList (pending_trans); node; node = node->next)
600  {
601  Split* pending_split = (Split*)node->data;
602  if (!xaccTransStillHasSplit (pending_trans, pending_split)) continue;
603  if (g_list_find (slist, pending_split) != NULL)
604  continue;
605 
606  if (g_list_find_custom (slist, pending_trans,
607  _find_split_with_parent_txn) != NULL)
608  continue;
609 
610  if (!we_own_slist)
611  {
612  // lazy-copy
613  slist = g_list_copy (slist);
614  we_own_slist = TRUE;
615  }
616  slist = g_list_append (slist, pending_split);
617  }
618  }
619 
620  if (multi_line)
621  trans_table = g_hash_table_new (g_direct_hash, g_direct_equal);
622 
623  // View reversed add blank transaction at the top
624  if (table->model->reverse_sort && !future_after_blank)
625  {
626  if (blank_trans == find_trans)
627  new_trans_row = vcell_loc.virt_row;
628 
629  if (blank_split == find_trans_split)
630  new_trans_split_row = vcell_loc.virt_row;
631 
632  /* go to blank on first pass */
633  if (info->first_pass)
634  {
635  save_loc.vcell_loc = vcell_loc;
636  save_loc.phys_row_offset = 0;
637  save_loc.phys_col_offset = 0;
638  }
639 
640  // used in the setting the rows insensitive
641  table->model->blank_trans_row = vcell_loc.virt_row;
642 
643  gnc_split_register_add_transaction (reg,
644  blank_trans, blank_split,
645  lead_cursor, split_cursor,
646  multi_line, start_primary_color,
647  info->blank_split_edited,
648  find_trans, find_split,
649  find_class, &new_split_row,
650  &vcell_loc);
651 
652  if (!multi_line)
653  start_primary_color = !start_primary_color;
654 
655  added_blank_trans = TRUE;
656  }
657 
658  gnc_completion_cell_clear_menu (
659  (CompletionCell*) gnc_table_layout_get_cell (reg->table->layout, DESC_CELL));
660 
662  (CompletionCell*) gnc_table_layout_get_cell (reg->table->layout, DESC_CELL),
663  table->model->reverse_sort);
664 
665  if (!info->first_pass && pre_filter_slist)
666  {
667  add_completions_from_pre_filter_slist (reg->table->layout, pre_filter_slist,
668  info->first_pass, info->quickfill_setup,
669  has_last_num);
670  }
671 
672  /* populate the table */
673  for (node = slist; node; node = node->next)
674  {
675  split = node->data;
676  trans = xaccSplitGetParent (split);
677 
678  if (!xaccTransStillHasSplit (trans, split))
679  continue;
680 
681  if (pending_trans == trans)
682  found_pending = TRUE;
683  /* If the transaction has only one split, and it's not our
684  * pending_trans, then it's another register's blank split and
685  * we don't want to see it.
686  */
687  else if (xaccTransCountSplits (trans) == 1 &&
688  xaccSplitGetAccount (split) == NULL)
689  continue;
690 
691  /* Do not load splits from the blank transaction. */
692  if (trans == blank_trans)
693  continue;
694 
695  if (multi_line)
696  {
697  /* Skip this split if its transaction has already been loaded. */
698  if (g_hash_table_lookup (trans_table, trans))
699  continue;
700 
701  g_hash_table_insert (trans_table, trans, trans);
702  }
703 
704  if (info->show_present_divider &&
705  use_autoreadonly &&
706  !found_divider_upper)
707  {
708  if (((table->model->reverse_sort && xaccTransGetDate(trans) < autoreadonly_time) ||
709  (!table->model->reverse_sort && xaccTransGetDate (trans) >= autoreadonly_time)))
710  {
711  table->model->dividing_row_upper = vcell_loc.virt_row;
712  found_divider_upper = TRUE;
713  }
714  else
715  {
716  need_divider_upper = TRUE;
717  }
718  }
719 
720  if (info->show_present_divider && !found_divider &&
721  ((table->model->reverse_sort && xaccTransGetDate (trans) < present) ||
722  (!table->model->reverse_sort && xaccTransGetDate (trans) > present)))
723  {
724  gint count_blank_splits = 1;
725  gint virt_row_offset = 2;
726  gboolean show_lower_divider = FALSE;
727 
728  if (table->model->reverse_sort)
729  {
730  count_blank_splits = xaccTransCountSplits (blank_trans);
731 
732  if (count_blank_splits > 1)
733  count_blank_splits ++;
734 
735  if (table->model->reverse_sort && future_after_blank)
736  virt_row_offset = 0;
737  }
738 
739  if ((table->model->reverse_sort && vcell_loc.virt_row != count_blank_splits + virt_row_offset) ||
740  !table->model->reverse_sort)
741  {
742  table->model->dividing_row = vcell_loc.virt_row; // blue top
743  show_lower_divider = TRUE;
744  }
745 
746  found_divider = TRUE;
747 
748  if (future_after_blank)
749  {
750  if (blank_trans == find_trans)
751  new_trans_row = vcell_loc.virt_row;
752 
753  if (blank_split == find_trans_split)
754  new_trans_split_row = vcell_loc.virt_row;
755 
756  /* go to blank on first pass */
757  if (info->first_pass)
758  {
759  save_loc.vcell_loc = vcell_loc;
760  save_loc.phys_row_offset = 0;
761  save_loc.phys_col_offset = 0;
762  }
763 
764  // used in the setting the rows insensitive
765  table->model->blank_trans_row = vcell_loc.virt_row;
766 
767  gnc_split_register_add_transaction (reg,
768  blank_trans, blank_split,
769  lead_cursor, split_cursor,
770  multi_line, start_primary_color,
771  info->blank_split_edited,
772  find_trans, find_split,
773  find_class, &new_split_row,
774  &vcell_loc);
775 
776 
777  if (show_lower_divider)
778  table->model->dividing_row_lower = vcell_loc.virt_row; // blue bottom
779 
780  if (!multi_line)
781  start_primary_color = !start_primary_color;
782 
783  added_blank_trans = TRUE;
784  }
785  }
786 
787  /* On first load the split list is empty so fill up the quickfill cells
788  * only on the next load. */
789  if (!info->first_pass && !pre_filter_slist && !info->quickfill_setup)
790  add_quickfill_completions (reg->table->layout, trans, split, has_last_num);
791 
792  if (!info->first_pass && !pre_filter_slist)
793  {
795  (CompletionCell*) gnc_table_layout_get_cell (reg->table->layout, DESC_CELL),
796  xaccTransGetDescription (trans));
797  }
798 
799  if (trans == find_trans)
800  new_trans_row = vcell_loc.virt_row;
801 
802  if (split == find_trans_split)
803  new_trans_split_row = vcell_loc.virt_row;
804 
805  gnc_split_register_add_transaction (reg, trans, split,
806  lead_cursor, split_cursor,
807  multi_line, start_primary_color,
808  TRUE,
809  find_trans, find_split, find_class,
810  &new_split_row, &vcell_loc);
811 
812  if (!multi_line)
813  start_primary_color = !start_primary_color;
814  }
815 
816  if (multi_line)
817  g_hash_table_destroy (trans_table);
818 
819  /* add the blank split at the end. */
820  if (pending_trans == blank_trans)
821  found_pending = TRUE;
822 
823  /* No upper divider yet? Store it now */
824  if (info->show_present_divider &&
825  use_autoreadonly &&
826  !found_divider_upper && need_divider_upper)
827  {
828  table->model->dividing_row_upper = vcell_loc.virt_row;
829  }
830 
831  /* If we didn't find the pending transaction, it was removed
832  * from the account. */
833  if (!found_pending)
834  {
835  info->pending_trans_guid = *guid_null();
836  if (xaccTransIsOpen (pending_trans))
837  xaccTransCommitEdit (pending_trans);
838  else if (pending_trans)
839  g_assert_not_reached();
840 
841  pending_trans = NULL;
842  }
843 
844  if (!added_blank_trans)
845  {
846  if (blank_trans == find_trans)
847  new_trans_row = vcell_loc.virt_row;
848 
849  if (blank_split == find_trans_split)
850  new_trans_split_row = vcell_loc.virt_row;
851 
852  /* go to blank on first pass */
853  if (info->first_pass)
854  {
855  save_loc.vcell_loc = vcell_loc;
856  save_loc.phys_row_offset = 0;
857  save_loc.phys_col_offset = 0;
858  }
859 
860  // used in the setting the rows insensitive
861  table->model->blank_trans_row = vcell_loc.virt_row;
862 
863  gnc_split_register_add_transaction (reg, blank_trans, blank_split,
864  lead_cursor, split_cursor,
865  multi_line, start_primary_color,
866  info->blank_split_edited,
867  find_trans, find_split,
868  find_class, &new_split_row,
869  &vcell_loc);
870 
871  if (future_after_blank)
872  {
873  table->model->dividing_row_lower = vcell_loc.virt_row;
874  }
875  }
876 
877  /* go to blank on first pass */
878  if (info->first_pass)
879  {
880  new_split_row = -1;
881  new_trans_split_row = -1;
882  new_trans_row = -1;
883  }
884 
885  /* resize the table to the sizes we just counted above */
886  /* num_virt_cols is always one. */
887  gnc_table_set_size (table, vcell_loc.virt_row, 1);
888 
889  /* restore the cursor to its rightful position */
890  {
891  VirtualLocation trans_split_loc;
892 
893  if (new_split_row > 0)
894  save_loc.vcell_loc.virt_row = new_split_row;
895  else if (new_trans_split_row > 0)
896  save_loc.vcell_loc.virt_row = new_trans_split_row;
897  else if (new_trans_row > 0)
898  save_loc.vcell_loc.virt_row = new_trans_row;
899 
900  trans_split_loc = save_loc;
901 
902  gnc_split_register_get_trans_split (reg, save_loc.vcell_loc,
903  &trans_split_loc.vcell_loc);
904 
905  if (dynamic || multi_line || info->trans_expanded)
906  {
908  table, trans_split_loc.vcell_loc,
909  gnc_split_register_get_active_cursor (reg));
910  gnc_split_register_set_trans_visible (reg, trans_split_loc.vcell_loc,
911  TRUE, multi_line);
912 
913  info->trans_expanded = (reg->style == REG_STYLE_LEDGER);
914  }
915  else
916  {
917  save_loc = trans_split_loc;
918  info->trans_expanded = FALSE;
919  }
920 
921  if (gnc_table_find_close_valid_cell (table, &save_loc, FALSE))
922  {
923  gnc_table_move_cursor_gui (table, save_loc);
924  new_split_row = save_loc.vcell_loc.virt_row;
925 
926  if (find_split == gnc_split_register_get_current_split (reg))
927  gnc_table_restore_current_cursor (table, cursor_buffer);
928  }
929  }
930  gnc_cursor_buffer_destroy (cursor_buffer);
931  cursor_buffer = NULL;
932 
933  update_info (info, reg);
934 
935  gnc_split_register_set_cell_fractions (
937 
939 
940  // if in reverse order, always show the first transaction
941  if (table->model->reverse_sort)
942  {
943  VirtualCellLocation vc_loc;
944  vc_loc.virt_row = 0;
945  vc_loc.virt_col = 0;
946  gnc_split_register_show_trans (reg, vc_loc);
947  }
948  else
949  gnc_split_register_show_trans (reg, table->current_cursor_loc.vcell_loc);
950 
951  /* enable callback for cursor user-driven moves */
952  gnc_table_control_allow_move (table->control, TRUE);
953 
954  if (we_own_slist)
955  g_list_free (slist);
956 
957  LEAVE (" ");
958 }
959 
960 /* ===================================================================== */
961 
962 #define QKEY "split_reg_shared_quickfill"
963 
964 static gboolean
965 skip_cb (Account* account, gpointer x)
966 {
967  /* commented out as per Bug#340885 Comments 1 and 2, option (2).
968  if (xaccAccountIsHidden(account))
969  return TRUE;
970  */
971  return xaccAccountGetPlaceholder (account);
972 }
973 
974 static void
975 gnc_split_register_load_xfer_cells (SplitRegister* reg, Account* base_account)
976 {
977  Account* root = NULL;
978  QuickFill* qf;
979  ComboCell* cell;
980  GtkListStore* store;
981 
982  if (base_account)
983  root = gnc_account_get_root (base_account);
984  if (root == NULL)
985  root = gnc_get_current_root_account();
986  if (root == NULL)
987  return;
988 
989  qf = gnc_get_shared_account_name_quickfill (root, QKEY, skip_cb, NULL);
990  store = gnc_get_shared_account_name_list_store (root, QKEY, skip_cb, NULL);
991 
992  cell = (ComboCell*)
993  gnc_table_layout_get_cell (reg->table->layout, XFRM_CELL);
995  gnc_combo_cell_use_list_store_cache (cell, store);
996 
997  cell = (ComboCell*)
998  gnc_table_layout_get_cell (reg->table->layout, MXFRM_CELL);
1000  gnc_combo_cell_use_list_store_cache (cell, store);
1001 }
1002 
1003 /* ====================== END OF FILE ================================== */
CursorClass gnc_split_register_get_current_cursor_class(SplitRegister *reg)
Returns the class of a register&#39;s current cursor.
Split * gnc_split_register_get_current_trans_split(SplitRegister *reg, VirtualCellLocation *trans_split_loc)
Gets the anchoring split of the transaction at the current cursor location, which may be on the trans...
void gnc_recn_cell_set_valid_flags(RecnCell *cell, const char *flags, char default_flag)
note that chars is copied into the RecnCell directly, but remains the "property" of the caller...
Definition: recncell.c:196
The RecnCell object implements a cell handler that will cycle through a series of single-character va...
Definition: recncell.h:47
Transaction * xaccMallocTransaction(QofBook *book)
The xaccMallocTransaction() will malloc memory and initialize it.
The CompletionCell object implements a cell handler with a "combination-box" pull-down menu in it...
const char * xaccAccountGetLastNum(const Account *acc)
Get the last num field of an Account.
Definition: Account.cpp:4638
void xaccTransSetDatePostedSecsNormalized(Transaction *trans, time64 time)
This function sets the posted date of the transaction, specified by a time64 (see ctime(3))...
time64 xaccTransGetDate(const Transaction *trans)
Retrieve the posted date of the transaction.
void gnc_completion_cell_reverse_sort(CompletionCell *cell, gboolean is_reversed)
Register the sort direction.
void gnc_completion_cell_set_sort_enabled(CompletionCell *cell, gboolean enabled)
Enable sorting of the menu item&#39;s contents.
gboolean xaccTransIsOpen(const Transaction *trans)
The xaccTransIsOpen() method returns TRUE if the transaction is open for editing. ...
utility functions for the GnuCash UI
The QuickFillCell implements a text cell with quick-fill capabilities.
Definition: quickfillcell.h:46
void gnc_split_register_set_trans_visible(SplitRegister *reg, VirtualCellLocation vcell_loc, gboolean visible, gboolean only_blank_split)
Set the visibility of the split rows belonging to a transaction located at vcell_loc.
Transaction * gnc_split_register_get_current_trans(SplitRegister *reg)
Gets the transaction at the current cursor location, which may be on the transaction itself or on any...
STRUCTS.
#define DEBUG(format, args...)
Print a debugging message.
Definition: qoflog.h:264
Create an account-name quick-fill.
void gnc_table_move_cursor_gui(Table *table, VirtualLocation new_virt_loc)
will move the cursor and its GUI to the indicated location.
Definition: table-allgui.c:887
gboolean gnc_table_find_close_valid_cell(Table *table, VirtualLocation *virt_loc, gboolean exact_pointer)
Find a close valid cell.
void gnc_table_set_size(Table *table, int virt_rows, int virt_cols)
The gnc_table_set_size() method will resize the table to the indicated dimensions.
Definition: table-allgui.c:587
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
The Doclinkcell object implements a cell handler that will cycle through a series of single-character...
Definition: doclinkcell.h:52
void gnc_split_register_load(SplitRegister *reg, GList *slist, GList *pre_filter_slist, Account *default_account)
Populates the rows of a register.
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
void gnc_combo_cell_set_complete_char(ComboCell *cell, gunichar complete_char)
Sets a character used for special completion processing.
QuickFill * gnc_get_shared_account_name_quickfill(Account *root, const char *key, AccountBoolCB cb, gpointer cb_data)
Create/fetch a quickfill of account names.
void xaccTransSetCurrency(Transaction *trans, gnc_commodity *curr)
Set a new currency on a transaction.
gnc_commodity * gnc_default_currency(void)
Return the default currency set by the user.
const char * xaccTransGetNotes(const Transaction *trans)
Gets the transaction Notes.
Transaction * xaccTransLookup(const GncGUID *guid, QofBook *book)
The xaccTransLookup() subroutine will return the transaction associated with the given id...
int xaccTransCountSplits(const Transaction *trans)
Returns the number of splits in this transaction.
#define xaccAccountGetGUID(X)
Definition: Account.h:252
GDate * qof_book_get_autoreadonly_gdate(const QofBook *book)
Returns the GDate that is the threshold for auto-read-only.
Definition: qofbook.cpp:988
Split * xaccSplitLookup(const GncGUID *guid, QofBook *book)
The xaccSplitLookup() subroutine will return the split associated with the given id, or NULL if there is no such split.
Definition: Split.cpp:1071
void gnc_table_refresh_gui(Table *table, gboolean do_scroll)
Refresh the whole GUI from the table.
Definition: table-gnome.c:165
Account handling public routines.
The ComboCell object implements a cell handler with a "combination-box" pull-down menu in it...
Definition: combocell.h:52
void gnc_doclink_cell_set_valid_flags(Doclinkcell *cell, const char *flags, char default_flag)
note that
Definition: doclinkcell.c:236
CursorClass
Types of cursors.
The PriceCell object implements a cell handler that stores a single double-precision value...
Definition: pricecell.h:54
const char * gnc_get_doclink_flag_order(void)
Get a string containing document link flag order.
#define CURSOR_HEADER
Standard Cursor Names.
Definition: table-layout.h:36
private declarations for SplitRegister
const char * xaccTransGetDescription(const Transaction *trans)
Gets the transaction Description.
time64 gdate_to_time64(GDate d)
Turns a GDate into a time64, returning the first second of the day.
Definition: gnc-date.cpp:1259
void gnc_table_set_vcell(Table *table, CellBlock *cursor, gconstpointer vcell_data, gboolean visible, gboolean start_primary_color, VirtualCellLocation vcell_loc)
Indicate what handler should be used for a given virtual block.
Definition: table-allgui.c:664
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
#define xaccSplitGetGUID(X)
Definition: Split.h:552
void xaccTransBeginEdit(Transaction *trans)
The xaccTransBeginEdit() method must be called before any changes are made to a transaction or any of...
API for checkbook register display area.
gnc_commodity * gnc_account_get_currency_or_parent(const Account *account)
Returns a gnc_commodity that is a currency, suitable for being a Transaction&#39;s currency.
Definition: Account.cpp:3378
Split * xaccMallocSplit(QofBook *book)
Constructor.
Definition: gmock-Split.cpp:37
#define xaccTransGetGUID(X)
Definition: Transaction.h:788
Generic api to store and retrieve preferences.
void gnc_completion_cell_add_menu_item(CompletionCell *cell, const char *menustr)
Add a menu item to the hash table list.
gnc_commodity * gnc_account_or_default_currency(const Account *account, gboolean *currency_from_account_found)
Returns a gnc_commodity that is a currency, suitable for being a Transaction&#39;s currency.
The NumCell object implements a number handling cell.
Definition: numcell.h:39
void gnc_price_cell_set_print_info(PriceCell *cell, GNCPrintAmountInfo print_info)
set the printing context of the price cell
Definition: pricecell.c:272
Account * xaccSplitGetAccount(const Split *split)
Returns the account of this split, which was set through xaccAccountInsertSplit().
Definition: gmock-Split.cpp:53
const GncGUID * guid_null(void)
Returns a GncGUID which is guaranteed to never reference any entity.
Definition: guid.cpp:130
gboolean xaccAccountGetPlaceholder(const Account *acc)
Get the "placeholder" flag for an account.
Definition: Account.cpp:4074
void gnc_table_set_virt_cell_cursor(Table *table, VirtualCellLocation vcell_loc, CellBlock *cursor)
Set the cellblock handler for a virtual cell.
Definition: table-allgui.c:737
time64 gnc_time64_get_today_end(void)
The gnc_time64_get_today_end() routine returns a time64 value corresponding to the last second of tod...
Definition: gnc-date.cpp:1362
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Get a boolean value from the preferences backend.
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
void gnc_combo_cell_use_quickfill_cache(ComboCell *cell, QuickFill *shared_qf)
Tell the combocell to use a shared QuickFill object.
const char * gnc_get_doclink_str(char link_flag)
Get a string representing the document link type.
const char * xaccSplitGetMemo(const Split *split)
Returns the memo string.
Definition: gmock-Split.cpp:99
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition: gnc-date.h:87
const char * gnc_get_doclink_valid_flags(void)
Get a string containing documentation link valid flags.
gboolean qof_book_uses_autoreadonly(const QofBook *book)
Returns TRUE if the auto-read-only feature should be used, otherwise FALSE.
Definition: qofbook.cpp:962
Account * gnc_account_get_root(Account *acc)
This routine returns the root account of the account tree that the specified account belongs to...
Definition: Account.cpp:2913
API for Transactions and Splits (journal entries)
Split * gnc_split_register_get_current_split(SplitRegister *reg)
Returns the split at which the cursor is currently located.
SplitList * xaccTransGetSplitList(const Transaction *trans)
The xaccTransGetSplitList() method returns a GList of the splits in a transaction.