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 ¤t_split, ¤t_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