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 
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-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 
52 /** Static Globals *******************************************************/
53 static QofLogModule log_module = GNC_MOD_LEDGER;
54 
55 /*****************************************************************************/
56 /*****************************************************************************/
57 
58 /* Read only dialog */
59 static gboolean
gtc_sr_is_trans_readonly_and_warn(GncTreeViewSplitReg * view,Transaction * trans)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 
75     if (xaccTransIsReadonlyByPostedDate (trans))
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
gnc_tree_control_split_reg_trans_open_and_warn(GncTreeViewSplitReg * view,Transaction * trans)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
gtc_sr_trans_test_for_edit(GncTreeViewSplitReg * view,Transaction * trans)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
gnc_tree_control_split_reg_balance_trans(GncTreeViewSplitReg * view,Transaction * trans)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
gnc_tree_control_split_reg_cancel_edit(GncTreeViewSplitReg * view,gboolean reg_closing)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
gnc_tree_control_split_reg_exchange_rate(GncTreeViewSplitReg * view)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
gnc_tree_control_split_reg_void_current_trans(GncTreeViewSplitReg * view,const char * reason)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
gnc_tree_control_split_reg_unvoid_current_trans(GncTreeViewSplitReg * view)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
gnc_tree_control_split_reg_jump_to_blank(GncTreeViewSplitReg * view)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
gnc_tree_control_split_reg_jump_to(GncTreeViewSplitReg * view,Transaction * trans,Split * split,gboolean amount)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 *
gnc_tree_control_split_reg_get_blank_trans(GncTreeViewSplitReg * view)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 *
gnc_tree_control_split_reg_get_current_trans_split(GncTreeViewSplitReg * view)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 *
gnc_tree_control_split_reg_get_blank_split(GncTreeViewSplitReg * view)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
gnc_tree_control_split_reg_goto_rel_trans_row(GncTreeViewSplitReg * view,gint relative)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
gnc_tree_control_split_reg_enter(GncTreeViewSplitReg * view)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
gnc_tree_control_split_reg_reinit(GncTreeViewSplitReg * view,gpointer data)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
gnc_tree_control_split_reg_delete(GncTreeViewSplitReg * view,gpointer data)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
gnc_tree_control_split_reg_reverse_current(GncTreeViewSplitReg * view)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
gnc_tree_control_split_reg_duplicate_current(GncTreeViewSplitReg * view)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 
gtcsr_move_current_entry_updown(GncTreeViewSplitReg * view,gboolean move_up,gboolean really_do_it)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 
gnc_tree_control_split_reg_move_current_entry_updown(GncTreeViewSplitReg * view,gboolean move_up)1639 gboolean gnc_tree_control_split_reg_move_current_entry_updown (GncTreeViewSplitReg *view,
1640                                                             gboolean move_up)
1641 {
1642     return gtcsr_move_current_entry_updown(view, move_up, TRUE);
1643 }
1644 
gnc_tree_control_split_reg_is_current_movable_updown(GncTreeViewSplitReg * view,gboolean move_up)1645 gboolean gnc_tree_control_split_reg_is_current_movable_updown (GncTreeViewSplitReg *view,
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
gnc_tree_control_split_reg_save(GncTreeViewSplitReg * view,gboolean reg_closing)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
gnc_tree_control_split_reg_recn_change(GncTreeViewSplitReg * view,GtkTreePath * spath)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
gnc_tree_control_split_reg_recn_test(GncTreeViewSplitReg * view,GtkTreePath * spath)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 *
gnc_tree_control_split_reg_get_account_by_name(GncTreeViewSplitReg * view,const char * name)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 *
gtc_sr_get_account_for_trans_ancestor(const Transaction * trans,const Account * ancestor)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
gnc_tree_control_split_reg_cut_trans(GncTreeViewSplitReg * view)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
gnc_tree_control_split_reg_copy_trans(GncTreeViewSplitReg * view)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
gnc_tree_control_split_reg_paste_trans(GncTreeViewSplitReg * view)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
gnc_tree_control_auto_complete(GncTreeViewSplitReg * view,Transaction * trans,const gchar * new_text)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 
2186