GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
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 <[email protected]> *
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 [email protected] *
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 
34 #include "gnc-tree-control-split-reg.h"
35 #include "gnc-tree-model-split-reg.h"
36 #include "gnc-tree-util-split-reg.h"
37 #include "gnc-tree-view-split-reg.h"
38 #include "gnc-component-manager.h"
39 #include "gnc-ui.h"
40 #include "gnc-prefs.h"
41 #include "gnc-gdate-utils.h"
42 #include "gnome-utils/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  GtkWidget *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_tree_view_split_reg_get_parent (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  GtkWidget *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_tree_view_split_reg_get_parent (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  Split *split;
837  GtkWidget *dialog, *window;
838  gint response;
839  const gchar *warning;
840 
841  const char *title = _("Remove the splits from this transaction?");
842  const char *recn_warn = _("This transaction contains reconciled splits. "
843  "Modifying it is not a good idea because that will "
844  "cause your reconciled balance to be off.");
845 
846  trans = gnc_tree_view_split_reg_get_current_trans (view);
847 
848  if (trans == NULL)
849  return;
850 
851  /* See if we were asked to change a blank trans. */
852  if (trans == gnc_tree_control_split_reg_get_blank_trans (view))
853  return;
854 
855  /* Test for read only */
856  if (gtc_sr_is_trans_readonly_and_warn (view, trans))
857  return;
858 
859  /* See if we are being edited in another register */
860  if (gtc_sr_trans_test_for_edit (view, trans))
861  return;
862 
863  /* Make sure we ask to commit any changes before we proceed */
864  if (gtc_sr_trans_open_and_warn (view, trans))
865  return;
866 
867  window = gnc_tree_view_split_reg_get_parent (view);
868 
869  dialog = gtk_message_dialog_new (GTK_WINDOW (window),
870  GTK_DIALOG_DESTROY_WITH_PARENT,
871  GTK_MESSAGE_WARNING,
872  GTK_BUTTONS_NONE,
873  "%s", title);
874 
875  if (xaccTransHasReconciledSplits (trans))
876  {
877  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
878  "%s", recn_warn);
879  warning = GNC_PREF_WARN_REG_SPLIT_DEL_ALL_RECD;
880  }
881  else
882  {
883  warning = GNC_PREF_WARN_REG_SPLIT_DEL_ALL;
884  }
885 
886  gtk_dialog_add_button (GTK_DIALOG (dialog),
887  GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
888  gnc_gtk_dialog_add_button(dialog, _("_Remove Splits"),
889  GTK_STOCK_DELETE, GTK_RESPONSE_ACCEPT);
890  response = gnc_dialog_run (GTK_DIALOG(dialog), warning);
891  gtk_widget_destroy (dialog);
892  if (response != GTK_RESPONSE_ACCEPT)
893  return;
894 
895  gnc_tree_view_split_reg_reinit_trans (view);
896 }
897 
898 
899 /* Delete the currently selected item */
900 void
901 gnc_tree_control_split_reg_delete (GncTreeViewSplitReg *view, gpointer data)
902 {
903  GncTreeModelSplitReg *model;
904  Account *anchor;
905  RowDepth depth;
906  Transaction *trans;
907  Split *split;
908  GtkWidget *dialog, *window;
909  gint response;
910  const gchar *warning;
911 
912  /* get the current split based on cursor position */
913  split = gnc_tree_view_split_reg_get_current_split (view);
914  if (split == NULL)
915  {
916  split = gnc_tree_control_split_reg_get_current_trans_split (view);
917  if (split == NULL)
918  {
919  LEAVE("split is NULL");
920  return;
921  }
922  }
923 
924  model = gnc_tree_view_split_reg_get_model_from_view (view);
925 
926  anchor = gnc_tree_model_split_reg_get_anchor (model);
927 
928  trans = xaccSplitGetParent (split);
929 
930  if (trans == NULL)
931  return;
932 
933  /* Test for read only */
934  if (gtc_sr_is_trans_readonly_and_warn (view, trans))
935  return;
936 
937  /* See if we are being edited in another register */
938  if (gtc_sr_trans_test_for_edit (view, trans))
939  return;
940 
941  depth = gnc_tree_view_reg_get_selected_row_depth (view);
942 
943  /* Deleting the blank split just cancels */
944  {
945  Split *blank_split = gnc_tree_control_split_reg_get_blank_split (view);
946 
947  if (split == blank_split)
948  return;
949  }
950 
951  /* Deleting the blank trans just cancels */
952  {
953  Transaction *blank_trans = gnc_tree_control_split_reg_get_blank_trans (view);
954 
955  if (trans == blank_trans)
956  return;
957  }
958 
959  window = gnc_tree_view_split_reg_get_parent (view);
960 
961  /* On a split cursor, just delete the one split. */
962  if (depth == SPLIT3)
963  {
964  const char *format = _("Delete the split '%s' from the transaction '%s'?");
965  const char *recn_warn = _("You would be deleting a reconciled split! "
966  "This is not a good idea as it will cause your "
967  "reconciled balance to be off.");
968  const char *anchor_error = _("You cannot delete this split.");
969  const char *anchor_split = _("This is the split anchoring this transaction "
970  "to the register. You may not delete it from "
971  "this register window. You may delete the "
972  "entire transaction from this window, or you "
973  "may navigate to a register that shows "
974  "another side of this same transaction and "
975  "delete the split from that register.");
976  char *buf = NULL;
977  const char *memo;
978  const char *desc;
979  char recn;
980  if ((split == gnc_tree_control_split_reg_get_current_trans_split (view)) ||
981  (split == gnc_tree_model_split_reg_trans_get_split_equal_to_ancestor (trans, anchor)))
982  {
983  dialog = gtk_message_dialog_new (GTK_WINDOW (window),
984  GTK_DIALOG_MODAL
985  | GTK_DIALOG_DESTROY_WITH_PARENT,
986  GTK_MESSAGE_ERROR,
987  GTK_BUTTONS_OK,
988  "%s", anchor_error);
989  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
990  "%s", anchor_split);
991  gtk_dialog_run (GTK_DIALOG (dialog));
992  gtk_widget_destroy (dialog);
993  return;
994  }
995 
996  memo = xaccSplitGetMemo (split);
997  memo = (memo && *memo) ? memo : _("(no memo)");
998 
999  desc = xaccTransGetDescription (trans);
1000  desc = (desc && *desc) ? desc : _("(no description)");
1001 
1002  /* ask for user confirmation before performing permanent damage */
1003  buf = g_strdup_printf (format, memo, desc);
1004  dialog = gtk_message_dialog_new (GTK_WINDOW (window),
1005  GTK_DIALOG_MODAL
1006  | GTK_DIALOG_DESTROY_WITH_PARENT,
1007  GTK_MESSAGE_QUESTION,
1008  GTK_BUTTONS_NONE,
1009  "%s", buf);
1010  g_free(buf);
1011  recn = xaccSplitGetReconcile (split);
1012  if (recn == YREC || recn == FREC)
1013  {
1014  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
1015  "%s", recn_warn);
1016  warning = GNC_PREF_WARN_REG_SPLIT_DEL_RECD;
1017  }
1018  else
1019  {
1020  warning = GNC_PREF_WARN_REG_SPLIT_DEL;
1021  }
1022 
1023  gtk_dialog_add_button (GTK_DIALOG (dialog),
1024  GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
1025  gnc_gtk_dialog_add_button (dialog, _("_Delete Split"),
1026  GTK_STOCK_DELETE, GTK_RESPONSE_ACCEPT);
1027  response = gnc_dialog_run (GTK_DIALOG (dialog), warning);
1028  gtk_widget_destroy (dialog);
1029  if (response != GTK_RESPONSE_ACCEPT)
1030  return;
1031 
1032  gnc_tree_view_split_reg_delete_current_split (view);
1033  return;
1034  }
1035 
1036  g_return_if_fail (depth == TRANS1 || depth == TRANS2);
1037 
1038  /* On a transaction cursor with 2 or fewer splits in single or double
1039  * mode, we just delete the whole transaction, kerblooie */
1040  {
1041  const char *title = _("Delete the current transaction?");
1042  const char *recn_warn = _("You would be deleting a transaction "
1043  "with reconciled splits! "
1044  "This is not a good idea as it will cause your "
1045  "reconciled balance to be off.");
1046 
1047  dialog = gtk_message_dialog_new (GTK_WINDOW (window),
1048  GTK_DIALOG_MODAL
1049  | GTK_DIALOG_DESTROY_WITH_PARENT,
1050  GTK_MESSAGE_WARNING,
1051  GTK_BUTTONS_NONE,
1052  "%s", title);
1053  if (xaccTransHasReconciledSplits (trans))
1054  {
1055  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
1056  "%s", recn_warn);
1057  warning = GNC_PREF_WARN_REG_TRANS_DEL_RECD;
1058  }
1059  else
1060  {
1061  warning = GNC_PREF_WARN_REG_TRANS_DEL;
1062  }
1063  gtk_dialog_add_button (GTK_DIALOG (dialog),
1064  GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL);
1065  gnc_gtk_dialog_add_button (dialog, _("_Delete Transaction"),
1066  GTK_STOCK_DELETE, GTK_RESPONSE_ACCEPT);
1067  response = gnc_dialog_run (GTK_DIALOG (dialog), warning);
1068  gtk_widget_destroy (dialog);
1069  if (response != GTK_RESPONSE_ACCEPT)
1070  return;
1071 
1072  gnc_tree_view_split_reg_delete_current_trans (view);
1073  return;
1074  }
1075 }
1076 
1077 
1078 /* Add Reverse Transaction */
1079 void
1080 gnc_tree_control_split_reg_reverse_current (GncTreeViewSplitReg *view)
1081 {
1082  GtkWidget *window;
1083  Transaction *trans = NULL, *new_trans = NULL;
1084  GList *snode = NULL;
1085  gboolean changed = FALSE;
1086 
1087  ENTER(" ");
1088 
1089  trans = gnc_tree_view_split_reg_get_current_trans (view);
1090 
1091  if (trans == NULL)
1092  {
1093  LEAVE("Trans is Null");
1094  return;
1095  }
1096 
1097  /* See if we were asked to reverse a blank trans. */
1098  if (trans == gnc_tree_control_split_reg_get_blank_trans (view))
1099  {
1100  LEAVE("Skip blank trans");
1101  return;
1102  }
1103 
1104  /* Test for read only */
1105  if (gtc_sr_is_trans_readonly_and_warn (view, trans))
1106  {
1107  LEAVE("Read only");
1108  return;
1109  }
1110 
1111  /* See if we are being edited in another register */
1112  if (gtc_sr_trans_test_for_edit (view, trans))
1113  {
1114  LEAVE("Open in different register");
1115  return;
1116  }
1117 
1118  window = gnc_tree_view_split_reg_get_parent (view);
1119 
1120  if (xaccTransGetReversedBy (trans))
1121  {
1122  gnc_error_dialog (window, "%s",
1123  _("A reversing entry has already been created for this transaction."));
1124  LEAVE("Already have reversing transaction");
1125  return;
1126  }
1127 
1128  /* Make sure we ask to commit any changes before we add reverse transaction */
1129  if (gtc_sr_trans_open_and_warn (view, trans))
1130  {
1131  LEAVE("save cancelled");
1132  return;
1133  }
1134 
1135  /* Create reverse transaction */
1136  new_trans = xaccTransReverse (trans);
1137 
1138  xaccTransBeginEdit (new_trans);
1139 
1140  /* Clear transaction level info */
1141  xaccTransSetDatePostedSecsNormalized (new_trans, gnc_time (NULL));
1142  xaccTransSetDateEnteredSecs (new_trans, gnc_time (NULL));
1143 
1144  xaccTransCommitEdit (new_trans);
1145 
1146  // We need to loop through the splits and send an event to update the register.
1147  for (snode = xaccTransGetSplitList (new_trans); snode; snode = snode->next)
1148  {
1149  if (xaccTransStillHasSplit (new_trans, snode->data))
1150  {
1151  /* Send an event based on the split account */
1152  qof_event_gen (QOF_INSTANCE (xaccSplitGetAccount(snode->data)), GNC_EVENT_ITEM_ADDED, snode->data);
1153  }
1154  }
1155 
1156  /* give gtk+ a chance to handle pending events */
1157  while (gtk_events_pending ())
1158  gtk_main_iteration ();
1159 
1160  /* Now jump to new trans */
1161  gnc_tree_control_split_reg_jump_to (view, NULL, xaccTransGetSplit (new_trans, 0), FALSE);
1162 
1163  LEAVE("Reverse transaction created");
1164 }
1165 
1166 
1167 /* Duplicate the current selection */
1168 gboolean
1169 gnc_tree_control_split_reg_duplicate_current (GncTreeViewSplitReg *view)
1170 {
1171  GncTreeModelSplitReg *model;
1172  GtkWidget *window;
1173  RowDepth depth;
1174  Transaction *trans;
1175  Split *blank_split;
1176  Split *split, *trans_split;
1177  gboolean changed = FALSE;
1178  gboolean use_split_action_for_num_field = FALSE;
1179 
1180  ENTER("");
1181 
1182  model = gnc_tree_view_split_reg_get_model_from_view (view);
1183 
1184  blank_split = gnc_tree_control_split_reg_get_blank_split (view);
1185  split = gnc_tree_view_split_reg_get_current_split (view);
1186  trans_split = gnc_tree_control_split_reg_get_current_trans_split (view);
1187 
1188 
1189  depth = gnc_tree_view_reg_get_selected_row_depth (view);
1190 
1191  use_split_action_for_num_field = qof_book_use_split_action_for_num_field (gnc_get_current_book());
1192 
1193  trans = gnc_tree_view_split_reg_get_current_trans (view);
1194 
1195  /* This shouldn't happen, but be paranoid. */
1196  if (trans == NULL)
1197  return FALSE;
1198 
1199  /* See if we were asked to change a blank trans. */
1200  if (trans == gnc_tree_control_split_reg_get_blank_trans (view))
1201  {
1202  LEAVE("Skip blank trans");
1203  return FALSE;
1204  }
1205 
1206  /* See if we were asked to change a blank split. */
1207  if (split == blank_split)
1208  {
1209  LEAVE("Skip blank split");
1210  return FALSE;
1211  }
1212 
1213  /* Test for read only */
1214  if (gtc_sr_is_trans_readonly_and_warn (view, trans))
1215  {
1216  LEAVE("Read only");
1217  return FALSE;
1218  }
1219 
1220  /* See if we are being edited in another register */
1221  if (gtc_sr_trans_test_for_edit (view, trans))
1222  {
1223  LEAVE("Open in different register");
1224  return FALSE;
1225  }
1226 
1227  /* Make sure we ask to commit any changes before we proceed */
1228  if (gtc_sr_trans_open_and_warn (view, trans))
1229  {
1230  LEAVE("save cancelled");
1231  return FALSE;
1232  }
1233 
1234  window = gnc_tree_view_split_reg_get_parent (view);
1235 
1236  /* Ok, we are now ready to make the copy. */
1237  if (depth == SPLIT3)
1238  {
1239  Split *new_split;
1240  gboolean new_act_num = FALSE;
1241  char *out_num;
1242  time64 date;
1243 
1244  /* We are on a split in an expanded transaction.
1245  * Just copy the split and add it to the transaction.
1246  * However, if the split-action field is being used as the register
1247  * number, and the action field is a number, request a new value or
1248  * cancel. Need to get next number and update account last num from
1249  * split account not register account, which may be the same or not */
1250 
1251  if (split != trans_split)
1252  {
1253  if (use_split_action_for_num_field && gnc_strisnum (gnc_get_num_action (NULL, split)))
1254  {
1255  Account *account = xaccSplitGetAccount (split);
1256  const char* title = _("New Split Information");
1257  const char *in_num = NULL;
1258  date = time (0);
1259 
1260  if (account)
1261  in_num = xaccAccountGetLastNum (account);
1262  else
1263  in_num = gnc_get_num_action (NULL, split);
1264 
1265  if (!gnc_dup_trans_dialog (window, title, FALSE,
1266  &date, in_num, &out_num, NULL, NULL))
1267  {
1268  LEAVE("dup cancelled");
1269  return FALSE;
1270  }
1271  new_act_num = TRUE;
1272  }
1273 
1274  new_split = xaccMallocSplit (gnc_get_current_book ());
1275 
1276  // Remove the blank split
1277  gnc_tree_model_split_reg_set_blank_split_parent (model, trans, TRUE);
1278 
1279  if (!xaccTransIsOpen (trans))
1280  xaccTransBeginEdit (trans);
1281  gnc_tree_view_split_reg_set_dirty_trans (view, trans);
1282 
1283  xaccSplitCopyOnto (split, new_split);
1284  xaccSplitSetParent (new_split, trans);
1285 
1286  // Add the blank split
1287  gnc_tree_model_split_reg_set_blank_split_parent (model, trans, FALSE);
1288 
1289  if (new_act_num) /* if new number supplied by user dialog */
1290  gnc_set_num_action (NULL, new_split, out_num, NULL);
1291 
1292  if (new_act_num && gnc_strisnum (out_num))
1293  {
1294  Account *account = xaccSplitGetAccount (new_split);
1295 
1296  /* If current register is for account, set last num */
1297  if (account == gnc_tree_model_split_reg_get_anchor (model))
1298  xaccAccountSetLastNum (account, out_num);
1299  }
1300  if (new_act_num)
1301  g_free (out_num);
1302  }
1303  else
1304  {
1305  gnc_error_dialog (window, "%s",
1306  _("This is the split anchoring this transaction to the register."
1307  " You can not duplicate it from this register window."));
1308  LEAVE("split anchoring this transaction");
1309  return FALSE;
1310  }
1311  }
1312  else
1313  {
1314  Transaction *new_trans;
1315  int trans_split_index;
1316  int split_index;
1317  const char *in_num = NULL;
1318  const char *in_tnum = NULL;
1319  char *out_num;
1320  char *out_tnum;
1321  time64 date;
1322  gboolean use_autoreadonly = qof_book_uses_autoreadonly (gnc_get_current_book());
1323 
1324  /* We are on a transaction row. Copy the whole transaction. */
1325 
1326  date = time (0);
1327  if (gnc_strisnum (gnc_get_num_action (trans, trans_split)))
1328  {
1329  Account *account = gnc_tree_model_split_reg_get_anchor (model);
1330 
1331  if (account)
1332  in_num = xaccAccountGetLastNum (account);
1333  else
1334  in_num = gnc_get_num_action (trans, trans_split);
1335  }
1336 
1337  in_tnum = (use_split_action_for_num_field
1338  ? gnc_get_num_action (trans, NULL)
1339  : NULL);
1340 
1341  if (!gnc_dup_trans_dialog (window, NULL, TRUE,
1342  &date, in_num, &out_num, in_tnum, &out_tnum))
1343  {
1344  LEAVE("dup cancelled");
1345  return FALSE;
1346  }
1347 
1348  if (use_autoreadonly)
1349  {
1350  GDate d;
1351  GDate *readonly_threshold = qof_book_get_autoreadonly_gdate (gnc_get_current_book());
1352  gnc_gdate_set_time64 (&d, date);
1353  if (g_date_compare (&d, readonly_threshold) < 0)
1354  {
1355  GtkWidget *dialog = gtk_message_dialog_new (GTK_WINDOW (window),
1356  0,
1357  GTK_MESSAGE_ERROR,
1358  GTK_BUTTONS_OK,
1359  "%s", _("Cannot store a transaction at this date"));
1360  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
1361  "%s", _("The entered date of the duplicated transaction is older than the \"Read-Only Threshold\" set for this book. "
1362  "This setting can be changed in File -> Properties -> Accounts."));
1363  gtk_dialog_run (GTK_DIALOG (dialog));
1364  gtk_widget_destroy (dialog);
1365 
1366  g_date_free (readonly_threshold);
1367  LEAVE("entered date older than read-only threshold");
1368  return FALSE;
1369  }
1370  g_date_free (readonly_threshold);
1371  }
1372 
1373  trans_split_index = xaccTransGetSplitIndex (trans, trans_split);
1374 
1375  new_trans = xaccMallocTransaction (gnc_get_current_book ());
1376 
1377  xaccTransBeginEdit (new_trans);
1378 
1379  xaccTransCopyOnto (trans, new_trans);
1380 
1381  xaccTransSetDatePostedSecsNormalized (new_trans, date);
1382 
1383  /* We also must set a new DateEntered on the new entry
1384  * because otherwise the ordering is not deterministic */
1385  xaccTransSetDateEnteredSecs(new_trans, gnc_time(NULL));
1386 
1387  /* set per book option */
1388  gnc_set_num_action (new_trans, NULL, out_num, out_tnum);
1389 
1390  if (gnc_strisnum (out_num))
1391  {
1392  Account *account = gnc_tree_model_split_reg_get_anchor (model);
1393 
1394  /* If current register is for account, set last num */
1395  if (account)
1396  xaccAccountSetLastNum (account, out_num);
1397  }
1398 
1399  if (use_split_action_for_num_field)
1400  {
1401  /* find split in new_trans that equals trans_split and set
1402  * split_action to out_num */
1403  gnc_set_num_action (NULL,
1404  xaccTransGetSplit (new_trans, trans_split_index),
1405  out_num, NULL);
1406  /* note that if the transaction has multiple splits to the register
1407  * account, only the anchor split will be set with user input. The
1408  * user will have to adjust other splits manually. */
1409  }
1410 
1411  xaccTransCommitEdit (new_trans);
1412 
1413  if (out_num != NULL)
1414  g_free (out_num);
1415 
1416  if (use_split_action_for_num_field && out_tnum != NULL)
1417  g_free (out_tnum);
1418  }
1419  LEAVE(" ");
1420  return TRUE;
1421 }
1422 
1423 
1424 static gboolean gtcsr_move_current_entry_updown(GncTreeViewSplitReg *view,
1425  gboolean move_up, gboolean really_do_it)
1426 {
1427  GncTreeModelSplitReg *model;
1428  GtkTreePath *mpath = NULL, *spath = NULL, *spath_target = NULL, *mpath_target = NULL;
1429  GtkTreeIter m_iter, m_iter_target;
1430  gboolean resultvalue = FALSE;
1431  g_return_val_if_fail(view, FALSE);
1432 
1433  ENTER("");
1434 
1435  // The allocated memory references will all be cleaned up in the
1436  // updown_finish: label.
1437 
1438  model = gnc_tree_view_split_reg_get_model_from_view (view);
1439  g_return_val_if_fail(model, FALSE);
1440 
1441  if (model->sort_col != COL_DATE)
1442  {
1443  LEAVE("Not sorted by date - no up/down move available");
1444  return FALSE;
1445  }
1446 
1447  mpath = gnc_tree_view_split_reg_get_current_path (view);
1448  if (!mpath)
1449  {
1450  LEAVE("No current path available - probably on the blank split.");
1451  goto updown_finish;
1452  }
1453 
1454  spath = gnc_tree_view_split_reg_get_sort_path_from_model_path (view, mpath);
1455  g_return_val_if_fail(spath, FALSE);
1456 
1457  spath_target = gtk_tree_path_copy(spath);
1458  if (move_up)
1459  {
1460  gboolean move_was_made = gtk_tree_path_prev(spath_target);
1461  if (!move_was_made)
1462  {
1463  LEAVE("huh, no path_prev() possible");
1464  goto updown_finish;
1465  }
1466  }
1467  else
1468  {
1469  gtk_tree_path_next(spath_target);
1470  // The path_next() function does not give a return value, see
1471  // https://mail.gnome.org/archives/gtk-list/2010-January/msg00171.html
1472  }
1473 
1474  if (gtk_tree_path_compare(spath, spath_target) == 0)
1475  {
1476  LEAVE("oops, paths are equal");
1477  goto updown_finish;
1478  }
1479 
1480  mpath_target = gnc_tree_view_split_reg_get_model_path_from_sort_path (view, spath_target);
1481  if (!mpath_target)
1482  {
1483  LEAVE("no path to target row");
1484  goto updown_finish;
1485  }
1486 
1487  if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &m_iter, mpath))
1488  {
1489  LEAVE("No iter for current row");
1490  goto updown_finish;
1491  }
1492  if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &m_iter_target, mpath_target))
1493  {
1494  LEAVE("No iter for target row");
1495  goto updown_finish;
1496  }
1497 
1498  {
1499  gboolean is_blank, is_blank_target;
1500  Split *current_split, *target_split;
1501  Transaction *current_trans, *target_trans;
1502  gnc_tree_model_split_reg_get_split_and_trans (GNC_TREE_MODEL_SPLIT_REG (model), &m_iter,
1503  NULL, NULL, NULL, &is_blank,
1504  &current_split, &current_trans);
1505  gnc_tree_model_split_reg_get_split_and_trans (GNC_TREE_MODEL_SPLIT_REG (model), &m_iter_target,
1506  NULL, NULL, NULL, &is_blank_target,
1507  &target_split, &target_trans);
1508  if (is_blank || is_blank_target)
1509  {
1510  LEAVE("blank split involved, ignored.");
1511  goto updown_finish;
1512  }
1513  if (xaccTransEqual(current_trans, target_trans, TRUE, FALSE, FALSE, FALSE))
1514  {
1515  LEAVE("two times the same txn, ignored.");
1516  goto updown_finish;
1517  }
1518  if (xaccTransGetIsClosingTxn(current_trans)
1519  || xaccTransGetIsClosingTxn(target_trans))
1520  {
1521  LEAVE("One of the txn is book-closing - no re-ordering allowed.");
1522  goto updown_finish;
1523  }
1524 
1525  /* Only continue if both have the same date and num, because the
1526  * "standard ordering" is tied to the date anyway. */
1527  {
1528  Timespec t1, t2;
1529  GDate d1 = xaccTransGetDatePostedGDate(current_trans),
1530  d2 = xaccTransGetDatePostedGDate(target_trans);
1531  if (g_date_compare(&d1, &d2) != 0)
1532  {
1533  LEAVE("unequal DatePosted, ignoring");
1534  goto updown_finish;
1535  }
1536  if (g_strcmp0(xaccTransGetNum(current_trans),
1537  xaccTransGetNum(target_trans)) != 0)
1538  {
1539  LEAVE("unequal Num, ignoring");
1540  goto updown_finish;
1541  }
1542 
1543  /* Special treatment if the equality doesn't hold if we access the
1544  dates as timespec. See the comment in gncEntrySetDateGDate() for the
1545  reason: Some code used the timespec at noon for the EntryDate, other
1546  code used the timespec at the start of day. */
1547  t1 = xaccTransRetDatePostedTS(current_trans);
1548  t2 = xaccTransRetDatePostedTS(target_trans);
1549  if (really_do_it && !timespec_equal(&t1, &t2))
1550  {
1551  /* Timespecs are not equal, even though the GDates were equal? Then
1552  we set the GDates again. This will force the timespecs to be equal
1553  as well. */
1554  xaccTransSetDatePostedGDate(current_trans, d1);
1555  xaccTransSetDatePostedGDate(target_trans, d2);
1556  }
1557  }
1558 
1559  // Check whether any of the two splits are frozen
1560  if (xaccSplitGetReconcile(current_split) == FREC
1561  || xaccSplitGetReconcile(target_split) == FREC)
1562  {
1563  LEAVE("either current or target split is frozen. No modification allowed.");
1564  goto updown_finish;
1565  }
1566 
1567  // If really_do_it is FALSE, we are only in query mode and shouldn't
1568  // modify anything. But if it is TRUE, please go ahead and do the move.
1569  if (really_do_it)
1570  {
1571  // Check whether any of the two splits are reconciled
1572  if (xaccSplitGetReconcile(current_split) == YREC
1573  && !gnc_tree_control_split_reg_recn_test(view, spath))
1574  {
1575  LEAVE("current split is reconciled and user chose not to modify it");
1576  goto updown_finish;
1577  }
1578  if (xaccSplitGetReconcile(target_split) == YREC
1579  && !gnc_tree_control_split_reg_recn_test(view, spath_target))
1580  {
1581  LEAVE("target split is reconciled and user chose not to modify it");
1582  goto updown_finish;
1583  }
1584 
1585  PINFO("Ok, about to switch ordering for current desc='%s' target desc='%s'",
1586  xaccTransGetDescription(current_trans),
1587  xaccTransGetDescription(target_trans));
1588 
1589  gnc_suspend_gui_refresh ();
1590 
1591  /* Swap the date-entered of both entries. That's already
1592  * sufficient! */
1593  {
1594  Timespec time_current = xaccTransRetDateEnteredTS(current_trans);
1595  Timespec time_target = xaccTransRetDateEnteredTS(target_trans);
1596 
1597  /* Special treatment for identical times (potentially caused
1598  * by the "duplicate entry" command) */
1599  if (timespec_equal(&time_current, &time_target))
1600  {
1601  g_warning("Surprise - both DateEntered are equal.");
1602  /* We just increment the DateEntered of the previously
1603  * lower of the two by one second. This might still cause
1604  * issues if multiple entries had this problem, but
1605  * whatever. */
1606  if (move_up)
1607  time_current.tv_sec++;
1608  else
1609  time_target.tv_sec++;
1610  }
1611 
1612  /* Write the new DateEntered. */
1613  xaccTransSetDateEnteredTS(current_trans, &time_target);
1614  xaccTransSetDateEnteredTS(target_trans, &time_current);
1615 
1616  /* FIXME: Do we need to notify anyone about the changed ordering? */
1617  }
1618 
1619  gnc_resume_gui_refresh ();
1620 
1621  LEAVE("two txn switched, done.");
1622  }
1623  resultvalue = TRUE;
1624  goto updown_finish;
1625  }
1626 updown_finish:
1627  // memory cleanup
1628  //gtk_tree_path_free (mpath); // Should this be freed??
1629  gtk_tree_path_free(spath);
1630  gtk_tree_path_free(spath_target);
1631  gtk_tree_path_free(mpath_target);
1632  return resultvalue;
1633 }
1634 
1635 gboolean gnc_tree_control_split_reg_move_current_entry_updown (GncTreeViewSplitReg *view,
1636  gboolean move_up)
1637 {
1638  return gtcsr_move_current_entry_updown(view, move_up, TRUE);
1639 }
1640 
1641 gboolean gnc_tree_control_split_reg_is_current_movable_updown (GncTreeViewSplitReg *view,
1642  gboolean move_up)
1643 {
1644  return gtcsr_move_current_entry_updown(view, move_up, FALSE);
1645 }
1646 
1647 
1648 /* Save any open edited transactions on closing register */
1649 gboolean
1650 gnc_tree_control_split_reg_save (GncTreeViewSplitReg *view, gboolean reg_closing)
1651 {
1652  GncTreeModelSplitReg *model;
1653  RowDepth depth;
1654  Transaction *dirty_trans;
1655  Transaction *blank_trans;
1656  Transaction *trans;
1657  Account *account;
1658  Split *blank_split;
1659  const char *memo;
1660  const char *desc;
1661  Split *split, *current_trans_split;
1662 
1663  ENTER("view=%p, reg_closing=%s", view, reg_closing ? "TRUE" : "FALSE");
1664 
1665  if (!view)
1666  {
1667  LEAVE("no view");
1668  return FALSE;
1669  }
1670 
1671  /* Make sure we have stopped editing */
1672  gnc_tree_view_split_reg_finish_edit (view);
1673 
1674  if (reg_closing)
1675  view->reg_closing = TRUE;
1676 
1677  model = gnc_tree_view_split_reg_get_model_from_view (view);
1678 
1679  blank_split = gnc_tree_control_split_reg_get_blank_split (view);
1680  dirty_trans = gnc_tree_view_split_reg_get_dirty_trans (view);
1681  blank_trans = gnc_tree_control_split_reg_get_blank_trans (view);
1682 
1683  /* get the handle to the current split and transaction */
1684  split = gnc_tree_view_split_reg_get_current_split (view);
1685  trans = gnc_tree_view_split_reg_get_current_trans (view);
1686 
1687  current_trans_split = gnc_tree_control_split_reg_get_current_trans_split (view);
1688 
1689  if (trans == NULL)
1690  {
1691  LEAVE("no transaction");
1692  return FALSE;
1693  }
1694 
1695  if (!xaccTransIsOpen (trans))
1696  {
1697  LEAVE("transaction not open");
1698  return FALSE;
1699  }
1700 
1701  if (trans == dirty_trans )
1702  {
1703  if (trans != blank_trans)
1704  {
1705  /* Existing Transaction, we are going to commit. */
1706 
1707  PINFO("committing trans (%p)", trans);
1708  xaccTransCommitEdit (trans);
1709  gnc_tree_view_split_reg_set_dirty_trans (view, NULL);
1710 
1711  LEAVE("Existing Transaction committed");
1712  return TRUE;
1713  }
1714  else
1715  {
1716  /* Blank Transaction, we are going to commit. */
1717 
1718  PINFO("start committing blank trans (%p)", trans);
1719 //FIXME More stuff ?
1720 
1721  if (xaccTransCountSplits (trans) == 0)
1722  {
1723  GtkWidget *dialog, *window;
1724  gint response;
1725  const char *title = _("Not enough information for Blank Transaction?");
1726  const char *message =
1727  _("The blank transaction does not have enough information to save it. Would you like to "
1728  "return to the transaction to update, or cancel the save?");
1729  window = gnc_tree_view_split_reg_get_parent (view);
1730  dialog = gtk_message_dialog_new (GTK_WINDOW (window),
1731  GTK_DIALOG_DESTROY_WITH_PARENT,
1732  GTK_MESSAGE_QUESTION,
1733  GTK_BUTTONS_CANCEL,
1734  "%s", title);
1735  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
1736  "%s", message);
1737  gtk_dialog_add_button (GTK_DIALOG (dialog),
1738  _("_Return"), GTK_RESPONSE_ACCEPT);
1739 
1740  gtk_widget_grab_focus (gtk_dialog_get_widget_for_response (GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT));
1741 
1742  response = gtk_dialog_run (GTK_DIALOG (dialog));
1743 // response = gnc_dialog_run (GTK_DIALOG (dialog), "transaction_incomplete");
1744  gtk_widget_destroy (dialog);
1745 
1746  if (response != GTK_RESPONSE_ACCEPT)
1747  {
1748  LEAVE("save cancelled");
1749  return TRUE;
1750  }
1751  LEAVE("return to transaction");
1752  return FALSE;
1753  }
1754 
1755  xaccTransCommitEdit (trans);
1756  gnc_tree_view_split_reg_set_dirty_trans (view, NULL);
1757 
1758  LEAVE("Blank Transaction committed");
1759  return TRUE;
1760  }
1761  }
1762 
1763  LEAVE(" ");
1764  return TRUE;
1765 }
1766 
1767 
1768 /* Allow the reconcile flag to be changed */
1769 gboolean
1770 gnc_tree_control_split_reg_recn_change (GncTreeViewSplitReg *view, GtkTreePath *spath)
1771 {
1772  GtkWidget *dialog, *window;
1773  GncTreeModelSplitReg *model;
1774  GtkTreePath *mpath;
1775  GtkTreeIter m_iter;
1776  Split *split = NULL;
1777  Transaction *trans = NULL;
1778  gboolean is_trow1, is_trow2, is_split, is_blank;
1779  Account *anchor;
1780  char rec;
1781  const gchar *title = _("Mark split as unreconciled?");
1782  const gchar *message =
1783  _("You are about to mark a reconciled split as unreconciled. Doing "
1784  "so might make future reconciliation difficult! Continue "
1785  "with this change?");
1786  gint response;
1787 
1788  ENTER(" ");
1789 
1790  model = gnc_tree_view_split_reg_get_model_from_view (view);
1791 
1792  anchor = gnc_tree_model_split_reg_get_anchor (model);
1793 
1794  mpath = gnc_tree_view_split_reg_get_model_path_from_sort_path (view, spath);
1795 
1796  if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &m_iter, mpath))
1797  {
1798  gtk_tree_path_free (mpath);
1799  return FALSE;
1800  }
1801 
1802  gnc_tree_model_split_reg_get_split_and_trans (GNC_TREE_MODEL_SPLIT_REG (model), &m_iter,
1803  &is_trow1, &is_trow2, &is_split, &is_blank, &split, &trans);
1804 
1805  if (is_trow1 || is_trow2)
1806  split = xaccTransFindSplitByAccount (trans, anchor);
1807 
1808  rec = xaccSplitGetReconcile (split);
1809 
1810  if (rec != YREC)
1811  {
1812  gtk_tree_path_free (mpath);
1813  LEAVE("Not reconciled");
1814  return TRUE;
1815  }
1816 
1817  /* Does the user want to be warned? */
1818  window = gnc_tree_view_split_reg_get_parent (view);
1819  dialog =
1820  gtk_message_dialog_new (GTK_WINDOW (window),
1821  GTK_DIALOG_DESTROY_WITH_PARENT,
1822  GTK_MESSAGE_WARNING,
1823  GTK_BUTTONS_CANCEL,
1824  "%s", title);
1825  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
1826  "%s", message);
1827  gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Unreconcile"),
1828  GTK_RESPONSE_YES);
1829  response = gnc_dialog_run (GTK_DIALOG (dialog), GNC_PREF_WARN_REG_RECD_SPLIT_UNREC);
1830  gtk_widget_destroy (dialog);
1831 
1832  if (response == GTK_RESPONSE_YES)
1833  {
1834  char rec = 'n';
1835  trans = xaccSplitGetParent (split);
1836 
1837  gnc_tree_view_split_reg_set_dirty_trans (view, trans);
1838  if (!xaccTransIsOpen (trans))
1839  xaccTransBeginEdit (trans);
1840 
1841  xaccSplitSetReconcile (split, rec);
1842 
1843  gtk_tree_path_free (mpath);
1844  LEAVE("mark split unreconciled");
1845  return TRUE;
1846  }
1847  gtk_tree_path_free (mpath);
1848  LEAVE("Canceled split unreconciled");
1849  return FALSE;
1850 }
1851 
1852 
1853 /* Test for splits being reconciled and decide to allow changes */
1854 gboolean
1855 gnc_tree_control_split_reg_recn_test (GncTreeViewSplitReg *view, GtkTreePath *spath)
1856 {
1857  GncTreeModelSplitReg *model;
1858  GtkTreePath *mpath;
1859  GtkTreeIter m_iter;
1860  Split *split = NULL;
1861  Transaction *trans = NULL;
1862  gboolean is_trow1, is_trow2, is_split, is_blank;
1863  Account *anchor;
1864  char recn;
1865 
1866  ENTER(" ");
1867 
1868  /* This assumes we reset the flag whenever we change splits. */
1869  if (view->change_allowed)
1870  {
1871  LEAVE("change allowed is set");
1872  return TRUE;
1873  }
1874 
1875  model = gnc_tree_view_split_reg_get_model_from_view (view);
1876 
1877  anchor = gnc_tree_model_split_reg_get_anchor (model);
1878 
1879  mpath = gnc_tree_view_split_reg_get_model_path_from_sort_path (view, spath);
1880 
1881  if (!gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &m_iter, mpath))
1882  {
1883  gtk_tree_path_free (mpath);
1884  LEAVE("No path");
1885  return TRUE;
1886  }
1887 
1888  gnc_tree_model_split_reg_get_split_and_trans (GNC_TREE_MODEL_SPLIT_REG (model), &m_iter,
1889  &is_trow1, &is_trow2, &is_split, &is_blank, &split, &trans);
1890 
1891  if (is_trow1 || is_trow2)
1892  split = xaccTransFindSplitByAccount (trans, anchor);
1893 
1894  if (!split)
1895  {
1896  gtk_tree_path_free (mpath);
1897  LEAVE("No split");
1898  return TRUE;
1899  }
1900 
1901  recn = xaccSplitGetReconcile (split);
1902 
1903  if (recn == YREC || xaccTransHasReconciledSplits (trans))
1904  {
1905  GtkWidget *dialog, *window;
1906  gint response;
1907  const gchar *title;
1908  const gchar *message;
1909 
1910  if(recn == YREC)
1911  {
1912  title = _("Change reconciled split?");
1913  message =
1914  _("You are about to change a reconciled split. Doing so might make "
1915  "future reconciliation difficult! Continue with this change?");
1916  }
1917  else
1918  {
1919  title = _("Change split linked to a reconciled split?");
1920  message =
1921  _("You are about to change a split that is linked to a reconciled split. "
1922  "Doing so might make future reconciliation difficult! Continue with this change?");
1923  }
1924 
1925  /* Does the user want to be warned? */
1926  window = gnc_tree_view_split_reg_get_parent (view);
1927  dialog =
1928  gtk_message_dialog_new (GTK_WINDOW (window),
1929  GTK_DIALOG_DESTROY_WITH_PARENT,
1930  GTK_MESSAGE_WARNING,
1931  GTK_BUTTONS_CANCEL,
1932  "%s", title);
1933  gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
1934  "%s", message);
1935  gtk_dialog_add_button (GTK_DIALOG (dialog), _("Chan_ge Split"),
1936  GTK_RESPONSE_YES);
1937  response = gnc_dialog_run (GTK_DIALOG (dialog), GNC_PREF_WARN_REG_RECD_SPLIT_MOD);
1938  gtk_widget_destroy (dialog);
1939 
1940  if (response != GTK_RESPONSE_YES)
1941  {
1942  gtk_tree_path_free (mpath);
1943  LEAVE("cancel reconciled split");
1944  return FALSE;
1945  }
1946  }
1947  view->change_allowed = TRUE;
1948  gtk_tree_path_free (mpath);
1949  LEAVE(" ");
1950  return TRUE;
1951 }
1952 
1953 
1954 /* Return the account for name given or create it */
1955 Account *
1956 gnc_tree_control_split_reg_get_account_by_name (GncTreeViewSplitReg *view, const char *name)
1957 {
1958  GtkWidget *window;
1959  const char *placeholder = _("The account %s does not allow transactions.");
1960  const char *missing = _("The account %s does not exist. "
1961  "Would you like to create it?");
1962  char *account_name;
1963  Account *account;
1964 
1965  if (!name || (strlen(name) == 0))
1966  return NULL;
1967 
1968  /* Find the account */
1969  if (gnc_prefs_get_bool (GNC_PREFS_GROUP_GENERAL_REGISTER, GNC_PREF_SHOW_LEAF_ACCT_NAMES))
1970  account = gnc_account_lookup_by_name (gnc_get_current_root_account(), name);
1971  else
1972  account = gnc_account_lookup_by_full_name (gnc_get_current_root_account(), name);
1973 
1974  if (!account)
1975  account = gnc_account_lookup_by_code (gnc_get_current_root_account(), name);
1976 
1977  window = gnc_tree_view_split_reg_get_parent (view);
1978 
1979  if (!account)
1980  {
1981  /* Ask if they want to create a new one. */
1982  if (!gnc_verify_dialog (window, TRUE, missing, name))
1983  return NULL;
1984 
1985  /* User said yes, they want to create a new account. */
1986  account = gnc_ui_new_accounts_from_name_window (name);
1987  if (!account)
1988  return NULL;
1989  }
1990  /* Now have the account. */
1991 
1992  /* See if the account (either old or new) is a placeholder. */
1993  if (xaccAccountGetPlaceholder (account))
1994  gnc_error_dialog (window, placeholder, name);
1995 
1996  /* Be seeing you. */
1997  return account;
1998 }
1999 
2000 /*****************************************************************************
2001  * ClipBoard Functions *
2002  *****************************************************************************/
2003 static Transaction *clipboard_trans = NULL;
2004 /* Must never dereference. */
2005 static const Account *clipboard_acct = NULL;
2006 
2007 
2008 /* Return the split account for which ancestor is it's parent */
2009 static Account *
2010 gtc_sr_get_account_for_trans_ancestor (const Transaction *trans, const Account *ancestor)
2011 {
2012  GList *node;
2013 
2014  for (node = xaccTransGetSplitList (trans); node; node = node->next)
2015  {
2016  Split *split = node->data;
2017  Account *split_acc = xaccSplitGetAccount (split);
2018 
2019  if (!xaccTransStillHasSplit (trans, split))
2020  continue;
2021 
2022  if (ancestor == split_acc)
2023  return split_acc;
2024 
2025  if (ancestor && xaccAccountHasAncestor (split_acc, ancestor))
2026  return split_acc;
2027  }
2028  return NULL;
2029 }
2030 
2031 
2032 void
2033 gnc_tree_control_split_reg_cut_trans (GncTreeViewSplitReg *view)
2034 {
2035  GncTreeModelSplitReg *model;
2036  Transaction *from_trans;
2037  Account *anchor;
2038 
2039  g_return_if_fail (GNC_IS_TREE_VIEW_SPLIT_REG (view));
2040 
2041  model = gnc_tree_view_split_reg_get_model_from_view (view);
2042 
2043  anchor = gnc_tree_model_split_reg_get_anchor (model);
2044 
2045  from_trans = gnc_tree_view_split_reg_get_current_trans (view);
2046  if (!from_trans)
2047  return;
2048 
2049  /* Test for read only */
2050  if (gtc_sr_is_trans_readonly_and_warn (view, from_trans))
2051  return;
2052 
2053  if (!xaccTransIsOpen (clipboard_trans))
2054  xaccTransBeginEdit (clipboard_trans);
2055  if (clipboard_trans)
2056  xaccTransDestroy (clipboard_trans);
2057 
2058  clipboard_trans = xaccTransCopyToClipBoard (from_trans);
2059  clipboard_acct = gtc_sr_get_account_for_trans_ancestor (from_trans, anchor);
2060 
2061  gnc_tree_view_split_reg_delete_current_trans (view);
2062 }
2063 
2064 
2065 void
2066 gnc_tree_control_split_reg_copy_trans (GncTreeViewSplitReg *view)
2067 {
2068  GncTreeModelSplitReg *model;
2069  Transaction *from_trans;
2070  Account *from_acc, *anchor;
2071 
2072  g_return_if_fail (GNC_IS_TREE_VIEW_SPLIT_REG (view));
2073 
2074  model = gnc_tree_view_split_reg_get_model_from_view (view);
2075 
2076  from_trans = gnc_tree_view_split_reg_get_current_trans (view);
2077  if (!from_trans)
2078  return;
2079 
2080  anchor = gnc_tree_model_split_reg_get_anchor (model);
2081 
2082  clipboard_acct = gtc_sr_get_account_for_trans_ancestor (from_trans, anchor);
2083 
2084  if (!xaccTransIsOpen (clipboard_trans))
2085  xaccTransBeginEdit (clipboard_trans);
2086  if (clipboard_trans)
2087  xaccTransDestroy (clipboard_trans);
2088 
2089  clipboard_trans = xaccTransCopyToClipBoard (from_trans);
2090 }
2091 
2092 void
2093 gnc_tree_control_split_reg_paste_trans (GncTreeViewSplitReg *view)
2094 {
2095  GncTreeModelSplitReg *model;
2096  Account *anchor_acct;
2097  Transaction *to_trans;
2098 
2099  g_return_if_fail (GNC_IS_TREE_VIEW_SPLIT_REG (view));
2100 
2101  model = gnc_tree_view_split_reg_get_model_from_view (view);
2102  anchor_acct = gnc_tree_model_split_reg_get_anchor (model);
2103 
2104  to_trans = gnc_tree_view_split_reg_get_current_trans (view);
2105  if (!to_trans || !clipboard_trans)
2106  return;
2107 
2108  /* See if we are being edited in another register */
2109  if (gtc_sr_trans_test_for_edit (view, to_trans))
2110  return;
2111 
2112  /* Test for read only */
2113  if (gtc_sr_is_trans_readonly_and_warn (view, to_trans))
2114  return;
2115 
2116  //FIXME You can not paste from gl to a register, is this too simplistic
2117  if (clipboard_acct == NULL && anchor_acct != NULL)
2118  {
2119  GtkWidget *window;
2120 
2121  window = gnc_tree_view_split_reg_get_parent (view);
2122  gnc_error_dialog (window, "%s",
2123  _("You can not paste from the general ledger to a register."));
2124  return;
2125  }
2126 
2127  gnc_tree_view_split_reg_set_dirty_trans (view, to_trans);
2128  if (!xaccTransIsOpen (to_trans))
2129  xaccTransBeginEdit (to_trans);
2130 
2131  // Remove the blank split
2132  gnc_tree_model_split_reg_set_blank_split_parent (model, to_trans, TRUE);
2133 
2134  xaccTransCopyFromClipBoard (clipboard_trans, to_trans, clipboard_acct, anchor_acct, FALSE);
2135 
2136  // Add the blank split back
2137  gnc_tree_model_split_reg_set_blank_split_parent (model, to_trans, FALSE);
2138 
2139  // Refresh the view
2140  g_signal_emit_by_name (model, "refresh_trans", NULL);
2141 }
2142 
2143 void
2144 gnc_tree_control_auto_complete (GncTreeViewSplitReg *view, Transaction *trans, const gchar *new_text)
2145 {
2146  GncTreeModelSplitReg *model;
2147  Transaction *btrans, *dirty_trans;
2148  GtkListStore *desc_list;
2149  GtkTreeIter iter;
2150  gboolean valid;
2151 
2152  g_return_if_fail (GNC_IS_TREE_VIEW_SPLIT_REG (view));
2153  DEBUG("auto_complete - trans %p and description '%s'", trans, new_text);
2154 
2155  model = gnc_tree_view_split_reg_get_model_from_view (view);
2156 
2157  btrans = gnc_tree_model_split_get_blank_trans (model);
2158 
2159  // if we are not looking at the blank trans, return.
2160  if (trans != btrans)
2161  return;
2162 
2163  desc_list = gnc_tree_model_split_reg_get_description_list (model);
2164 
2165  valid = gtk_tree_model_get_iter_first (GTK_TREE_MODEL (desc_list), &iter);
2166  while (valid)
2167  {
2168  Transaction *trans_from;
2169  gchar *text;
2170  // Walk through the list, reading each row
2171  gtk_tree_model_get (GTK_TREE_MODEL (desc_list), &iter, 0, &text, 1, &trans_from, -1);
2172 
2173  if (g_strcmp0 (text, new_text) == 0)
2174  {
2175  xaccTransCopyOnto (trans_from, trans);
2176  g_free (text);
2177  break;
2178  }
2179  g_free (text);
2180 
2181  valid = gtk_tree_model_iter_next (GTK_TREE_MODEL (desc_list), &iter);
2182  }
2183 }
2184 
gboolean xaccTransHasReconciledSplits(const Transaction *trans)
Definition: Transaction.c:2433
Transaction * xaccMallocTransaction(QofBook *book)
Definition: Transaction.c:513
const char * xaccAccountGetLastNum(const Account *acc)
Definition: Account.c:4472
void xaccTransSetDatePostedSecsNormalized(Transaction *trans, time64 time)
Definition: Transaction.c:1920
gboolean gnc_commodity_is_currency(const gnc_commodity *cm)
Split * xaccTransGetSplit(const Transaction *trans, int i)
Definition: Transaction.c:2144
gboolean xaccTransUseTradingAccounts(const Transaction *trans)
Definition: Transaction.c:1015
gboolean xaccTransIsReadonlyByPostedDate(const Transaction *trans)
Definition: Transaction.c:2345
Dialog for create/edit an account.
gboolean xaccTransIsOpen(const Transaction *trans)
Definition: Transaction.c:1819
#define PINFO(format, args...)
Definition: qoflog.h:249
GNCAccountType xaccAccountGetType(const Account *acc)
Definition: Account.c:3009
gnc_numeric gnc_numeric_neg(gnc_numeric a)
#define DEBUG(format, args...)
Definition: qoflog.h:255
void xaccSplitCopyOnto(const Split *from_split, Split *to_split)
Definition: Split.c:686
gboolean qof_book_use_split_action_for_num_field(const QofBook *book)
char xaccSplitGetReconcile(const Split *split)
Definition: Split.c:1980
gboolean timespec_equal(const Timespec *ta, const Timespec *tb)
Account * gnc_ui_new_accounts_from_name_window(const char *name)
Use a 64-bit unsigned int timespec.
Definition: gnc-date.h:299
void xaccTransCopyOnto(const Transaction *from_trans, Transaction *to_trans)
Definition: Transaction.c:718
void xaccSplitSetReconcile(Split *split, char recn)
Definition: Split.c:1826
Transaction * xaccSplitGetParent(const Split *split)
Definition: Split.c:1903
gboolean xaccTransIsBalanced(const Transaction *trans)
Definition: Transaction.c:1124
const char * xaccTransGetNum(const Transaction *trans)
Definition: Transaction.c:2178
#define PERR(format, args...)
Definition: qoflog.h:237
#define ENTER(format, args...)
Definition: qoflog.h:261
gboolean gnc_strisnum(const gchar *s)
void xaccAccountSetLastNum(Account *acc, const char *num)
Definition: Account.c:4481
void xaccTransSetDatePostedGDate(Transaction *trans, GDate date)
Definition: Transaction.c:1928
void xaccTransSetDateEnteredTS(Transaction *trans, const Timespec *ts)
Definition: Transaction.c:1988
gboolean gnc_numeric_negative_p(gnc_numeric a)
#define VREC
Definition: Split.h:71
void xaccTransDestroy(Transaction *trans)
Definition: Transaction.c:1402
Account * gnc_account_lookup_by_name(const Account *parent, const char *name)
Definition: Account.c:2803
int xaccTransCountSplits(const Transaction *trans)
Definition: Transaction.c:2170
convert single-entry accounts to clean double-entry
GDate * qof_book_get_autoreadonly_gdate(const QofBook *book)
gboolean xaccTransEqual(const Transaction *ta, const Transaction *tb, gboolean check_guids, gboolean check_splits, gboolean check_balances, gboolean assume_ordered)
Definition: Transaction.c:857
void xaccTransVoid(Transaction *trans, const char *reason)
Definition: Transaction.c:2495
#define YREC
Definition: Split.h:68
Account * gnc_account_lookup_by_code(const Account *parent, const char *code)
Definition: Account.c:2836
#define FREC
Definition: Split.h:69
void gnc_monetary_list_free(MonetaryList *list)
Timespec xaccTransRetDateEnteredTS(const Transaction *trans)
Definition: Transaction.c:2273
void xaccTransScrubImbalance(Transaction *trans, Account *root, Account *account)
Definition: Scrub.c:521
void xaccTransCopyFromClipBoard(const Transaction *from_trans, Transaction *to_trans, const Account *from_acc, Account *to_acc, gboolean no_date)
Definition: Transaction.c:742
const char * xaccTransGetDescription(const Transaction *trans)
Definition: Transaction.c:2184
Account * gnc_account_lookup_by_full_name(const Account *any_acc, const gchar *name)
Definition: Account.c:2915
void xaccTransCommitEdit(Transaction *trans)
Definition: Transaction.c:1579
Additional event handling code.
void xaccTransBeginEdit(Transaction *trans)
Definition: Transaction.c:1380
const char * xaccTransGetReadOnly(const Transaction *trans)
Definition: Transaction.c:2313
int xaccTransGetSplitIndex(const Transaction *trans, const Split *split)
Definition: Transaction.c:2154
void xaccTransUnvoid(Transaction *trans)
Definition: Transaction.c:2552
gboolean gnc_numeric_positive_p(gnc_numeric a)
Split * xaccMallocSplit(QofBook *book)
Definition: Split.c:582
Generic api to store and retrieve preferences.
Transaction * xaccTransReverse(Transaction *orig)
Definition: Transaction.c:2579
GDate helper routines.
Definition: SplitP.h:71
gnc_numeric xaccSplitGetValue(const Split *split)
Definition: Split.c:1993
gboolean xaccAccountHasAncestor(const Account *acc, const Account *ancestor)
Definition: Account.c:4004
Account * xaccSplitGetAccount(const Split *s)
Definition: Split.c:968
gnc_commodity * xaccAccountGetCommodity(const Account *acc)
Definition: Account.c:3148
gboolean xaccTransGetIsClosingTxn(const Transaction *trans)
Definition: Transaction.c:2204
gnc_commodity * xaccTransGetCurrency(const Transaction *trans)
Definition: Transaction.c:1348
gboolean xaccAccountGetPlaceholder(const Account *acc)
Definition: Account.c:3912
MonetaryList * xaccTransGetImbalance(const Transaction *trans)
Definition: Transaction.c:1052
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Definition: gnc-prefs.c:196
Transaction * xaccTransGetReversedBy(const Transaction *trans)
Definition: Transaction.c:2606
Timespec xaccTransRetDatePostedTS(const Transaction *trans)
Definition: Transaction.c:2243
Split * xaccSplitGetOtherSplit(const Split *split)
Definition: Split.c:2086
#define LEAVE(format, args...)
Definition: qoflog.h:271
time64 gnc_time(time64 *tbuf)
get the current local time
const char * xaccSplitGetMemo(const Split *split)
Definition: Split.c:1968
gint64 time64
Definition: gnc-date.h:83
void xaccTransSetDateEnteredSecs(Transaction *trans, time64 secs)
Definition: Transaction.c:1951
gboolean qof_book_uses_autoreadonly(const QofBook *book)
Account * gnc_account_get_root(Account *acc)
Definition: Account.c:2630
void qof_event_gen(QofInstance *entity, QofEventId event_type, gpointer event_data)
Invoke all registered event handlers using the given arguments.
#define GNC_EVENT_ITEM_ADDED
Definition: gnc-event.h:45
GDate xaccTransGetDatePostedGDate(const Transaction *trans)
Definition: Transaction.c:2250
API for Transactions and Splits (journal entries)
SplitList * xaccTransGetSplitList(const Transaction *trans)
Definition: Transaction.c:2164
Transaction * xaccTransCopyToClipBoard(const Transaction *from_trans)
Definition: Transaction.c:702
gboolean gnc_commodity_equiv(const gnc_commodity *a, const gnc_commodity *b)
const gchar * QofLogModule
Definition: qofid.h:89
void gnc_gdate_set_time64(GDate *gd, time64 time)
gnc_numeric xaccSplitGetAmount(const Split *split)
Definition: Split.c:1987