Register rewrite Update, fixes for duplicate and reversing transaction. This update fixes duplicate transaction and reversing transaction. Also included is a minor change to the model, added the test for unbalanced transaction along with some other dialogs. Tab key navigation has been revised but still further work. Account key seperator works along with new account creation. Author: Robert Fewell

git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@22883 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
John Ralls 2013-04-07 22:14:09 +00:00
parent bb26969082
commit 5a6b5027a0
6 changed files with 991 additions and 241 deletions

View File

@ -132,7 +132,9 @@ gnc_dup_trans_dialog_create (GtkWidget * parent, DupTransDialog *dt_dialog,
}
else
{
dt_dialog->date_edit = NULL;
GtkWidget *date_edit;
date_edit = gnc_date_edit_new (date, FALSE, FALSE);
dt_dialog->date_edit = date_edit;
}
dt_dialog->duplicate_title_label = GTK_WIDGET(gtk_builder_get_object (builder, "duplicate_title_label"));
@ -246,7 +248,7 @@ gnc_dup_trans_dialog_internal (GtkWidget * parent, const char* title,
if (date_p)
*date_p = gnc_date_edit_get_date (GNC_DATE_EDIT (dt_dialog->date_edit));
if (gdate_p)
gnc_date_edit_get_gdate(GNC_DATE_EDIT (dt_dialog->date_edit), gdate_p);
gnc_date_edit_get_gdate (GNC_DATE_EDIT (dt_dialog->date_edit), gdate_p);
if (out_num)
*out_num = g_strdup (gtk_entry_get_text (GTK_ENTRY (dt_dialog->num_edit)));
if (tnum)

View File

@ -41,9 +41,12 @@
#include "dialog-utils.h"
#include "guile-util.h"
#include "dialog-dup-trans.h"
#include "dialog-account.h"
#include "Transaction.h"
#include "engine-helpers.h"
#include "gnc-event.h"
#include "Scrub.h"
/** Static Globals *******************************************************/
static QofLogModule log_module = GNC_MOD_LEDGER;
@ -88,25 +91,29 @@ gtc_copy_trans_onto_trans (Transaction *from, Transaction *to,
gnc_get_current_book ());
}
/*****************************************************************************/
/*****************************************************************************/
/*************************************************************************/
/* Read only dialoue */
/* Read only dialog */
static gboolean
gtc_is_trans_readonly_and_warn (const Transaction *trans)
gtc_is_trans_readonly_and_warn (GncTreeViewSplitReg *view, Transaction *trans)
{
GncTreeModelSplitReg *model;
GtkWidget *window;
GtkWidget *dialog;
const gchar *reason;
const gchar *title = _("Cannot modify or delete this transaction.");
const gchar *message =
const gchar *message_reason =
_("This transaction is marked read-only with the comment: '%s'");
if (!trans) return FALSE;
window = gnc_tree_view_split_reg_get_parent (view);
model = gnc_tree_view_split_reg_get_model_from_view (view);
if (xaccTransIsReadonlyByPostedDate (trans))
{
dialog = gtk_message_dialog_new (NULL,
dialog = gtk_message_dialog_new (GTK_WINDOW (window),
0,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_OK,
@ -122,17 +129,253 @@ gtc_is_trans_readonly_and_warn (const Transaction *trans)
reason = xaccTransGetReadOnly (trans);
if (reason)
{
dialog = gtk_message_dialog_new (NULL,
dialog = gtk_message_dialog_new (GTK_WINDOW (window),
0,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_OK,
"%s", title);
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
message, reason);
message_reason, reason);
gtk_dialog_run (GTK_DIALOG (dialog));
gtk_widget_destroy (dialog);
return TRUE;
}
if (gnc_tree_model_split_reg_get_read_only (model, trans))
{
dialog = gtk_message_dialog_new (GTK_WINDOW (window),
0,
GTK_MESSAGE_ERROR,
GTK_BUTTONS_OK,
"%s", title);
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
"%s", _("You can not change this transaction, the Book or Register is set to Read Only."));
gtk_dialog_run (GTK_DIALOG (dialog));
gtk_widget_destroy (dialog);
return TRUE;
}
return FALSE;
}
/* Transaction is being edited dialog */
static gboolean
gtc_trans_open_and_warn (GncTreeViewSplitReg *view, Transaction *trans)
{
Transaction *dirty_trans;
GtkWidget *window;
GtkWidget *dialog;
gint response;
const char *title = _("Save Transaction before proceding?");
const char *message =
_("The current transaction has been changed. Would you like to "
"record the changes before proceding, or cancel?");
window = gnc_tree_view_split_reg_get_parent (view);
dirty_trans = gnc_tree_view_split_reg_get_dirty_trans (view);
if (trans == dirty_trans)
{
dialog = gtk_message_dialog_new (GTK_WINDOW (window),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_QUESTION,
GTK_BUTTONS_CANCEL,
"%s", title);
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
"%s", message);
gtk_dialog_add_button (GTK_DIALOG (dialog),
_("_Record"), GTK_RESPONSE_ACCEPT);
response = gnc_dialog_run (GTK_DIALOG (dialog), "transaction_being_edited");
gtk_widget_destroy (dialog);
if (response != GTK_RESPONSE_ACCEPT)
return TRUE;
xaccTransCommitEdit (trans);
gnc_tree_view_split_reg_set_dirty_trans (view, NULL);
return FALSE;
}
else
return FALSE;
}
static gboolean
gtc_trans_test_for_edit (GncTreeViewSplitReg *view, Transaction *trans)
{
GtkWidget *window;
Transaction *dirty_trans;
/* Make sure we have stopped editing */
gnc_tree_view_split_reg_finish_edit (view);
window = gnc_tree_view_split_reg_get_parent (view);
/* Get dirty_trans */
dirty_trans = gnc_tree_view_split_reg_get_dirty_trans (view);
/* We are being edited in a different register */
if (xaccTransIsOpen (trans) && (dirty_trans != trans))
{
gnc_error_dialog (window, "%s",
_("This transaction is being edited in a different register."));
return TRUE;
}
return FALSE;
}
/*****************************************************************************/
/*****************************************************************************/
gboolean
gnc_tree_control_split_reg_balance_trans (GncTreeViewSplitReg *view, Transaction *trans)
{
GncTreeModelSplitReg *model;
GtkWidget *window;
int choice;
int default_value;
Account *default_account;
Account *other_account;
Account *root;
GList *radio_list = NULL;
const char *title = _("Rebalance Transaction");
const char *message = _("The current transaction is not balanced.");
Split *split;
Split *other_split;
gboolean two_accounts;
gboolean multi_currency;
if (xaccTransIsBalanced (trans))
return FALSE;
window = gnc_tree_view_split_reg_get_parent (view);
model = gnc_tree_view_split_reg_get_model_from_view (view);
//FIXME ## Trading ## Copied from split-register-control, needs testing
if (xaccTransUseTradingAccounts (trans))
{
MonetaryList *imbal_list;
gnc_monetary *imbal_mon;
imbal_list = xaccTransGetImbalance (trans);
/* See if the imbalance is only in the transaction's currency */
if (!imbal_list)
/* Value imbalance, but not commodity imbalance. This shouldn't
be something that scrubbing can cause to happen. Perhaps someone
entered invalid splits. */
multi_currency = TRUE;
else
{
imbal_mon = imbal_list->data;
if (!imbal_list->next &&
gnc_commodity_equiv(gnc_monetary_commodity(*imbal_mon),
xaccTransGetCurrency(trans)))
multi_currency = FALSE;
else
multi_currency = TRUE;
}
/* We're done with the imbalance list, the real work will be done
by xaccTransScrubImbalance which will get it again. */
gnc_monetary_list_free(imbal_list);
}
else
multi_currency = FALSE;
//FIXME
split = xaccTransGetSplit (trans, 0);
other_split = xaccSplitGetOtherSplit (split);
if (other_split == NULL)
{
/* Attempt to handle the inverted many-to-one mapping */
split = xaccTransGetSplit (trans, 1);
if (split) other_split = xaccSplitGetOtherSplit (split);
else split = xaccTransGetSplit (trans, 0);
}
if (other_split == NULL || multi_currency)
{
two_accounts = FALSE;
other_account = NULL;
}
else
{
two_accounts = TRUE;
other_account = xaccSplitGetAccount (other_split);
}
default_account = gnc_tree_model_split_reg_get_anchor (model);
/* If the two pointers are the same, the account from other_split
* is actually the default account. We must make other_account
* the account from split instead. */
if (default_account == other_account)
other_account = xaccSplitGetAccount (split);
/* If the two pointers are still the same, we have two splits, but
* they both refer to the same account. While non-sensical, we don't
* object. */
if (default_account == other_account)
two_accounts = FALSE;
radio_list = g_list_append (radio_list,
_("Balance it _manually"));
radio_list = g_list_append (radio_list,
_("Let GnuCash _add an adjusting split"));
if (model->type < NUM_SINGLE_REGISTER_TYPES2 && !multi_currency)
{
radio_list = g_list_append (radio_list,
_("Adjust current account _split total"));
default_value = 2;
if (two_accounts)
{
radio_list = g_list_append (radio_list,
_("Adjust _other account split total"));
default_value = 3;
}
}
else
default_value = 0;
choice = gnc_choose_radio_option_dialog
(window,
title,
message,
_("_Rebalance"),
default_value,
radio_list);
g_list_free (radio_list);
root = gnc_account_get_root(default_account);
switch (choice)
{
default:
case 0:
return TRUE;
break;
case 1:
xaccTransScrubImbalance (trans, root, NULL);
break;
case 2:
xaccTransScrubImbalance (trans, root, default_account);
break;
case 3:
xaccTransScrubImbalance (trans, root, other_account);
break;
}
return FALSE;
}
@ -174,7 +417,23 @@ gnc_tree_control_split_reg_exchange_rate (GncTreeViewSplitReg *view)
anchor = gnc_tree_model_split_reg_get_anchor (model);
txn_com = xaccTransGetCurrency (trans);
if (gtc_is_trans_readonly_and_warn (trans))
if (trans == NULL)
return;
/* See if we were asked to change a blank trans. */
if (trans == gnc_tree_control_split_reg_get_blank_trans (view))
return;
/* Test for read only */
if (gtc_is_trans_readonly_and_warn (view, trans))
return;
/* See if we are being edited in another register */
if (gtc_trans_test_for_edit (view, trans))
return;
/* Make sure we ask to commit any changes before we procede */
if (gtc_trans_open_and_warn (view, trans))
return;
if (num_splits < 2)
@ -206,8 +465,8 @@ gnc_tree_control_split_reg_exchange_rate (GncTreeViewSplitReg *view)
value = xaccSplitGetValue (split);
xaccTransBeginEdit (trans);
gnc_tree_view_split_reg_set_dirty_trans (view, trans);
xaccTransBeginEdit (trans);
if (txn_com == xaccAccountGetCommodity (xaccSplitGetAccount(split)))
gnc_tree_view_split_reg_set_value_for (view, trans, osplit, gnc_numeric_neg (value), TRUE);
@ -256,7 +515,7 @@ gnc_tree_control_split_reg_void_current_trans (GncTreeViewSplitReg *view, const
blank_split = gnc_tree_control_split_reg_get_blank_split (view);
/* get the current split based on cursor position */
/* get the current split */
split = gnc_tree_view_split_reg_get_current_split (view);
if (split == NULL)
return;
@ -271,6 +530,25 @@ gnc_tree_control_split_reg_void_current_trans (GncTreeViewSplitReg *view, const
trans = xaccSplitGetParent (split);
if (trans == NULL)
return;
/* See if we were asked to change a blank trans. */
if (trans == gnc_tree_control_split_reg_get_blank_trans (view))
return;
/* Test for read only */
if (gtc_is_trans_readonly_and_warn (view, trans))
return;
/* See if we are being edited in another register */
if (gtc_trans_test_for_edit (view, trans))
return;
/* Make sure we ask to commit any changes before we procede */
if (gtc_trans_open_and_warn (view, trans))
return;
gnc_tree_view_split_reg_set_dirty_trans (view, trans);
xaccTransVoid (trans, reason);
@ -311,6 +589,13 @@ gnc_tree_control_split_reg_unvoid_current_trans (GncTreeViewSplitReg *view)
trans = xaccSplitGetParent (split);
if (trans == NULL)
return;
/* See if we were asked to change a blank trans. */
if (trans == gnc_tree_control_split_reg_get_blank_trans (view))
return;
gnc_tree_view_split_reg_set_dirty_trans (view, trans);
xaccTransUnvoid (trans);
@ -334,6 +619,9 @@ gnc_tree_control_split_reg_jump_to_blank (GncTreeViewSplitReg *view)
gtk_tree_selection_select_path (gtk_tree_view_get_selection (GTK_TREE_VIEW (view)), spath);
/* Set cursor to new spath */
gtk_tree_view_set_cursor (GTK_TREE_VIEW (view), spath, NULL, FALSE);
gtk_tree_path_free (spath);
gtk_tree_path_free (mpath);
@ -361,6 +649,9 @@ gnc_tree_control_split_reg_jump_to_split (GncTreeViewSplitReg *view, Split *spli
gtk_tree_selection_select_path (gtk_tree_view_get_selection (GTK_TREE_VIEW (view)), spath);
/* Set cursor to new spath */
gtk_tree_view_set_cursor (GTK_TREE_VIEW (view), spath, NULL, FALSE);
gtk_tree_path_free (spath);
gtk_tree_path_free (mpath);
@ -454,6 +745,9 @@ gnc_tree_control_split_reg_goto_rel_trans_row (GncTreeViewSplitReg *view, gint r
gnc_tree_view_split_reg_block_selection (view, FALSE);
gtk_tree_selection_select_path (gtk_tree_view_get_selection (GTK_TREE_VIEW (view)), new_spath);
/* Set cursor to new spath */
gtk_tree_view_set_cursor (GTK_TREE_VIEW (view), new_spath, NULL, FALSE);
LEAVE("new_spath is %s", gtk_tree_path_to_string (new_spath));
gtk_tree_path_free (new_spath);
@ -471,6 +765,8 @@ gnc_tree_control_split_reg_enter (GncTreeViewSplitReg *view, gboolean next_trans
ENTER("view=%p, next_transaction=%s", view, next_transaction ? "TRUE" : "FALSE");
//FIXME Might need more...
model = gnc_tree_view_split_reg_get_model_from_view (view);
goto_blank = gnc_gconf_get_bool (GCONF_GENERAL_REGISTER,
@ -508,7 +804,7 @@ gnc_tree_control_split_reg_enter (GncTreeViewSplitReg *view, gboolean next_trans
gnc_tree_view_split_reg_collapse_trans (view, NULL);
/* Now move. */
if (goto_blank)
if (goto_blank) //FIXME What do we want to do here...
gnc_tree_control_split_reg_jump_to_blank (view);
else if (next_transaction)
gnc_tree_control_split_reg_goto_rel_trans_row (view, 1);
@ -533,7 +829,24 @@ gnc_tree_control_split_reg_reinit (GncTreeViewSplitReg *view, gpointer data)
"cause your reconciled balance to be off.");
trans = gnc_tree_view_split_reg_get_current_trans (view);
if (gtc_is_trans_readonly_and_warn (trans))
if (trans == NULL)
return;
/* See if we were asked to change a blank trans. */
if (trans == gnc_tree_control_split_reg_get_blank_trans (view))
return;
/* Test for read only */
if (gtc_is_trans_readonly_and_warn (view, trans))
return;
/* See if we are being edited in another register */
if (gtc_trans_test_for_edit (view, trans))
return;
/* Make sure we ask to commit any changes before we procede */
if (gtc_trans_open_and_warn (view, trans))
return;
window = gnc_tree_view_split_reg_get_parent (view);
@ -543,6 +856,7 @@ gnc_tree_control_split_reg_reinit (GncTreeViewSplitReg *view, gpointer data)
GTK_MESSAGE_WARNING,
GTK_BUTTONS_NONE,
"%s", title);
if (xaccTransHasReconciledSplits (trans))
{
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
@ -582,10 +896,27 @@ gnc_tree_control_split_reg_delete (GncTreeViewSplitReg *view, gpointer data)
split = gnc_tree_view_split_reg_get_current_split (view);
if (split == NULL)
{
return;
split = gnc_tree_control_split_reg_get_current_trans_split (view);
if (split == NULL)
{
LEAVE("split is NULL");
return;
}
}
trans = xaccSplitGetParent (split);
if (trans == NULL)
return;
/* Test for read only */
if (gtc_is_trans_readonly_and_warn (view, trans))
return;
/* See if we are being edited in another register */
if (gtc_trans_test_for_edit (view, trans))
return;
depth = gnc_tree_view_reg_get_selected_row_depth (view);
/* Deleting the blank split just cancels */
@ -593,14 +924,9 @@ gnc_tree_control_split_reg_delete (GncTreeViewSplitReg *view, gpointer data)
Split *blank_split = gnc_tree_control_split_reg_get_blank_split (view);
if (split == blank_split)
{
return;
}
}
if (gtc_is_trans_readonly_and_warn (trans))
return;
window = gnc_tree_view_split_reg_get_parent (view);
/* On a split cursor, just delete the one split. */
@ -726,41 +1052,58 @@ gnc_tree_control_split_reg_reverse_current (GncTreeViewSplitReg *view)
{
GtkWidget *window;
Transaction *trans = NULL, *new_trans = NULL;
GList *snode = NULL;
gboolean changed = FALSE;
ENTER(" ");
trans = gnc_tree_view_split_reg_get_current_trans (view);
if (trans == NULL)
{
LEAVE("Trans is Null");
return;
//FIXME Need same tests as duplicate ?????
window = gnc_tree_view_split_reg_get_parent (view);
/* Make sure we have stopped editing */
gnc_tree_view_split_reg_finish_edit (view);
}
/* See if we were asked to reverse a blank trans. */
if (trans == gnc_tree_control_split_reg_get_blank_trans (view))
{
LEAVE("skip blank trans");
LEAVE("Skip blank trans");
return;
}
/* Test for read only */
if (gtc_is_trans_readonly_and_warn (view, trans))
{
LEAVE("Read only");
return;
}
/* See if we are being edited in another register */
if (gtc_trans_test_for_edit (view, trans))
{
LEAVE("Open in different register");
return;
}
window = gnc_tree_view_split_reg_get_parent (view);
if (xaccTransGetReversedBy (trans))
{
gnc_error_dialog (window, "%s",
_("A reversing entry has already been created for this transaction."));
LEAVE("Already have reversing transaction");
return;
}
#ifdef skip
//FIXME Test for trans in edit....
gnc_tree_view_split_reg_set_dirty_trans (view, trans);
xaccTransBeginEdit (trans);
/* Make sure we ask to commit any changes before we add reverse transaction */
if (gtc_trans_open_and_warn (view, trans))
{
LEAVE("save cancelled");
return;
}
/* Create reverse transaction */
new_trans = xaccTransReverse (trans);
xaccTransBeginEdit (new_trans);
@ -770,14 +1113,25 @@ gnc_tree_control_split_reg_reverse_current (GncTreeViewSplitReg *view)
xaccTransSetDateEnteredSecs (new_trans, gnc_time (NULL));
xaccTransCommitEdit (new_trans);
xaccTransCommitEdit (trans);
gnc_tree_view_split_reg_set_dirty_trans (view, NULL);
// We need to loop through the splits and send an event to update the register.
for (snode = xaccTransGetSplitList (new_trans); snode; snode = snode->next)
{
if (xaccTransStillHasSplit (new_trans, snode->data))
{
/* Send an event based on the split account */
qof_event_gen (QOF_INSTANCE (xaccSplitGetAccount(snode->data)), GNC_EVENT_ITEM_ADDED, snode->data);
}
}
/* give gtk+ a chance to handle pending events */
while (gtk_events_pending ())
gtk_main_iteration ();
/* Now jump to new trans */
// gnc_tree_control_split_reg_jump_to_split (view, xaccTransGetSplit (new_trans, 0));
gnc_tree_control_split_reg_jump_to_split (view, xaccTransGetSplit (new_trans, 0));
#endif
LEAVE("Reverse transaction created");
}
@ -792,6 +1146,7 @@ gnc_tree_control_split_reg_duplicate_current (GncTreeViewSplitReg *view)
Split *blank_split;
Split *split, *trans_split;
gboolean changed = FALSE;
gboolean use_split_action_for_num_field = FALSE;
ENTER("");
@ -800,99 +1155,119 @@ gnc_tree_control_split_reg_duplicate_current (GncTreeViewSplitReg *view)
blank_split = gnc_tree_control_split_reg_get_blank_split (view);
split = gnc_tree_view_split_reg_get_current_split (view);
trans_split = gnc_tree_control_split_reg_get_current_trans_split (view);
trans = gnc_tree_view_split_reg_get_current_trans (view);
depth = gnc_tree_view_reg_get_selected_row_depth (view);
#ifdef skip
use_split_action_for_num_field = qof_book_use_split_action_for_num_field (gnc_get_current_book());
trans = gnc_tree_view_split_reg_get_current_trans (view);
/* This shouldn't happen, but be paranoid. */
if (trans == NULL)
{
LEAVE("no transaction");
return FALSE;
}
if (gtc_is_trans_readonly_and_warn (trans))
{
LEAVE("read only transaction");
return FALSE;
}
/* Make sure we have stopped editing */
gnc_tree_view_split_reg_finish_edit (view);
/* See if we are editing this transcation all ready */
if (trans == gnc_tree_view_split_reg_get_dirty_trans (view))
changed = TRUE;
/* See if we were asked to duplicate a blank split. */
if (split == gnc_tree_control_split_reg_get_blank_split (view))
{
LEAVE("skip blank split");
return FALSE;
}
/* See if we were asked to duplicate a blank trans. */
/* See if we were asked to change a blank trans. */
if (trans == gnc_tree_control_split_reg_get_blank_trans (view))
{
LEAVE("skip blank trans");
LEAVE("Skip blank trans");
return FALSE;
}
gnc_suspend_gui_refresh ();
/* See if we were asked to change a blank split. */
if (split == blank_split)
{
LEAVE("Skip blank split");
return FALSE;
}
/* Test for read only */
if (gtc_is_trans_readonly_and_warn (view, trans))
{
LEAVE("Read only");
return FALSE;
}
/* See if we are being edited in another register */
if (gtc_trans_test_for_edit (view, trans))
{
LEAVE("Open in different register");
return FALSE;
}
/* Make sure we ask to commit any changes before we procede */
if (gtc_trans_open_and_warn (view, trans))
{
LEAVE("save cancelled");
return FALSE;
}
window = gnc_tree_view_split_reg_get_parent (view);
/* If the cursor has been edited, we are going to have to commit
* it before we can duplicate. Make sure the user wants to do that. */
if (changed)
{
GtkWidget *dialog;
gint response;
const char *title = _("Save transaction before duplicating?");
const char *message =
_("The current transaction has been changed. Would you like to "
"record the changes before duplicating the transaction, or "
"cancel the duplication?");
dialog = gtk_message_dialog_new (GTK_WINDOW (window),
GTK_DIALOG_DESTROY_WITH_PARENT,
GTK_MESSAGE_QUESTION,
GTK_BUTTONS_CANCEL,
"%s", title);
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
"%s", message);
gtk_dialog_add_button (GTK_DIALOG (dialog),
_("_Record"), GTK_RESPONSE_ACCEPT);
response = gnc_dialog_run (GTK_DIALOG (dialog), "transaction_duplicated");
gtk_widget_destroy (dialog);
if (response != GTK_RESPONSE_ACCEPT)
{
gnc_resume_gui_refresh ();
LEAVE("save cancelled");
return FALSE;
}
xaccTransCommitEdit (trans);
gnc_tree_view_split_reg_set_dirty_trans (view, NULL);
}
/* Ok, we are now ready to make the copy. */
if (depth == SPLIT3)
{
Split *new_split;
gboolean new_act_num = FALSE;
char *out_num;
time64 date;
/* We are on a split in an expanded transaction.
* Just copy the split and add it to the transaction. */
* Just copy the split and add it to the transaction.
* However, if the split-action field is being used as the register
* number, and the action field is a number, request a new value or
* cancel. Need to get next number and update account last num from
* split account not register account, which may be the same or not */
if (split != trans_split)
{
if (use_split_action_for_num_field && gnc_strisnum (gnc_get_num_action (NULL, split)))
{
Account *account = xaccSplitGetAccount (split);
const char* title = _("New Split Information");
const char *in_num = NULL;
date = time (0);
if (account)
in_num = xaccAccountGetLastNum (account);
else
in_num = gnc_get_num_action (NULL, split);
if (!gnc_dup_trans_dialog (window, title, FALSE,
&date, in_num, &out_num, NULL, NULL))
{
LEAVE("dup cancelled");
return FALSE;
}
new_act_num = TRUE;
}
new_split = xaccMallocSplit (gnc_get_current_book ());
// Remove the blank split
gnc_tree_model_split_reg_set_blank_split_parent (model, trans, TRUE);
xaccTransBeginEdit (trans);
gnc_tree_view_split_reg_set_dirty_trans (view, trans);
xaccSplitSetParent (new_split, trans);
gtc_copy_split_onto_split (split, new_split, FALSE);
xaccTransCommitEdit (trans);
// Add the blank split
gnc_tree_model_split_reg_set_blank_split_parent (model, trans, FALSE);
if (new_act_num) /* if new number supplied by user dialog */
gnc_set_num_action (NULL, new_split, out_num, NULL);
if (new_act_num && gnc_strisnum (out_num))
{
Account *account = xaccSplitGetAccount (new_split);
/* If current register is for account, set last num */
if (account == gnc_tree_model_split_reg_get_anchor (model))
xaccAccountSetLastNum (account, out_num);
}
if (new_act_num)
g_free (out_num);
}
else
{
@ -906,14 +1281,14 @@ gnc_tree_control_split_reg_duplicate_current (GncTreeViewSplitReg *view)
else
{
Transaction *new_trans;
int trans_split_index;
int split_index;
const char *in_num = NULL;
const char *in_tnum = NULL;
char *out_num;
char *out_tnum;
time64 date;
gboolean use_autoreadonly = qof_book_uses_autoreadonly (gnc_get_current_book());
gboolean use_split_action_for_num_field = qof_book_use_split_action_for_num_field
(gnc_get_current_book());
/* We are on a transaction row. Copy the whole transaction. */
@ -924,16 +1299,16 @@ gnc_tree_control_split_reg_duplicate_current (GncTreeViewSplitReg *view)
if (account)
in_num = xaccAccountGetLastNum (account);
else
in_num = xaccTransGetNum (trans);
in_tnum = (use_split_action_for_num_field
in_num = gnc_get_num_action (trans, trans_split);
in_tnum = (!use_split_action_for_num_field
? NULL
: gnc_get_num_action (trans, NULL)); //FIXME is this right way round ?
: gnc_get_num_action (trans, NULL));
}
if (!gnc_dup_trans_dialog (window, NULL, TRUE,
&date, in_num, &out_num, in_tnum, &out_tnum))
{
gnc_resume_gui_refresh ();
LEAVE("dup cancelled");
return FALSE;
}
@ -963,19 +1338,35 @@ gnc_tree_control_split_reg_duplicate_current (GncTreeViewSplitReg *view)
g_date_free (readonly_threshold);
}
split_index = xaccTransGetSplitIndex (trans, split);
trans_split_index = xaccTransGetSplitIndex (trans, trans_split);
new_trans = xaccMallocTransaction (gnc_get_current_book ());
xaccTransBeginEdit (new_trans);
gtc_copy_trans_onto_trans (trans, new_trans, FALSE, FALSE);
xaccTransSetDatePostedSecs (new_trans, date);
xaccTransSetNum (new_trans, out_num);
/* set per book option */
gnc_set_num_action (new_trans, NULL, out_num, out_tnum);
if (!use_split_action_for_num_field)
{
/* find split in new_trans that equals trans_split and set
* split_action to out_num */
gnc_set_num_action (NULL,
xaccTransGetSplit (new_trans, trans_split_index),
out_num, NULL);
/* note that if the transaction has multiple splits to the register
* account, only the anchor split will be set with user input. The
* user will have to adjust other splits manually. */
}
xaccTransCommitEdit (new_trans);
g_free (out_num);
if (!use_split_action_for_num_field)
g_free (out_tnum);
}
/* Refresh the GUI. */
gnc_resume_gui_refresh ();
#endif
LEAVE(" ");
return TRUE;
}
@ -987,7 +1378,7 @@ gnc_tree_control_split_reg_save (GncTreeViewSplitReg *view, gboolean reg_closing
{
GncTreeModelSplitReg *model;
RowDepth depth;
Transaction *pending_trans;
Transaction *dirty_trans;
Transaction *blank_trans;
Transaction *trans;
Account *account;
@ -1013,7 +1404,7 @@ gnc_tree_control_split_reg_save (GncTreeViewSplitReg *view, gboolean reg_closing
model = gnc_tree_view_split_reg_get_model_from_view (view);
blank_split = gnc_tree_control_split_reg_get_blank_split (view);
pending_trans = gnc_tree_view_split_reg_get_dirty_trans (view);
dirty_trans = gnc_tree_view_split_reg_get_dirty_trans (view);
blank_trans = gnc_tree_control_split_reg_get_blank_trans (view);
/* get the handle to the current split and transaction */
@ -1034,7 +1425,7 @@ gnc_tree_control_split_reg_save (GncTreeViewSplitReg *view, gboolean reg_closing
return FALSE;
}
if (trans == pending_trans )
if (trans == dirty_trans )
{
if (trans != blank_trans)
{
@ -1250,6 +1641,52 @@ gnc_tree_control_split_reg_recn_test (GncTreeViewSplitReg *view)
}
/* Return the account for name given or create it */
Account *
gnc_tree_control_split_reg_get_account_by_name (GncTreeViewSplitReg *view, const char *name)
{
GtkWidget *window;
const char *placeholder = _("The account %s does not allow transactions.");
const char *missing = _("The account %s does not exist. "
"Would you like to create it?");
char *account_name;
Account *account;
if (!name || (strlen(name) == 0))
return NULL;
/* Find the account */
if (gnc_gconf_get_bool (GCONF_GENERAL_REGISTER, "show_leaf_account_names", NULL))
account = gnc_account_lookup_by_name (gnc_get_current_root_account(), name);
else
account = gnc_account_lookup_by_full_name (gnc_get_current_root_account(), name);
if (!account)
account = gnc_account_lookup_by_code (gnc_get_current_root_account(), name);
window = gnc_tree_view_split_reg_get_parent (view);
if (!account)
{
/* Ask if they want to create a new one. */
if (!gnc_verify_dialog (window, TRUE, missing, name))
return NULL;
/* User said yes, they want to create a new account. */
account = gnc_ui_new_accounts_from_name_window (name);
if (!account)
return NULL;
}
/* Now have the account. */
/* See if the account (either old or new) is a placeholder. */
if (xaccAccountGetPlaceholder (account))
gnc_error_dialog (window, placeholder, name);
/* Be seeing you. */
return account;
}
/*****************************************************************************
* ClipBoard Functions *
*****************************************************************************/
@ -1272,15 +1709,9 @@ gnc_tree_control_split_reg_cut_trans (GncTreeViewSplitReg *view)
if (!from_trans)
return;
if (gnc_tree_model_split_reg_get_read_only (model, from_trans))
{
GtkWidget *window;
window = gnc_tree_view_split_reg_get_parent (view);
gnc_error_dialog (window, "%s",
_("You can not cut from a read only transaction or register."));
/* Test for read only */
if (gtc_is_trans_readonly_and_warn (view, from_trans))
return;
}
xaccTransBeginEdit (clipboard_trans);
if (clipboard_trans)
@ -1354,15 +1785,13 @@ gnc_tree_control_split_reg_paste_trans (GncTreeViewSplitReg *view)
if (!to_trans || !clipboard_trans)
return;
if (gnc_tree_model_split_reg_get_read_only (model, to_trans))
{
GtkWidget *window;
window = gnc_tree_view_split_reg_get_parent (view);
gnc_error_dialog (window, "%s",
_("You can not paste to a read only transaction or register."));
/* See if we are being edited in another register */
if (gtc_trans_test_for_edit (view, to_trans))
return;
/* Test for read only */
if (gtc_is_trans_readonly_and_warn (view, to_trans))
return;
}
//FIXME You can not paste from gl to a register, is this too simplistic
if (clipboard_acct == NULL && anchor_acct != NULL)

View File

@ -71,6 +71,10 @@ gboolean gnc_tree_control_split_reg_recn_change (GncTreeViewSplitReg *view);
gboolean gnc_tree_control_split_reg_recn_test (GncTreeViewSplitReg *view);
gboolean gnc_tree_control_split_reg_balance_trans (GncTreeViewSplitReg *view, Transaction *trans);
Account * gnc_tree_control_split_reg_get_account_by_name (GncTreeViewSplitReg *view, const char *name);
/*****************************************************************************/
/* Cut transaction and copy to clipboard */

View File

@ -345,18 +345,14 @@ gnc_tree_model_split_reg_gconf_changed (GConfEntry *entry, gpointer user_data)
if (model == NULL)
return;
//g_print("gnc_tree_model_split_reg_gconf_changed\n");
if (g_str_has_suffix (entry->key, KEY_ACCOUNTING_LABELS))
{
// FIXME This only works on create, dynamic ?
model->use_accounting_labels = gnc_gconf_get_bool (GCONF_GENERAL, KEY_ACCOUNTING_LABELS, NULL);
//g_print("model->use_accounting_labels changed %d\n", model->use_accounting_labels);
}
else if (g_str_has_suffix (entry->key, KEY_ACCOUNT_SEPARATOR))
{
model->separator_changed = TRUE; // FIXME Not dealt with this
model->separator_changed = TRUE;
}
else
{
@ -804,45 +800,68 @@ gnc_tree_model_split_reg_get_iter (GtkTreeModel *tree_model,
if (depth == 1) { /* Trans Row 1 */
flags = TROW1;
/* Check if this is the blank trans */
if (tnode->data == model->priv->btrans) {
if (tnode->data == model->priv->btrans)
{
flags |= BLANK;
snode = NULL;
if (xaccTransCountSplits (tnode->data) == 0)
{
if (model->priv->bsplit_parent_node == tnode)
snode = model->priv->bsplit_node; // blank split
else
snode = NULL; // blank trans - not selected
}
else
{
split = xaccTransGetSplit (tnode->data, 0);
snode = g_list_find (slist, split); // else first split
}
}
else
{
split = xaccTransGetSplit (tnode->data, 0); // else first split
snode = g_list_find (slist, split);
split = xaccTransGetSplit (tnode->data, 0);
snode = g_list_find (slist, split); // else first split
}
}
else if (depth == 2) { /* Trans Row 2 */
flags = TROW2;
/* Check if this is the blank trans */
if (tnode->data == model->priv->btrans) {
if (tnode->data == model->priv->btrans)
{
flags |= BLANK;
snode = NULL;
if (xaccTransCountSplits (tnode->data) == 0)
{
if (model->priv->bsplit_parent_node == tnode)
snode = model->priv->bsplit_node; // blank split
else
snode = NULL; // blank trans - not selected
}
else
{
split = xaccTransGetSplit (tnode->data, 0);
snode = g_list_find (slist, split); // else first split
}
}
else
{
split = xaccTransGetSplit (tnode->data, 0); // else first split
snode = g_list_find (slist, split);
split = xaccTransGetSplit (tnode->data, 0);
snode = g_list_find (slist, split); // else first split
}
}
else if (depth == 3) /* Split */
{
else if (depth == 3) { /* Split */
flags = SPLIT;
/* Check if this is the blank split */
if ((tnode == model->priv->bsplit_parent_node) && (xaccTransCountSplits (tnode->data) == indices[2]))
{
flags |= BLANK;
snode = model->priv->bsplit_node;
snode = model->priv->bsplit_node; // blank split = number of splits in list
}
else
{
split = xaccTransGetSplit (tnode->data, indices[2]);
snode = g_list_find (slist, split);
snode = g_list_find (slist, split); // split = position in list
}
if (!snode) {
@ -1228,14 +1247,27 @@ gnc_tree_model_split_reg_iter_next (GtkTreeModel *tree_model, GtkTreeIter *iter)
slist = xaccTransGetSplitList (tnode->data);
/* Check if this is the blank trans */
if (tnode->data == model->priv->btrans) {
if (tnode->data == model->priv->btrans)
{
flags |= BLANK;
snode = NULL;
if (xaccTransCountSplits (tnode->data) == 0)
{
if (model->priv->bsplit_parent_node == tnode)
snode = model->priv->bsplit_node; // blank split
else
snode = NULL; // blank trans with no splits
}
else
{
split = xaccTransGetSplit (tnode->data, 0);
snode = g_list_find (slist, split); // else first split
}
}
else
{
split = xaccTransGetSplit (tnode->data, 0);
snode = g_list_find (slist, split);
snode = g_list_find (slist, split); // else first split
}
}
@ -1291,7 +1323,7 @@ gnc_tree_model_split_reg_iter_children (GtkTreeModel *tree_model,
ENTER("model %p, iter %p , parent %s",
tree_model, iter, (parent_iter ? iter_to_string (parent_iter) : "(null)"));
if (!parent_iter)
if (!parent_iter) // special parent iter is NULL
{
/* Get the very first iter */
tnode = g_list_first (model->priv->tlist);
@ -1302,12 +1334,24 @@ gnc_tree_model_split_reg_iter_children (GtkTreeModel *tree_model,
if (tnode->data == model->priv->btrans)
{
flags |= BLANK;
snode = NULL;
if (xaccTransCountSplits (tnode->data) == 0)
{
if (model->priv->bsplit_parent_node == tnode)
snode = model->priv->bsplit_node; // blank split
else
snode = NULL; // blank trans with no splits
}
else
{
split = xaccTransGetSplit (tnode->data, 0);
snode = g_list_find (slist, split); // else first split
}
}
else
{
split = xaccTransGetSplit (tnode->data, 0);
snode = g_list_find (slist, split);
snode = g_list_find (slist, split); // else first split
}
*iter = gtm_make_iter (model, flags, tnode, snode);
@ -1332,12 +1376,24 @@ gnc_tree_model_split_reg_iter_children (GtkTreeModel *tree_model,
if (tnode->data == model->priv->btrans)
{
flags |= BLANK;
snode = NULL;
if (xaccTransCountSplits (tnode->data) == 0)
{
if (model->priv->bsplit_parent_node == tnode)
snode = model->priv->bsplit_node; // blank split
else
snode = NULL; // blank trans with no splits
}
else
{
split = xaccTransGetSplit (tnode->data, 0);
snode = g_list_find (slist, split); // else first split
}
}
else
{
split = xaccTransGetSplit (tnode->data, 0);
snode = g_list_find (slist, split);
snode = g_list_find (slist, split); // else first split
}
}
@ -1358,12 +1414,12 @@ gnc_tree_model_split_reg_iter_children (GtkTreeModel *tree_model,
if (((tnode->data == model->priv->btrans) || (xaccTransCountSplits (tnode->data) == 0)) && (tnode == model->priv->bsplit_parent_node))
{
flags |= BLANK;
snode = model->priv->bsplit_node;
snode = model->priv->bsplit_node; // blank split on blank trans
}
else
{
split = xaccTransGetSplit (tnode->data, 0);
snode = g_list_find (slist, split);
snode = g_list_find (slist, split); // else first split
}
}
}
@ -1394,13 +1450,13 @@ gnc_tree_model_split_reg_iter_has_child (GtkTreeModel *tree_model, GtkTreeIter *
tnode = iter->user_data2;
if (IS_TROW1 (iter)) //Normal Transaction TROW1
if (IS_TROW1 (iter)) // Normal Transaction TROW1
{
LEAVE ("Transaction Row 1 is yes");
return TRUE;
}
if (IS_TROW2 (iter) && !(IS_BLANK (iter))) //Normal Transaction TROW2
if (IS_TROW2 (iter) && !(IS_BLANK (iter))) // Normal Transaction TROW2
{
if (xaccTransCountSplits (tnode->data) != 0) // with splits
{
@ -1417,7 +1473,7 @@ gnc_tree_model_split_reg_iter_has_child (GtkTreeModel *tree_model, GtkTreeIter *
}
}
if (IS_TROW2 (iter) && IS_BLANK (iter) && (tnode == model->priv->bsplit_parent_node)) //Blank Transaction TROW2
if (IS_TROW2 (iter) && IS_BLANK (iter) && (tnode == model->priv->bsplit_parent_node)) // Blank Transaction TROW2
{
LEAVE ("Blank Transaction Row 2 is yes");
return TRUE;
@ -1486,7 +1542,7 @@ gnc_tree_model_split_reg_iter_nth_child (GtkTreeModel *tree_model,
tnode = g_list_nth (model->priv->tlist, n);
if (!tnode) {
PERR("Trans list should never be NULL.");
PERR("Index greater than trans list.");
goto fail;
}
@ -1496,12 +1552,24 @@ gnc_tree_model_split_reg_iter_nth_child (GtkTreeModel *tree_model,
if (tnode->data == model->priv->btrans)
{
flags |= BLANK;
snode = NULL;
if (xaccTransCountSplits (tnode->data) == 0)
{
if (model->priv->bsplit_parent_node == tnode)
snode = model->priv->bsplit_node; // blank split
else
snode = NULL; // blank trans with no splits
}
else
{
split = xaccTransGetSplit (tnode->data, 0);
snode = g_list_find (slist, split); // else first split
}
}
else
{
split = xaccTransGetSplit (tnode->data, 0);
snode = g_list_find (slist, split);
snode = g_list_find (slist, split); // else first split
}
*iter = gtm_make_iter (model, flags, tnode, snode);
@ -1925,15 +1993,14 @@ gtm_insert_trans (GncTreeModelSplitReg *model, Transaction *trans)
iter = gtm_make_iter (model, TROW1, tnode, NULL);
gtm_insert_row_at (model, &iter);
path = gnc_tree_model_split_reg_get_path (GTK_TREE_MODEL (model), &iter);
gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (model), path, &iter);
gtk_tree_path_free (path);
iter = gtm_make_iter (model, TROW2, tnode, NULL);
gtm_insert_row_at (model, &iter);
path = gnc_tree_model_split_reg_get_path (GTK_TREE_MODEL (model), &iter);
gtk_tree_path_up (path); // to TROW1
gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path);
gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (model), path, &iter);
gtk_tree_path_free (path);
DEBUG("insert %d splits for transaction %p\n", xaccTransCountSplits (trans), trans);
@ -1945,6 +2012,11 @@ gtm_insert_trans (GncTreeModelSplitReg *model, Transaction *trans)
gtm_insert_row_at (model, &iter);
}
}
gtk_tree_path_down (path); // to TROW2
gtk_tree_model_get_iter (GTK_TREE_MODEL (model), &iter, path);
gtk_tree_model_row_has_child_toggled (GTK_TREE_MODEL (model), path, &iter);
gtk_tree_path_free (path);
LEAVE(" ");
}
@ -2515,6 +2587,37 @@ gnc_tree_model_split_reg_update_num_list (GncTreeModelSplitReg *model)
}
}
static int
gtm_account_order_by_name (const Account *aa, const Account *ab)
{
const char *na, *nb;
int retval;
na = xaccAccountGetName (aa);
nb = xaccAccountGetName (ab);
retval = g_utf8_collate (na, nb);
if (retval)
return retval;
return 0;
}
static int
gtm_account_order_by_full_name (const Account *aa, const Account *ab)
{
char *fna, *fnb;
int retval;
fna = gnc_account_get_full_name (aa);
fnb = gnc_account_get_full_name (ab);
retval = g_utf8_collate (fna, fnb);
if (retval)
return retval;
return 0;
}
/* Return the GtkListstore of Accounts */
void
@ -2524,7 +2627,7 @@ gnc_tree_model_split_reg_update_account_list (GncTreeModelSplitReg *model)
Account *root;
Account *acc;
GtkTreeIter iter;
GList *accts, *ptr;
GList *accts, *accts_cpy, *ptr;
gboolean valid;
const gchar *name;
gchar *fname;
@ -2536,10 +2639,19 @@ gnc_tree_model_split_reg_update_account_list (GncTreeModelSplitReg *model)
gtk_list_store_clear (priv->account_list);
root = gnc_book_get_root_account (gnc_get_current_book());
/*FIXME This does not look sorted to me, need to look at this */
accts = gnc_account_get_descendants_sorted (root);
for (ptr = accts, i = 0; ptr; ptr = g_list_next (ptr), i++)
// Get a list of accounts.
accts = gnc_account_get_descendants (root);
// Copy the accts, put it in full name order.
accts_cpy = g_list_copy (accts);
if (gnc_gconf_get_bool (GCONF_GENERAL_REGISTER, "show_leaf_account_names", NULL))
accts_cpy = g_list_sort (accts_cpy, (GCompareFunc)gtm_account_order_by_name);
else
accts_cpy = g_list_sort (accts_cpy, (GCompareFunc)gtm_account_order_by_full_name);
for (ptr = accts_cpy, i = 0; ptr; ptr = g_list_next (ptr), i++)
{
acc = ptr->data;
@ -2553,6 +2665,7 @@ gnc_tree_model_split_reg_update_account_list (GncTreeModelSplitReg *model)
}
}
g_list_free (accts);
g_list_free (accts_cpy);
}
@ -2704,7 +2817,6 @@ gnc_tree_model_split_reg_event_handler (QofInstance *entity,
gtm_changed_row_at (model, &iter2);
g_signal_emit_by_name (model, "refresh_view", NULL);
}
break;
case QOF_EVENT_DESTROY:
if (priv->btrans == trans)

View File

@ -281,6 +281,7 @@ struct GncTreeViewSplitRegPrivate
#define BLUECELL "#1D80DF"
#define BLACKCELL "#CBCBD2"
#define YELLOWCELL "#FFEF98"
#define ORANGECELL "#F39536"
/* This could be a preference setting, the minimum length of characters in order to start completing */
@ -756,10 +757,10 @@ gnc_tree_view_split_reg_set_cols (GncTreeViewSplitReg *view,
// This will refresh the view.
g_signal_connect (G_OBJECT (model), "refresh_view", G_CALLBACK (gtv_split_reg_refresh_cb), view);
// This should be for key navigation, tabbing...
// This is for key navigation, tabbing...
g_signal_connect (G_OBJECT (view), "key-press-event", G_CALLBACK (gtv_split_reg_key_press_cb), NULL);
// This should be for mouse buttons...
// This is for mouse buttons...
g_signal_connect (G_OBJECT (view), "button_press_event", G_CALLBACK (gtv_split_reg_button_cb), NULL);
return view;
@ -907,6 +908,9 @@ gtv_split_reg_refresh_cb (GncTreeModelSplitReg *model, gpointer user_data)
{
GncTreeViewSplitReg *view = user_data;
/* Refilter the tree view register */
gnc_tree_view_split_reg_refilter (view);
if (view->reg_closing != TRUE)
/* Set the view format */
g_idle_add ((GSourceFunc)gnc_tree_view_split_reg_set_format, view);
@ -1046,6 +1050,10 @@ gnc_tree_view_split_reg_default_selection (GncTreeViewSplitReg *view)
gtk_tree_path_free (spath);
gtk_tree_path_free (new_mpath);
/* give gtk+ a chance to handle pending events */
// while (gtk_events_pending ())
// gtk_main_iteration ();
/* Refilter the tree view register */
gnc_tree_view_split_reg_refilter (view);
@ -1158,13 +1166,22 @@ handle_exchange_rate (GncTreeViewSplitReg *view, gnc_numeric amount, Transaction
/* Rate from trans-curr to split-comm */
rate_split_ok = xaccTransGetRateForCommodity (trans, xfer_comm, split, &rate_split);
DEBUG("rate_split_ok %d and xfer_comm %s", rate_split_ok, gnc_commodity_get_fullname (xfer_comm));
/* Rate from trans-curr to reg-comm */
rate_reg_ok = xaccTransGetRateForCommodity (trans, reg_comm, split, &rate_reg);
DEBUG("rate_reg_ok %d and reg_comm %s", rate_reg_ok, gnc_commodity_get_fullname (reg_comm));
/* Are we expanded */
expanded = view->priv->expanded;
if (gnc_commodity_equal (trans_curr, xfer_comm) && rate_split_ok)
{
xaccSplitSetAmount (split, amount);
xaccSplitSetValue (split, amount);
return TRUE;
}
if (rate_reg_ok && rate_split_ok && !force)
{
value = gnc_numeric_div (amount, rate_reg, gnc_commodity_get_fraction (trans_curr), GNC_HOW_DENOM_REDUCE);
@ -1440,6 +1457,7 @@ gnc_tree_view_split_reg_get_amount_denom (Split *split)
static void
set_number_for_input (GncTreeViewSplitReg *view, Transaction *trans, Split *split, gnc_numeric input, gint viewcol)
{
GncTreeModelSplitReg *model;
gnc_numeric price;
gnc_numeric amount;
gnc_numeric value;
@ -1452,9 +1470,34 @@ set_number_for_input (GncTreeViewSplitReg *view, Transaction *trans, Split *spli
gboolean recalc_price = FALSE;
gboolean recalc_value = FALSE;
int denom;
Account *account;
ENTER("set_number_for_input trans %p and split %p and input is %s and viewcol is %d", trans, split, gnc_numeric_to_string (input), viewcol);
//FIXME ## Trading ## Copied from split-register, needs testing
model = gnc_tree_view_split_reg_get_model_from_view (view);
account = gnc_tree_model_split_reg_get_anchor (model);
if (!account)
account = xaccSplitGetAccount (split);
if (!xaccAccountIsPriced (account))
return;
/* If we are using commodity trading accounts then the value may
not really be the value. Punt if so. */
if (xaccTransUseTradingAccounts (xaccSplitGetParent (split)))
{
gnc_commodity *acc_commodity;
acc_commodity = xaccAccountGetCommodity (account);
if (!(xaccAccountIsPriced (account) || !gnc_commodity_is_iso (acc_commodity)))
return;
}
//FIXME
if (gnc_numeric_zero_p (input))
{
xaccSplitSetValue (split, input);
@ -1503,7 +1546,7 @@ set_number_for_input (GncTreeViewSplitReg *view, Transaction *trans, Split *spli
}
}
if (viewcol == COL_CREDIT || viewcol == COL_DEBIT)
if ((viewcol == COL_CREDIT || viewcol == COL_DEBIT) && !view->priv->expanded)
{
amount_changed = TRUE;
if (gnc_numeric_zero_p (value))
@ -1514,6 +1557,17 @@ set_number_for_input (GncTreeViewSplitReg *view, Transaction *trans, Split *spli
return;
}
}
else if ((viewcol == COL_CREDIT || viewcol == COL_DEBIT) && view->priv->expanded)
{
value_changed = TRUE;
if (gnc_numeric_zero_p (value))
{
xaccSplitSetValue (split, input);
xaccSplitSetAmount (split, input);
LEAVE("");
return;
}
}
DEBUG("value_changed %d, price_changed %d, amount_changed %d", value_changed, price_changed, amount_changed);
@ -1660,29 +1714,31 @@ set_number_for_input (GncTreeViewSplitReg *view, Transaction *trans, Split *spli
value = gnc_numeric_mul (amount, price, denom, GNC_HOW_RND_ROUND_HALF_UP);
xaccSplitSetValue (split, value);
}
}
/* If the number of splits is two, change other split to balance */
if ((xaccTransCountSplits (trans) == 2) && view->priv->expanded)
/* If the number of splits is two, change other split to balance */
if ((xaccTransCountSplits (trans) == 2) && view->priv->expanded)
{
Split *osplit;
gnc_commodity *osplit_com;
osplit = get_other_split (view, trans);
value = xaccSplitGetValue (split);
osplit_com = xaccAccountGetCommodity (xaccSplitGetAccount (osplit));
if (gnc_commodity_is_currency (osplit_com))
{
Split *osplit;
gnc_commodity *split_com;
osplit = get_other_split (view, trans);
split_com = xaccAccountGetCommodity (xaccSplitGetAccount (osplit));
if (gnc_commodity_is_currency (split_com))
if (!gnc_numeric_negative_p (value))
{
if (gnc_numeric_negative_p (value))
{
xaccSplitSetValue (osplit, gnc_numeric_neg (value));
xaccSplitSetAmount (osplit, gnc_numeric_neg (value));
}
else
{
xaccSplitSetValue (osplit, value);
xaccSplitSetAmount (osplit, value);
}
xaccSplitSetValue (osplit, gnc_numeric_neg (value));
xaccSplitSetAmount (osplit, gnc_numeric_neg (value));
}
else
{
xaccSplitSetValue (osplit, value);
xaccSplitSetAmount (osplit, value);
}
}
}
@ -1746,6 +1802,7 @@ get_rate_for (GncTreeViewSplitReg *view, Transaction *trans, Split *split, gbool
static gboolean
get_split_pair (GncTreeViewSplitReg *view, Transaction *trans, Split **osplit, Split **split)
{
GncTreeModelSplitReg *model;
QofBook *book;
gint count = xaccTransCountSplits (trans);
@ -1753,9 +1810,11 @@ get_split_pair (GncTreeViewSplitReg *view, Transaction *trans, Split **osplit, S
book = gnc_get_current_book();
if (count == 0)
model = gnc_tree_view_split_reg_get_model_from_view (view);
if (count == 0) // blank trans
{
*split = xaccMallocSplit (book);
*split = gnc_tree_model_split_get_blank_split (model);
xaccSplitSetAccount (*split, anchor);
xaccSplitSetParent (*split, trans);
*osplit = xaccMallocSplit (book);
@ -2547,7 +2606,7 @@ cdf (GtkTreeViewColumn *col, GtkCellRenderer *cell, GtkTreeModel *s_model,
if (read_only && !open_edited)
g_object_set(cell, "cell-background", REDCELL, (gchar*)NULL);
else if (read_only && open_edited)
g_object_set(cell, "cell-background", YELLOWCELL, (gchar*)NULL);
g_object_set(cell, "cell-background", ORANGECELL, (gchar*)NULL);
else if (xaccTransInFutureByPostedDate (trans))
g_object_set(cell, "cell-background", BLUECELL, (gchar*)NULL);
else
@ -2851,9 +2910,14 @@ transaction_changed_confirm (GncTreeViewSplitReg *view,
"The current transaction has changed. Would you like to "
"record the changes, or discard the changes?");
// Look for dirty_trans not being new_trans.
if (!view->priv->dirty_trans || view->priv->dirty_trans == new_trans)
return FALSE;
// Test if the transaction is balanced.
if (gnc_tree_control_split_reg_balance_trans (view, view->priv->dirty_trans))
return TRUE;
model = gnc_tree_view_split_reg_get_model_from_view (view);
window = gnc_tree_view_split_reg_get_parent (view);
@ -2864,10 +2928,11 @@ transaction_changed_confirm (GncTreeViewSplitReg *view,
"%s", title);
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
"%s", message);
gtk_dialog_add_buttons(
GTK_DIALOG(dialog),_("_Discard Changes"), GTK_RESPONSE_REJECT,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
_("_Record Changes"), GTK_RESPONSE_ACCEPT, NULL);
gtk_dialog_add_buttons (GTK_DIALOG(dialog),_("_Discard Changes"), GTK_RESPONSE_REJECT,
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
_("_Record Changes"), GTK_RESPONSE_ACCEPT, NULL);
response = gnc_dialog_run (GTK_DIALOG (dialog), "transaction_changed");
gtk_widget_destroy (dialog);
@ -3820,6 +3885,7 @@ static gboolean
gtv_split_reg_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
{
GncTreeViewSplitReg *view = GNC_TREE_VIEW_SPLIT_REG (widget);
GncTreeModelSplitReg *model;
GtkTreeViewColumn *col;
GtkTreePath *spath;
@ -3829,6 +3895,8 @@ gtv_split_reg_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user
//g_print("column title is %s and path is %s\n", gtk_tree_view_column_get_title (col), gtk_tree_path_to_string (spath));
model = gnc_tree_view_split_reg_get_model_from_view (view);
if (event->type != GDK_KEY_PRESS)
return FALSE;
@ -3878,12 +3946,32 @@ gtv_split_reg_key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user
/* Have we stepped off the end */
if (!spath || !gnc_tree_view_path_is_valid (GNC_TREE_VIEW (view), spath)) // We have stepped off the end
{
/* no need to restore cursor because we won't move. */
//Only ask for confirmation if data was edited
if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT(view), "data-edited")))
//Ask for confirmation if data has been edited, transaction_changed_confirm return TRUE if canceled
if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (view), "data-edited")) && transaction_changed_confirm (view, NULL))
{
transaction_changed_confirm (GNC_TREE_VIEW_SPLIT_REG (view), NULL);
g_object_set_data (G_OBJECT (view), "data-edited", GINT_TO_POINTER (FALSE));
/* Restore position - Cancel / Discard */
if (view->priv->current_ref != NULL)
{
gtk_tree_row_reference_free (view->priv->current_ref);
view->priv->current_ref = NULL;
}
view->priv->current_ref = gtk_tree_row_reference_copy (view->priv->edit_ref);
// Jump to the first split of dirty_trans.
gnc_tree_control_split_reg_jump_to_split (view, xaccTransGetSplit (view->priv->dirty_trans, 0));
/* Remove the blank split and re-add - done so we keep it last in list */
gnc_tree_model_split_reg_set_blank_split_parent (model, view->priv->dirty_trans, TRUE);
gnc_tree_model_split_reg_set_blank_split_parent (model, view->priv->dirty_trans, FALSE);
// if (xaccTransCountSplits (view->priv->dirty_trans) > 2) //FIXME Maybe we should just expand for split-trans
// {
/* give gtk+ a chance to handle pending events */
while (gtk_events_pending ())
gtk_main_iteration ();
gnc_tree_view_split_reg_expand_trans (view, NULL);
// }
}
}
else
@ -3986,14 +4074,28 @@ gtv_split_reg_motion_cb (GtkTreeSelection *sel, gpointer user_data)
}
view->priv->current_ref = gtk_tree_row_reference_copy (view->priv->edit_ref);
gnc_tree_view_split_reg_default_selection (view);
// Jump to the first split of dirty_trans.
gnc_tree_control_split_reg_jump_to_split (view, xaccTransGetSplit (view->priv->dirty_trans, 0));
/* Remove the blank split and re-add - done so we keep it last in list */
gnc_tree_model_split_reg_set_blank_split_parent (model, view->priv->dirty_trans, TRUE);
gnc_tree_model_split_reg_set_blank_split_parent (model, view->priv->dirty_trans, FALSE);
// if (xaccTransCountSplits (view->priv->dirty_trans) > 2) //FIXME Maybe we should just expand for split-trans
// {
/* give gtk+ a chance to handle pending events */
while (gtk_events_pending ())
gtk_main_iteration ();
gnc_tree_view_split_reg_expand_trans (view, NULL);
// }
return;
}
else
{
{
//g_print("Commit and skip\n");
/* Commit and skip */
/* Move the blank split */
gnc_tree_model_split_reg_set_blank_split_parent (model, trans, FALSE);
}
@ -4093,10 +4195,6 @@ gtv_split_reg_edited_cb (GtkCellRendererText *cell, const gchar *path_string,
model = gnc_tree_view_split_reg_get_model_from_view (view);
g_return_if_fail (model);
//FIXME this may be a hack, blank split is not part of blank trans when entering
// action field in two line mode..
bsplit_action = xaccSplitGetAction (gnc_tree_model_split_get_blank_split (model));
gnc_tree_model_split_reg_get_split_and_trans (
model, &m_iter, &is_trow1, &is_trow2, &is_split, &is_blank, &split, &trans);
@ -4128,6 +4226,10 @@ gtv_split_reg_edited_cb (GtkCellRendererText *cell, const gchar *path_string,
/* set per book option */
gnc_set_num_action (trans, get_this_split (view, trans),
new_text, NULL);
// Set the last number value for this account.
if (gnc_strisnum (new_text))
xaccAccountSetLastNum (xaccSplitGetAccount (get_this_split (view, trans)), new_text);
}
if (is_trow2)
{
@ -4140,7 +4242,13 @@ gtv_split_reg_edited_cb (GtkCellRendererText *cell, const gchar *path_string,
/* Set split-action with gnc_set_num_action which is the same as
* xaccSplitSetAction with these arguments */
gnc_set_num_action (NULL, split, NULL, new_text);
// Set the last number value for this account.
if (gnc_strisnum (new_text))
xaccAccountSetLastNum (xaccSplitGetAccount (split), new_text);
}
break;
case COL_DESCNOTES:
@ -4200,19 +4308,13 @@ gtv_split_reg_edited_cb (GtkCellRendererText *cell, const gchar *path_string,
case COL_DEBIT:
case COL_CREDIT:
{
Account *acct, *old_acct;
gnc_numeric input;
Split *osplit = NULL;
QofBook *book; //do we have this
Account *root; // do we have this
gboolean valid_input = FALSE;
gboolean force = FALSE;
gboolean input_used = FALSE;
book = gnc_get_current_book();
root = gnc_book_get_root_account (book);
gtv_begin_edit (view, NULL, trans);
/* Get the split pair if anchored to a register */
@ -4228,10 +4330,12 @@ gtv_split_reg_edited_cb (GtkCellRendererText *cell, const gchar *path_string,
/* Setup the account field */
if (viewcol == COL_TRANSVOID)
{
if (view->priv->acct_short_names)
acct = gnc_account_lookup_by_name (root, new_text);
else
acct = gnc_account_lookup_by_full_name (root, new_text);
acct = gnc_tree_control_split_reg_get_account_by_name (view, new_text);
if (acct == NULL)
{
PERR("Account is NULL");
break;
}
if (acct != NULL && is_split)
{
@ -4247,9 +4351,6 @@ gtv_split_reg_edited_cb (GtkCellRendererText *cell, const gchar *path_string,
if (!gnc_commodity_equiv (xaccAccountGetCommodity (old_acct), xaccAccountGetCommodity (acct)))
force = TRUE;
}
//FIXME see above...
if (bsplit_action != NULL)
xaccSplitSetAction (split, bsplit_action);
}
else
{
@ -4356,6 +4457,70 @@ gtv_split_reg_edited_cb (GtkCellRendererText *cell, const gchar *path_string,
}
/* Callback for Account seperator key */
static void
gtv_split_reg_acct_cb (GtkEntry *entry,
const gchar *text,
gint length,
gint *position,
gpointer user_data)
{
GtkEditable *editable = GTK_EDITABLE (entry);
GncTreeViewSplitReg *view = GNC_TREE_VIEW_SPLIT_REG (user_data);
GtkEntryCompletion *completion;
GtkTreeModel *model;
GtkTreeIter iter;
const gchar *sep_char;
const gchar *entered_string;
gchar *item = NULL;
gboolean valid;
entered_string = gtk_editable_get_chars (editable, 0, -1);
sep_char = gnc_get_account_separator_string ();
if (g_strcmp0 (text, sep_char) != 0) // test for seperator char.
return;
// Get the completion and model
completion = gtk_entry_get_completion (entry);
model = gtk_entry_completion_get_model (completion);
// Get the first item in the list
valid = gtk_tree_model_get_iter_first (model, &iter);
while (valid)
{
// Walk through the list, reading each row
if (view->priv->acct_short_names)
gtk_tree_model_get (model, &iter, 0, &item, -1);
else
gtk_tree_model_get (model, &iter, 1, &item, -1);
if (g_str_has_prefix (g_utf8_strdown (item, -1), g_utf8_strdown (entered_string, -1)))
{
if (g_utf8_strlen (entered_string, -1) < g_utf8_strlen (item, -1))
break;
}
valid = gtk_tree_model_iter_next (model, &iter);
}
g_signal_handlers_block_by_func (editable, (gpointer) gtv_split_reg_acct_cb, user_data);
gtk_editable_delete_text (editable, 0, -1);
gtk_editable_set_position (editable, 0);
if (strlen (entered_string) == 1)
gtk_editable_insert_text (editable, item, -1, position);
else
gtk_editable_insert_text (editable, g_strconcat(item, sep_char, NULL), -1, position);
g_signal_handlers_unblock_by_func (editable, (gpointer) gtv_split_reg_acct_cb, user_data);
g_signal_stop_emission_by_name (editable, "insert_text");
}
/* Callback for changing reconcile setting with space bar */
static void
gtv_split_reg_recn_cb (GtkEntry *entry,
@ -4503,17 +4668,19 @@ gtv_get_editable_start_editing_cb (GtkCellRenderer *cr, GtkCellEditable *editabl
gtk_entry_completion_set_popup_completion (completion, TRUE);
gtk_entry_completion_set_inline_selection (completion, TRUE);
gtk_entry_completion_set_popup_set_width (completion, FALSE);
gtk_entry_completion_set_minimum_key_length (completion, KEY_LENGTH);
gtk_entry_completion_set_minimum_key_length (completion, 1);
//?? g_signal_connect(G_OBJECT(completion), "match-selected", (GCallback) gtv_split_reg_match_selected_cb, view);
g_object_unref (completion);
//Copy the string in the GtkEntry for later comparison
g_object_set_data(G_OBJECT (cr), "current-string", g_strdup (gtk_entry_get_text (entry)));
g_signal_connect (G_OBJECT (GTK_ENTRY (entry)), "insert_text", (GCallback) gtv_split_reg_acct_cb, view);
//?? g_signal_connect (G_OBJECT (cr), "changed", (GCallback) gtv_split_reg_changed_cb, view);
g_signal_connect (G_OBJECT (editable), "remove-widget", (GCallback) remove_edit_combo, view);
DEBUG("Current String tv is '%s'", g_strdup(gtk_entry_get_text (entry)));
DEBUG("Current String tv is '%s'", g_strdup (gtk_entry_get_text (entry)));
}
/* NUMBER / ACTION COLUMN */
@ -4902,7 +5069,6 @@ gnc_tree_view_split_reg_delete_current_split (GncTreeViewSplitReg *view)
void
gnc_tree_view_split_reg_delete_current_trans (GncTreeViewSplitReg *view)
{
GncTreeModelSplitReg *model;
Transaction *trans;
gboolean was_open;
@ -4935,12 +5101,31 @@ gnc_tree_view_split_reg_delete_current_trans (GncTreeViewSplitReg *view)
gboolean
gnc_tree_view_split_reg_enter (GncTreeViewSplitReg *view)
{
GncTreeModelSplitReg *model;
model = gnc_tree_view_split_reg_get_model_from_view (view);
/* Make sure we have stopped editing */
gnc_tree_view_split_reg_finish_edit (view);
/* Ask for confirmation if data has been edited, transaction_changed_confirm return TRUE if canceled */
if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (view), "data-edited")) && transaction_changed_confirm (view, NULL))
{
// Jump to the first split of dirty_trans.
gnc_tree_control_split_reg_jump_to_split (view, xaccTransGetSplit (view->priv->dirty_trans, 0));
/* Remove the blank split and re-add - done so we keep it last in list */
gnc_tree_model_split_reg_set_blank_split_parent (model, view->priv->dirty_trans, TRUE);
gnc_tree_model_split_reg_set_blank_split_parent (model, view->priv->dirty_trans, FALSE);
// if (xaccTransCountSplits (view->priv->dirty_trans) > 2) //FIXME Maybe we should just expand for split-trans
// {
/* give gtk+ a chance to handle pending events */
while (gtk_events_pending ())
gtk_main_iteration ();
gnc_tree_view_split_reg_expand_trans (view, NULL);
// }
return FALSE;
}
return TRUE;
@ -4986,6 +5171,11 @@ gnc_tree_view_split_reg_cancel_edit (GncTreeViewSplitReg *view, gboolean reg_clo
view->change_allowed = FALSE;
view->priv->auto_complete = FALSE; // reset auto_complete has run flag
/* This updates the plugin page gui */
if (view->moved_cb)
(view->moved_cb)(view, view->moved_cb_data);
LEAVE(" ");
}
@ -5110,6 +5300,11 @@ gnc_tree_view_split_reg_collapse_trans (GncTreeViewSplitReg *view, Transaction *
gtk_tree_path_free (spath);
view->priv->expanded = FALSE;
/* This updates the plugin page gui */
if (view->moved_cb)
(view->moved_cb)(view, view->moved_cb_data);
LEAVE(" ");
}
@ -5145,6 +5340,10 @@ gnc_tree_view_split_reg_expand_trans (GncTreeViewSplitReg *view, Transaction *tr
gtk_tree_path_free (mpath);
gtk_tree_path_free (spath);
/* This updates the plugin page gui */
if (view->moved_cb)
(view->moved_cb)(view, view->moved_cb_data);
LEAVE(" ");
}

View File

@ -3130,8 +3130,12 @@ gnc_plugin_page_register2_cmd_jump (GtkAction *action,
split = gnc_tree_view_split_reg_get_current_split (view);
if (split == NULL)
{
LEAVE("split is NULL");
return;
split = gnc_tree_control_split_reg_get_current_trans_split (view);
if (split == NULL)
{
LEAVE("split is NULL");
return;
}
}
if (!gnc_tree_view_split_reg_trans_expanded (view, NULL))