GnuCash  4.12-11-g8193d7f23a+
gnc-tree-control-split-reg.c
1 /********************************************************************\
2  * gnc-tree-control-split-reg.c -- GtkTreeView implementation *
3  * to display registers in a GtkTreeView. *
4  * *
5  * Copyright (C) 2006-2007 Chris Shoemaker <c.shoemaker@cox.net> *
6  * Copyright (C) 2012 Robert Fewell *
7  * *
8  * This program is free software; you can redistribute it and/or *
9  * modify it under the terms of the GNU General Public License as *
10  * published by the Free Software Foundation; either version 2 of *
11  * the License, or (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License*
19  * along with this program; if not, contact: *
20  * *
21  * Free Software Foundation Voice: +1-617-542-5942 *
22  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
23  * Boston, MA 02110-1301, USA gnu@gnu.org *
24  * *
25 \********************************************************************/
26 
27 #include <config.h>
28 
29 #include <gtk/gtk.h>
30 #include <glib/gi18n.h>
31 #include <stdlib.h>
32 #include <string.h>
33 
38 #include "gnc-component-manager.h"
39 #include "gnc-date.h"
40 #include "gnc-ui.h"
41 #include "gnc-prefs.h"
42 #include "gnc-warnings.h"
43 #include "dialog-utils.h"
44 #include "dialog-dup-trans.h"
45 #include "dialog-account.h"
46 
47 #include "Transaction.h"
48 #include "engine-helpers.h"
49 #include "gnc-event.h"
50 #include "Scrub.h"
51 
53 static QofLogModule log_module = GNC_MOD_LEDGER;
54 
55 /*****************************************************************************/
56 /*****************************************************************************/
57 
58 /* Read only dialog */
59 static gboolean
60 gtc_sr_is_trans_readonly_and_warn (GncTreeViewSplitReg *view, Transaction *trans)
61 {
62  GncTreeModelSplitReg *model;
63  GtkWidget *window;
64  GtkWidget *dialog;
65  const gchar *reason;
66  const gchar *title = _("Cannot modify or delete this transaction.");
67  const gchar *message_reason =
68  _("This transaction is marked read-only with the comment: '%s'");
69 
70  if (!trans) return FALSE;
71 
72  window = gnc_tree_view_split_reg_get_parent (view);
73  model = gnc_tree_view_split_reg_get_model_from_view (view);
74 
76  {
77  dialog = gtk_message_dialog_new (GTK_WINDOW (window),
78  0,
79  GTK_MESSAGE_ERROR,
80  GTK_BUTTONS_OK,
81  "%s", title);
82  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
83  "%s", _("The date of this transaction is older than the \"Read-Only Threshold\" set for this book. "
84  "This setting can be changed in File->Properties->Accounts."));
85  gtk_dialog_run (GTK_DIALOG (dialog));
86  gtk_widget_destroy (dialog);
87  return TRUE;
88  }
89 
90  reason = xaccTransGetReadOnly (trans);
91  if (reason)
92  {
93  dialog = gtk_message_dialog_new (GTK_WINDOW (window),
94  0,
95  GTK_MESSAGE_ERROR,
96  GTK_BUTTONS_OK,
97  "%s", title);
98  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
99  message_reason, reason);
100  gtk_dialog_run (GTK_DIALOG (dialog));
101  gtk_widget_destroy (dialog);
102  return TRUE;
103  }
104 
105  if (gnc_tree_model_split_reg_get_read_only (model, trans))
106  {
107  dialog = gtk_message_dialog_new (GTK_WINDOW (window),
108  0,
109  GTK_MESSAGE_ERROR,
110  GTK_BUTTONS_OK,
111  "%s", title);
112  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
113  "%s", _("You can not change this transaction, the Book or Register is set to Read Only."));
114  gtk_dialog_run (GTK_DIALOG (dialog));
115  gtk_widget_destroy (dialog);
116  return TRUE;
117  }
118  return FALSE;
119 }
120 
121 
122 /* Transaction is being edited dialog */
123 #define gtc_sr_trans_open_and_warn gnc_tree_control_split_reg_trans_open_and_warn
124 gboolean
125 gnc_tree_control_split_reg_trans_open_and_warn (GncTreeViewSplitReg *view, Transaction *trans)
126 {
127  Transaction *dirty_trans;
128  GtkWidget *window;
129  GtkWidget *dialog;
130  gint response;
131  const char *title = _("Save Transaction before proceeding?");
132  const char *message =
133  _("The current transaction has been changed. Would you like to "
134  "record the changes before proceeding, or cancel?");
135 
136  window = gnc_tree_view_split_reg_get_parent (view);
137  dirty_trans = gnc_tree_view_split_reg_get_dirty_trans (view);
138 
139  if (trans == dirty_trans)
140  {
141  dialog = gtk_message_dialog_new (GTK_WINDOW (window),
142  GTK_DIALOG_DESTROY_WITH_PARENT,
143  GTK_MESSAGE_QUESTION,
144  GTK_BUTTONS_CANCEL,
145  "%s", title);
146  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
147  "%s", message);
148  gtk_dialog_add_button (GTK_DIALOG (dialog),
149  _("_Record"), GTK_RESPONSE_ACCEPT);
150  response = gnc_dialog_run (GTK_DIALOG (dialog), GNC_PREF_WARN_REG_TRANS_MOD);
151  gtk_widget_destroy (dialog);
152 
153  if (response != GTK_RESPONSE_ACCEPT)
154  return TRUE;
155 
156  xaccTransCommitEdit (trans);
157  gnc_tree_view_split_reg_set_dirty_trans (view, NULL);
158 
159  return FALSE;
160  }
161  else
162  return FALSE;
163 }
164 
165 
166 #define gtc_sr_trans_test_for_edit gnc_tree_control_split_reg_trans_test_for_edit
167 gboolean
168 gtc_sr_trans_test_for_edit (GncTreeViewSplitReg *view, Transaction *trans)
169 {
170  GtkWindow *window;
171  Transaction *dirty_trans;
172 
173  /* Make sure we have stopped editing */
174  gnc_tree_view_split_reg_finish_edit (view);
175 
176  window = gnc_ui_get_main_window (GTK_WIDGET (view));
177 
178  /* Get dirty_trans */
179  dirty_trans = gnc_tree_view_split_reg_get_dirty_trans (view);
180 
181  /* We are being edited in a different register */
182  if (xaccTransIsOpen (trans) && (dirty_trans != trans))
183  {
184  gnc_error_dialog (window, "%s",
185  _("This transaction is being edited in a different register."));
186  return TRUE;
187  }
188  return FALSE;
189 }
190 
191 /*****************************************************************************/
192 /*****************************************************************************/
193 
194 gboolean
195 gnc_tree_control_split_reg_balance_trans (GncTreeViewSplitReg *view, Transaction *trans)
196 {
197  GncTreeModelSplitReg *model;
198  GtkWidget *window;
199  int choice;
200  int default_value;
201  Account *default_account;
202  Account *other_account;
203  Account *root;
204  GList *radio_list = NULL;
205  const char *title = _("Rebalance Transaction");
206  const char *message = _("The current transaction is not balanced.");
207  Split *split;
208  Split *other_split;
209  gboolean two_accounts;
210  gboolean multi_currency;
211 
212 
213  if (xaccTransIsBalanced (trans))
214  return FALSE;
215 
216  window = gnc_tree_view_split_reg_get_parent (view);
217  model = gnc_tree_view_split_reg_get_model_from_view (view);
218 
219  if (xaccTransUseTradingAccounts (trans))
220  {
221  MonetaryList *imbal_list;
222  gnc_monetary *imbal_mon;
223  imbal_list = xaccTransGetImbalance (trans);
224 
225  /* See if the imbalance is only in the transaction's currency */
226  if (!imbal_list)
227  /* Value imbalance, but not commodity imbalance. This shouldn't
228  be something that scrubbing can cause to happen. Perhaps someone
229  entered invalid splits. */
230  multi_currency = TRUE;
231  else
232  {
233  imbal_mon = imbal_list->data;
234  if (!imbal_list->next &&
235  gnc_commodity_equiv(gnc_monetary_commodity(*imbal_mon),
236  xaccTransGetCurrency(trans)))
237  multi_currency = FALSE;
238  else
239  multi_currency = TRUE;
240  }
241 
242  /* We're done with the imbalance list, the real work will be done
243  by xaccTransScrubImbalance which will get it again. */
244  gnc_monetary_list_free(imbal_list);
245  }
246  else
247  multi_currency = FALSE;
248 
249  split = xaccTransGetSplit (trans, 0);
250  other_split = xaccSplitGetOtherSplit (split);
251 
252  if (other_split == NULL)
253  {
254  /* Attempt to handle the inverted many-to-one mapping */
255  split = xaccTransGetSplit (trans, 1);
256  if (split) other_split = xaccSplitGetOtherSplit (split);
257  else split = xaccTransGetSplit (trans, 0);
258  }
259  if (other_split == NULL || multi_currency)
260  {
261  two_accounts = FALSE;
262  other_account = NULL;
263  }
264  else
265  {
266  two_accounts = TRUE;
267  other_account = xaccSplitGetAccount (other_split);
268  }
269 
270  default_account = gnc_tree_model_split_reg_get_anchor (model);
271 
272  /* If the two pointers are the same, the account from other_split
273  * is actually the default account. We must make other_account
274  * the account from split instead. */
275 
276  if (default_account == other_account)
277  other_account = xaccSplitGetAccount (split);
278 
279  /* If the two pointers are still the same, we have two splits, but
280  * they both refer to the same account. While non-sensical, we don't
281  * object. */
282 
283  if (default_account == other_account)
284  two_accounts = FALSE;
285 
286  radio_list = g_list_append (radio_list,
287  _("Balance it _manually"));
288  radio_list = g_list_append (radio_list,
289  _("Let GnuCash _add an adjusting split"));
290 
291  if (model->type < NUM_SINGLE_REGISTER_TYPES2 && !multi_currency)
292  {
293  radio_list = g_list_append (radio_list,
294  _("Adjust current account _split total"));
295 
296  default_value = 2;
297  if (two_accounts)
298  {
299  radio_list = g_list_append (radio_list,
300  _("Adjust _other account split total"));
301  default_value = 3;
302  }
303  }
304  else
305  default_value = 0;
306 
307  choice = gnc_choose_radio_option_dialog
308  (window,
309  title,
310  message,
311  _("_Rebalance"),
312  default_value,
313  radio_list);
314 
315  g_list_free (radio_list);
316 
317  root = gnc_account_get_root(default_account);
318  switch (choice)
319  {
320  default:
321  case 0:
322  return TRUE;
323  break;
324 
325  case 1:
326  xaccTransScrubImbalance (trans, root, NULL);
327  break;
328 
329  case 2:
330  xaccTransScrubImbalance (trans, root, default_account);
331  break;
332 
333  case 3:
334  xaccTransScrubImbalance (trans, root, other_account);
335  break;
336  }
337  return FALSE;
338 }
339 
340 
341 /* Cancel the edit and Rollback */
342 void
343 gnc_tree_control_split_reg_cancel_edit (GncTreeViewSplitReg *view, gboolean reg_closing)
344 {
345  /* Make sure we have stopped editing */
346  gnc_tree_view_split_reg_finish_edit (view);
347 
348  gnc_tree_view_split_reg_cancel_edit (view, reg_closing);
349 }
350 
351 
352 /* Amend the Exchange Rate of the transaction */
353 void
354 gnc_tree_control_split_reg_exchange_rate (GncTreeViewSplitReg *view)
355 {
356  GncTreeModelSplitReg *model;
357  GtkWindow *window;
358  Account *anchor;
359  Transaction *trans;
360  Split *split = NULL;
361  Split *osplit = NULL;
362  gnc_numeric value;
363  gboolean expanded;
364  gint depth;
365  gint num_splits;
366  const char *message;
367  gnc_commodity *txn_com;
368 
369  model = gnc_tree_view_split_reg_get_model_from_view (view);
370 
371  trans = gnc_tree_view_split_reg_get_current_trans (view);
372  expanded = gnc_tree_view_split_reg_trans_expanded (view, NULL);
373  depth = gnc_tree_view_reg_get_selected_row_depth (view);
374  num_splits = xaccTransCountSplits (trans);
375  anchor = gnc_tree_model_split_reg_get_anchor (model);
376  txn_com = xaccTransGetCurrency (trans);
377 
378  if (trans == NULL)
379  return;
380 
381  /* See if we were asked to change a blank trans. */
382  if (trans == gnc_tree_control_split_reg_get_blank_trans (view))
383  return;
384 
385  /* Test for read only */
386  if (gtc_sr_is_trans_readonly_and_warn (view, trans))
387  return;
388 
389  /* See if we are being edited in another register */
390  if (gtc_sr_trans_test_for_edit (view, trans))
391  return;
392 
393  /* Make sure we ask to commit any changes before we proceed */
394  if (gtc_sr_trans_open_and_warn (view, trans))
395  return;
396 
397  if (num_splits < 2)
398  return;
399 
400  window = gnc_ui_get_main_window (GTK_WIDGET (view));
401 
402  /* Make sure we NEED this for this type of register */
403  if (!gnc_tree_util_split_reg_has_rate (view))
404  {
405  message = _("This register does not support editing exchange rates.");
406  gnc_error_dialog(window, "%s", message);
407  return;
408  }
409 
410  /* If the anchor commodity is not a currency, cancel */
411  if (anchor && !gnc_commodity_is_currency (xaccAccountGetCommodity (anchor)))
412  {
413  message = _("This register does not support editing exchange rates.");
414  gnc_error_dialog (window, "%s", message);
415  return;
416  }
417 
418  /* If we're not expanded AND number of splits greater than two, nothing to do */
419  if ((gnc_tree_util_split_reg_is_multi (xaccTransGetSplit (trans, 0))) && !expanded)
420  {
421  message = _("You need to expand the transaction in order to modify its "
422  "exchange rates.");
423  gnc_error_dialog (window, "%s", message);
424  return;
425  }
426 
427  if (!gnc_tree_util_split_reg_is_multi (xaccTransGetSplit (trans, 0)) && anchor != NULL && !expanded)
428  {
429  split = gnc_tree_control_split_reg_get_current_trans_split (view);
430 
431  if (xaccAccountGetType (xaccSplitGetAccount (split)) == ACCT_TYPE_TRADING) // trading split
432  return;
433 
434  osplit = xaccSplitGetOtherSplit (split);
435 
436  value = xaccSplitGetValue (split);
437 
438  gnc_tree_view_split_reg_set_dirty_trans (view, trans);
439  xaccTransBeginEdit (trans);
440 
441  if (txn_com == xaccAccountGetCommodity (xaccSplitGetAccount(split)))
442  gnc_tree_util_split_reg_set_value_for (view, trans, osplit, gnc_numeric_neg (value), TRUE);
443  else
444  gnc_tree_util_split_reg_set_value_for (view, trans, split, value, TRUE);
445 
446  xaccTransCommitEdit (trans);
447  gnc_tree_view_split_reg_set_dirty_trans (view, NULL);
448  }
449 
450  if (num_splits > 1 && expanded && depth == 3)
451  {
452  split = gnc_tree_view_split_reg_get_current_split (view);
453 
454  if (xaccAccountGetType (xaccSplitGetAccount (split)) == ACCT_TYPE_TRADING) // trading split
455  return;
456 
457  value = xaccSplitGetValue (split);
458 
459  if (txn_com == xaccAccountGetCommodity (xaccSplitGetAccount(split)))
460  {
461  message = _("The two currencies involved equal each other.");
462  gnc_error_dialog (window, "%s", message);
463  return;
464  }
465  else
466  {
467  gnc_tree_view_split_reg_set_dirty_trans (view, trans);
468  xaccTransBeginEdit (trans);
469 
470  gnc_tree_util_split_reg_set_value_for (view, trans, split, value, TRUE);
471 
472  xaccTransCommitEdit (trans);
473  gnc_tree_view_split_reg_set_dirty_trans (view, NULL);
474  }
475  }
476 }
477 
478 
479 /* Void current transaction */
480 void
481 gnc_tree_control_split_reg_void_current_trans (GncTreeViewSplitReg *view, const char *reason)
482 {
483  Transaction *trans;
484  Split *blank_split;
485  Split *split;
486 
487  if (!view) return;
488 
489  blank_split = gnc_tree_control_split_reg_get_blank_split (view);
490 
491  /* get the current split */
492  split = gnc_tree_view_split_reg_get_current_split (view);
493  if (split == NULL)
494  return;
495 
496  /* Bail if trying to void the blank split. */
497  if (split == blank_split)
498  return;
499 
500  /* already voided. */
501  if (xaccSplitGetReconcile (split) == VREC)
502  return;
503 
504  trans = xaccSplitGetParent (split);
505 
506  if (trans == NULL)
507  return;
508 
509  /* See if we were asked to change a blank trans. */
510  if (trans == gnc_tree_control_split_reg_get_blank_trans (view))
511  return;
512 
513  /* Test for read only */
514  if (gtc_sr_is_trans_readonly_and_warn (view, trans))
515  return;
516 
517  /* See if we are being edited in another register */
518  if (gtc_sr_trans_test_for_edit (view, trans))
519  return;
520 
521  /* Make sure we ask to commit any changes before we proceed */
522  if (gtc_sr_trans_open_and_warn (view, trans))
523  return;
524 
525  gnc_tree_view_split_reg_set_dirty_trans (view, trans);
526 
527  xaccTransVoid (trans, reason);
528 
529  if (xaccTransIsOpen (trans))
530  {
531  PERR("We should not be voiding an open transaction.");
532  xaccTransCommitEdit (trans);
533  }
534  gnc_tree_view_split_reg_set_dirty_trans (view, NULL);
535 }
536 
537 
538 /* Unvoid current transaction */
539 void
540 gnc_tree_control_split_reg_unvoid_current_trans (GncTreeViewSplitReg *view)
541 {
542  Transaction *trans;
543  Split *blank_split;
544  Split *split;
545 
546  if (!view) return;
547 
548  blank_split = gnc_tree_control_split_reg_get_blank_split (view);
549 
550  /* get the current split based on cursor position */
551  split = gnc_tree_view_split_reg_get_current_split (view);
552  if (split == NULL)
553  return;
554 
555  /* Bail if trying to unvoid the blank split. */
556  if (split == blank_split)
557  return;
558 
559  /* not voided. */
560  if (xaccSplitGetReconcile (split) != VREC)
561  return;
562 
563  trans = xaccSplitGetParent (split);
564 
565  if (trans == NULL)
566  return;
567 
568  /* See if we were asked to change a blank trans. */
569  if (trans == gnc_tree_control_split_reg_get_blank_trans (view))
570  return;
571 
572  gnc_tree_view_split_reg_set_dirty_trans (view, trans);
573 
574  xaccTransUnvoid (trans);
575 
576  gnc_tree_view_split_reg_set_dirty_trans (view, NULL);
577 }
578 
579 
580 /* Jump to the Blank transaction */
581 gboolean
582 gnc_tree_control_split_reg_jump_to_blank (GncTreeViewSplitReg *view)
583 {
584  GncTreeModelSplitReg *model;
585  GtkTreePath *mpath, *spath;
586  Transaction *btrans;
587 
588  model = gnc_tree_view_split_reg_get_model_from_view (view);
589 
590  btrans = gnc_tree_model_split_get_blank_trans (model);
591 
592  model->current_trans = btrans;
593 
594  if (!gnc_tree_model_split_reg_trans_is_in_view (model, btrans))
595  g_signal_emit_by_name (model, "refresh_trans");
596  else
597  {
598  mpath = gnc_tree_model_split_reg_get_path_to_split_and_trans (model, NULL, btrans);
599 
600  spath = gnc_tree_view_split_reg_get_sort_path_from_model_path (view, mpath);
601 
602  /* Set cursor to new spath */
603  gtk_tree_view_set_cursor (GTK_TREE_VIEW (view), spath, NULL, FALSE);
604 
605  gtk_tree_path_free (spath);
606  gtk_tree_path_free (mpath);
607 
608  /* scroll when view idle */
609  g_idle_add ((GSourceFunc)gnc_tree_view_split_reg_scroll_to_cell, view );
610  }
611  return FALSE;
612 }
613 
614 
615 /* Jump to transaction or split */
616 void
617 gnc_tree_control_split_reg_jump_to (GncTreeViewSplitReg *view, Transaction *trans, Split *split, gboolean amount)
618 {
619  GncTreeModelSplitReg *model;
620  GtkTreePath *mpath, *spath;
621 
622  model = gnc_tree_view_split_reg_get_model_from_view (view);
623 
624  if (split)
625  trans = NULL;
626 
627  mpath = gnc_tree_model_split_reg_get_path_to_split_and_trans (model, split, trans);
628 
629  spath = gnc_tree_view_split_reg_get_sort_path_from_model_path (view, mpath);
630 
631  if (split)
632  gnc_tree_view_split_reg_expand_trans (view, xaccSplitGetParent (split));
633 
634  /* Set cursor to new spath, if amount, cursor is set to correct column ready for editing */
635  if (amount)
636  {
637  GtkCellRenderer *cr0;
638  GList *renderers;
639  GList *columns;
640  GList *column;
641  gint i;
642 
643  columns = gtk_tree_view_get_columns (GTK_TREE_VIEW (view));
644 
645  for (column = columns, i = 1; column; column = g_list_next (column), i++)
646  {
647  GtkTreeViewColumn *tvc;
648  ViewCol viewcol;
649 
650  tvc = column->data;
651 
652  // Get the first renderer, it has the view-column value.
653  renderers = gtk_cell_layout_get_cells (GTK_CELL_LAYOUT (tvc));
654  cr0 = g_list_nth_data (renderers, 0);
655  g_list_free (renderers);
656 
657  viewcol = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (cr0), "view_column"));
658 
659  if (viewcol == COL_DEBIT && gnc_numeric_positive_p (xaccSplitGetAmount (split)))
660  gtk_tree_view_set_cursor (GTK_TREE_VIEW (view), spath, tvc, TRUE);
661 
662  if (viewcol == COL_CREDIT && gnc_numeric_negative_p (xaccSplitGetAmount (split)))
663  gtk_tree_view_set_cursor (GTK_TREE_VIEW (view), spath, tvc, TRUE);
664  }
665  g_list_free (columns);
666  }
667  else
668  gtk_tree_view_set_cursor (GTK_TREE_VIEW (view), spath, NULL, FALSE);
669 
670  /* Scroll to cell, mid view */
671  gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (view), spath, NULL, TRUE, 0.5, 0.0);
672 
673  gtk_tree_path_free (spath);
674  gtk_tree_path_free (mpath);
675 }
676 
677 
678 /* Returns the Blank Transaction */
679 Transaction *
680 gnc_tree_control_split_reg_get_blank_trans (GncTreeViewSplitReg *view)
681 {
682  GncTreeModelSplitReg *model;
683 
684  model = gnc_tree_view_split_reg_get_model_from_view (view);
685 
686  return gnc_tree_model_split_get_blank_trans (model);
687 }
688 
689 
690 /* Return the Split for the current Transaction */
691 Split *
692 gnc_tree_control_split_reg_get_current_trans_split (GncTreeViewSplitReg *view)
693 {
694  GncTreeModelSplitReg *model;
695  GtkTreePath *mpath;
696  GtkTreeIter m_iter;
697  Split *split = NULL;
698  Transaction *trans = NULL;
699  Account *anchor;
700  gboolean is_trow1, is_trow2, is_split, is_blank;
701 
702  model = gnc_tree_view_split_reg_get_model_from_view (view);
703 
704  mpath = gnc_tree_view_split_reg_get_current_path (view);
705 
706  gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &m_iter, mpath);
707 
708  gnc_tree_model_split_reg_get_split_and_trans (
709  GNC_TREE_MODEL_SPLIT_REG (model), &m_iter, &is_trow1, &is_trow2, &is_split, &is_blank, &split, &trans);
710 
711  anchor = gnc_tree_model_split_reg_get_anchor (model);
712 
713  split = gnc_tree_model_split_reg_trans_get_split_equal_to_ancestor (trans, anchor);
714 
715  gtk_tree_path_free (mpath);
716 
717  return split;
718 }
719 
720 
721 /* Returns the Blank Split */
722 Split *
723 gnc_tree_control_split_reg_get_blank_split (GncTreeViewSplitReg *view)
724 {
725  GncTreeModelSplitReg *model;
726 
727  model = gnc_tree_view_split_reg_get_model_from_view (view);
728 
729  return gnc_tree_model_split_get_blank_split (model);
730 }
731 
732 
733 /* Move to the relative transaction */
734 void
735 gnc_tree_control_split_reg_goto_rel_trans_row (GncTreeViewSplitReg *view, gint relative)
736 {
737  GncTreeModelSplitReg *model;
738  GtkTreePath *mpath, *spath;
739  GtkTreePath *new_mpath, *new_spath;
740  gint *indices, sort_direction;
741  gchar *sstring;
742 
743  ENTER("Move relative, view is %p, relative is %d", view, relative);
744 
745 //FIXME Do we need to do some checks on relative maybe -1,0,1 ??
746 
747  model = gnc_tree_view_split_reg_get_model_from_view (view);
748 
749  mpath = gnc_tree_view_split_reg_get_current_path (view);
750 
751  spath = gnc_tree_view_split_reg_get_sort_path_from_model_path (view, mpath);
752 
753  indices = gtk_tree_path_get_indices (spath);
754 
755  if (model->sort_direction == GTK_SORT_DESCENDING)
756  sort_direction = -1;
757  else
758  sort_direction = 1;
759 
760  new_spath = gtk_tree_path_new_from_indices (indices[0] + (relative * sort_direction), -1);
761 
762  // if relative == 0 we block all selection changes
763  gnc_tree_view_split_reg_block_selection (view, TRUE);
764  gtk_tree_selection_unselect_path (gtk_tree_view_get_selection (GTK_TREE_VIEW (view)), spath);
765 
766  if (relative != 0)
767  gnc_tree_view_split_reg_block_selection (view, FALSE);
768 
769  /* Set cursor to new spath */
770  gtk_tree_view_set_cursor (GTK_TREE_VIEW (view), new_spath, NULL, FALSE);
771 
772  if (relative == 0)
773  {
774  gnc_tree_view_split_reg_block_selection (view, FALSE);
775 
776  /* Get the new model path we are pointing at */
777  new_mpath = gnc_tree_view_split_reg_get_model_path_from_sort_path (view, new_spath);
778 
779  /* As we are not emitting selection change, we need to save the current path ref */
780  gnc_tree_view_split_reg_set_current_path (view, new_mpath);
781  gtk_tree_path_free (new_mpath);
782  }
783 
784  sstring = gtk_tree_path_to_string (new_spath);
785  LEAVE("new_spath is %s", sstring);
786  g_free (sstring);
787 
788  gtk_tree_path_free (new_spath);
789  gtk_tree_path_free (mpath);
790  gtk_tree_path_free (spath);
791 }
792 
793 
794 /* Enter the transaction */
795 void
796 gnc_tree_control_split_reg_enter (GncTreeViewSplitReg *view)
797 {
798  GncTreeModelSplitReg *model;
799  Transaction *btrans, *ctrans;
800  gboolean goto_blank = FALSE;
801  gboolean next_trans = TRUE;
802 
803  model = gnc_tree_view_split_reg_get_model_from_view (view);
804 
805  goto_blank = gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER,
806  GNC_PREF_ENTER_MOVES_TO_END);
807 
808  ENTER("view=%p, goto_blank = %s", view, goto_blank ? "TRUE" : "FALSE");
809 
810  btrans = gnc_tree_model_split_get_blank_trans (model);
811 
812  ctrans = gnc_tree_view_split_reg_get_current_trans (view);
813 
814  /* Are we on the blank transaction */
815  if (btrans == ctrans)
816  next_trans = FALSE;
817 
818  /* First record the transaction */
819  if (gnc_tree_view_split_reg_enter (view))
820  {
821  /* Now move. */
822  if (goto_blank)
823  gnc_tree_control_split_reg_jump_to_blank (view);
824  else if (next_trans)
825  gnc_tree_control_split_reg_goto_rel_trans_row (view, 1);
826  }
827  LEAVE(" ");
828 }
829 
830 
831 /* Reinit the transaction */
832 void
833 gnc_tree_control_split_reg_reinit (GncTreeViewSplitReg *view, gpointer data)
834 {
835  Transaction *trans;
836  GtkWidget *dialog, *window;
837  gint response;
838  const gchar *warning;
839 
840  const char *title = _("Remove the splits from this transaction?");
841  const char *recn_warn = _("This transaction contains reconciled splits. "
842  "Modifying it is not a good idea because that will "
843  "cause your reconciled balance to be off.");
844 
845  trans = gnc_tree_view_split_reg_get_current_trans (view);
846 
847  if (trans == NULL)
848  return;
849 
850  /* See if we were asked to change a blank trans. */
851  if (trans == gnc_tree_control_split_reg_get_blank_trans (view))
852  return;
853 
854  /* Test for read only */
855  if (gtc_sr_is_trans_readonly_and_warn (view, trans))
856  return;
857 
858  /* See if we are being edited in another register */
859  if (gtc_sr_trans_test_for_edit (view, trans))
860  return;
861 
862  /* Make sure we ask to commit any changes before we proceed */
863  if (gtc_sr_trans_open_and_warn (view, trans))
864  return;
865 
866  window = gnc_tree_view_split_reg_get_parent (view);
867 
868  dialog = gtk_message_dialog_new (GTK_WINDOW (window),
869  GTK_DIALOG_DESTROY_WITH_PARENT,
870  GTK_MESSAGE_WARNING,
871  GTK_BUTTONS_NONE,
872  "%s", title);
873 
874  if (xaccTransHasReconciledSplits (trans))
875  {
876  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
877  "%s", recn_warn);
878  warning = GNC_PREF_WARN_REG_SPLIT_DEL_ALL_RECD;
879  }
880  else
881  {
882  warning = GNC_PREF_WARN_REG_SPLIT_DEL_ALL;
883  }
884 
885  gtk_dialog_add_button (GTK_DIALOG (dialog),
886  _("_Cancel"), GTK_RESPONSE_CANCEL);
887  gnc_gtk_dialog_add_button(dialog, _("_Remove Splits"),
888  "edit-delete", GTK_RESPONSE_ACCEPT);
889  response = gnc_dialog_run (GTK_DIALOG(dialog), warning);
890  gtk_widget_destroy (dialog);
891  if (response != GTK_RESPONSE_ACCEPT)
892  return;
893 
894  gnc_tree_view_split_reg_reinit_trans (view);
895 }
896 
897 
898 /* Delete the currently selected item */
899 void
900 gnc_tree_control_split_reg_delete (GncTreeViewSplitReg *view, gpointer data)
901 {
902  GncTreeModelSplitReg *model;
903  Account *anchor;
904  RowDepth depth;
905  Transaction *trans;
906  Split *split;
907  GtkWidget *dialog, *window;
908  gint response;
909  const gchar *warning;
910 
911  /* get the current split based on cursor position */
912  split = gnc_tree_view_split_reg_get_current_split (view);
913  if (split == NULL)
914  {
915  split = gnc_tree_control_split_reg_get_current_trans_split (view);
916  if (split == NULL)
917  {
918  LEAVE("split is NULL");
919  return;
920  }
921  }
922 
923  model = gnc_tree_view_split_reg_get_model_from_view (view);
924 
925  anchor = gnc_tree_model_split_reg_get_anchor (model);
926 
927  trans = xaccSplitGetParent (split);
928 
929  if (trans == NULL)
930  return;
931 
932  /* Test for read only */
933  if (gtc_sr_is_trans_readonly_and_warn (view, trans))
934  return;
935 
936  /* See if we are being edited in another register */
937  if (gtc_sr_trans_test_for_edit (view, trans))
938  return;
939 
940  depth = gnc_tree_view_reg_get_selected_row_depth (view);
941 
942  /* Deleting the blank split just cancels */
943  {
944  Split *blank_split = gnc_tree_control_split_reg_get_blank_split (view);
945 
946  if (split == blank_split)
947  return;
948  }
949 
950  /* Deleting the blank trans just cancels */
951  {
952  Transaction *blank_trans = gnc_tree_control_split_reg_get_blank_trans (view);
953 
954  if (trans == blank_trans)
955  return;
956  }
957 
958  window = gnc_tree_view_split_reg_get_parent (view);
959 
960  /* On a split cursor, just delete the one split. */
961  if (depth == SPLIT3)
962  {
963  const char *format = _("Delete the split '%s' from the transaction '%s'?");
964  const char *recn_warn = _("You would be deleting a reconciled split! "
965  "This is not a good idea as it will cause your "
966  "reconciled balance to be off.");
967  const char *anchor_error = _("You cannot delete this split.");
968  const char *anchor_split = _("This is the split anchoring this transaction "
969  "to the register. You may not delete it from "
970  "this register window. You may delete the "
971  "entire transaction from this window, or you "
972  "may navigate to a register that shows "
973  "another side of this same transaction and "
974  "delete the split from that register.");
975  char *buf = NULL;
976  const char *memo;
977  const char *desc;
978  char recn;
979  if ((split == gnc_tree_control_split_reg_get_current_trans_split (view)) ||
980  (split == gnc_tree_model_split_reg_trans_get_split_equal_to_ancestor (trans, anchor)))
981  {
982  dialog = gtk_message_dialog_new (GTK_WINDOW (window),
983  GTK_DIALOG_MODAL
984  | GTK_DIALOG_DESTROY_WITH_PARENT,
985  GTK_MESSAGE_ERROR,
986  GTK_BUTTONS_OK,
987  "%s", anchor_error);
988  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
989  "%s", anchor_split);
990  gtk_dialog_run (GTK_DIALOG (dialog));
991  gtk_widget_destroy (dialog);
992  return;
993  }
994 
995  memo = xaccSplitGetMemo (split);
996  memo = (memo && *memo) ? memo : _("(no memo)");
997 
998  desc = xaccTransGetDescription (trans);
999  desc = (desc && *desc) ? desc : _("(no description)");
1000 
1001  /* ask for user confirmation before performing permanent damage */
1002  buf = g_strdup_printf (format, memo, desc);
1003  dialog = gtk_message_dialog_new (GTK_WINDOW (window),
1004  GTK_DIALOG_MODAL
1005  | GTK_DIALOG_DESTROY_WITH_PARENT,
1006  GTK_MESSAGE_QUESTION,
1007  GTK_BUTTONS_NONE,
1008  "%s", buf);
1009  g_free(buf);
1010  recn = xaccSplitGetReconcile (split);
1011  if (recn == YREC || recn == FREC)
1012  {
1013  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
1014  "%s", recn_warn);
1015  warning = GNC_PREF_WARN_REG_SPLIT_DEL_RECD;
1016  }
1017  else
1018  {
1019  warning = GNC_PREF_WARN_REG_SPLIT_DEL;
1020  }
1021 
1022  gtk_dialog_add_button (GTK_DIALOG (dialog),
1023  _("_Cancel"), GTK_RESPONSE_CANCEL);
1024  gnc_gtk_dialog_add_button (dialog, _("_Delete Split"),
1025  "edit-delete", GTK_RESPONSE_ACCEPT);
1026  response = gnc_dialog_run (GTK_DIALOG (dialog), warning);
1027  gtk_widget_destroy (dialog);
1028  if (response != GTK_RESPONSE_ACCEPT)
1029  return;
1030 
1031  gnc_tree_view_split_reg_delete_current_split (view);
1032  return;
1033  }
1034 
1035  g_return_if_fail (depth == TRANS1 || depth == TRANS2);
1036 
1037  /* On a transaction cursor with 2 or fewer splits in single or double
1038  * mode, we just delete the whole transaction, kerblooie */
1039  {
1040  const char *title = _("Delete the current transaction?");
1041  const char *recn_warn = _("You would be deleting a transaction "
1042  "with reconciled splits! "
1043  "This is not a good idea as it will cause your "
1044  "reconciled balance to be off.");
1045 
1046  dialog = gtk_message_dialog_new (GTK_WINDOW (window),
1047  GTK_DIALOG_MODAL
1048  | GTK_DIALOG_DESTROY_WITH_PARENT,
1049  GTK_MESSAGE_WARNING,
1050  GTK_BUTTONS_NONE,
1051  "%s", title);
1052  if (xaccTransHasReconciledSplits (trans))
1053  {
1054  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
1055  "%s", recn_warn);
1056  warning = GNC_PREF_WARN_REG_TRANS_DEL_RECD;
1057  }
1058  else
1059  {
1060  warning = GNC_PREF_WARN_REG_TRANS_DEL;
1061  }
1062  gtk_dialog_add_button (GTK_DIALOG (dialog),
1063  _("_Cancel"), GTK_RESPONSE_CANCEL);
1064  gnc_gtk_dialog_add_button (dialog, _("_Delete Transaction"),
1065  "edit-delete", GTK_RESPONSE_ACCEPT);
1066  response = gnc_dialog_run (GTK_DIALOG (dialog), warning);
1067  gtk_widget_destroy (dialog);
1068  if (response != GTK_RESPONSE_ACCEPT)
1069  return;
1070 
1071  gnc_tree_view_split_reg_delete_current_trans (view);
1072  return;
1073  }
1074 }
1075 
1076 
1077 /* Add Reverse Transaction */
1078 void
1079 gnc_tree_control_split_reg_reverse_current (GncTreeViewSplitReg *view)
1080 {
1081  GtkWindow *window;
1082  Transaction *trans = NULL, *new_trans = NULL;
1083  GList *snode = NULL;
1084 
1085  ENTER(" ");
1086 
1087  trans = gnc_tree_view_split_reg_get_current_trans (view);
1088 
1089  if (trans == NULL)
1090  {
1091  LEAVE("Trans is Null");
1092  return;
1093  }
1094 
1095  /* See if we were asked to reverse a blank trans. */
1096  if (trans == gnc_tree_control_split_reg_get_blank_trans (view))
1097  {
1098  LEAVE("Skip blank trans");
1099  return;
1100  }
1101 
1102  /* Test for read only */
1103  if (gtc_sr_is_trans_readonly_and_warn (view, trans))
1104  {
1105  LEAVE("Read only");
1106  return;
1107  }
1108 
1109  /* See if we are being edited in another register */
1110  if (gtc_sr_trans_test_for_edit (view, trans))
1111  {
1112  LEAVE("Open in different register");
1113  return;
1114  }
1115 
1116  window = gnc_ui_get_main_window (GTK_WIDGET (view));
1117 
1118  if (xaccTransGetReversedBy (trans))
1119  {
1120  gnc_error_dialog (window, "%s",
1121  _("A reversing entry has already been created for this transaction."));
1122  LEAVE("Already have reversing transaction");
1123  return;
1124  }
1125 
1126  /* Make sure we ask to commit any changes before we add reverse transaction */
1127  if (gtc_sr_trans_open_and_warn (view, trans))
1128  {
1129  LEAVE("save cancelled");
1130  return;
1131  }
1132 
1133  /* Create reverse transaction */
1134  new_trans = xaccTransReverse (trans);
1135 
1136  xaccTransBeginEdit (new_trans);
1137 
1138  /* Clear transaction level info */
1139  xaccTransSetDatePostedSecsNormalized (new_trans, gnc_time (NULL));
1140  xaccTransSetDateEnteredSecs (new_trans, gnc_time (NULL));
1141 
1142  xaccTransCommitEdit (new_trans);
1143 
1144  // We need to loop through the splits and send an event to update the register.
1145  for (snode = xaccTransGetSplitList (new_trans); snode; snode = snode->next)
1146  {
1147  if (xaccTransStillHasSplit (new_trans, snode->data))
1148  {
1149  /* Send an event based on the split account */
1150  qof_event_gen (QOF_INSTANCE (xaccSplitGetAccount(snode->data)), GNC_EVENT_ITEM_ADDED, snode->data);
1151  }
1152  }
1153 
1154  /* give gtk+ a chance to handle pending events */
1155  while (gtk_events_pending ())
1156  gtk_main_iteration ();
1157 
1158  /* Now jump to new trans */
1159  gnc_tree_control_split_reg_jump_to (view, NULL, xaccTransGetSplit (new_trans, 0), FALSE);
1160 
1161  LEAVE("Reverse transaction created");
1162 }
1163 
1164 
1165 /* Duplicate the current selection */
1166 gboolean
1167 gnc_tree_control_split_reg_duplicate_current (GncTreeViewSplitReg *view)
1168 {
1169  GncTreeModelSplitReg *model;
1170  GtkWindow *window;
1171  RowDepth depth;
1172  Transaction *trans;
1173  Split *blank_split;
1174  Split *split, *trans_split;
1175  gboolean use_split_action_for_num_field = FALSE;
1176 
1177  ENTER("");
1178 
1179  model = gnc_tree_view_split_reg_get_model_from_view (view);
1180 
1181  blank_split = gnc_tree_control_split_reg_get_blank_split (view);
1182  split = gnc_tree_view_split_reg_get_current_split (view);
1183  trans_split = gnc_tree_control_split_reg_get_current_trans_split (view);
1184 
1185 
1186  depth = gnc_tree_view_reg_get_selected_row_depth (view);
1187 
1188  use_split_action_for_num_field = qof_book_use_split_action_for_num_field (gnc_get_current_book());
1189 
1190  trans = gnc_tree_view_split_reg_get_current_trans (view);
1191 
1192  /* This shouldn't happen, but be paranoid. */
1193  if (trans == NULL)
1194  return FALSE;
1195 
1196  /* See if we were asked to change a blank trans. */
1197  if (trans == gnc_tree_control_split_reg_get_blank_trans (view))
1198  {
1199  LEAVE("Skip blank trans");
1200  return FALSE;
1201  }
1202 
1203  /* See if we were asked to change a blank split. */
1204  if (split == blank_split)
1205  {
1206  LEAVE("Skip blank split");
1207  return FALSE;
1208  }
1209 
1210  /* Test for read only */
1211  if (gtc_sr_is_trans_readonly_and_warn (view, trans))
1212  {
1213  LEAVE("Read only");
1214  return FALSE;
1215  }
1216 
1217  /* See if we are being edited in another register */
1218  if (gtc_sr_trans_test_for_edit (view, trans))
1219  {
1220  LEAVE("Open in different register");
1221  return FALSE;
1222  }
1223 
1224  /* Make sure we ask to commit any changes before we proceed */
1225  if (gtc_sr_trans_open_and_warn (view, trans))
1226  {
1227  LEAVE("save cancelled");
1228  return FALSE;
1229  }
1230 
1231  window = gnc_ui_get_main_window (GTK_WIDGET (view));
1232 
1233  /* Ok, we are now ready to make the copy. */
1234  if (depth == SPLIT3)
1235  {
1236  Split *new_split;
1237  gboolean new_act_num = FALSE;
1238  char *out_num;
1239  time64 date;
1240 
1241  /* We are on a split in an expanded transaction.
1242  * Just copy the split and add it to the transaction.
1243  * However, if the split-action field is being used as the register
1244  * number, and the action field is a number, request a new value or
1245  * cancel. Need to get next number and update account last num from
1246  * split account not register account, which may be the same or not */
1247 
1248  if (split != trans_split)
1249  {
1250  if (use_split_action_for_num_field && gnc_strisnum (gnc_get_num_action (NULL, split)))
1251  {
1252  Account *account = xaccSplitGetAccount (split);
1253  const char* title = _("New Split Information");
1254  const char *in_num = NULL;
1255  date = time (0);
1256 
1257  if (account)
1258  in_num = xaccAccountGetLastNum (account);
1259  else
1260  in_num = gnc_get_num_action (NULL, split);
1261 
1262  if (!gnc_dup_trans_dialog (GTK_WIDGET (window), title, FALSE,
1263  &date, in_num, &out_num, NULL, NULL, NULL, NULL))
1264  {
1265  LEAVE("dup cancelled");
1266  return FALSE;
1267  }
1268  new_act_num = TRUE;
1269  }
1270 
1271  new_split = xaccMallocSplit (gnc_get_current_book ());
1272 
1273  // Remove the blank split
1274  gnc_tree_model_split_reg_set_blank_split_parent (model, trans, TRUE);
1275 
1276  if (!xaccTransIsOpen (trans))
1277  xaccTransBeginEdit (trans);
1278  gnc_tree_view_split_reg_set_dirty_trans (view, trans);
1279 
1280  xaccSplitCopyOnto (split, new_split);
1281  xaccSplitSetParent (new_split, trans);
1282 
1283  // Add the blank split
1284  gnc_tree_model_split_reg_set_blank_split_parent (model, trans, FALSE);
1285 
1286  if (new_act_num) /* if new number supplied by user dialog */
1287  gnc_set_num_action (NULL, new_split, out_num, NULL);
1288 
1289  if (new_act_num && gnc_strisnum (out_num))
1290  {
1291  Account *account = xaccSplitGetAccount (new_split);
1292 
1293  /* If current register is for account, set last num */
1294  if (account == gnc_tree_model_split_reg_get_anchor (model))
1295  xaccAccountSetLastNum (account, out_num);
1296  }
1297  if (new_act_num)
1298  g_free (out_num);
1299  }
1300  else
1301  {
1302  gnc_error_dialog (window, "%s",
1303  _("This is the split anchoring this transaction to the register."
1304  " You can not duplicate it from this register window."));
1305  LEAVE("split anchoring this transaction");
1306  return FALSE;
1307  }
1308  }
1309  else
1310  {
1311  Transaction *new_trans;
1312  int trans_split_index;
1313  const char *in_num = NULL;
1314  const char *in_tnum = NULL;
1315  char *out_num;
1316  char *out_tnum;
1317  char *out_tdoclink = NULL;
1318  time64 date;
1319  gboolean use_autoreadonly = qof_book_uses_autoreadonly (gnc_get_current_book());
1320 
1321  /* We are on a transaction row. Copy the whole transaction. */
1322 
1323  date = time (0);
1324  if (gnc_strisnum (gnc_get_num_action (trans, trans_split)))
1325  {
1326  Account *account = gnc_tree_model_split_reg_get_anchor (model);
1327 
1328  if (account)
1329  in_num = xaccAccountGetLastNum (account);
1330  else
1331  in_num = gnc_get_num_action (trans, trans_split);
1332  }
1333 
1334  in_tnum = (use_split_action_for_num_field
1335  ? gnc_get_num_action (trans, NULL)
1336  : NULL);
1337 
1338  if (!gnc_dup_trans_dialog (GTK_WIDGET (window), NULL, TRUE,
1339  &date, in_num, &out_num, in_tnum, &out_tnum,
1340  xaccTransGetDocLink (trans), &out_tdoclink))
1341  {
1342  LEAVE("dup cancelled");
1343  return FALSE;
1344  }
1345 
1346  if (use_autoreadonly)
1347  {
1348  GDate d;
1349  GDate *readonly_threshold = qof_book_get_autoreadonly_gdate (gnc_get_current_book());
1350  gnc_gdate_set_time64 (&d, date);
1351  if (g_date_compare (&d, readonly_threshold) < 0)
1352  {
1353  GtkWidget *dialog = gtk_message_dialog_new (window,
1354  0,
1355  GTK_MESSAGE_ERROR,
1356  GTK_BUTTONS_OK,
1357  "%s", _("Cannot store a transaction at this date"));
1358  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
1359  "%s", _("The entered date of the duplicated transaction is older than the \"Read-Only Threshold\" set for this book. "
1360  "This setting can be changed in File->Properties->Accounts."));
1361  gtk_dialog_run (GTK_DIALOG (dialog));
1362  gtk_widget_destroy (dialog);
1363 
1364  g_date_free (readonly_threshold);
1365  LEAVE("entered date older than read-only threshold");
1366  return FALSE;
1367  }
1368  g_date_free (readonly_threshold);
1369  }
1370 
1371  trans_split_index = xaccTransGetSplitIndex (trans, trans_split);
1372 
1373  new_trans = xaccMallocTransaction (gnc_get_current_book ());
1374 
1375  xaccTransBeginEdit (new_trans);
1376 
1377  xaccTransCopyOnto (trans, new_trans);
1378 
1379  xaccTransSetDatePostedSecsNormalized (new_trans, date);
1380 
1381  /* We also must set a new DateEntered on the new entry
1382  * because otherwise the ordering is not deterministic */
1383  xaccTransSetDateEnteredSecs(new_trans, gnc_time(NULL));
1384 
1385  /* clear the linked document entry if returned value NULL */
1386  if (out_tdoclink == NULL)
1387  xaccTransSetDocLink (new_trans, "");
1388  else
1389  g_free (out_tdoclink);
1390 
1391  /* set per book option */
1392  gnc_set_num_action (new_trans, NULL, out_num, out_tnum);
1393 
1394  if (gnc_strisnum (out_num))
1395  {
1396  Account *account = gnc_tree_model_split_reg_get_anchor (model);
1397 
1398  /* If current register is for account, set last num */
1399  if (account)
1400  xaccAccountSetLastNum (account, out_num);
1401  }
1402 
1403  if (use_split_action_for_num_field)
1404  {
1405  /* find split in new_trans that equals trans_split and set
1406  * split_action to out_num */
1407  gnc_set_num_action (NULL,
1408  xaccTransGetSplit (new_trans, trans_split_index),
1409  out_num, NULL);
1410  /* note that if the transaction has multiple splits to the register
1411  * account, only the anchor split will be set with user input. The
1412  * user will have to adjust other splits manually. */
1413  }
1414 
1415  xaccTransCommitEdit (new_trans);
1416 
1417  if (out_num != NULL)
1418  g_free (out_num);
1419 
1420  if (use_split_action_for_num_field && out_tnum != NULL)
1421  g_free (out_tnum);
1422  }
1423  LEAVE(" ");
1424  return TRUE;
1425 }
1426 
1427 
1428 static gboolean gtcsr_move_current_entry_updown(GncTreeViewSplitReg *view,
1429  gboolean move_up, gboolean really_do_it)
1430 {
1431  GncTreeModelSplitReg *model;
1432  GtkTreePath *mpath = NULL, *spath = NULL, *spath_target = NULL, *mpath_target = NULL;
1433  GtkTreeIter m_iter, m_iter_target;
1434  gboolean resultvalue = FALSE;
1435  g_return_val_if_fail(view, FALSE);
1436 
1437  ENTER("");
1438 
1439  // The allocated memory references will all be cleaned up in the
1440  // updown_finish: label.
1441 
1442  model = gnc_tree_view_split_reg_get_model_from_view (view);
1443  g_return_val_if_fail(model, FALSE);
1444 
1445  if (model->sort_col != COL_DATE)
1446  {
1447  LEAVE("Not sorted by date - no up/down move available");
1448  return FALSE;
1449  }
1450 
1451  mpath = gnc_tree_view_split_reg_get_current_path (view);
1452  if (!mpath)
1453  {
1454  LEAVE("No current path available - probably on the blank split.");
1455  goto updown_finish;
1456  }
1457 
1458  spath = gnc_tree_view_split_reg_get_sort_path_from_model_path (view, mpath);
1459  g_return_val_if_fail(spath, FALSE);
1460 
1461  spath_target = gtk_tree_path_copy(spath);
1462  if (move_up)
1463  {
1464  gboolean move_was_made = gtk_tree_path_prev(spath_target);
1465  if (!move_was_made)
1466  {
1467  LEAVE("huh, no path_prev() possible");
1468  goto updown_finish;
1469  }
1470  }
1471  else
1472  {
1473  gtk_tree_path_next(spath_target);
1474  // The path_next() function does not give a return value, see
1475  // https://mail.gnome.org/archives/gtk-list/2010-January/msg00171.html
1476  }
1477 
1478  if (gtk_tree_path_compare(spath, spath_target) == 0)
1479  {
1480  LEAVE("oops, paths are equal");
1481  goto updown_finish;
1482  }
1483 
1484  mpath_target = gnc_tree_view_split_reg_get_model_path_from_sort_path (view, spath_target);
1485  if (!mpath_target)
1486  {
1487  LEAVE("no path to target row");
1488  goto updown_finish;
1489  }
1490 
1491  if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &m_iter, mpath))
1492  {
1493  LEAVE("No iter for current row");
1494  goto updown_finish;
1495  }
1496  if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &m_iter_target, mpath_target))
1497  {
1498  LEAVE("No iter for target row");
1499  goto updown_finish;
1500  }
1501 
1502  {
1503  gboolean is_blank, is_blank_target;
1504  Split *current_split, *target_split;
1505  Transaction *current_trans, *target_trans;
1506  gnc_tree_model_split_reg_get_split_and_trans (GNC_TREE_MODEL_SPLIT_REG (model), &m_iter,
1507  NULL, NULL, NULL, &is_blank,
1508  &current_split, &current_trans);
1509  gnc_tree_model_split_reg_get_split_and_trans (GNC_TREE_MODEL_SPLIT_REG (model), &m_iter_target,
1510  NULL, NULL, NULL, &is_blank_target,
1511  &target_split, &target_trans);
1512  if (is_blank || is_blank_target)
1513  {
1514  LEAVE("blank split involved, ignored.");
1515  goto updown_finish;
1516  }
1517  if (xaccTransEqual(current_trans, target_trans, TRUE, FALSE, FALSE, FALSE))
1518  {
1519  LEAVE("two times the same txn, ignored.");
1520  goto updown_finish;
1521  }
1522  if (xaccTransGetIsClosingTxn(current_trans)
1523  || xaccTransGetIsClosingTxn(target_trans))
1524  {
1525  LEAVE("One of the txn is book-closing - no re-ordering allowed.");
1526  goto updown_finish;
1527  }
1528 
1529  /* Only continue if both have the same date and num, because the
1530  * "standard ordering" is tied to the date anyway. */
1531  {
1532  time64 time1, time2;
1533  GDate d1 = xaccTransGetDatePostedGDate(current_trans),
1534  d2 = xaccTransGetDatePostedGDate(target_trans);
1535  if (g_date_compare(&d1, &d2) != 0)
1536  {
1537  LEAVE("unequal DatePosted, ignoring");
1538  goto updown_finish;
1539  }
1540  if (g_strcmp0(xaccTransGetNum(current_trans),
1541  xaccTransGetNum(target_trans)) != 0)
1542  {
1543  LEAVE("unequal Num, ignoring");
1544  goto updown_finish;
1545  }
1546 
1547  /* Special treatment if the equality doesn't hold if we access the
1548  dates as time64. See the comment in gncEntrySetDateGDate() for the
1549  reason: Some code used the time64 at noon for the EntryDate, other
1550  code used the time64 at the start of day. */
1551  time1 = xaccTransRetDatePosted(current_trans);
1552  time2 = xaccTransRetDatePosted(target_trans);
1553  if (really_do_it && time1 != time2)
1554  {
1555  /* Times are not equal, even though the GDates were equal? Then
1556  we set the GDates again. This will force the times to be equal
1557  as well. */
1558  xaccTransSetDatePostedGDate(current_trans, d1);
1559  xaccTransSetDatePostedGDate(target_trans, d2);
1560  }
1561  }
1562 
1563  // Check whether any of the two splits are frozen
1564  if (xaccSplitGetReconcile(current_split) == FREC
1565  || xaccSplitGetReconcile(target_split) == FREC)
1566  {
1567  LEAVE("either current or target split is frozen. No modification allowed.");
1568  goto updown_finish;
1569  }
1570 
1571  // If really_do_it is FALSE, we are only in query mode and shouldn't
1572  // modify anything. But if it is TRUE, please go ahead and do the move.
1573  if (really_do_it)
1574  {
1575  // Check whether any of the two splits are reconciled
1576  if (xaccSplitGetReconcile(current_split) == YREC
1577  && !gnc_tree_control_split_reg_recn_test(view, spath))
1578  {
1579  LEAVE("current split is reconciled and user chose not to modify it");
1580  goto updown_finish;
1581  }
1582  if (xaccSplitGetReconcile(target_split) == YREC
1583  && !gnc_tree_control_split_reg_recn_test(view, spath_target))
1584  {
1585  LEAVE("target split is reconciled and user chose not to modify it");
1586  goto updown_finish;
1587  }
1588 
1589  PINFO("Ok, about to switch ordering for current desc='%s' target desc='%s'",
1590  xaccTransGetDescription(current_trans),
1591  xaccTransGetDescription(target_trans));
1592 
1593  gnc_suspend_gui_refresh ();
1594 
1595  /* Swap the date-entered of both entries. That's already
1596  * sufficient! */
1597  {
1598  time64 time_current = xaccTransRetDateEntered(current_trans);
1599  time64 time_target = xaccTransRetDateEntered(target_trans);
1600 
1601  /* Special treatment for identical times (potentially caused
1602  * by the "duplicate entry" command) */
1603  if (time_current == time_target)
1604  {
1605  g_warning("Surprise - both DateEntered are equal.");
1606  /* We just increment the DateEntered of the previously
1607  * lower of the two by one second. This might still cause
1608  * issues if multiple entries had this problem, but
1609  * whatever. */
1610  if (move_up)
1611  ++time_current;
1612  else
1613  ++time_target;
1614  }
1615 
1616  /* Write the new DateEntered. */
1617  xaccTransSetDateEnteredSecs(current_trans, time_target);
1618  xaccTransSetDateEnteredSecs(target_trans, time_current);
1619 
1620  /* FIXME: Do we need to notify anyone about the changed ordering? */
1621  }
1622 
1623  gnc_resume_gui_refresh ();
1624 
1625  LEAVE("two txn switched, done.");
1626  }
1627  resultvalue = TRUE;
1628  goto updown_finish;
1629  }
1630 updown_finish:
1631  // memory cleanup
1632  //gtk_tree_path_free (mpath); // Should this be freed??
1633  gtk_tree_path_free(spath);
1634  gtk_tree_path_free(spath_target);
1635  gtk_tree_path_free(mpath_target);
1636  return resultvalue;
1637 }
1638 
1640  gboolean move_up)
1641 {
1642  return gtcsr_move_current_entry_updown(view, move_up, TRUE);
1643 }
1644 
1646  gboolean move_up)
1647 {
1648  return gtcsr_move_current_entry_updown(view, move_up, FALSE);
1649 }
1650 
1651 
1652 /* Save any open edited transactions on closing register */
1653 gboolean
1654 gnc_tree_control_split_reg_save (GncTreeViewSplitReg *view, gboolean reg_closing)
1655 {
1656  Transaction *dirty_trans;
1657  Transaction *blank_trans;
1658  Transaction *trans;
1659 // Split *split;
1660 // Split *current_trans_split;
1661 
1662  ENTER("view=%p, reg_closing=%s", view, reg_closing ? "TRUE" : "FALSE");
1663 
1664  if (!view)
1665  {
1666  LEAVE("no view");
1667  return FALSE;
1668  }
1669 
1670  /* Make sure we have stopped editing */
1671  gnc_tree_view_split_reg_finish_edit (view);
1672 
1673  if (reg_closing)
1674  view->reg_closing = TRUE;
1675 
1676  dirty_trans = gnc_tree_view_split_reg_get_dirty_trans (view);
1677  blank_trans = gnc_tree_control_split_reg_get_blank_trans (view);
1678 
1679  /* get the handle to the current split and transaction */
1680 // split = gnc_tree_view_split_reg_get_current_split (view);
1681  trans = gnc_tree_view_split_reg_get_current_trans (view);
1682 
1683 // current_trans_split = gnc_tree_control_split_reg_get_current_trans_split (view);
1684 
1685  if (trans == NULL)
1686  {
1687  LEAVE("no transaction");
1688  return FALSE;
1689  }
1690 
1691  if (!xaccTransIsOpen (trans))
1692  {
1693  LEAVE("transaction not open");
1694  return FALSE;
1695  }
1696 
1697  if (trans == dirty_trans )
1698  {
1699  if (trans != blank_trans)
1700  {
1701  /* Existing Transaction, we are going to commit. */
1702 
1703  PINFO("committing trans (%p)", trans);
1704  xaccTransCommitEdit (trans);
1705  gnc_tree_view_split_reg_set_dirty_trans (view, NULL);
1706 
1707  LEAVE("Existing Transaction committed");
1708  return TRUE;
1709  }
1710  else
1711  {
1712  /* Blank Transaction, we are going to commit. */
1713 
1714  PINFO("start committing blank trans (%p)", trans);
1715 //FIXME More stuff ?
1716 
1717  if (xaccTransCountSplits (trans) == 0)
1718  {
1719  GtkWidget *dialog, *window;
1720  gint response;
1721  /* Translators: This message will be presented when a user
1722  attempts to record a transaction without splits */
1723  const char *title = _("Not enough information for Blank Transaction?");
1724  const char *message =
1725  _("The blank transaction does not have enough information to save it. Would you like to "
1726  "return to the transaction to update, or cancel the save?");
1727  window = gnc_tree_view_split_reg_get_parent (view);
1728  dialog = gtk_message_dialog_new (GTK_WINDOW (window),
1729  GTK_DIALOG_DESTROY_WITH_PARENT,
1730  GTK_MESSAGE_QUESTION,
1731  GTK_BUTTONS_CANCEL,
1732  "%s", title);
1733  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
1734  "%s", message);
1735  gtk_dialog_add_button (GTK_DIALOG (dialog),
1736  /* Translators: Return to the transaction to update */
1737  _("_Return"), GTK_RESPONSE_ACCEPT);
1738 
1739  gtk_widget_grab_focus (gtk_dialog_get_widget_for_response (GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT));
1740 
1741  response = gtk_dialog_run (GTK_DIALOG (dialog));
1742 // response = gnc_dialog_run (GTK_DIALOG (dialog), "transaction_incomplete");
1743  gtk_widget_destroy (dialog);
1744 
1745  if (response != GTK_RESPONSE_ACCEPT)
1746  {
1747  LEAVE("save cancelled");
1748  return TRUE;
1749  }
1750  LEAVE("return to transaction");
1751  return FALSE;
1752  }
1753 
1754  xaccTransCommitEdit (trans);
1755  gnc_tree_view_split_reg_set_dirty_trans (view, NULL);
1756 
1757  LEAVE("Blank Transaction committed");
1758  return TRUE;
1759  }
1760  }
1761 
1762  LEAVE(" ");
1763  return TRUE;
1764 }
1765 
1766 
1767 /* Allow the reconcile flag to be changed */
1768 gboolean
1769 gnc_tree_control_split_reg_recn_change (GncTreeViewSplitReg *view, GtkTreePath *spath)
1770 {
1771  GtkWidget *dialog, *window;
1772  GncTreeModelSplitReg *model;
1773  GtkTreePath *mpath;
1774  GtkTreeIter m_iter;
1775  Split *split = NULL;
1776  Transaction *trans = NULL;
1777  gboolean is_trow1, is_trow2, is_split, is_blank;
1778  Account *anchor;
1779  char rec;
1780  const gchar *title = _("Mark split as unreconciled?");
1781  const gchar *message =
1782  _("You are about to mark a reconciled split as unreconciled. Doing "
1783  "so might make future reconciliation difficult! Continue "
1784  "with this change?");
1785  gint response;
1786 
1787  ENTER(" ");
1788 
1789  model = gnc_tree_view_split_reg_get_model_from_view (view);
1790 
1791  anchor = gnc_tree_model_split_reg_get_anchor (model);
1792 
1793  mpath = gnc_tree_view_split_reg_get_model_path_from_sort_path (view, spath);
1794 
1795  if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &m_iter, mpath))
1796  {
1797  gtk_tree_path_free (mpath);
1798  return FALSE;
1799  }
1800 
1801  gnc_tree_model_split_reg_get_split_and_trans (GNC_TREE_MODEL_SPLIT_REG (model), &m_iter,
1802  &is_trow1, &is_trow2, &is_split, &is_blank, &split, &trans);
1803 
1804  if (is_trow1 || is_trow2)
1805  split = xaccTransFindSplitByAccount (trans, anchor);
1806 
1807  rec = xaccSplitGetReconcile (split);
1808 
1809  if (rec != YREC)
1810  {
1811  gtk_tree_path_free (mpath);
1812  LEAVE("Not reconciled");
1813  return TRUE;
1814  }
1815 
1816  /* Does the user want to be warned? */
1817  window = gnc_tree_view_split_reg_get_parent (view);
1818  dialog =
1819  gtk_message_dialog_new (GTK_WINDOW (window),
1820  GTK_DIALOG_DESTROY_WITH_PARENT,
1821  GTK_MESSAGE_WARNING,
1822  GTK_BUTTONS_CANCEL,
1823  "%s", title);
1824  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
1825  "%s", message);
1826  gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Unreconcile"),
1827  GTK_RESPONSE_YES);
1828  response = gnc_dialog_run (GTK_DIALOG (dialog), GNC_PREF_WARN_REG_RECD_SPLIT_UNREC);
1829  gtk_widget_destroy (dialog);
1830 
1831  if (response == GTK_RESPONSE_YES)
1832  {
1833  char rec = 'n';
1834  trans = xaccSplitGetParent (split);
1835 
1836  gnc_tree_view_split_reg_set_dirty_trans (view, trans);
1837  if (!xaccTransIsOpen (trans))
1838  xaccTransBeginEdit (trans);
1839 
1840  xaccSplitSetReconcile (split, rec);
1841 
1842  gtk_tree_path_free (mpath);
1843  LEAVE("mark split unreconciled");
1844  return TRUE;
1845  }
1846  gtk_tree_path_free (mpath);
1847  LEAVE("Canceled split unreconciled");
1848  return FALSE;
1849 }
1850 
1851 
1852 /* Test for splits being reconciled and decide to allow changes */
1853 gboolean
1854 gnc_tree_control_split_reg_recn_test (GncTreeViewSplitReg *view, GtkTreePath *spath)
1855 {
1856  GncTreeModelSplitReg *model;
1857  GtkTreePath *mpath;
1858  GtkTreeIter m_iter;
1859  Split *split = NULL;
1860  Transaction *trans = NULL;
1861  gboolean is_trow1, is_trow2, is_split, is_blank;
1862  Account *anchor;
1863  char recn;
1864 
1865  ENTER(" ");
1866 
1867  /* This assumes we reset the flag whenever we change splits. */
1868  if (view->change_allowed)
1869  {
1870  LEAVE("change allowed is set");
1871  return TRUE;
1872  }
1873 
1874  model = gnc_tree_view_split_reg_get_model_from_view (view);
1875 
1876  anchor = gnc_tree_model_split_reg_get_anchor (model);
1877 
1878  mpath = gnc_tree_view_split_reg_get_model_path_from_sort_path (view, spath);
1879 
1880  if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &m_iter, mpath))
1881  {
1882  gtk_tree_path_free (mpath);
1883  LEAVE("No path");
1884  return TRUE;
1885  }
1886 
1887  gnc_tree_model_split_reg_get_split_and_trans (GNC_TREE_MODEL_SPLIT_REG (model), &m_iter,
1888  &is_trow1, &is_trow2, &is_split, &is_blank, &split, &trans);
1889 
1890  if (is_trow1 || is_trow2)
1891  split = xaccTransFindSplitByAccount (trans, anchor);
1892 
1893  if (!split)
1894  {
1895  gtk_tree_path_free (mpath);
1896  LEAVE("No split");
1897  return TRUE;
1898  }
1899 
1900  recn = xaccSplitGetReconcile (split);
1901 
1902  if (recn == YREC || xaccTransHasReconciledSplits (trans))
1903  {
1904  GtkWidget *dialog, *window;
1905  gint response;
1906  const gchar *title;
1907  const gchar *message;
1908 
1909  if(recn == YREC)
1910  {
1911  title = _("Change reconciled split?");
1912  message =
1913  _("You are about to change a reconciled split. Doing so might make "
1914  "future reconciliation difficult! Continue with this change?");
1915  }
1916  else
1917  {
1918  title = _("Change split linked to a reconciled split?");
1919  message =
1920  _("You are about to change a split that is linked to a reconciled split. "
1921  "Doing so might make future reconciliation difficult! Continue with this change?");
1922  }
1923 
1924  /* Does the user want to be warned? */
1925  window = gnc_tree_view_split_reg_get_parent (view);
1926  dialog =
1927  gtk_message_dialog_new (GTK_WINDOW (window),
1928  GTK_DIALOG_DESTROY_WITH_PARENT,
1929  GTK_MESSAGE_WARNING,
1930  GTK_BUTTONS_CANCEL,
1931  "%s", title);
1932  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
1933  "%s", message);
1934  gtk_dialog_add_button (GTK_DIALOG (dialog), _("Chan_ge Split"),
1935  GTK_RESPONSE_YES);
1936  response = gnc_dialog_run (GTK_DIALOG (dialog), GNC_PREF_WARN_REG_RECD_SPLIT_MOD);
1937  gtk_widget_destroy (dialog);
1938 
1939  if (response != GTK_RESPONSE_YES)
1940  {
1941  gtk_tree_path_free (mpath);
1942  LEAVE("cancel reconciled split");
1943  return FALSE;
1944  }
1945  }
1946  view->change_allowed = TRUE;
1947  gtk_tree_path_free (mpath);
1948  LEAVE(" ");
1949  return TRUE;
1950 }
1951 
1952 
1953 /* Return the account for name given or create it */
1954 Account *
1955 gnc_tree_control_split_reg_get_account_by_name (GncTreeViewSplitReg *view, const char *name)
1956 {
1957  GtkWindow *window;
1958  const char *placeholder = _("The account %s does not allow transactions.");
1959  const char *missing = _("The account %s does not exist. "
1960  "Would you like to create it?");
1961  Account *account;
1962 
1963  if (!name || (strlen(name) == 0))
1964  return NULL;
1965 
1966  /* Find the account */
1967  if (gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER, GNC_PREF_SHOW_LEAF_ACCT_NAMES))
1968  account = gnc_account_lookup_by_name (gnc_get_current_root_account(), name);
1969  else
1970  account = gnc_account_lookup_by_full_name (gnc_get_current_root_account(), name);
1971 
1972  if (!account)
1973  account = gnc_account_lookup_by_code (gnc_get_current_root_account(), name);
1974 
1975  window = gnc_ui_get_main_window (GTK_WIDGET (view));
1976 
1977  if (!account)
1978  {
1979  /* Ask if they want to create a new one. */
1980  if (!gnc_verify_dialog (window, TRUE, missing, name))
1981  return NULL;
1982 
1983  /* User said yes, they want to create a new account. */
1984  account = gnc_ui_new_accounts_from_name_window (window, name);
1985  if (!account)
1986  return NULL;
1987  }
1988  /* Now have the account. */
1989 
1990  /* See if the account (either old or new) is a placeholder. */
1991  if (xaccAccountGetPlaceholder (account))
1992  gnc_error_dialog (window, placeholder, name);
1993 
1994  /* Be seeing you. */
1995  return account;
1996 }
1997 
1998 /*****************************************************************************
1999  * ClipBoard Functions *
2000  *****************************************************************************/
2001 static Transaction *clipboard_trans = NULL;
2002 /* Must never dereference. */
2003 static const Account *clipboard_acct = NULL;
2004 
2005 
2006 /* Return the split account for which ancestor is it's parent */
2007 static Account *
2008 gtc_sr_get_account_for_trans_ancestor (const Transaction *trans, const Account *ancestor)
2009 {
2010  GList *node;
2011 
2012  for (node = xaccTransGetSplitList (trans); node; node = node->next)
2013  {
2014  Split *split = node->data;
2015  Account *split_acc = xaccSplitGetAccount (split);
2016 
2017  if (!xaccTransStillHasSplit (trans, split))
2018  continue;
2019 
2020  if (ancestor == split_acc)
2021  return split_acc;
2022 
2023  if (ancestor && xaccAccountHasAncestor (split_acc, ancestor))
2024  return split_acc;
2025  }
2026  return NULL;
2027 }
2028 
2029 
2030 void
2031 gnc_tree_control_split_reg_cut_trans (GncTreeViewSplitReg *view)
2032 {
2033  GncTreeModelSplitReg *model;
2034  Transaction *from_trans;
2035  Account *anchor;
2036 
2037  g_return_if_fail (GNC_IS_TREE_VIEW_SPLIT_REG (view));
2038 
2039  model = gnc_tree_view_split_reg_get_model_from_view (view);
2040 
2041  anchor = gnc_tree_model_split_reg_get_anchor (model);
2042 
2043  from_trans = gnc_tree_view_split_reg_get_current_trans (view);
2044  if (!from_trans)
2045  return;
2046 
2047  /* Test for read only */
2048  if (gtc_sr_is_trans_readonly_and_warn (view, from_trans))
2049  return;
2050 
2051  if (!xaccTransIsOpen (clipboard_trans))
2052  xaccTransBeginEdit (clipboard_trans);
2053  if (clipboard_trans)
2054  xaccTransDestroy (clipboard_trans);
2055 
2056  clipboard_trans = xaccTransCopyToClipBoard (from_trans);
2057  clipboard_acct = gtc_sr_get_account_for_trans_ancestor (from_trans, anchor);
2058 
2059  gnc_tree_view_split_reg_delete_current_trans (view);
2060 }
2061 
2062 
2063 void
2064 gnc_tree_control_split_reg_copy_trans (GncTreeViewSplitReg *view)
2065 {
2066  GncTreeModelSplitReg *model;
2067  Transaction *from_trans;
2068  Account *anchor;
2069 
2070  g_return_if_fail (GNC_IS_TREE_VIEW_SPLIT_REG (view));
2071 
2072  model = gnc_tree_view_split_reg_get_model_from_view (view);
2073 
2074  from_trans = gnc_tree_view_split_reg_get_current_trans (view);
2075  if (!from_trans)
2076  return;
2077 
2078  anchor = gnc_tree_model_split_reg_get_anchor (model);
2079 
2080  clipboard_acct = gtc_sr_get_account_for_trans_ancestor (from_trans, anchor);
2081 
2082  if (!xaccTransIsOpen (clipboard_trans))
2083  xaccTransBeginEdit (clipboard_trans);
2084  if (clipboard_trans)
2085  xaccTransDestroy (clipboard_trans);
2086 
2087  clipboard_trans = xaccTransCopyToClipBoard (from_trans);
2088 }
2089 
2090 void
2091 gnc_tree_control_split_reg_paste_trans (GncTreeViewSplitReg *view)
2092 {
2093  GncTreeModelSplitReg *model;
2094  Account *anchor_acct;
2095  Transaction *to_trans;
2096 
2097  g_return_if_fail (GNC_IS_TREE_VIEW_SPLIT_REG (view));
2098 
2099  model = gnc_tree_view_split_reg_get_model_from_view (view);
2100  anchor_acct = gnc_tree_model_split_reg_get_anchor (model);
2101 
2102  to_trans = gnc_tree_view_split_reg_get_current_trans (view);
2103  if (!to_trans || !clipboard_trans)
2104  return;
2105 
2106  /* See if we are being edited in another register */
2107  if (gtc_sr_trans_test_for_edit (view, to_trans))
2108  return;
2109 
2110  /* Test for read only */
2111  if (gtc_sr_is_trans_readonly_and_warn (view, to_trans))
2112  return;
2113 
2114  //FIXME You can not paste from gl to a register, is this too simplistic
2115  if (clipboard_acct == NULL && anchor_acct != NULL)
2116  {
2117  GtkWindow *window;
2118 
2119  window = gnc_ui_get_main_window (GTK_WIDGET (view));
2120  gnc_error_dialog (window, "%s",
2121  _("You can not paste from the general journal to a register."));
2122  return;
2123  }
2124 
2125  gnc_tree_view_split_reg_set_dirty_trans (view, to_trans);
2126  if (!xaccTransIsOpen (to_trans))
2127  xaccTransBeginEdit (to_trans);
2128 
2129  // Remove the blank split
2130  gnc_tree_model_split_reg_set_blank_split_parent (model, to_trans, TRUE);
2131 
2132  xaccTransCopyFromClipBoard (clipboard_trans, to_trans, clipboard_acct, anchor_acct, FALSE);
2133 
2134  // Add the blank split back
2135  gnc_tree_model_split_reg_set_blank_split_parent (model, to_trans, FALSE);
2136 
2137  // Refresh the view
2138  g_signal_emit_by_name (model, "refresh_trans", NULL);
2139 }
2140 
2141 void
2142 gnc_tree_control_auto_complete (GncTreeViewSplitReg *view, Transaction *trans, const gchar *new_text)
2143 {
2144  GncTreeModelSplitReg *model;
2145  Transaction *btrans;
2146  GtkListStore *desc_list;
2147  GtkTreeIter iter;
2148  gboolean valid;
2149 
2150  g_return_if_fail (GNC_IS_TREE_VIEW_SPLIT_REG (view));
2151  DEBUG("auto_complete - trans %p and description '%s'", trans, new_text);
2152 
2153  model = gnc_tree_view_split_reg_get_model_from_view (view);
2154 
2155  btrans = gnc_tree_model_split_get_blank_trans (model);
2156 
2157  // if we are not looking at the blank trans, return.
2158  if (trans != btrans)
2159  return;
2160 
2161  desc_list = gnc_tree_model_split_reg_get_description_list (model);
2162 
2163  valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (desc_list), &iter);
2164  while (valid)
2165  {
2166  Transaction *trans_from;
2167  gchar *text;
2168  // Walk through the list, reading each row
2169  gtk_tree_model_get (GTK_TREE_MODEL (desc_list), &iter, 0, &text, 1, &trans_from, -1);
2170 
2171  if (g_strcmp0 (text, new_text) == 0)
2172  {
2173  xaccTransCopyOnto (trans_from, trans);
2174  /* if there is a doclink, lets clear it */
2175  if (xaccTransGetDocLink (trans_from) != NULL)
2176  xaccTransSetDocLink (trans, "");
2177  g_free (text);
2178  break;
2179  }
2180  g_free (text);
2181 
2182  valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (desc_list), &iter);
2183  }
2184 }
2185 
gboolean xaccTransHasReconciledSplits(const Transaction *trans)
FIXME: document me.
Definition: Transaction.c:2723
Transaction * xaccMallocTransaction(QofBook *book)
The xaccMallocTransaction() will malloc memory and initialize it.
Definition: Transaction.c:511
const char * xaccAccountGetLastNum(const Account *acc)
Get the last num field of an Account.
Definition: Account.cpp:4933
void xaccTransSetDatePostedSecsNormalized(Transaction *trans, time64 time)
This function sets the posted date of the transaction, specified by a time64 (see ctime(3))...
gboolean gnc_commodity_is_currency(const gnc_commodity *cm)
Checks to see if the specified commodity is an ISO 4217 recognized currency or a legacy currency...
Account * gnc_ui_new_accounts_from_name_window(GtkWindow *parent, const char *name)
Display a modal window for creating a new account.
Split * xaccTransGetSplit(const Transaction *trans, int i)
Return a pointer to the indexed split in this transaction&#39;s split list.
gboolean xaccTransUseTradingAccounts(const Transaction *trans)
Determine whether this transaction should use commodity trading accounts.
Definition: Transaction.c:1034
gboolean xaccTransIsReadonlyByPostedDate(const Transaction *trans)
Returns TRUE if this Transaction is read-only because its posted-date is older than the "auto-readonl...
Definition: Transaction.c:2635
Date and Time handling routines.
This file contains the functions to present a gui to the user for creating a new account or editing a...
GtkWindow * gnc_ui_get_main_window(GtkWidget *widget)
Get a pointer to the final GncMainWindow widget is rooted in.
gboolean xaccTransIsOpen(const Transaction *trans)
The xaccTransIsOpen() method returns TRUE if the transaction is open for editing. ...
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:256
GNCAccountType xaccAccountGetType(const Account *acc)
Returns the account&#39;s account type.
Definition: Account.cpp:3279
gnc_numeric gnc_numeric_neg(gnc_numeric a)
Returns a newly created gnc_numeric that is the negative of the given gnc_numeric value...
gint sort_col
This is the column the sort direction is based on.
const char * xaccTransGetReadOnly(Transaction *trans)
Returns a non-NULL value if this Transaction was marked as read-only with some specific "reason" text...
Definition: Transaction.c:2596
#define DEBUG(format, args...)
Print a debugging message.
Definition: qoflog.h:264
void xaccSplitCopyOnto(const Split *from_split, Split *to_split)
This is really a helper for xaccTransCopyOnto.
Definition: Split.c:639
gboolean qof_book_use_split_action_for_num_field(const QofBook *book)
Returns TRUE if this book uses split action field as the &#39;Num&#39; field, FALSE if it uses transaction nu...
char xaccSplitGetReconcile(const Split *split)
Returns the value of the reconcile flag.
SplitRegisterType2 type
FIXME ? This may be the wrong place for these, may be the view ?
GtkSortType sort_direction
This is the direction of sort.
void xaccTransCopyOnto(const Transaction *from_trans, Transaction *to_trans)
Copy a transaction to another using the function below without changing any account information...
Definition: Transaction.c:727
void xaccSplitSetReconcile(Split *split, char recn)
Set the reconcile flag.
Transaction * xaccSplitGetParent(const Split *split)
Returns the parent transaction of the split.
Account * gnc_tree_model_split_reg_get_anchor(GncTreeModelSplitReg *model)
Return the default account for this register model.
gboolean xaccTransIsBalanced(const Transaction *trans)
Returns true if the transaction is balanced according to the rules currently in effect.
Definition: Transaction.c:1143
const char * xaccTransGetNum(const Transaction *trans)
Gets the transaction Number (or ID) field; rather than use this function directly, see &#39;gnc_get_num_action&#39; and &#39;gnc_get_action_num&#39; in engine/engine-helpers.c & .h which takes a user-set book option for selecting the source for the num-cell (the transaction-number or the split-action field) in registers/reports into account automatically.
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
gboolean gnc_strisnum(const gchar *s)
Returns true if string s is a number, possibly surrounded by whitespace.
Definition: qofutil.cpp:187
void xaccAccountSetLastNum(Account *acc, const char *num)
Set the last num field of an Account.
Definition: Account.cpp:4945
void xaccTransSetDatePostedGDate(Transaction *trans, GDate date)
This method modifies posted date of the transaction, specified by a GDate.
Definition: Transaction.c:2035
const char * xaccTransGetDocLink(const Transaction *trans)
Gets the transaction Document Link.
Definition: Transaction.c:2425
gboolean gnc_numeric_negative_p(gnc_numeric a)
Returns 1 if a < 0, otherwise returns 0.
#define VREC
split is void
Definition: Split.h:75
Account used to record multiple commodity transactions.
Definition: Account.h:158
void xaccTransDestroy(Transaction *trans)
Destroys a transaction.
Transaction * current_trans
Current transaction.
Account * gnc_account_lookup_by_name(const Account *parent, const char *name)
The gnc_account_lookup_by_name() subroutine fetches the account by name from the descendants of the s...
Definition: Account.cpp:3083
gboolean gnc_tree_model_split_reg_trans_is_in_view(GncTreeModelSplitReg *model, Transaction *trans)
Return TRUE if transaction is in the view list.
int xaccTransCountSplits(const Transaction *trans)
Returns the number of splits in this transaction.
Definition: Transaction.c:2404
convert single-entry accounts to clean double-entry
GDate * qof_book_get_autoreadonly_gdate(const QofBook *book)
Returns the GDate that is the threshold for auto-read-only.
Definition: qofbook.cpp:1112
gboolean xaccTransEqual(const Transaction *ta, const Transaction *tb, gboolean check_guids, gboolean check_splits, gboolean check_balances, gboolean assume_ordered)
Equality.
Definition: Transaction.c:875
void xaccTransVoid(Transaction *trans, const char *reason)
xaccTransVoid voids a transaction.
Definition: Transaction.c:2785
#define YREC
The Split has been reconciled.
Definition: Split.h:72
Account * gnc_account_lookup_by_code(const Account *parent, const char *code)
The gnc_account_lookup_by_code() subroutine works like gnc_account_lookup_by_name, but uses the account code.
Definition: Account.cpp:3096
#define FREC
frozen into accounting period
Definition: Split.h:73
void gnc_monetary_list_free(MonetaryList *list)
Free a MonetaryList and all the monetaries it points to.
void xaccTransScrubImbalance(Transaction *trans, Account *root, Account *account)
Correct transaction imbalances.
Definition: Scrub.c:794
time64 xaccTransRetDatePosted(const Transaction *trans)
Retrieve the posted date of the transaction.
Definition: Transaction.c:2492
void xaccTransCopyFromClipBoard(const Transaction *from_trans, Transaction *to_trans, const Account *from_acc, Account *to_acc, gboolean no_date)
This function explicitly must robustly handle some unusual input.
Definition: Transaction.c:751
const char * xaccTransGetDescription(const Transaction *trans)
Gets the transaction Description.
Account * gnc_account_lookup_by_full_name(const Account *any_acc, const gchar *name)
The gnc_account_lookup_full_name() subroutine works like gnc_account_lookup_by_name, but uses fully-qualified names using the given separator.
Definition: Account.cpp:3163
void xaccTransCommitEdit(Transaction *trans)
The xaccTransCommitEdit() method indicates that the changes to the transaction and its splits are com...
Additional event handling code.
void xaccTransBeginEdit(Transaction *trans)
The xaccTransBeginEdit() method must be called before any changes are made to a transaction or any of...
int xaccTransGetSplitIndex(const Transaction *trans, const Split *split)
Inverse of xaccTransGetSplit()
Definition: Transaction.c:2311
void xaccTransUnvoid(Transaction *trans)
xaccTransUnvoid restores a voided transaction to its original state.
Definition: Transaction.c:2869
gboolean gnc_numeric_positive_p(gnc_numeric a)
Returns 1 if a > 0, otherwise returns 0.
gboolean gnc_tree_control_split_reg_move_current_entry_updown(GncTreeViewSplitReg *view, gboolean move_up)
This implements the command of moving the current entry (where the cursor is currently located) one r...
Split * xaccMallocSplit(QofBook *book)
Constructor.
Definition: gmock-Split.cpp:37
Generic api to store and retrieve preferences.
Transaction * xaccTransReverse(Transaction *orig)
xaccTransReverse creates a Transaction that reverses the given transaction by inverting all the numer...
Definition: Transaction.c:2897
gnc_numeric xaccSplitGetValue(const Split *split)
Returns the value of this split in the transaction&#39;s commodity.
Definition: gmock-Split.cpp:84
void gnc_gdate_set_time64(GDate *gd, time64 time)
Set a GDate to a time64.
Definition: gnc-date.cpp:1247
gboolean xaccAccountHasAncestor(const Account *acc, const Account *ancestor)
Returns true if the account is &#39;ancestor&#39; or has &#39;ancestor&#39; as an ancestor.
Definition: Account.cpp:4385
Account * xaccSplitGetAccount(const Split *split)
Returns the account of this split, which was set through xaccAccountInsertSplit().
Definition: gmock-Split.cpp:53
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Get the account&#39;s commodity.
Definition: Account.cpp:3448
gboolean xaccTransGetIsClosingTxn(const Transaction *trans)
Returns whether this transaction is a "closing transaction".
Definition: Transaction.c:2455
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Returns the valuation commodity of this transaction.
Definition: Transaction.c:1367
gboolean xaccAccountGetPlaceholder(const Account *acc)
Get the "placeholder" flag for an account.
Definition: Account.cpp:4262
gboolean gnc_tree_control_split_reg_is_current_movable_updown(GncTreeViewSplitReg *view, gboolean move_up)
Query whether the current entry (where the cursor is currently located) can be moved one row upwards ...
MonetaryList * xaccTransGetImbalance(const Transaction *trans)
The xaccTransGetImbalance method returns a list giving the value of the transaction in each currency ...
Definition: Transaction.c:1071
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Get a boolean value from the preferences backend.
void xaccTransSetDocLink(Transaction *trans, const char *doclink)
Sets the transaction Document Link.
Definition: Transaction.c:2211
Transaction * xaccTransGetReversedBy(const Transaction *trans)
Returns the transaction that reversed the given transaction.
Definition: Transaction.c:2937
Split * xaccSplitGetOtherSplit(const Split *split)
The xaccSplitGetOtherSplit() is a convenience routine that returns the other of a pair of splits...
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
time64 gnc_time(time64 *tbuf)
get the current local time
Definition: gnc-date.cpp:273
The instance data structure for an account tree model.
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
void xaccTransSetDateEnteredSecs(Transaction *trans, time64 secs)
Modify the date of when the transaction was entered.
Definition: Transaction.c:2054
time64 xaccTransRetDateEntered(const Transaction *trans)
Retrieve the date of when the transaction was entered.
Definition: Transaction.c:2533
gboolean qof_book_uses_autoreadonly(const QofBook *book)
Returns TRUE if the auto-read-only feature should be used, otherwise FALSE.
Definition: qofbook.cpp:1086
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:2906
void qof_event_gen(QofInstance *entity, QofEventId event_id, gpointer event_data)
Invoke all registered event handlers using the given arguments.
Definition: qofevent.cpp:231
#define GNC_EVENT_ITEM_ADDED
These events are used when a split is added to an account.
Definition: gnc-event.h:45
GDate xaccTransGetDatePostedGDate(const Transaction *trans)
Retrieve the posted date of the transaction.
Definition: Transaction.c:2498
API for Transactions and Splits (journal entries)
SplitList * xaccTransGetSplitList(const Transaction *trans)
The xaccTransGetSplitList() method returns a GList of the splits in a transaction.
Transaction * xaccTransCopyToClipBoard(const Transaction *from_trans)
Copy a transaction to the &#39;clipboard&#39; transaction using dupe_transaction.
Definition: Transaction.c:711
gboolean gnc_commodity_equiv(const gnc_commodity *a, const gnc_commodity *b)
This routine returns TRUE if the two commodities are equivalent.
gnc_numeric xaccSplitGetAmount(const Split *split)
Returns the amount of the split in the account&#39;s commodity.
Definition: gmock-Split.cpp:69