GnuCash  4.14+
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 "gnc-component-manager.h"
36 #include "qof.h"
37 #include "gnc-ui-util.h"
38 #include "gnc-gui-query.h"
39 #include "numcell.h"
40 #include "quickfillcell.h"
41 #include "doclinkcell.h"
42 #include "recncell.h"
43 #include "split-register.h"
44 #include "split-register-p.h"
45 #include "engine-helpers.h"
46 #include "gnc-prefs.h"
47 #include "pricecell.h"
48 
49 
50 /* This static indicates the debugging module that this .o belongs to. */
51 static QofLogModule log_module = GNC_MOD_LEDGER;
52 
53 
54 static void gnc_split_register_load_xfer_cells (SplitRegister* reg,
55  Account* base_account);
56 
57 static void
58 gnc_split_register_load_recn_cells (SplitRegister* reg)
59 {
60  RecnCell* cell;
61  const char* s;
62 
63  if (!reg) return;
64 
65  cell = (RecnCell*)
66  gnc_table_layout_get_cell (reg->table->layout, RECN_CELL);
67 
68  if (!cell) return;
69 
70  s = gnc_get_reconcile_valid_flags();
71  gnc_recn_cell_set_valid_flags (cell, s, *s);
72  gnc_recn_cell_set_flag_order (cell, gnc_get_reconcile_flag_order());
73  gnc_recn_cell_set_string_getter (cell, gnc_get_reconcile_str);
74 }
75 
76 static void
77 gnc_split_register_load_doclink_cells (SplitRegister* reg)
78 {
79  Doclinkcell *cell;
80  const char * s;
81 
82  if (!reg) return;
83 
84  cell = (Doclinkcell *)
85  gnc_table_layout_get_cell (reg->table->layout, DOCLINK_CELL);
86 
87  if (!cell) return;
88 
89  /* FIXME: These should get moved to an i18n function */
91  gnc_doclink_cell_set_valid_flags (cell, s, ' ');
92  gnc_doclink_cell_set_flag_order (cell, gnc_get_doclink_flag_order ());
93  gnc_doclink_cell_set_string_getter (cell, gnc_get_doclink_str);
94  gnc_doclink_cell_set_read_only (cell, TRUE);
95 }
96 
97 static void
98 gnc_split_register_load_type_cells (SplitRegister* reg)
99 {
100  RecnCell* cell;
101 
102  if (!reg) return;
103 
104  cell = (RecnCell*)
105  gnc_table_layout_get_cell (reg->table->layout, TYPE_CELL);
106 
107  if (!cell) return;
108 
109  /* FIXME: These should get moved to an i18n function */
110  gnc_recn_cell_set_valid_flags (cell, "IP?", 'I');
111  gnc_recn_cell_set_flag_order (cell, "IP");
112  gnc_recn_cell_set_read_only (cell, TRUE);
113 }
114 
177 static void
178 gnc_split_register_add_transaction (SplitRegister* reg,
179  Transaction* trans,
180  Split* split,
181  CellBlock* lead_cursor,
182  CellBlock* split_cursor,
183  gboolean visible_splits,
184  gboolean start_primary_color,
185  gboolean add_empty,
186  Transaction* find_trans,
187  Split* find_split,
188  CursorClass find_class,
189  int* new_split_row,
190  VirtualCellLocation* vcell_loc)
191 {
192  GList* node;
193 
194  g_return_if_fail (reg);
195  g_return_if_fail (vcell_loc);
196 
197  if (split == find_split)
198  *new_split_row = vcell_loc->virt_row;
199 
200  /* Set the "leading" virtual cell. */
201  gnc_table_set_vcell (reg->table, lead_cursor, xaccSplitGetGUID (split),
202  TRUE, start_primary_color, *vcell_loc);
203  vcell_loc->virt_row++;
204 
205  /* Continue setting up virtual cells in a column, using a row for each
206  * split in the transaction. */
207  for (node = xaccTransGetSplitList (trans); node; node = node->next)
208  {
209  Split* secondary = node->data;
210 
211  if (!xaccTransStillHasSplit (trans, secondary)) continue;
212  if (secondary == find_split && find_class == CURSOR_CLASS_SPLIT)
213  *new_split_row = vcell_loc->virt_row;
214 
215  gnc_table_set_vcell (reg->table, split_cursor,
216  xaccSplitGetGUID (secondary),
217  visible_splits, TRUE, *vcell_loc);
218  vcell_loc->virt_row++;
219  }
220 
221  /* If requested, add an empty split row at the end. */
222  if (add_empty)
223  {
224  if (find_trans == trans && find_split == NULL &&
225  find_class == CURSOR_CLASS_SPLIT)
226  *new_split_row = vcell_loc->virt_row;
227 
228  gnc_table_set_vcell (reg->table, split_cursor, xaccSplitGetGUID (NULL),
229  FALSE, TRUE, *vcell_loc);
230  vcell_loc->virt_row++;
231  }
232 }
233 
234 static gint
235 _find_split_with_parent_txn (gconstpointer a, gconstpointer b)
236 {
237  Split* split = (Split*)a;
238  Transaction* txn = (Transaction*)b;
239 
240  return xaccSplitGetParent (split) == txn ? 0 : 1;
241 }
242 
243 static void add_quickfill_completions (TableLayout* layout, Transaction* trans,
244  Split* split, gboolean has_last_num)
245 {
246  gnc_quickfill_cell_add_completion (
247  (QuickFillCell*) gnc_table_layout_get_cell (layout, DESC_CELL),
248  xaccTransGetDescription (trans));
249 
250  gnc_quickfill_cell_add_completion (
251  (QuickFillCell*) gnc_table_layout_get_cell (layout, NOTES_CELL),
252  xaccTransGetNotes (trans));
253 
254  if (!has_last_num)
255  gnc_num_cell_set_last_num (
256  (NumCell*) gnc_table_layout_get_cell (layout, NUM_CELL),
257  gnc_get_num_action (trans, split));
258 
259  for (GList *n = xaccTransGetSplitList (trans); n; n = n->next)
260  {
261  Split *s = n->data;
262  gnc_quickfill_cell_add_completion (
263  (QuickFillCell*) gnc_table_layout_get_cell (layout, MEMO_CELL),
264  xaccSplitGetMemo (s));
265  }
266 }
267 
268 static Split*
269 create_blank_split (Account* default_account, SRInfo* info)
270 {
271  Transaction* new_trans;
272  gboolean currency_from_account = TRUE;
273  Split* blank_split = NULL;
274  /* Determine the proper currency to use for this transaction.
275  * if default_account != NULL and default_account->commodity is
276  * a currency, then use that. Otherwise use the default currency.
277  */
278  gnc_commodity* currency = gnc_account_or_default_currency (default_account,
279  &currency_from_account);
280 
281  if (default_account != NULL && !currency_from_account)
282  {
283  /* If we don't have a currency then pop up a warning dialog */
284  gnc_info_dialog (NULL, "%s",
285  _ ("Could not determine the account currency. "
286  "Using the default currency provided by your system."));
287  }
288 
289  gnc_suspend_gui_refresh();
290 
291  new_trans = xaccMallocTransaction (gnc_get_current_book());
292 
293  xaccTransBeginEdit (new_trans);
294  xaccTransSetCurrency (new_trans, currency);
295  xaccTransSetDatePostedSecsNormalized (new_trans, info->last_date_entered);
296  blank_split = xaccMallocSplit (gnc_get_current_book());
297  xaccSplitSetParent (blank_split, new_trans);
298  /* We don't want to commit this transaction yet, because the split
299  doesn't even belong to an account yet. But, we don't want to
300  set this transaction as the pending transaction either, because
301  we want to pretend that it hasn't been changed. We depend on
302  some other code (somewhere) to commit this transaction if we
303  really edit it, even though it's not marked as the pending
304  transaction. */
305 
306  info->blank_split_guid = *xaccSplitGetGUID (blank_split);
307  info->blank_split_edited = FALSE;
308  info->auto_complete = FALSE;
309  DEBUG ("created new blank_split=%p", blank_split);
310 
311  gnc_resume_gui_refresh();
312  return blank_split;
313 }
314 
315 static void
316 change_account_separator (SRInfo* info, Table* table, SplitRegister* reg)
317 {
318  info->separator_changed = FALSE;
319 
320  /* set the completion character for the xfer cells */
322  (ComboCell*) gnc_table_layout_get_cell (table->layout, MXFRM_CELL),
323  gnc_get_account_separator());
324 
326  (ComboCell*) gnc_table_layout_get_cell (table->layout, XFRM_CELL),
327  gnc_get_account_separator());
328 
329  /* set the confirmation callback for the reconcile cell */
330  gnc_recn_cell_set_confirm_cb (
331  (RecnCell*) gnc_table_layout_get_cell (table->layout, RECN_CELL),
332  gnc_split_register_recn_cell_confirm, reg);
333 }
334 
335 static void
336 update_info (SRInfo* info, SplitRegister* reg)
337 {
338  /* Set up the hint transaction, split, transaction split, and column. */
339  info->cursor_hint_trans = gnc_split_register_get_current_trans (reg);
340  info->cursor_hint_split = gnc_split_register_get_current_split (reg);
341  info->cursor_hint_trans_split =
343  info->cursor_hint_cursor_class =
345  info->hint_set_by_traverse = FALSE;
346  info->traverse_to_new = FALSE;
347  info->exact_traversal = FALSE;
348  info->first_pass = FALSE;
349  info->reg_loaded = TRUE;
350 }
351 
352 void
353 gnc_split_register_load (SplitRegister* reg, GList* slist,
354  Account* default_account)
355 {
356  SRInfo* info;
357  Transaction* pending_trans;
358  CursorBuffer* cursor_buffer;
359  GHashTable* trans_table = NULL;
360  CellBlock* cursor_header;
361  CellBlock* lead_cursor;
362  CellBlock* split_cursor;
363  Transaction* blank_trans;
364  Transaction* find_trans;
365  Transaction* trans;
366  CursorClass find_class;
367  Split* find_trans_split;
368  Split* blank_split;
369  Split* find_split;
370  Split* split;
371  Table* table;
372  GList* node;
373  gnc_commodity *account_comm = NULL;
374 
375  gboolean start_primary_color = TRUE;
376  gboolean found_pending = FALSE;
377  gboolean need_divider_upper = FALSE;
378  gboolean found_divider_upper = FALSE;
379  gboolean found_divider = FALSE;
380  gboolean has_last_num = FALSE;
381  gboolean multi_line;
382  gboolean dynamic;
383  gboolean we_own_slist = FALSE;
384  gboolean use_autoreadonly = qof_book_uses_autoreadonly (
385  gnc_get_current_book());
386  gboolean future_after_blank = gnc_prefs_get_bool (
387  GNC_PREFS_GROUP_GENERAL_REGISTER,
388  GNC_PREF_FUTURE_AFTER_BLANK);
389  gboolean added_blank_trans = FALSE;
390 
391  VirtualCellLocation vcell_loc;
392  VirtualLocation save_loc;
393 
394  int new_trans_split_row = -1;
395  int new_trans_row = -1;
396  int new_split_row = -1;
397  time64 present, autoreadonly_time = 0;
398 
399  g_return_if_fail (reg);
400  table = reg->table;
401  g_return_if_fail (table);
402  info = gnc_split_register_get_info (reg);
403  g_return_if_fail (info);
404 
405  ENTER ("reg=%p, slist=%p, default_account=%p", reg, slist, default_account);
406 
407  blank_split = xaccSplitLookup (&info->blank_split_guid,
408  gnc_get_current_book());
409 
410  pending_trans = xaccTransLookup (&info->pending_trans_guid,
411  gnc_get_current_book());
412 
413  if (default_account)
414  account_comm = gnc_account_get_currency_or_parent (default_account);
415 
416  if (!account_comm)
417  account_comm = gnc_default_currency ();
418 
419  /* Bug 742089: Set the debit and credit cells' print_info to the account */
421  ((PriceCell*) gnc_table_layout_get_cell (table->layout, DEBT_CELL),
422  gnc_commodity_print_info (account_comm, FALSE));
423 
425  ((PriceCell*) gnc_table_layout_get_cell (table->layout, CRED_CELL),
426  gnc_commodity_print_info (account_comm, FALSE));
427 
429  ((PriceCell*) gnc_table_layout_get_cell (reg->table->layout, PRIC_CELL),
430  gnc_commodity_print_info (account_comm, FALSE));
431 
432  gnc_doclink_cell_set_use_glyphs
433  ((Doclinkcell *) gnc_table_layout_get_cell (table->layout, DOCLINK_CELL));
434 
435  /* make sure we have a blank split */
436  if (blank_split == NULL)
437  {
438  /* Wouldn't it be a bug to open the new transaction if there was
439  * already a pending transaction?
440  */
441  g_assert (pending_trans == NULL);
442  blank_split = create_blank_split (default_account, info);
443  }
444  blank_trans = xaccSplitGetParent (blank_split);
445 
446  DEBUG ("blank_split=%p, blank_trans=%p, pending_trans=%p",
447  blank_split, blank_trans, pending_trans);
448 
449  info->default_account = *xaccAccountGetGUID (default_account);
450 
451  // gnc_table_leave_update (table, table->current_cursor_loc);
452 
453  multi_line = (reg->style == REG_STYLE_JOURNAL);
454  dynamic = (reg->style == REG_STYLE_AUTO_LEDGER);
455 
456  lead_cursor = gnc_split_register_get_passive_cursor (reg);
457  split_cursor = gnc_table_layout_get_cursor (table->layout, CURSOR_SPLIT);
458 
459  /* figure out where we are going to. */
460  if (info->traverse_to_new)
461  {
462  find_trans = blank_trans;
463  find_split = NULL;
464  find_trans_split = blank_split;
465  find_class = CURSOR_CLASS_SPLIT;
466  }
467  else
468  {
469  find_trans = info->cursor_hint_trans;
470  find_split = info->cursor_hint_split;
471  find_trans_split = info->cursor_hint_trans_split;
472  find_class = info->cursor_hint_cursor_class;
473  }
474 
475  save_loc = table->current_cursor_loc;
476 
477  /* If the current cursor has changed we save the values for later
478  * possible restoration. */
479  if (gnc_table_current_cursor_changed (table, TRUE) &&
480  (find_split == gnc_split_register_get_current_split (reg)))
481  {
482  cursor_buffer = gnc_cursor_buffer_new();
483  gnc_table_save_current_cursor (table, cursor_buffer);
484  }
485  else
486  cursor_buffer = NULL;
487 
488  /* disable move callback -- we don't want the cascade of
489  * callbacks while we are fiddling with loading the register */
490  gnc_table_control_allow_move (table->control, FALSE);
491 
492  /* invalidate the cursor */
493  {
494  VirtualLocation virt_loc;
495 
496  gnc_virtual_location_init (&virt_loc);
497  gnc_table_move_cursor_gui (table, virt_loc);
498  }
499 
500  /* make sure that the header is loaded */
501  vcell_loc.virt_row = 0;
502  vcell_loc.virt_col = 0;
503  cursor_header = gnc_table_layout_get_cursor (table->layout, CURSOR_HEADER);
504  gnc_table_set_vcell (table, cursor_header, NULL, TRUE, TRUE, vcell_loc);
505  vcell_loc.virt_row++;
506 
507  /* get the current time and reset the dividing row */
508  present = gnc_time64_get_today_end();
509  if (use_autoreadonly)
510  {
511  GDate* d = qof_book_get_autoreadonly_gdate (gnc_get_current_book());
512  // "d" is NULL if use_autoreadonly is FALSE
513  autoreadonly_time = d ? gdate_to_time64 (*d) : 0;
514  g_date_free (d);
515  }
516 
517  if (info->first_pass)
518  {
519  if (default_account)
520  {
521  const char* last_num = xaccAccountGetLastNum (default_account);
522 
523  if (last_num)
524  {
525  NumCell* cell;
526 
527  cell = (NumCell*) gnc_table_layout_get_cell (table->layout, NUM_CELL);
528  gnc_num_cell_set_last_num (cell, last_num);
529  has_last_num = TRUE;
530  }
531  }
532 
533  /* load up account names into the transfer combobox menus */
534  gnc_split_register_load_xfer_cells (reg, default_account);
535  gnc_split_register_load_doclink_cells (reg);
536  gnc_split_register_load_recn_cells (reg);
537  gnc_split_register_load_type_cells (reg);
538  }
539 
540  if (info->separator_changed)
541  change_account_separator (info, table, reg);
542 
543  table->model->dividing_row_upper = -1;
544  table->model->dividing_row = -1;
545  table->model->dividing_row_lower = -1;
546 
547  // Ensure that the transaction and splits being edited are in the split
548  // list we're about to load.
549  if (pending_trans != NULL)
550  {
551  for (node = xaccTransGetSplitList (pending_trans); node; node = node->next)
552  {
553  Split* pending_split = (Split*)node->data;
554  if (!xaccTransStillHasSplit (pending_trans, pending_split)) continue;
555  if (g_list_find (slist, pending_split) != NULL)
556  continue;
557 
558  if (g_list_find_custom (slist, pending_trans,
559  _find_split_with_parent_txn) != NULL)
560  continue;
561 
562  if (!we_own_slist)
563  {
564  // lazy-copy
565  slist = g_list_copy (slist);
566  we_own_slist = TRUE;
567  }
568  slist = g_list_append (slist, pending_split);
569  }
570  }
571 
572  if (multi_line)
573  trans_table = g_hash_table_new (g_direct_hash, g_direct_equal);
574 
575  /* populate the table */
576  for (node = slist; node; node = node->next)
577  {
578  split = node->data;
579  trans = xaccSplitGetParent (split);
580 
581  if (!xaccTransStillHasSplit (trans, split))
582  continue;
583 
584  if (pending_trans == trans)
585  found_pending = TRUE;
586  /* If the transaction has only one split, and it's not our
587  * pending_trans, then it's another register's blank split and
588  * we don't want to see it.
589  */
590  else if (xaccTransCountSplits (trans) == 1 &&
591  xaccSplitGetAccount (split) == NULL)
592  continue;
593 
594 
595  /* Do not load splits from the blank transaction. */
596  if (trans == blank_trans)
597  continue;
598 
599  if (multi_line)
600  {
601  /* Skip this split if its transaction has already been loaded. */
602  if (g_hash_table_lookup (trans_table, trans))
603  continue;
604 
605  g_hash_table_insert (trans_table, trans, trans);
606  }
607 
608  if (info->show_present_divider &&
609  use_autoreadonly &&
610  !found_divider_upper)
611  {
612  if (((table->model->reverse_sort && xaccTransGetDate(trans) < autoreadonly_time) ||
613  (!table->model->reverse_sort && xaccTransGetDate (trans) >= autoreadonly_time)))
614  {
615  table->model->dividing_row_upper = vcell_loc.virt_row;
616  found_divider_upper = TRUE;
617  }
618  else
619  {
620  need_divider_upper = TRUE;
621  }
622  }
623 
624  if (info->show_present_divider && !found_divider &&
625  ((table->model->reverse_sort && xaccTransGetDate (trans) < present) ||
626  (!table->model->reverse_sort && xaccTransGetDate (trans) > present)))
627  {
628  table->model->dividing_row = vcell_loc.virt_row;
629  found_divider = TRUE;
630 
631  if (future_after_blank)
632  {
633  if (blank_trans == find_trans)
634  new_trans_row = vcell_loc.virt_row;
635 
636  if (blank_split == find_trans_split)
637  new_trans_split_row = vcell_loc.virt_row;
638 
639  /* go to blank on first pass */
640  if (info->first_pass)
641  {
642  save_loc.vcell_loc = vcell_loc;
643  save_loc.phys_row_offset = 0;
644  save_loc.phys_col_offset = 0;
645  }
646 
647  // used in the setting the rows insensitive
648  table->model->blank_trans_row = vcell_loc.virt_row;
649 
650  gnc_split_register_add_transaction (reg,
651  blank_trans, blank_split,
652  lead_cursor, split_cursor,
653  multi_line, start_primary_color,
654  info->blank_split_edited,
655  find_trans, find_split,
656  find_class, &new_split_row,
657  &vcell_loc);
658 
659  table->model->dividing_row_lower = vcell_loc.virt_row;
660  if (!multi_line)
661  start_primary_color = !start_primary_color;
662 
663  added_blank_trans = TRUE;
664  }
665  }
666 
667  /* If this is the first load of the register,
668  * fill up the quickfill cells. */
669  if (info->first_pass)
670  add_quickfill_completions (reg->table->layout, trans, split, has_last_num);
671 
672  if (trans == find_trans)
673  new_trans_row = vcell_loc.virt_row;
674 
675  if (split == find_trans_split)
676  new_trans_split_row = vcell_loc.virt_row;
677 
678  gnc_split_register_add_transaction (reg, trans, split,
679  lead_cursor, split_cursor,
680  multi_line, start_primary_color,
681  TRUE,
682  find_trans, find_split, find_class,
683  &new_split_row, &vcell_loc);
684 
685  if (!multi_line)
686  start_primary_color = !start_primary_color;
687  }
688 
689  if (multi_line)
690  g_hash_table_destroy (trans_table);
691 
692  /* add the blank split at the end. */
693  if (pending_trans == blank_trans)
694  found_pending = TRUE;
695 
696  /* No upper divider yet? Store it now */
697  if (info->show_present_divider &&
698  use_autoreadonly &&
699  !found_divider_upper && need_divider_upper)
700  {
701  table->model->dividing_row_upper = vcell_loc.virt_row;
702  }
703 
704  /* If we didn't find the pending transaction, it was removed
705  * from the account. */
706  if (!found_pending)
707  {
708  info->pending_trans_guid = *guid_null();
709  if (xaccTransIsOpen (pending_trans))
710  xaccTransCommitEdit (pending_trans);
711  else if (pending_trans)
712  g_assert_not_reached();
713 
714  pending_trans = NULL;
715  }
716 
717  if (!added_blank_trans) {
718  if (blank_trans == find_trans)
719  new_trans_row = vcell_loc.virt_row;
720 
721  if (blank_split == find_trans_split)
722  new_trans_split_row = vcell_loc.virt_row;
723 
724  /* go to blank on first pass */
725  if (info->first_pass)
726  {
727  save_loc.vcell_loc = vcell_loc;
728  save_loc.phys_row_offset = 0;
729  save_loc.phys_col_offset = 0;
730  }
731 
732  // used in the setting the rows insensitive
733  table->model->blank_trans_row = vcell_loc.virt_row;
734 
735  gnc_split_register_add_transaction (reg, blank_trans, blank_split,
736  lead_cursor, split_cursor,
737  multi_line, start_primary_color,
738  info->blank_split_edited,
739  find_trans, find_split,
740  find_class, &new_split_row,
741  &vcell_loc);
742 
743  if (future_after_blank)
744  {
745  table->model->dividing_row_lower = vcell_loc.virt_row;
746  }
747  }
748 
749  /* go to blank on first pass */
750  if (info->first_pass)
751  {
752  new_split_row = -1;
753  new_trans_split_row = -1;
754  new_trans_row = -1;
755  }
756 
757  /* resize the table to the sizes we just counted above */
758  /* num_virt_cols is always one. */
759  gnc_table_set_size (table, vcell_loc.virt_row, 1);
760 
761  /* restore the cursor to its rightful position */
762  {
763  VirtualLocation trans_split_loc;
764 
765  if (new_split_row > 0)
766  save_loc.vcell_loc.virt_row = new_split_row;
767  else if (new_trans_split_row > 0)
768  save_loc.vcell_loc.virt_row = new_trans_split_row;
769  else if (new_trans_row > 0)
770  save_loc.vcell_loc.virt_row = new_trans_row;
771 
772  trans_split_loc = save_loc;
773 
774  gnc_split_register_get_trans_split (reg, save_loc.vcell_loc,
775  &trans_split_loc.vcell_loc);
776 
777  if (dynamic || multi_line || info->trans_expanded)
778  {
780  table, trans_split_loc.vcell_loc,
781  gnc_split_register_get_active_cursor (reg));
782  gnc_split_register_set_trans_visible (reg, trans_split_loc.vcell_loc,
783  TRUE, multi_line);
784 
785  info->trans_expanded = (reg->style == REG_STYLE_LEDGER);
786  }
787  else
788  {
789  save_loc = trans_split_loc;
790  info->trans_expanded = FALSE;
791  }
792 
793  if (gnc_table_find_close_valid_cell (table, &save_loc, FALSE))
794  {
795  gnc_table_move_cursor_gui (table, save_loc);
796  new_split_row = save_loc.vcell_loc.virt_row;
797 
798  if (find_split == gnc_split_register_get_current_split (reg))
799  gnc_table_restore_current_cursor (table, cursor_buffer);
800  }
801  }
802  gnc_cursor_buffer_destroy (cursor_buffer);
803  cursor_buffer = NULL;
804 
805  update_info (info, reg);
806 
807  gnc_split_register_set_cell_fractions (
809 
811 
812  gnc_split_register_show_trans (reg, table->current_cursor_loc.vcell_loc);
813 
814  /* enable callback for cursor user-driven moves */
815  gnc_table_control_allow_move (table->control, TRUE);
816 
817  if (we_own_slist)
818  g_list_free (slist);
819 
820  LEAVE (" ");
821 }
822 
823 /* ===================================================================== */
824 
825 #define QKEY "split_reg_shared_quickfill"
826 
827 static gboolean
828 skip_cb (Account* account, gpointer x)
829 {
830  /* commented out as per Bug#340885 Comments 1 and 2, option (2).
831  if (xaccAccountIsHidden(account))
832  return TRUE;
833  */
834  return xaccAccountGetPlaceholder (account);
835 }
836 
837 static void
838 gnc_split_register_load_xfer_cells (SplitRegister* reg, Account* base_account)
839 {
840  Account* root = NULL;
841  QuickFill* qf;
842  ComboCell* cell;
843  GtkListStore* store;
844 
845  if (base_account)
846  root = gnc_account_get_root (base_account);
847  if (root == NULL)
848  root = gnc_get_current_root_account();
849  if (root == NULL)
850  return;
851 
852  qf = gnc_get_shared_account_name_quickfill (root, QKEY, skip_cb, NULL);
853  store = gnc_get_shared_account_name_list_store (root, QKEY, skip_cb, NULL);
854 
855  cell = (ComboCell*)
856  gnc_table_layout_get_cell (reg->table->layout, XFRM_CELL);
858  gnc_combo_cell_use_list_store_cache (cell, store);
859 
860  cell = (ComboCell*)
861  gnc_table_layout_get_cell (reg->table->layout, MXFRM_CELL);
863  gnc_combo_cell_use_list_store_cache (cell, store);
864 }
865 
866 /* ====================== 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.
Definition: Transaction.c:503
const char * xaccAccountGetLastNum(const Account *acc)
Get the last num field of an Account.
Definition: Account.cpp:4939
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_split_register_load(SplitRegister *reg, GList *slist, Account *default_account)
Populates the rows of a register.
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...
#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
#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.
Definition: Transaction.c:1409
gnc_commodity * gnc_default_currency(void)
Return the default currency set by the user.
Definition: gnc-ui-util.c:1204
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...
Definition: Transaction.c:1026
int xaccTransCountSplits(const Transaction *trans)
Returns the number of splits in this transaction.
Definition: Transaction.c:2362
#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:1114
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.c:1074
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:48
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:50
const char * gnc_get_doclink_flag_order(void)
Get a string containing document link flag order.
Definition: gnc-ui-util.c:942
#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:1257
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:554
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:3461
Split * xaccMallocSplit(QofBook *book)
Constructor.
Definition: gmock-Split.cpp:37
Generic api to store and retrieve preferences.
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.
Definition: gnc-ui-util.c:1209
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:131
gboolean xaccAccountGetPlaceholder(const Account *acc)
Get the "placeholder" flag for an account.
Definition: Account.cpp:4268
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:1360
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.
Definition: gnc-ui-util.c:918
const char * xaccSplitGetMemo(const Split *split)
Returns the memo string.
Definition: gmock-Split.cpp:99
gint64 time64
Many systems, including Microsoft Windows and BSD-derived Unixes like Darwin, are retaining the int-3...
Definition: gnc-date.h:93
const char * gnc_get_doclink_valid_flags(void)
Get a string containing documentation link valid flags.
Definition: gnc-ui-util.c:935
gboolean qof_book_uses_autoreadonly(const QofBook *book)
Returns TRUE if the auto-read-only feature should be used, otherwise FALSE.
Definition: qofbook.cpp:1088
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:2912
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.