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  gnc_quickfill_cell_add_completion (
276  (QuickFillCell*) gnc_table_layout_get_cell (layout, MEMO_CELL),
277  xaccSplitGetMemo (s));
278  }
279 }
280 
281 static Split*
282 create_blank_split (Account* default_account, SRInfo* info)
283 {
284  Transaction* new_trans;
285  gboolean currency_from_account = TRUE;
286  Split* blank_split = NULL;
287  /* Determine the proper currency to use for this transaction.
288  * if default_account != NULL and default_account->commodity is
289  * a currency, then use that. Otherwise use the default currency.
290  */
291  gnc_commodity* currency = gnc_account_or_default_currency (default_account,
292  &currency_from_account);
293 
294  if (default_account != NULL && !currency_from_account)
295  {
296  /* If we don't have a currency then pop up a warning dialog */
297  gnc_info_dialog (NULL, "%s",
298  _ ("Could not determine the account currency. "
299  "Using the default currency provided by your system."));
300  }
301 
302  gnc_suspend_gui_refresh();
303 
304  new_trans = xaccMallocTransaction (gnc_get_current_book());
305 
306  xaccTransBeginEdit (new_trans);
307  xaccTransSetCurrency (new_trans, currency);
308  xaccTransSetDatePostedSecsNormalized (new_trans, info->last_date_entered);
309  blank_split = xaccMallocSplit (gnc_get_current_book());
310  xaccSplitSetParent (blank_split, new_trans);
311  /* We don't want to commit this transaction yet, because the split
312  doesn't even belong to an account yet. But, we don't want to
313  set this transaction as the pending transaction either, because
314  we want to pretend that it hasn't been changed. We depend on
315  some other code (somewhere) to commit this transaction if we
316  really edit it, even though it's not marked as the pending
317  transaction. */
318 
319  info->blank_split_guid = *xaccSplitGetGUID (blank_split);
320  info->blank_split_edited = FALSE;
321  info->auto_complete = FALSE;
322  DEBUG ("created new blank_split=%p", blank_split);
323 
324  gnc_resume_gui_refresh();
325  return blank_split;
326 }
327 
328 static void
329 change_account_separator (SRInfo* info, Table* table, SplitRegister* reg)
330 {
331  info->separator_changed = FALSE;
332 
333  /* set the completion character for the xfer cells */
335  (ComboCell*) gnc_table_layout_get_cell (table->layout, MXFRM_CELL),
336  gnc_get_account_separator());
337 
339  (ComboCell*) gnc_table_layout_get_cell (table->layout, XFRM_CELL),
340  gnc_get_account_separator());
341 
342  /* set the confirmation callback for the reconcile cell */
343  gnc_recn_cell_set_confirm_cb (
344  (RecnCell*) gnc_table_layout_get_cell (table->layout, RECN_CELL),
345  gnc_split_register_recn_cell_confirm, reg);
346 }
347 
348 static void
349 update_info (SRInfo* info, SplitRegister* reg)
350 {
351  /* Set up the hint transaction, split, transaction split, and column. */
352  info->cursor_hint_trans = gnc_split_register_get_current_trans (reg);
353  info->cursor_hint_split = gnc_split_register_get_current_split (reg);
354  info->cursor_hint_trans_split =
356  info->cursor_hint_cursor_class =
358 
359  if (!info->first_pass && !info->quickfill_setup)
360  info->quickfill_setup = TRUE;
361 
362  info->hint_set_by_traverse = FALSE;
363  info->traverse_to_new = FALSE;
364  info->exact_traversal = FALSE;
365  info->first_pass = FALSE;
366  info->reg_loaded = TRUE;
367 }
368 
369 static void
370 add_completions_from_pre_filter_slist (TableLayout* layout, GList *pre_filter_slist,
371  gboolean first_pass, gboolean quickfill_setup,
372  gboolean has_last_num)
373 {
374  GList *node;
375 
376  for (node = pre_filter_slist; node; node = node->next)
377  {
378  Split *split = node->data;
379  Transaction *trans = xaccSplitGetParent (split);
380 
382  (CompletionCell*) gnc_table_layout_get_cell (layout, DESC_CELL),
383  xaccTransGetDescription (trans));
384 
385  if (!first_pass && !quickfill_setup)
386  add_quickfill_completions (layout, trans, split, has_last_num);
387  }
388 }
389 
390 void
391 gnc_split_register_load (SplitRegister* reg, GList* slist,
392  GList* pre_filter_slist, Account* default_account)
393 {
394  SRInfo* info;
395  Transaction* pending_trans;
396  CursorBuffer* cursor_buffer;
397  GHashTable* trans_table = NULL;
398  CellBlock* cursor_header;
399  CellBlock* lead_cursor;
400  CellBlock* split_cursor;
401  Transaction* blank_trans;
402  Transaction* find_trans;
403  Transaction* trans;
404  CursorClass find_class;
405  Split* find_trans_split;
406  Split* blank_split;
407  Split* find_split;
408  Split* split;
409  Table* table;
410  GList* node;
411  gnc_commodity *account_comm = NULL;
412 
413  gboolean start_primary_color = TRUE;
414  gboolean found_pending = FALSE;
415  gboolean need_divider_upper = FALSE;
416  gboolean found_divider_upper = FALSE;
417  gboolean found_divider = FALSE;
418  gboolean has_last_num = FALSE;
419  gboolean multi_line;
420  gboolean dynamic;
421  gboolean we_own_slist = FALSE;
422  gboolean use_autoreadonly = qof_book_uses_autoreadonly (
423  gnc_get_current_book());
424  gboolean future_after_blank = gnc_prefs_get_bool (
425  GNC_PREFS_GROUP_GENERAL_REGISTER,
426  GNC_PREF_FUTURE_AFTER_BLANK);
427  gboolean added_blank_trans = FALSE;
428 
429  VirtualCellLocation vcell_loc;
430  VirtualLocation save_loc;
431 
432  int new_trans_split_row = -1;
433  int new_trans_row = -1;
434  int new_split_row = -1;
435  time64 present, autoreadonly_time = 0;
436 
437  g_return_if_fail (reg);
438  table = reg->table;
439  g_return_if_fail (table);
440  info = gnc_split_register_get_info (reg);
441  g_return_if_fail (info);
442 
443  ENTER ("reg=%p, slist=%p, default_account=%p", reg, slist, default_account);
444 
445  blank_split = xaccSplitLookup (&info->blank_split_guid,
446  gnc_get_current_book());
447 
448  pending_trans = xaccTransLookup (&info->pending_trans_guid,
449  gnc_get_current_book());
450 
451  if (default_account)
452  account_comm = gnc_account_get_currency_or_parent (default_account);
453 
454  if (!account_comm)
455  account_comm = gnc_default_currency ();
456 
457  /* Bug 742089: Set the debit and credit cells' print_info to the account */
459  ((PriceCell*) gnc_table_layout_get_cell (table->layout, DEBT_CELL),
460  gnc_commodity_print_info (account_comm, FALSE));
461 
463  ((PriceCell*) gnc_table_layout_get_cell (table->layout, CRED_CELL),
464  gnc_commodity_print_info (account_comm, FALSE));
465 
467  ((PriceCell*) gnc_table_layout_get_cell (reg->table->layout, PRIC_CELL),
468  gnc_commodity_print_info (account_comm, FALSE));
469 
470  /* Only test for linked document glyths once */
471  if (info->first_pass)
472  {
473  gnc_doclink_cell_set_use_glyphs
474  ((Doclinkcell *) gnc_table_layout_get_cell (table->layout, DOCLINK_CELL));
475  }
476 
477  /* make sure we have a blank split */
478  if (blank_split == NULL)
479  {
480  /* Wouldn't it be a bug to open the new transaction if there was
481  * already a pending transaction?
482  */
483  g_assert (pending_trans == NULL);
484  blank_split = create_blank_split (default_account, info);
485  }
486  blank_trans = xaccSplitGetParent (blank_split);
487 
488  DEBUG ("blank_split=%p, blank_trans=%p, pending_trans=%p",
489  blank_split, blank_trans, pending_trans);
490 
491  info->default_account = *xaccAccountGetGUID (default_account);
492 
493  // gnc_table_leave_update (table, table->current_cursor_loc);
494 
495  multi_line = (reg->style == REG_STYLE_JOURNAL);
496  dynamic = (reg->style == REG_STYLE_AUTO_LEDGER);
497 
498  lead_cursor = gnc_split_register_get_passive_cursor (reg);
499  split_cursor = gnc_table_layout_get_cursor (table->layout, CURSOR_SPLIT);
500 
501  /* figure out where we are going to. */
502  if (info->traverse_to_new)
503  {
504  find_trans = blank_trans;
505  find_split = NULL;
506  find_trans_split = blank_split;
507  find_class = CURSOR_CLASS_SPLIT;
508  }
509  else
510  {
511  find_trans = info->cursor_hint_trans;
512  find_split = info->cursor_hint_split;
513  find_trans_split = info->cursor_hint_trans_split;
514  find_class = info->cursor_hint_cursor_class;
515  }
516 
517  save_loc = table->current_cursor_loc;
518 
519  /* If the current cursor has changed we save the values for later
520  * possible restoration. */
521  if (gnc_table_current_cursor_changed (table, TRUE) &&
522  (find_split == gnc_split_register_get_current_split (reg)))
523  {
524  cursor_buffer = gnc_cursor_buffer_new();
525  gnc_table_save_current_cursor (table, cursor_buffer);
526  }
527  else
528  cursor_buffer = NULL;
529 
530  /* disable move callback -- we don't want the cascade of
531  * callbacks while we are fiddling with loading the register */
532  gnc_table_control_allow_move (table->control, FALSE);
533 
534  /* invalidate the cursor */
535  {
536  VirtualLocation virt_loc;
537 
538  gnc_virtual_location_init (&virt_loc);
539  gnc_table_move_cursor_gui (table, virt_loc);
540  }
541 
542  /* make sure that the header is loaded */
543  vcell_loc.virt_row = 0;
544  vcell_loc.virt_col = 0;
545  cursor_header = gnc_table_layout_get_cursor (table->layout, CURSOR_HEADER);
546  gnc_table_set_vcell (table, cursor_header, NULL, TRUE, TRUE, vcell_loc);
547  vcell_loc.virt_row++;
548 
549  /* get the current time and reset the dividing row */
550  present = gnc_time64_get_today_end();
551  if (use_autoreadonly)
552  {
553  GDate* d = qof_book_get_autoreadonly_gdate (gnc_get_current_book());
554  // "d" is NULL if use_autoreadonly is FALSE
555  autoreadonly_time = d ? gdate_to_time64 (*d) : 0;
556  g_date_free (d);
557  }
558 
559  if (info->first_pass)
560  {
561  if (default_account)
562  {
563  const char* last_num = xaccAccountGetLastNum (default_account);
564 
565  if (last_num)
566  {
567  NumCell* cell;
568 
569  cell = (NumCell*) gnc_table_layout_get_cell (table->layout, NUM_CELL);
570  gnc_num_cell_set_last_num (cell, last_num);
571  has_last_num = TRUE;
572  }
573  }
574 
575  /* load up account names into the transfer combobox menus */
576  gnc_split_register_load_xfer_cells (reg, default_account);
577  gnc_split_register_load_desc_cells (reg);
578  gnc_split_register_load_doclink_cells (reg);
579  gnc_split_register_load_recn_cells (reg);
580  gnc_split_register_load_type_cells (reg);
581  }
582 
583  if (info->separator_changed)
584  change_account_separator (info, table, reg);
585 
586  table->model->dividing_row_upper = -1;
587  table->model->dividing_row = -1;
588  table->model->dividing_row_lower = -1;
589 
590  // Ensure that the transaction and splits being edited are in the split
591  // list we're about to load.
592  if (pending_trans != NULL)
593  {
594  for (node = xaccTransGetSplitList (pending_trans); node; node = node->next)
595  {
596  Split* pending_split = (Split*)node->data;
597  if (!xaccTransStillHasSplit (pending_trans, pending_split)) continue;
598  if (g_list_find (slist, pending_split) != NULL)
599  continue;
600 
601  if (g_list_find_custom (slist, pending_trans,
602  _find_split_with_parent_txn) != NULL)
603  continue;
604 
605  if (!we_own_slist)
606  {
607  // lazy-copy
608  slist = g_list_copy (slist);
609  we_own_slist = TRUE;
610  }
611  slist = g_list_append (slist, pending_split);
612  }
613  }
614 
615  if (multi_line)
616  trans_table = g_hash_table_new (g_direct_hash, g_direct_equal);
617 
618  // View reversed add blank transaction at the top
619  if (table->model->reverse_sort && !future_after_blank)
620  {
621  if (blank_trans == find_trans)
622  new_trans_row = vcell_loc.virt_row;
623 
624  if (blank_split == find_trans_split)
625  new_trans_split_row = vcell_loc.virt_row;
626 
627  /* go to blank on first pass */
628  if (info->first_pass)
629  {
630  save_loc.vcell_loc = vcell_loc;
631  save_loc.phys_row_offset = 0;
632  save_loc.phys_col_offset = 0;
633  }
634 
635  // used in the setting the rows insensitive
636  table->model->blank_trans_row = vcell_loc.virt_row;
637 
638  gnc_split_register_add_transaction (reg,
639  blank_trans, blank_split,
640  lead_cursor, split_cursor,
641  multi_line, start_primary_color,
642  info->blank_split_edited,
643  find_trans, find_split,
644  find_class, &new_split_row,
645  &vcell_loc);
646 
647  if (!multi_line)
648  start_primary_color = !start_primary_color;
649 
650  added_blank_trans = TRUE;
651  }
652 
653  gnc_completion_cell_clear_menu (
654  (CompletionCell*) gnc_table_layout_get_cell (reg->table->layout, DESC_CELL));
655 
657  (CompletionCell*) gnc_table_layout_get_cell (reg->table->layout, DESC_CELL),
658  table->model->reverse_sort);
659 
660  if (!info->first_pass && pre_filter_slist)
661  {
662  add_completions_from_pre_filter_slist (reg->table->layout, pre_filter_slist,
663  info->first_pass, info->quickfill_setup,
664  has_last_num);
665  }
666 
667  /* populate the table */
668  for (node = slist; node; node = node->next)
669  {
670  split = node->data;
671  trans = xaccSplitGetParent (split);
672 
673  if (!xaccTransStillHasSplit (trans, split))
674  continue;
675 
676  if (pending_trans == trans)
677  found_pending = TRUE;
678  /* If the transaction has only one split, and it's not our
679  * pending_trans, then it's another register's blank split and
680  * we don't want to see it.
681  */
682  else if (xaccTransCountSplits (trans) == 1 &&
683  xaccSplitGetAccount (split) == NULL)
684  continue;
685 
686  /* Do not load splits from the blank transaction. */
687  if (trans == blank_trans)
688  continue;
689 
690  if (multi_line)
691  {
692  /* Skip this split if its transaction has already been loaded. */
693  if (g_hash_table_lookup (trans_table, trans))
694  continue;
695 
696  g_hash_table_insert (trans_table, trans, trans);
697  }
698 
699  if (info->show_present_divider &&
700  use_autoreadonly &&
701  !found_divider_upper)
702  {
703  if (((table->model->reverse_sort && xaccTransGetDate(trans) < autoreadonly_time) ||
704  (!table->model->reverse_sort && xaccTransGetDate (trans) >= autoreadonly_time)))
705  {
706  table->model->dividing_row_upper = vcell_loc.virt_row;
707  found_divider_upper = TRUE;
708  }
709  else
710  {
711  need_divider_upper = TRUE;
712  }
713  }
714 
715  if (info->show_present_divider && !found_divider &&
716  ((table->model->reverse_sort && xaccTransGetDate (trans) < present) ||
717  (!table->model->reverse_sort && xaccTransGetDate (trans) > present)))
718  {
719  gint count_blank_splits = 1;
720  gint virt_row_offset = 2;
721  gboolean show_lower_divider = FALSE;
722 
723  if (table->model->reverse_sort)
724  {
725  count_blank_splits = xaccTransCountSplits (blank_trans);
726 
727  if (count_blank_splits > 1)
728  count_blank_splits ++;
729 
730  if (table->model->reverse_sort && future_after_blank)
731  virt_row_offset = 0;
732  }
733 
734  if ((table->model->reverse_sort && vcell_loc.virt_row != count_blank_splits + virt_row_offset) ||
735  !table->model->reverse_sort)
736  {
737  table->model->dividing_row = vcell_loc.virt_row; // blue top
738  show_lower_divider = TRUE;
739  }
740 
741  found_divider = TRUE;
742 
743  if (future_after_blank)
744  {
745  if (blank_trans == find_trans)
746  new_trans_row = vcell_loc.virt_row;
747 
748  if (blank_split == find_trans_split)
749  new_trans_split_row = vcell_loc.virt_row;
750 
751  /* go to blank on first pass */
752  if (info->first_pass)
753  {
754  save_loc.vcell_loc = vcell_loc;
755  save_loc.phys_row_offset = 0;
756  save_loc.phys_col_offset = 0;
757  }
758 
759  // used in the setting the rows insensitive
760  table->model->blank_trans_row = vcell_loc.virt_row;
761 
762  gnc_split_register_add_transaction (reg,
763  blank_trans, blank_split,
764  lead_cursor, split_cursor,
765  multi_line, start_primary_color,
766  info->blank_split_edited,
767  find_trans, find_split,
768  find_class, &new_split_row,
769  &vcell_loc);
770 
771 
772  if (show_lower_divider)
773  table->model->dividing_row_lower = vcell_loc.virt_row; // blue bottom
774 
775  if (!multi_line)
776  start_primary_color = !start_primary_color;
777 
778  added_blank_trans = TRUE;
779  }
780  }
781 
782  /* On first load the split list is empty so fill up the quickfill cells
783  * only on the next load. */
784  if (!info->first_pass && !pre_filter_slist && !info->quickfill_setup)
785  add_quickfill_completions (reg->table->layout, trans, split, has_last_num);
786 
787  if (!info->first_pass && !pre_filter_slist)
788  {
790  (CompletionCell*) gnc_table_layout_get_cell (reg->table->layout, DESC_CELL),
791  xaccTransGetDescription (trans));
792  }
793 
794  if (trans == find_trans)
795  new_trans_row = vcell_loc.virt_row;
796 
797  if (split == find_trans_split)
798  new_trans_split_row = vcell_loc.virt_row;
799 
800  gnc_split_register_add_transaction (reg, trans, split,
801  lead_cursor, split_cursor,
802  multi_line, start_primary_color,
803  TRUE,
804  find_trans, find_split, find_class,
805  &new_split_row, &vcell_loc);
806 
807  if (!multi_line)
808  start_primary_color = !start_primary_color;
809  }
810 
811  if (multi_line)
812  g_hash_table_destroy (trans_table);
813 
814  /* add the blank split at the end. */
815  if (pending_trans == blank_trans)
816  found_pending = TRUE;
817 
818  /* No upper divider yet? Store it now */
819  if (info->show_present_divider &&
820  use_autoreadonly &&
821  !found_divider_upper && need_divider_upper)
822  {
823  table->model->dividing_row_upper = vcell_loc.virt_row;
824  }
825 
826  /* If we didn't find the pending transaction, it was removed
827  * from the account. */
828  if (!found_pending)
829  {
830  info->pending_trans_guid = *guid_null();
831  if (xaccTransIsOpen (pending_trans))
832  xaccTransCommitEdit (pending_trans);
833  else if (pending_trans)
834  g_assert_not_reached();
835 
836  pending_trans = NULL;
837  }
838 
839  if (!added_blank_trans)
840  {
841  if (blank_trans == find_trans)
842  new_trans_row = vcell_loc.virt_row;
843 
844  if (blank_split == find_trans_split)
845  new_trans_split_row = vcell_loc.virt_row;
846 
847  /* go to blank on first pass */
848  if (info->first_pass)
849  {
850  save_loc.vcell_loc = vcell_loc;
851  save_loc.phys_row_offset = 0;
852  save_loc.phys_col_offset = 0;
853  }
854 
855  // used in the setting the rows insensitive
856  table->model->blank_trans_row = vcell_loc.virt_row;
857 
858  gnc_split_register_add_transaction (reg, blank_trans, blank_split,
859  lead_cursor, split_cursor,
860  multi_line, start_primary_color,
861  info->blank_split_edited,
862  find_trans, find_split,
863  find_class, &new_split_row,
864  &vcell_loc);
865 
866  if (future_after_blank)
867  {
868  table->model->dividing_row_lower = vcell_loc.virt_row;
869  }
870  }
871 
872  /* go to blank on first pass */
873  if (info->first_pass)
874  {
875  new_split_row = -1;
876  new_trans_split_row = -1;
877  new_trans_row = -1;
878  }
879 
880  /* resize the table to the sizes we just counted above */
881  /* num_virt_cols is always one. */
882  gnc_table_set_size (table, vcell_loc.virt_row, 1);
883 
884  /* restore the cursor to its rightful position */
885  {
886  VirtualLocation trans_split_loc;
887 
888  if (new_split_row > 0)
889  save_loc.vcell_loc.virt_row = new_split_row;
890  else if (new_trans_split_row > 0)
891  save_loc.vcell_loc.virt_row = new_trans_split_row;
892  else if (new_trans_row > 0)
893  save_loc.vcell_loc.virt_row = new_trans_row;
894 
895  trans_split_loc = save_loc;
896 
897  gnc_split_register_get_trans_split (reg, save_loc.vcell_loc,
898  &trans_split_loc.vcell_loc);
899 
900  if (dynamic || multi_line || info->trans_expanded)
901  {
903  table, trans_split_loc.vcell_loc,
904  gnc_split_register_get_active_cursor (reg));
905  gnc_split_register_set_trans_visible (reg, trans_split_loc.vcell_loc,
906  TRUE, multi_line);
907 
908  info->trans_expanded = (reg->style == REG_STYLE_LEDGER);
909  }
910  else
911  {
912  save_loc = trans_split_loc;
913  info->trans_expanded = FALSE;
914  }
915 
916  if (gnc_table_find_close_valid_cell (table, &save_loc, FALSE))
917  {
918  gnc_table_move_cursor_gui (table, save_loc);
919  new_split_row = save_loc.vcell_loc.virt_row;
920 
921  if (find_split == gnc_split_register_get_current_split (reg))
922  gnc_table_restore_current_cursor (table, cursor_buffer);
923  }
924  }
925  gnc_cursor_buffer_destroy (cursor_buffer);
926  cursor_buffer = NULL;
927 
928  update_info (info, reg);
929 
930  gnc_split_register_set_cell_fractions (
932 
934 
935  // if in reverse order, always show the first transaction
936  if (table->model->reverse_sort)
937  {
938  VirtualCellLocation vc_loc;
939  vc_loc.virt_row = 0;
940  vc_loc.virt_col = 0;
941  gnc_split_register_show_trans (reg, vc_loc);
942  }
943  else
944  gnc_split_register_show_trans (reg, table->current_cursor_loc.vcell_loc);
945 
946  /* enable callback for cursor user-driven moves */
947  gnc_table_control_allow_move (table->control, TRUE);
948 
949  if (we_own_slist)
950  g_list_free (slist);
951 
952  LEAVE (" ");
953 }
954 
955 /* ===================================================================== */
956 
957 #define QKEY "split_reg_shared_quickfill"
958 
959 static gboolean
960 skip_cb (Account* account, gpointer x)
961 {
962  /* commented out as per Bug#340885 Comments 1 and 2, option (2).
963  if (xaccAccountIsHidden(account))
964  return TRUE;
965  */
966  return xaccAccountGetPlaceholder (account);
967 }
968 
969 static void
970 gnc_split_register_load_xfer_cells (SplitRegister* reg, Account* base_account)
971 {
972  Account* root = NULL;
973  QuickFill* qf;
974  ComboCell* cell;
975  GtkListStore* store;
976 
977  if (base_account)
978  root = gnc_account_get_root (base_account);
979  if (root == NULL)
980  root = gnc_get_current_root_account();
981  if (root == NULL)
982  return;
983 
984  qf = gnc_get_shared_account_name_quickfill (root, QKEY, skip_cb, NULL);
985  store = gnc_get_shared_account_name_list_store (root, QKEY, skip_cb, NULL);
986 
987  cell = (ComboCell*)
988  gnc_table_layout_get_cell (reg->table->layout, XFRM_CELL);
990  gnc_combo_cell_use_list_store_cache (cell, store);
991 
992  cell = (ComboCell*)
993  gnc_table_layout_get_cell (reg->table->layout, MXFRM_CELL);
995  gnc_combo_cell_use_list_store_cache (cell, store);
996 }
997 
998 /* ====================== 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:4861
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:248
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:1070
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:1252
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:3420
Split * xaccMallocSplit(QofBook *book)
Constructor.
Definition: gmock-Split.cpp:37
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:4195
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:1355
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:2884
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.